Skip to content

Commit 571b1d1

Browse files
authored
Get-SqlDscLogin: command to retrieve SQL Server logins (#2134)
1 parent 14c5107 commit 571b1d1

File tree

6 files changed

+466
-0
lines changed

6 files changed

+466
-0
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
exists as a login, throwing a terminating error if it doesn't exist.
1616
- Supports pipeline input and provides detailed error messages with localization.
1717
- Uses `Test-SqlDscIsLogin` command for login validation following module patterns.
18+
- `Get-SqlDscLogin`
19+
- Added new public command to get a SQL Server login from a Database Engine instance.
20+
- Returns a `Microsoft.SqlServer.Management.Smo.Login` object that represents
21+
the login.
22+
- Supports getting a specific login by name or all logins if no name is specified.
23+
- Includes a `-Refresh` parameter to refresh the server's login collection
24+
before retrieval.
1825

1926
### Changed
2027

azure-pipelines.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ stages:
249249
'tests/Integration/Commands/Connect-SqlDscDatabaseEngine.Integration.Tests.ps1'
250250
# Group 2
251251
'tests/Integration/Commands/Assert-SqlDscLogin.Integration.Tests.ps1'
252+
'tests/Integration/Commands/Get-SqlDscLogin.Integration.Tests.ps1'
252253
# Group 9
253254
'tests/Integration/Commands/Uninstall-SqlDscServer.Integration.Tests.ps1'
254255
)

source/Public/Get-SqlDscLogin.ps1

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<#
2+
.SYNOPSIS
3+
Gets SQL Server logins.
4+
5+
.DESCRIPTION
6+
Retrieves login objects from a SQL Server Database Engine instance. Specify -Name
7+
to return a specific login, or omit -Name to return all logins. Use -Refresh to
8+
refresh the login collection before retrieval.
9+
10+
.PARAMETER ServerObject
11+
Specifies the current server connection object.
12+
.PARAMETER Name
13+
Specifies the name of the server login to get.
14+
15+
.PARAMETER Refresh
16+
Specifies that the **ServerObject** logins should be refreshed before
17+
trying to get the login object. This is helpful when logins might have
18+
been modified outside of the **ServerObject**, for example through T-SQL.
19+
On instances with a large number of logins, consider ensuring the
20+
**ServerObject** is recent enough.
21+
22+
.EXAMPLE
23+
$serverObject = Connect-SqlDscDatabaseEngine -InstanceName 'MyInstance'
24+
$serverObject | Get-SqlDscLogin -Name 'MyLogin'
25+
26+
Get the login named **MyLogin**.
27+
28+
.OUTPUTS
29+
`[Microsoft.SqlServer.Management.Smo.Login]`
30+
31+
Returns a single Login object when the Name parameter is specified and a
32+
match is found.
33+
34+
.OUTPUTS
35+
`[Microsoft.SqlServer.Management.Smo.Login[]]`
36+
37+
Returns an array of Login objects when the Name parameter is not specified
38+
(returns all logins) or when multiple matches are found.
39+
#>
40+
function Get-SqlDscLogin
41+
{
42+
[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.')]
43+
[OutputType([Microsoft.SqlServer.Management.Smo.Login[]])]
44+
[CmdletBinding()]
45+
param
46+
(
47+
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
48+
[Microsoft.SqlServer.Management.Smo.Server]
49+
$ServerObject,
50+
51+
[Parameter()]
52+
[System.String]
53+
$Name,
54+
55+
[Parameter()]
56+
[System.Management.Automation.SwitchParameter]
57+
$Refresh
58+
)
59+
60+
process
61+
{
62+
if ($Refresh.IsPresent)
63+
{
64+
Write-Verbose -Message ($script:localizedData.Login_Get_RefreshingLogins -f $ServerObject.InstanceName)
65+
66+
# Make sure the logins are up-to-date to get any newly created logins.
67+
$ServerObject.Logins.Refresh()
68+
}
69+
70+
$loginObject = @()
71+
72+
if ($PSBoundParameters.ContainsKey('Name'))
73+
{
74+
Write-Verbose -Message ($script:localizedData.Login_Get_RetrievingByName -f $Name, $ServerObject.InstanceName)
75+
76+
$loginObject = $ServerObject.Logins[$Name]
77+
78+
if (-not $loginObject)
79+
{
80+
$missingLoginMessage = $script:localizedData.Login_Get_Missing -f $Name
81+
82+
$writeErrorParameters = @{
83+
Message = $missingLoginMessage
84+
Category = 'ObjectNotFound'
85+
ErrorId = 'GSDL0001' # cspell: disable-line
86+
TargetObject = $Name
87+
}
88+
89+
Write-Error @writeErrorParameters
90+
}
91+
}
92+
else
93+
{
94+
Write-Verbose -Message ($script:localizedData.Login_Get_ReturningAllLogins -f $ServerObject.InstanceName)
95+
96+
$loginObject = $ServerObject.Logins
97+
}
98+
99+
return [Microsoft.SqlServer.Management.Smo.Login[]] $loginObject
100+
}
101+
}

source/en-US/SqlServerDsc.strings.psd1

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ ConvertFrom-StringData @'
6161
## Get-SqlDscAudit
6262
Audit_Missing = There is no audit with the name '{0}'.
6363
64+
## Get-SqlDscLogin
65+
Login_Get_Missing = There is no login with the name '{0}'.
66+
Login_Get_RefreshingLogins = Refreshing logins on server '{0}'.
67+
Login_Get_RetrievingByName = Retrieving login by name '{0}' from server '{1}'.
68+
Login_Get_ReturningAllLogins = Returning all logins from server '{0}'.
69+
6470
## Remove-SqlDscAudit
6571
Audit_Remove_ShouldProcessVerboseDescription = Removing the audit '{0}' on the instance '{1}'.
6672
Audit_Remove_ShouldProcessVerboseWarning = Are you sure you want to remove the audit '{0}'?
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')]
2+
param ()
3+
4+
BeforeDiscovery {
5+
try
6+
{
7+
if (-not (Get-Module -Name 'DscResource.Test'))
8+
{
9+
# Assumes dependencies have been resolved, so if this module is not available, run 'noop' task.
10+
if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable))
11+
{
12+
# Redirect all streams to $null, except the error stream (stream 2)
13+
& "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null
14+
}
15+
16+
# If the dependencies have not been resolved, this will throw an error.
17+
Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop'
18+
}
19+
}
20+
catch [System.IO.FileNotFoundException]
21+
{
22+
throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.'
23+
}
24+
}
25+
26+
BeforeAll {
27+
$script:dscModuleName = 'SqlServerDsc'
28+
29+
Import-Module -Name $script:dscModuleName
30+
}
31+
32+
Describe 'Get-SqlDscLogin' -Tag @('Integration_SQL2016', 'Integration_SQL2017', 'Integration_SQL2019', 'Integration_SQL2022') {
33+
BeforeAll {
34+
# Starting the named instance SQL Server service prior to running tests.
35+
Start-Service -Name 'MSSQL$DSCSQLTEST' -Verbose -ErrorAction 'Stop'
36+
37+
$script:mockInstanceName = 'DSCSQLTEST'
38+
$script:mockComputerName = Get-ComputerName
39+
40+
$mockSqlAdministratorUserName = 'SqlAdmin' # Using computer name as NetBIOS name throw exception.
41+
$mockSqlAdministratorPassword = ConvertTo-SecureString -String 'P@ssw0rd1' -AsPlainText -Force
42+
43+
$script:mockSqlAdminCredential = [System.Management.Automation.PSCredential]::new($mockSqlAdministratorUserName, $mockSqlAdministratorPassword)
44+
45+
$script:serverObject = Connect-SqlDscDatabaseEngine -InstanceName $script:mockInstanceName -Credential $script:mockSqlAdminCredential
46+
}
47+
48+
AfterAll {
49+
# Stop the named instance SQL Server service to save memory on the build worker.
50+
Stop-Service -Name 'MSSQL$DSCSQLTEST' -Verbose -ErrorAction 'Stop'
51+
}
52+
53+
54+
Context 'When getting all SQL Server logins' {
55+
It 'Should return an array of Login objects' {
56+
$result = Get-SqlDscLogin -ServerObject $script:serverObject
57+
58+
<#
59+
Casting to array to ensure we get the count on Windows PowerShell
60+
when there is only one login.
61+
#>
62+
@($result).Count | Should -BeGreaterOrEqual 1
63+
@($result)[0] | Should -BeOfType 'Microsoft.SqlServer.Management.Smo.Login'
64+
}
65+
66+
It 'Should return system logins including sa' {
67+
$result = Get-SqlDscLogin -ServerObject $script:serverObject
68+
69+
$result.Name | Should -Contain 'sa'
70+
}
71+
}
72+
73+
Context 'When getting a specific SQL Server login' {
74+
It 'Should return the specified login when it exists' {
75+
$result = Get-SqlDscLogin -ServerObject $script:serverObject -Name 'sa'
76+
77+
$result | Should -BeOfType 'Microsoft.SqlServer.Management.Smo.Login'
78+
$result.Name | Should -Be 'sa'
79+
$result.LoginType | Should -Be 'SqlLogin'
80+
}
81+
82+
It 'Should throw an error when the login does not exist' {
83+
{ Get-SqlDscLogin -ServerObject $script:serverObject -Name 'NonExistentLogin' -ErrorAction 'Stop' } |
84+
Should -Throw -ExpectedMessage 'There is no login with the name ''NonExistentLogin''.'
85+
}
86+
87+
It 'Should return null when the login does not exist and error action is SilentlyContinue' {
88+
$result = Get-SqlDscLogin -ServerObject $script:serverObject -Name 'NonExistentLogin' -ErrorAction 'SilentlyContinue'
89+
90+
$result | Should -BeNullOrEmpty
91+
}
92+
}
93+
94+
Context 'When using the Refresh parameter' {
95+
It 'Should return the same results with and without Refresh' {
96+
$resultWithoutRefresh = Get-SqlDscLogin -ServerObject $script:serverObject
97+
$resultWithRefresh = Get-SqlDscLogin -ServerObject $script:serverObject -Refresh
98+
99+
@($resultWithoutRefresh).Count | Should -Be @($resultWithRefresh).Count
100+
}
101+
}
102+
103+
Context 'When using pipeline input' {
104+
It 'Should accept ServerObject from pipeline' {
105+
$result = $script:serverObject | Get-SqlDscLogin -Name 'sa'
106+
107+
$result | Should -BeOfType 'Microsoft.SqlServer.Management.Smo.Login'
108+
$result.Name | Should -Be 'sa'
109+
}
110+
}
111+
}

0 commit comments

Comments
 (0)