Skip to content

Commit ea52565

Browse files
committed
Get-SqlDscLogin: function to retrieve SQL Server logins
1 parent 14c5107 commit ea52565

File tree

6 files changed

+451
-0
lines changed

6 files changed

+451
-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: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<#
2+
.SYNOPSIS
3+
Get server login.
4+
5+
.DESCRIPTION
6+
This command gets a server login from a SQL Server Database Engine instance.
7+
8+
.PARAMETER ServerObject
9+
Specifies current server connection object.
10+
11+
.PARAMETER Name
12+
Specifies the name of the server login to get.
13+
14+
.PARAMETER Refresh
15+
Specifies that the **ServerObject**'s logins should be refreshed before
16+
trying get the login object. This is helpful when logins could have been
17+
modified outside of the **ServerObject**, for example through T-SQL. But
18+
on instances with a large amount of logins it might be better to make
19+
sure the **ServerObject** is recent enough, or pass in **LoginObject**.
20+
21+
.EXAMPLE
22+
$serverObject = Connect-SqlDscDatabaseEngine -InstanceName 'MyInstance'
23+
$serverObject | Get-SqlDscLogin -Name 'MyLogin'
24+
25+
Get the login named **MyLogin**.
26+
27+
.OUTPUTS
28+
`[Microsoft.SqlServer.Management.Smo.Login]`
29+
#>
30+
function Get-SqlDscLogin
31+
{
32+
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseOutputTypeCorrectly', '', Justification = 'Because the rule does not understands that the command returns [System.String[]] when using , (comma) in the return statement')]
33+
[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.')]
34+
[OutputType([Microsoft.SqlServer.Management.Smo.Login[]])]
35+
[CmdletBinding()]
36+
param
37+
(
38+
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
39+
[Microsoft.SqlServer.Management.Smo.Server]
40+
$ServerObject,
41+
42+
[Parameter()]
43+
[System.String]
44+
$Name,
45+
46+
[Parameter()]
47+
[System.Management.Automation.SwitchParameter]
48+
$Refresh
49+
)
50+
51+
process
52+
{
53+
if ($Refresh.IsPresent)
54+
{
55+
# Make sure the logins are up-to-date to get any newly created logins.
56+
$ServerObject.Logins.Refresh()
57+
}
58+
59+
$loginObject = @()
60+
61+
if ($PSBoundParameters.ContainsKey('Name'))
62+
{
63+
$loginObject = $ServerObject.Logins[$Name]
64+
65+
if (-not $loginObject)
66+
{
67+
$missingLoginMessage = $script:localizedData.Login_Missing -f $Name
68+
69+
$writeErrorParameters = @{
70+
Message = $missingLoginMessage
71+
Category = 'InvalidOperation'
72+
ErrorId = 'GSDL0001' # cspell: disable-line
73+
TargetObject = $Name
74+
}
75+
76+
Write-Error @writeErrorParameters
77+
}
78+
}
79+
else
80+
{
81+
$loginObject = $ServerObject.Logins
82+
}
83+
84+
return [Microsoft.SqlServer.Management.Smo.Login[]] $loginObject
85+
}
86+
}

source/en-US/SqlServerDsc.strings.psd1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ ConvertFrom-StringData @'
6161
## Get-SqlDscAudit
6262
Audit_Missing = There is no audit with the name '{0}'.
6363
64+
## Get-SqlDscLogin
65+
Login_Missing = There is no login with the name '{0}'.
66+
6467
## Remove-SqlDscAudit
6568
Audit_Remove_ShouldProcessVerboseDescription = Removing the audit '{0}' on the instance '{1}'.
6669
Audit_Remove_ShouldProcessVerboseWarning = Are you sure you want to remove the audit '{0}'?
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
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 has 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 has 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+
# Loading stub cmdlets
32+
Import-Module -Name "$PSScriptRoot/../../Stubs/SqlServerStub.psm1" -Force
33+
34+
$PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscModuleName
35+
$PSDefaultParameterValues['Mock:ModuleName'] = $script:dscModuleName
36+
$PSDefaultParameterValues['Should:ModuleName'] = $script:dscModuleName
37+
}
38+
39+
AfterAll {
40+
$PSDefaultParameterValues.Remove('InModuleScope:ModuleName')
41+
$PSDefaultParameterValues.Remove('Mock:ModuleName')
42+
$PSDefaultParameterValues.Remove('Should:ModuleName')
43+
44+
# Unload the module being tested so that it doesn't impact any other tests.
45+
Get-Module -Name $script:dscModuleName -All | Remove-Module -Force
46+
}
47+
48+
Describe 'Get-SqlDscLogin' -Tag @('Integration_SQL2016', 'Integration_SQL2017', 'Integration_SQL2019', 'Integration_SQL2022') {
49+
BeforeAll {
50+
$mockInstanceName = $env:COMPUTERNAME
51+
$mockSqlCredential = $null
52+
$mockConnectTimeout = 30
53+
$mockEncryptConnection = $true
54+
55+
if ($env:INTEGRATION_TESTS_SQLSERVER_CREDENTIAL)
56+
{
57+
<#
58+
This is set by the pipeline so we can run the tests towards the
59+
SQL Server instance on the AppVeyor build worker.
60+
#>
61+
$mockSqlCredential = (ConvertFrom-Json -InputObject $env:INTEGRATION_TESTS_SQLSERVER_CREDENTIAL)
62+
}
63+
64+
try
65+
{
66+
$serverObject = Connect-SqlDscDatabaseEngine -InstanceName $mockInstanceName -Credential $mockSqlCredential -ConnectTimeout $mockConnectTimeout -EncryptConnection $mockEncryptConnection
67+
}
68+
catch
69+
{
70+
Set-ItResult -Skip -Because 'Could not connect to SQL Server instance'
71+
}
72+
}
73+
74+
Context 'When getting all SQL Server logins' {
75+
It 'Should return an array of Login objects' {
76+
$result = Get-SqlDscLogin -ServerObject $serverObject
77+
78+
<#
79+
Casting to array to ensure we get the count on Windows PowerShell
80+
when there is only one login.
81+
#>
82+
@($result).Count | Should -BeGreaterOrEqual 1
83+
$result[0] | Should -BeOfType 'Microsoft.SqlServer.Management.Smo.Login'
84+
}
85+
86+
It 'Should return system logins including sa' {
87+
$result = Get-SqlDscLogin -ServerObject $serverObject
88+
89+
$result.Name | Should -Contain 'sa'
90+
}
91+
}
92+
93+
Context 'When getting a specific SQL Server login' {
94+
It 'Should return the specified login when it exists' {
95+
$result = Get-SqlDscLogin -ServerObject $serverObject -Name 'sa'
96+
97+
$result | Should -BeOfType 'Microsoft.SqlServer.Management.Smo.Login'
98+
$result.Name | Should -Be 'sa'
99+
$result.LoginType | Should -Be 'SqlLogin'
100+
}
101+
102+
It 'Should throw an error when the login does not exist' {
103+
{ Get-SqlDscLogin -ServerObject $serverObject -Name 'NonExistentLogin' -ErrorAction 'Stop' } |
104+
Should -Throw -ExpectedMessage "There is no login with the name 'NonExistentLogin'."
105+
}
106+
107+
It 'Should return null when the login does not exist and error action is SilentlyContinue' {
108+
$result = Get-SqlDscLogin -ServerObject $serverObject -Name 'NonExistentLogin' -ErrorAction 'SilentlyContinue'
109+
110+
$result | Should -BeNullOrEmpty
111+
}
112+
}
113+
114+
Context 'When using the Refresh parameter' {
115+
It 'Should return the same results with and without Refresh' {
116+
$resultWithoutRefresh = Get-SqlDscLogin -ServerObject $serverObject
117+
$resultWithRefresh = Get-SqlDscLogin -ServerObject $serverObject -Refresh
118+
119+
$resultWithoutRefresh.Count | Should -Be $resultWithRefresh.Count
120+
}
121+
}
122+
123+
Context 'When using pipeline input' {
124+
It 'Should accept ServerObject from pipeline' {
125+
$result = $serverObject | Get-SqlDscLogin -Name 'sa'
126+
127+
$result | Should -BeOfType 'Microsoft.SqlServer.Management.Smo.Login'
128+
$result.Name | Should -Be 'sa'
129+
}
130+
}
131+
}

0 commit comments

Comments
 (0)