Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ea52565
`Get-SqlDscLogin`: function to retrieve SQL Server logins
johlju Aug 14, 2025
e382411
Force import of SqlServerDsc module in test setup
johlju Aug 14, 2025
66a4d34
Remove unnecessary stub cmdlet loading and cleanup from Get-SqlDscLog…
johlju Aug 15, 2025
15d6926
Fix connection
johlju Aug 15, 2025
b713731
Rename error message for missing login in Get-SqlDscLogin to improve …
johlju Aug 15, 2025
ccd0a7f
Remove reference to passing **LoginObject** in Get-SqlDscLogin docume…
johlju Aug 15, 2025
8f3d576
Remove unnecessary suppression of PSUseOutputTypeCorrectly warning in…
johlju Aug 15, 2025
da84289
Fix array access syntax in Get-SqlDscLogin integration tests for type…
johlju Aug 15, 2025
a21c6d2
Fix expected error message format in Get-SqlDscLogin integration test…
johlju Aug 15, 2025
452005a
Fix array count comparison in Get-SqlDscLogin integration tests to en…
johlju Aug 15, 2025
12614f0
Refactor Get-SqlDscLogin integration tests to use script-scoped varia…
johlju Aug 15, 2025
4519969
Update documentation for Get-SqlDscLogin to clarify output types and …
johlju Aug 16, 2025
45a8000
Fix comments for clarity and consistency in Get-SqlDscLogin integrati…
johlju Aug 16, 2025
33dc0e2
Fix comments for clarity and correct grammatical errors in Get-SqlDsc…
johlju Aug 16, 2025
72d1c69
Change error category from 'InvalidOperation' to 'ObjectNotFound' in …
johlju Aug 16, 2025
1c03af1
Add tests for parameter metadata in Get-SqlDscLogin function
johlju Aug 16, 2025
22e3e7a
Update source/Public/Get-SqlDscLogin.ps1
johlju Aug 16, 2025
7606c11
Update source/Public/Get-SqlDscLogin.ps1
johlju Aug 16, 2025
3b68e4d
Update source/Public/Get-SqlDscLogin.ps1
johlju Aug 16, 2025
7c31fd9
Update source/Public/Get-SqlDscLogin.ps1
johlju Aug 16, 2025
7bad8de
Add verbose logging for login retrieval in Get-SqlDscLogin function
johlju Aug 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
exists as a login, throwing a terminating error if it doesn't exist.
- Supports pipeline input and provides detailed error messages with localization.
- Uses `Test-SqlDscIsLogin` command for login validation following module patterns.
- `Get-SqlDscLogin`
- Added new public command to get a SQL Server login from a Database Engine instance.
- Returns a `Microsoft.SqlServer.Management.Smo.Login` object that represents
the login.
- Supports getting a specific login by name or all logins if no name is specified.
- Includes a `-Refresh` parameter to refresh the server's login collection
before retrieval.

### Changed

Expand Down
1 change: 1 addition & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ stages:
'tests/Integration/Commands/Connect-SqlDscDatabaseEngine.Integration.Tests.ps1'
# Group 2
'tests/Integration/Commands/Assert-SqlDscLogin.Integration.Tests.ps1'
'tests/Integration/Commands/Get-SqlDscLogin.Integration.Tests.ps1'
# Group 9
'tests/Integration/Commands/Uninstall-SqlDscServer.Integration.Tests.ps1'
)
Expand Down
94 changes: 94 additions & 0 deletions source/Public/Get-SqlDscLogin.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<#
.SYNOPSIS
Get server login.

.DESCRIPTION
This command gets a server login from a SQL Server Database Engine instance.
Comment thread
johlju marked this conversation as resolved.
Outdated

.PARAMETER ServerObject
Specifies current server connection object.

Comment thread
johlju marked this conversation as resolved.
Outdated
.PARAMETER Name
Specifies the name of the server login to get.

.PARAMETER Refresh
Specifies that the **ServerObject**'s logins should be refreshed before
trying get the login object. This is helpful when logins could have been
modified outside of the **ServerObject**, for example through T-SQL. But
on instances with a large amount of logins it might be better to make
sure the **ServerObject** is recent enough.
Comment thread
johlju marked this conversation as resolved.
Outdated

.EXAMPLE
$serverObject = Connect-SqlDscDatabaseEngine -InstanceName 'MyInstance'
$serverObject | Get-SqlDscLogin -Name 'MyLogin'

Get the login named **MyLogin**.

.OUTPUTS
`[Microsoft.SqlServer.Management.Smo.Login]`

Returns a single Login object when the Name parameter is specified and a
match is found.

.OUTPUTS
`[Microsoft.SqlServer.Management.Smo.Login[]]`

Returns an array of Login objects when the Name parameter is not specified
(returns all logins) or when multiple matches are found.
#>
Comment thread
johlju marked this conversation as resolved.
Comment thread
johlju marked this conversation as resolved.
Comment thread
johlju marked this conversation as resolved.
function Get-SqlDscLogin
{
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the rule does not yet support parsing the code when a parameter type is not available. The ScriptAnalyzer rule UseSyntacticallyCorrectExamples will always error in the editor due to https://github.com/indented-automation/Indented.ScriptAnalyzerRules/issues/8.')]
[OutputType([Microsoft.SqlServer.Management.Smo.Login[]])]
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[Microsoft.SqlServer.Management.Smo.Server]
$ServerObject,

[Parameter()]
[System.String]
$Name,

[Parameter()]
[System.Management.Automation.SwitchParameter]
$Refresh
)

process
{
if ($Refresh.IsPresent)
{
# Make sure the logins are up-to-date to get any newly created logins.
$ServerObject.Logins.Refresh()
}

Comment thread
johlju marked this conversation as resolved.
$loginObject = @()

if ($PSBoundParameters.ContainsKey('Name'))
{
$loginObject = $ServerObject.Logins[$Name]

if (-not $loginObject)
{
$missingLoginMessage = $script:localizedData.Login_Get_Missing -f $Name

$writeErrorParameters = @{
Message = $missingLoginMessage
Category = 'ObjectNotFound'
ErrorId = 'GSDL0001' # cspell: disable-line
TargetObject = $Name
}

Write-Error @writeErrorParameters
}
Comment thread
johlju marked this conversation as resolved.
}
Comment thread
johlju marked this conversation as resolved.
else
{
$loginObject = $ServerObject.Logins
}

return [Microsoft.SqlServer.Management.Smo.Login[]] $loginObject
}
}
3 changes: 3 additions & 0 deletions source/en-US/SqlServerDsc.strings.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ ConvertFrom-StringData @'
## Get-SqlDscAudit
Audit_Missing = There is no audit with the name '{0}'.

## Get-SqlDscLogin
Login_Get_Missing = There is no login with the name '{0}'.

Comment thread
johlju marked this conversation as resolved.
## Remove-SqlDscAudit
Audit_Remove_ShouldProcessVerboseDescription = Removing the audit '{0}' on the instance '{1}'.
Audit_Remove_ShouldProcessVerboseWarning = Are you sure you want to remove the audit '{0}'?
Expand Down
111 changes: 111 additions & 0 deletions tests/Integration/Commands/Get-SqlDscLogin.Integration.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')]
param ()

BeforeDiscovery {
try
{
if (-not (Get-Module -Name 'DscResource.Test'))
{
# Assumes dependencies have been resolved, so if this module is not available, run 'noop' task.
if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable))
{
# Redirect all streams to $null, except the error stream (stream 2)
& "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null
}

# If the dependencies have not been resolved, this will throw an error.
Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop'
}
}
catch [System.IO.FileNotFoundException]
{
throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.'
}
}

BeforeAll {
$script:dscModuleName = 'SqlServerDsc'

Import-Module -Name $script:dscModuleName
}

Describe 'Get-SqlDscLogin' -Tag @('Integration_SQL2016', 'Integration_SQL2017', 'Integration_SQL2019', 'Integration_SQL2022') {
BeforeAll {
# Starting the named instance SQL Server service prior to running tests.
Start-Service -Name 'MSSQL$DSCSQLTEST' -Verbose -ErrorAction 'Stop'

$script:mockInstanceName = 'DSCSQLTEST'
$script:mockComputerName = Get-ComputerName

$mockSqlAdministratorUserName = 'SqlAdmin' # Using computer name as NetBIOS name throw exception.
Comment thread
johlju marked this conversation as resolved.
$mockSqlAdministratorPassword = ConvertTo-SecureString -String 'P@ssw0rd1' -AsPlainText -Force

$script:mockSqlAdminCredential = [System.Management.Automation.PSCredential]::new($mockSqlAdministratorUserName, $mockSqlAdministratorPassword)

$script:serverObject = Connect-SqlDscDatabaseEngine -InstanceName $script:mockInstanceName -Credential $script:mockSqlAdminCredential
}

AfterAll {
# Stop the named instance SQL Server service to save memory on the build worker.
Stop-Service -Name 'MSSQL$DSCSQLTEST' -Verbose -ErrorAction 'Stop'
}


Context 'When getting all SQL Server logins' {
It 'Should return an array of Login objects' {
$result = Get-SqlDscLogin -ServerObject $script:serverObject

<#
Casting to array to ensure we get the count on Windows PowerShell
when there is only one login.
#>
@($result).Count | Should -BeGreaterOrEqual 1
@($result)[0] | Should -BeOfType 'Microsoft.SqlServer.Management.Smo.Login'
}

Comment thread
johlju marked this conversation as resolved.
It 'Should return system logins including sa' {
$result = Get-SqlDscLogin -ServerObject $script:serverObject

$result.Name | Should -Contain 'sa'
}
Comment thread
johlju marked this conversation as resolved.
}

Context 'When getting a specific SQL Server login' {
It 'Should return the specified login when it exists' {
$result = Get-SqlDscLogin -ServerObject $script:serverObject -Name 'sa'

$result | Should -BeOfType 'Microsoft.SqlServer.Management.Smo.Login'
$result.Name | Should -Be 'sa'
$result.LoginType | Should -Be 'SqlLogin'
}

It 'Should throw an error when the login does not exist' {
{ Get-SqlDscLogin -ServerObject $script:serverObject -Name 'NonExistentLogin' -ErrorAction 'Stop' } |
Should -Throw -ExpectedMessage 'There is no login with the name ''NonExistentLogin''.'
}
Comment thread
johlju marked this conversation as resolved.

It 'Should return null when the login does not exist and error action is SilentlyContinue' {
$result = Get-SqlDscLogin -ServerObject $script:serverObject -Name 'NonExistentLogin' -ErrorAction 'SilentlyContinue'

$result | Should -BeNullOrEmpty
}
}

Context 'When using the Refresh parameter' {
It 'Should return the same results with and without Refresh' {
$resultWithoutRefresh = Get-SqlDscLogin -ServerObject $script:serverObject
$resultWithRefresh = Get-SqlDscLogin -ServerObject $script:serverObject -Refresh

@($resultWithoutRefresh).Count | Should -Be @($resultWithRefresh).Count
}
Comment thread
johlju marked this conversation as resolved.
}

Context 'When using pipeline input' {
It 'Should accept ServerObject from pipeline' {
$result = $script:serverObject | Get-SqlDscLogin -Name 'sa'

$result | Should -BeOfType 'Microsoft.SqlServer.Management.Smo.Login'
$result.Name | Should -Be 'sa'
}
}
}
Loading
Loading