From 9edeabb6b6902ac5277acf585252659911f7a42d Mon Sep 17 00:00:00 2001 From: cai-n Date: Fri, 13 Feb 2026 17:13:34 +0100 Subject: [PATCH 01/13] add sid parameter to SqlLogin --- .../DSC_SqlLogin/DSC_SqlLogin.psm1 | 39 ++++++++++++++-- .../DSC_SqlLogin/DSC_SqlLogin.schema.mof | 1 + .../en-US/DSC_SqlLogin.strings.psd1 | 1 + tests/Unit/DSC_SqlLogin.Tests.ps1 | 46 +++++++++++++++++-- tests/Unit/Stubs/SMO.cs | 1 + 5 files changed, 81 insertions(+), 7 deletions(-) diff --git a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 index a691294c0..3efcd16fd 100644 --- a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 +++ b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 @@ -72,6 +72,7 @@ function Get-TargetResource Disabled = $login.IsDisabled DefaultDatabase = $login.DefaultDatabase Language = $login.Language + Sid = $login.Sid } if ($login.LoginType -eq 'SqlLogin') @@ -124,6 +125,9 @@ function Get-TargetResource .PARAMETER Language Specifies the default language for the login. + + .PARAMETER Sid + Specifies the login Sid. #> function Set-TargetResource { @@ -187,7 +191,11 @@ function Set-TargetResource [Parameter()] [System.String] - $Language + $Language, + + [Parameter()] + [System.String] + $Sid ) $serverObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName -ErrorAction 'Stop' @@ -272,7 +280,8 @@ function Set-TargetResource } if ( ( $PSBoundParameters.ContainsKey('DefaultDatabase') -and ($login.DefaultDatabase -ne $DefaultDatabase) ) -or - ( $PSBoundParameters.ContainsKey('Language') -and $login.Language -ne $Language ) ) + ( $PSBoundParameters.ContainsKey('Language') -and ($login.Language -ne $Language) ) + ) { if ( $PSBoundParameters.ContainsKey('DefaultDatabase') ) { @@ -336,6 +345,11 @@ function Set-TargetResource $LoginCreateOptions = [Microsoft.SqlServer.Management.Smo.LoginCreateOptions]::None } + if ( $PSBoundParameters.ContainsKey('Sid') ) + { + $login.Sid = ([byte[]] -split ( $Sid -replace '^0x','' -replace '..', '0x$& ')) + } + New-SQLServerLogin -Login $login -LoginCreateOptions $LoginCreateOptions -SecureString $LoginCredential.Password -ErrorAction 'Stop' } @@ -356,7 +370,8 @@ function Set-TargetResource } if ( ( $PSBoundParameters.ContainsKey('DefaultDatabase') -and ($login.DefaultDatabase -ne $DefaultDatabase) ) -or - ( $PSBoundParameters.ContainsKey('Language') -and $login.Language -ne $Language ) ) + ( $PSBoundParameters.ContainsKey('Language') -and ($login.Language -ne $Language) ) + ) { # Set the default database if specified if ( $PSBoundParameters.ContainsKey('DefaultDatabase') ) @@ -491,7 +506,11 @@ function Test-TargetResource [Parameter()] [System.String] - $Language + $Language, + + [Parameter()] + [System.String] + $Sid ) Write-Verbose -Message ( @@ -565,6 +584,18 @@ function Test-TargetResource $testPassed = $false } + if ( $PSBoundParameters.ContainsKey('Sid') ) + { + $InfoSid = '0x' + [System.BitConverter]::ToString($loginInfo.Sid).Replace('-', '') + if ( $InfoSid -ne $Sid ) + { + Write-Verbose -Message ( + $script:localizedData.WrongSid -f $Name, $InfoSid, $Sid + ) + $testPassed = $false + } + } + if ( $LoginType -eq 'SqlLogin' ) { if ( $PSBoundParameters.ContainsKey('LoginPasswordExpirationEnabled') -and $LoginPasswordExpirationEnabled -ne $loginInfo.LoginPasswordExpirationEnabled ) diff --git a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.schema.mof b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.schema.mof index 5ef638f33..8d648e0ac 100644 --- a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.schema.mof +++ b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.schema.mof @@ -15,4 +15,5 @@ class DSC_SqlLogin : OMI_BaseResource [Write, Description("Specifies if the login is disabled. Default value is `$false`.")] Boolean Disabled; [Write, Description("Specifies the default database name.")] String DefaultDatabase; [Write, Description("Specifies the default language.")] String Language; + [Write, Description("Specifies the login sid.")] String Sid; }; diff --git a/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 b/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 index f76b737e1..bdb33cf1f 100644 --- a/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 +++ b/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 @@ -20,6 +20,7 @@ ConvertFrom-StringData @' ExpectedEnabled = Expected the login '{0}' to be enabled, but it is disabled. WrongDefaultDatabase = The login '{0}' has the default database '{1}', but expected it to have the default database '{2}'. WrongLanguage = The login '{0}' has the default language '{1}', but expected it to have the default language '{2}'. + WrongSid = The login '{0}' has the Sid '{1}', but expected it to have the Sid '{2}'. ExpectedLoginPasswordExpirationDisabled = The login '{0}' has the password expiration enabled, but expected it to be disabled. ExpectedLoginPasswordExpirationEnabled = The login '{0}' has the password expiration disabled, but expected it to be enabled. ExpectedLoginPasswordPolicyEnforcedDisabled = The login '{0}' has the password policy enforced enabled, but expected it to be disabled. diff --git a/tests/Unit/DSC_SqlLogin.Tests.ps1 b/tests/Unit/DSC_SqlLogin.Tests.ps1 index 08fff817c..e2dc7c1b3 100644 --- a/tests/Unit/DSC_SqlLogin.Tests.ps1 +++ b/tests/Unit/DSC_SqlLogin.Tests.ps1 @@ -117,6 +117,7 @@ Describe 'SqlLogin\Get-TargetResource' -Tag 'Get' { Add-Member -MemberType NoteProperty -Name 'LoginType' -Value $MockLoginType -PassThru | Add-Member -MemberType NoteProperty -Name 'DefaultDatabase' -Value 'master' -PassThru | Add-Member -MemberType NoteProperty -Name 'Language' -Value 'us_english' -PassThru | + Add-Member -MemberType NoteProperty -Name 'Sid' -Value ([byte[]] -split ('0xB76150A66B38F64FAE9470091789AA66' -replace '^0x','' -replace '..', '0x$& ')) -PassThru | Add-Member -MemberType NoteProperty -Name 'IsDisabled' -Value $true -PassThru | Add-Member -MemberType NoteProperty -Name 'MustChangePassword' -Value $true -PassThru | Add-Member -MemberType NoteProperty -Name 'PasswordExpirationEnabled' -Value $true -PassThru | @@ -147,6 +148,7 @@ Describe 'SqlLogin\Get-TargetResource' -Tag 'Get' { $result.Disabled | Should -BeTrue $result.DefaultDatabase | Should -Be 'master' $result.Language | Should -Be 'us_english' + $result.Sid | Should -Be ([byte[]] -split ('0xB76150A66B38F64FAE9470091789AA66' -replace '^0x','' -replace '..', '0x$& ')) if ($MockLoginType -eq 'SqlLogin') { @@ -200,6 +202,7 @@ Describe 'SqlLogin\Get-TargetResource' -Tag 'Get' { Add-Member -MemberType NoteProperty -Name 'LoginType' -Value 'SqlLogin' -PassThru | Add-Member -MemberType NoteProperty -Name 'DefaultDatabase' -Value 'master' -PassThru | Add-Member -MemberType NoteProperty -Name 'Language' -Value 'us_english' -PassThru | + Add-Member -MemberType NoteProperty -Name 'Sid' -Value ([byte[]] -split ('0xB76150A66B38F64FAE9470091789AA66' -replace '^0x','' -replace '..', '0x$& ')) -PassThru | Add-Member -MemberType NoteProperty -Name 'IsDisabled' -Value $true -PassThru | Add-Member -MemberType NoteProperty -Name 'MustChangePassword' -Value $true -PassThru | Add-Member -MemberType NoteProperty -Name 'PasswordExpirationEnabled' -Value $true -PassThru | @@ -230,6 +233,7 @@ Describe 'SqlLogin\Get-TargetResource' -Tag 'Get' { $result.Disabled | Should -BeFalse $result.DefaultDatabase | Should -BeNullOrEmpty $result.Language | Should -BeNullOrEmpty + $result.Sid | Should -BeNullOrEmpty if ($MockLoginType -eq 'SqlLogin') { @@ -548,7 +552,7 @@ Describe 'SqlLogin\Test-TargetResource' -Tag 'Test' { } Context 'When evaluating the login credentials for a SQL login' { - Context 'When the parmeter Disabled is set to True for a SQL login (if login fails the login credentials are not in desired state)' { + Context 'When the parameter Disabled is set to True for a SQL login (if login fails the login credentials are not in desired state)' { BeforeAll { Mock -CommandName Connect-SQL -MockWith { $mockLoginFailedException = New-Object System.Exception 'Login failed' @@ -586,7 +590,7 @@ Describe 'SqlLogin\Test-TargetResource' -Tag 'Test' { } } - Context 'When the parmeter Disabled is set to False for a SQL login (if login fails the login credentials are not in desired state)' { + Context 'When the parameter Disabled is set to False for a SQL login (if login fails the login credentials are not in desired state)' { BeforeAll { Mock -CommandName Connect-SQL -MockWith { $mockLoginFailedException = New-Object System.Exception 'Login failed' @@ -623,7 +627,7 @@ Describe 'SqlLogin\Test-TargetResource' -Tag 'Test' { } } - Context 'When the parmeter Disabled is set to True for a SQL login (and an unexpected exception is thrown)' { + Context 'When the parameter Disabled is set to True for a SQL login (and an unexpected exception is thrown)' { BeforeAll { Mock -CommandName Connect-SQL -MockWith { $mockException = New-Object System.Exception 'Something went wrong' @@ -1022,6 +1026,42 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { } } + Context 'When creating a new login of type SqlLogin and specifying a Sid' { + BeforeAll { + $mockConnectSQL = { + return New-Object -TypeName Object | + Add-Member -MemberType 'NoteProperty' -Name 'LoginMode' -Value 'Mixed' -PassThru | + Add-Member -MemberType 'ScriptProperty' -Name 'Logins' -Value { + # Mocks no existing logins. + return @{} + } -PassThru -Force + } + + Mock -CommandName Connect-SQL -MockWith $mockConnectSQL + Mock -CommandName New-SQLServerLogin + } + + It 'Should not throw and call the correct mocks' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $mockPassword = ConvertTo-SecureString -String 'P@ssw0rd-12P@ssw0rd-12' -AsPlainText -Force + + $mockSetTargetResourceParameters.Name = 'SqlLogin1' + $mockSetTargetResourceParameters.LoginType = 'SqlLogin' + $mockSetTargetResourceParameters.Sid = '0x17442048803848B58686603376A84216' + $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockTestTargetResourceParameters.Name, $mockPassword) + + $null = Set-TargetResource @mockSetTargetResourceParameters -ErrorAction 'Stop' + } + + Should -Invoke -CommandName Connect-SQL -Exactly -Times 1 -Scope It + Should -Invoke -CommandName New-SQLServerLogin -ParameterFilter { + $Login.Name -eq 'SqlLogin1' -and @(Compare-Object $login.Sid ([byte[]] -split ( '0x17442048803848B58686603376A84216' -replace '^0x','' -replace '..', '0x$& ')) -SyncWindow 0).Length -eq 0 + } -Exactly -Times 1 -Scope It + } + } + Context 'When creating a new login of type SqlLogin and specifying that it should be disabled' { BeforeAll { $mockConnectSQL = { diff --git a/tests/Unit/Stubs/SMO.cs b/tests/Unit/Stubs/SMO.cs index a29567d86..90d613303 100644 --- a/tests/Unit/Stubs/SMO.cs +++ b/tests/Unit/Stubs/SMO.cs @@ -774,6 +774,7 @@ public void Enable() public string Certificate; public string AsymmetricKey; public string Language; + public byte[] Sid; public void Drop() { From a3571646d814bc2ca07a3ac269675a566b2babd3 Mon Sep 17 00:00:00 2001 From: cai-n Date: Fri, 13 Feb 2026 17:18:41 +0100 Subject: [PATCH 02/13] Update readme --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0858125e..11c74ab14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - SqlScript - Added integration test configuration that creates script files and executes the resource in a single configuration using `DependsOn`. +- SqlLogin + - Added parameter `Sid` to allow setting the sid of the new login. ([issue #1470](https://github.com/dsccommunity/SqlServerDsc/issues/1470)) ## [17.5.1] - 2026-02-05 From 4db0cfc787c1fd9523744362eb1fe752ea4b1db3 Mon Sep 17 00:00:00 2001 From: cai-n Date: Fri, 13 Feb 2026 17:31:11 +0100 Subject: [PATCH 03/13] update formatting and Sid description --- source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 | 8 ++++---- source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.schema.mof | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 index 3efcd16fd..81251f6b3 100644 --- a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 +++ b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 @@ -347,7 +347,7 @@ function Set-TargetResource if ( $PSBoundParameters.ContainsKey('Sid') ) { - $login.Sid = ([byte[]] -split ( $Sid -replace '^0x','' -replace '..', '0x$& ')) + $login.Sid = ([byte[]] -split ( $Sid -replace '^0x', '' -replace '..', '0x$& ')) } New-SQLServerLogin -Login $login -LoginCreateOptions $LoginCreateOptions -SecureString $LoginCredential.Password -ErrorAction 'Stop' @@ -586,11 +586,11 @@ function Test-TargetResource if ( $PSBoundParameters.ContainsKey('Sid') ) { - $InfoSid = '0x' + [System.BitConverter]::ToString($loginInfo.Sid).Replace('-', '') - if ( $InfoSid -ne $Sid ) + $infoSid = '0x' + [System.BitConverter]::ToString($loginInfo.Sid).Replace('-', '') + if ( $infoSid -ne $Sid ) { Write-Verbose -Message ( - $script:localizedData.WrongSid -f $Name, $InfoSid, $Sid + $script:localizedData.WrongSid -f $Name, $infoSid, $Sid ) $testPassed = $false } diff --git a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.schema.mof b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.schema.mof index 8d648e0ac..0a5756385 100644 --- a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.schema.mof +++ b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.schema.mof @@ -15,5 +15,5 @@ class DSC_SqlLogin : OMI_BaseResource [Write, Description("Specifies if the login is disabled. Default value is `$false`.")] Boolean Disabled; [Write, Description("Specifies the default database name.")] String DefaultDatabase; [Write, Description("Specifies the default language.")] String Language; - [Write, Description("Specifies the login sid.")] String Sid; + [Write, Description("Specifies the security identifier (SID) for the login. Only applies to _SQL Logins_. The value should be a hexadecimal string (e.g. `'0x1234...'`).")] String Sid; }; From 22f8e399c2390c6adec15b9bd50bb06994ccf7e8 Mon Sep 17 00:00:00 2001 From: cai-n Date: Mon, 16 Feb 2026 15:12:13 +0100 Subject: [PATCH 04/13] add example with sid and check if property null --- .../DSC_SqlLogin/DSC_SqlLogin.psm1 | 16 ++++-- .../Resources/SqlLogin/1-AddSqlLogin.ps1 | 53 +++++++++++++++++++ .../{1-AddLogin.ps1 => 1-AddWindowsUser.ps1} | 0 tests/Unit/DSC_SqlLogin.Tests.ps1 | 20 +++---- 4 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 rename source/Examples/Resources/SqlLogin/{1-AddLogin.ps1 => 1-AddWindowsUser.ps1} (100%) diff --git a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 index 81251f6b3..db9912de3 100644 --- a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 +++ b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 @@ -586,14 +586,20 @@ function Test-TargetResource if ( $PSBoundParameters.ContainsKey('Sid') ) { - $infoSid = '0x' + [System.BitConverter]::ToString($loginInfo.Sid).Replace('-', '') - if ( $infoSid -ne $Sid ) + if ($null -eq $loginInfo.Sid) { - Write-Verbose -Message ( - $script:localizedData.WrongSid -f $Name, $infoSid, $Sid - ) $testPassed = $false } + else { + $infoSid = '0x' + [System.BitConverter]::ToString($loginInfo.Sid).Replace('-', '') + if ( $infoSid -ne $Sid ) + { + Write-Verbose -Message ( + $script:localizedData.WrongSid -f $Name, $infoSid, $Sid + ) + $testPassed = $false + } + } } if ( $LoginType -eq 'SqlLogin' ) diff --git a/source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 b/source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 new file mode 100644 index 000000000..31ae996ae --- /dev/null +++ b/source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 @@ -0,0 +1,53 @@ +<# + .DESCRIPTION + This example shows how to ensure that the Windows user 'CONTOSO\WindowsUser', + Windows group 'CONTOSO\WindowsGroup', and the SQL Login 'SqlLogin' exists. +#> + +Configuration Example +{ + param + ( + [Parameter(Mandatory = $true)] + [System.Management.Automation.PSCredential] + $SqlAdministratorCredential, + + [Parameter(Mandatory = $true)] + [System.Management.Automation.PSCredential] + $LoginCredential + ) + + Import-DscResource -ModuleName 'SqlServerDsc' + + node localhost + { + SqlLogin 'Add_SqlLogin' + { + Ensure = 'Present' + Name = 'SqlLogin' + LoginType = 'SqlLogin' + ServerName = 'TestServer.company.local' + InstanceName = 'DSC' + LoginCredential = $LoginCredential + LoginMustChangePassword = $false + LoginPasswordExpirationEnabled = $true + LoginPasswordPolicyEnforced = $true + PsDscRunAsCredential = $SqlAdministratorCredential + } + + SqlLogin 'Add_SqlLogin_Set_Login_Sid' + { + Ensure = 'Present' + Name = 'SqlLogin2' + LoginType = 'SqlLogin' + ServerName = 'TestServer.company.local' + InstanceName = 'DSC' + LoginCredential = $LoginCredential + LoginMustChangePassword = $false + LoginPasswordExpirationEnabled = $true + LoginPasswordPolicyEnforced = $true + PsDscRunAsCredential = $SqlAdministratorCredential + Sid = '0x5283175DBF354E508FB7582940E87500' + } + } +} diff --git a/source/Examples/Resources/SqlLogin/1-AddLogin.ps1 b/source/Examples/Resources/SqlLogin/1-AddWindowsUser.ps1 similarity index 100% rename from source/Examples/Resources/SqlLogin/1-AddLogin.ps1 rename to source/Examples/Resources/SqlLogin/1-AddWindowsUser.ps1 diff --git a/tests/Unit/DSC_SqlLogin.Tests.ps1 b/tests/Unit/DSC_SqlLogin.Tests.ps1 index e2dc7c1b3..b7797e5b4 100644 --- a/tests/Unit/DSC_SqlLogin.Tests.ps1 +++ b/tests/Unit/DSC_SqlLogin.Tests.ps1 @@ -117,7 +117,7 @@ Describe 'SqlLogin\Get-TargetResource' -Tag 'Get' { Add-Member -MemberType NoteProperty -Name 'LoginType' -Value $MockLoginType -PassThru | Add-Member -MemberType NoteProperty -Name 'DefaultDatabase' -Value 'master' -PassThru | Add-Member -MemberType NoteProperty -Name 'Language' -Value 'us_english' -PassThru | - Add-Member -MemberType NoteProperty -Name 'Sid' -Value ([byte[]] -split ('0xB76150A66B38F64FAE9470091789AA66' -replace '^0x','' -replace '..', '0x$& ')) -PassThru | + Add-Member -MemberType NoteProperty -Name 'Sid' -Value ([byte[]] -split ('B76150A66B38F64FAE9470091789AA66' -replace '..', '0x$& ')) -PassThru | Add-Member -MemberType NoteProperty -Name 'IsDisabled' -Value $true -PassThru | Add-Member -MemberType NoteProperty -Name 'MustChangePassword' -Value $true -PassThru | Add-Member -MemberType NoteProperty -Name 'PasswordExpirationEnabled' -Value $true -PassThru | @@ -148,7 +148,7 @@ Describe 'SqlLogin\Get-TargetResource' -Tag 'Get' { $result.Disabled | Should -BeTrue $result.DefaultDatabase | Should -Be 'master' $result.Language | Should -Be 'us_english' - $result.Sid | Should -Be ([byte[]] -split ('0xB76150A66B38F64FAE9470091789AA66' -replace '^0x','' -replace '..', '0x$& ')) + $result.Sid | Should -Be ([byte[]] -split ('B76150A66B38F64FAE9470091789AA66' -replace '..', '0x$& ')) if ($MockLoginType -eq 'SqlLogin') { @@ -886,7 +886,7 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { $mockSetTargetResourceParameters.Name = 'SqlLogin1' $mockSetTargetResourceParameters.LoginType = 'SqlLogin' $mockSetTargetResourceParameters.LoginMustChangePassword = $true - $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockTestTargetResourceParameters.Name, $mockPassword) + $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockSetTargetResourceParameters.Name, $mockPassword) $null = Set-TargetResource @mockSetTargetResourceParameters -ErrorAction 'Stop' } @@ -934,7 +934,7 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { $mockSetTargetResourceParameters.Name = 'SqlLogin1' $mockSetTargetResourceParameters.LoginType = 'SqlLogin' $mockSetTargetResourceParameters.LoginMustChangePassword = $false - $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockTestTargetResourceParameters.Name, $mockPassword) + $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockSetTargetResourceParameters.Name, $mockPassword) $null = Set-TargetResource @mockSetTargetResourceParameters -ErrorAction 'Stop' } @@ -978,7 +978,7 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { $mockSetTargetResourceParameters.Name = 'SqlLogin1' $mockSetTargetResourceParameters.LoginType = 'SqlLogin' $mockSetTargetResourceParameters.DefaultDatabase = 'NewDatabase' - $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockTestTargetResourceParameters.Name, $mockPassword) + $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockSetTargetResourceParameters.Name, $mockPassword) $null = Set-TargetResource @mockSetTargetResourceParameters -ErrorAction 'Stop' } @@ -1014,7 +1014,7 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { $mockSetTargetResourceParameters.Name = 'SqlLogin1' $mockSetTargetResourceParameters.LoginType = 'SqlLogin' $mockSetTargetResourceParameters.Language = 'Français' - $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockTestTargetResourceParameters.Name, $mockPassword) + $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockSetTargetResourceParameters.Name, $mockPassword) $null = Set-TargetResource @mockSetTargetResourceParameters -ErrorAction 'Stop' } @@ -1050,7 +1050,7 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { $mockSetTargetResourceParameters.Name = 'SqlLogin1' $mockSetTargetResourceParameters.LoginType = 'SqlLogin' $mockSetTargetResourceParameters.Sid = '0x17442048803848B58686603376A84216' - $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockTestTargetResourceParameters.Name, $mockPassword) + $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockSetTargetResourceParameters.Name, $mockPassword) $null = Set-TargetResource @mockSetTargetResourceParameters -ErrorAction 'Stop' } @@ -1107,7 +1107,7 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { $mockSetTargetResourceParameters.Name = 'SqlLogin1' $mockSetTargetResourceParameters.LoginType = 'SqlLogin' $mockSetTargetResourceParameters.Disabled = $true - $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockTestTargetResourceParameters.Name, $mockPassword) + $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockSetTargetResourceParameters.Name, $mockPassword) $null = Set-TargetResource @mockSetTargetResourceParameters -ErrorAction 'Stop' @@ -1144,7 +1144,7 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { $mockSetTargetResourceParameters.Name = 'SqlLogin1' $mockSetTargetResourceParameters.LoginType = 'SqlLogin' - $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockTestTargetResourceParameters.Name, $mockPassword) + $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockSetTargetResourceParameters.Name, $mockPassword) $mockErrorMessage = $script:localizedData.IncorrectLoginMode -f 'localhost', 'MSSQLSERVER', 'Integrated' @@ -1615,7 +1615,7 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { $mockSetTargetResourceParameters.Name = 'SqlLogin1' $mockSetTargetResourceParameters.LoginType = 'SqlLogin' - $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockTestTargetResourceParameters.Name, $mockPassword) + $mockSetTargetResourceParameters.LoginCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @($mockSetTargetResourceParameters.Name, $mockPassword) $null = Set-TargetResource @mockSetTargetResourceParameters -ErrorAction 'Stop' } From 18a5b8562a12bbc9079867558dccca65e8219016 Mon Sep 17 00:00:00 2001 From: cai-n Date: Mon, 16 Feb 2026 15:17:24 +0100 Subject: [PATCH 05/13] add test to cover Sid not in desired state --- tests/Unit/DSC_SqlLogin.Tests.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Unit/DSC_SqlLogin.Tests.ps1 b/tests/Unit/DSC_SqlLogin.Tests.ps1 index b7797e5b4..fcdabb3e9 100644 --- a/tests/Unit/DSC_SqlLogin.Tests.ps1 +++ b/tests/Unit/DSC_SqlLogin.Tests.ps1 @@ -519,6 +519,10 @@ Describe 'SqlLogin\Test-TargetResource' -Tag 'Test' { MockPropertyName = 'LoginPasswordPolicyEnforced' MockPropertyValue = $false } + @{ + MockPropertyName = 'Sid' + MockPropertyValue = '0x5283175DBF354E508FB7582940E87500' + } ) { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { From a31a388806a330a2ec2187923f8d14cf3768b1d6 Mon Sep 17 00:00:00 2001 From: cai-n Date: Mon, 16 Feb 2026 15:21:08 +0100 Subject: [PATCH 06/13] update examples description --- .../Resources/SqlLogin/1-AddSqlLogin.ps1 | 4 ++-- .../Resources/SqlLogin/1-AddWindowsUser.ps1 | 17 ++--------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 b/source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 index 31ae996ae..56f2eddc3 100644 --- a/source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 +++ b/source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 @@ -1,7 +1,7 @@ <# .DESCRIPTION - This example shows how to ensure that the Windows user 'CONTOSO\WindowsUser', - Windows group 'CONTOSO\WindowsGroup', and the SQL Login 'SqlLogin' exists. + This example shows how to ensure that the SQL logins 'SqlLogin' and + 'SqlLogin2' exist, where 'SqlLogin2' is created with an explicit SID. #> Configuration Example diff --git a/source/Examples/Resources/SqlLogin/1-AddWindowsUser.ps1 b/source/Examples/Resources/SqlLogin/1-AddWindowsUser.ps1 index fea578340..91106c110 100644 --- a/source/Examples/Resources/SqlLogin/1-AddWindowsUser.ps1 +++ b/source/Examples/Resources/SqlLogin/1-AddWindowsUser.ps1 @@ -1,7 +1,8 @@ <# .DESCRIPTION This example shows how to ensure that the Windows user 'CONTOSO\WindowsUser', - Windows group 'CONTOSO\WindowsGroup', and the SQL Login 'SqlLogin' exists. + 'CONTOSO\WindowsUser2', 'CONTOSO\WindowsUser3', + and Windows group 'CONTOSO\WindowsGroup' exists. #> Configuration Example @@ -62,19 +63,5 @@ Configuration Example InstanceName = 'DSC' PsDscRunAsCredential = $SqlAdministratorCredential } - - SqlLogin 'Add_SqlLogin' - { - Ensure = 'Present' - Name = 'SqlLogin' - LoginType = 'SqlLogin' - ServerName = 'TestServer.company.local' - InstanceName = 'DSC' - LoginCredential = $LoginCredential - LoginMustChangePassword = $false - LoginPasswordExpirationEnabled = $true - LoginPasswordPolicyEnforced = $true - PsDscRunAsCredential = $SqlAdministratorCredential - } } } From 6a496c4b679b2edf83348d8278c8b8af334ffe32 Mon Sep 17 00:00:00 2001 From: cai-n Date: Mon, 16 Feb 2026 16:06:17 +0100 Subject: [PATCH 07/13] remove all double replace for sid in tests --- source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 | 6 +++++- tests/Unit/DSC_SqlLogin.Tests.ps1 | 14 +++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 index db9912de3..451dd190f 100644 --- a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 +++ b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 @@ -443,6 +443,9 @@ function Set-TargetResource .PARAMETER Language Specifies the default language for the login. + + .PARAMETER Sid + Specifies the login Sid. #> function Test-TargetResource { @@ -590,7 +593,8 @@ function Test-TargetResource { $testPassed = $false } - else { + else + { $infoSid = '0x' + [System.BitConverter]::ToString($loginInfo.Sid).Replace('-', '') if ( $infoSid -ne $Sid ) { diff --git a/tests/Unit/DSC_SqlLogin.Tests.ps1 b/tests/Unit/DSC_SqlLogin.Tests.ps1 index fcdabb3e9..a3887e440 100644 --- a/tests/Unit/DSC_SqlLogin.Tests.ps1 +++ b/tests/Unit/DSC_SqlLogin.Tests.ps1 @@ -202,7 +202,7 @@ Describe 'SqlLogin\Get-TargetResource' -Tag 'Get' { Add-Member -MemberType NoteProperty -Name 'LoginType' -Value 'SqlLogin' -PassThru | Add-Member -MemberType NoteProperty -Name 'DefaultDatabase' -Value 'master' -PassThru | Add-Member -MemberType NoteProperty -Name 'Language' -Value 'us_english' -PassThru | - Add-Member -MemberType NoteProperty -Name 'Sid' -Value ([byte[]] -split ('0xB76150A66B38F64FAE9470091789AA66' -replace '^0x','' -replace '..', '0x$& ')) -PassThru | + Add-Member -MemberType NoteProperty -Name 'Sid' -Value ([byte[]] -split ('B76150A66B38F64FAE9470091789AA66' -replace '..', '0x$& ')) -PassThru | Add-Member -MemberType NoteProperty -Name 'IsDisabled' -Value $true -PassThru | Add-Member -MemberType NoteProperty -Name 'MustChangePassword' -Value $true -PassThru | Add-Member -MemberType NoteProperty -Name 'PasswordExpirationEnabled' -Value $true -PassThru | @@ -534,7 +534,15 @@ Describe 'SqlLogin\Test-TargetResource' -Tag 'Test' { #> LoginPasswordPolicyEnforced = -not $MockPropertyValue LoginPasswordExpirationEnabled = -not $MockPropertyValue - } + Sid = if ($MockPropertyName -eq 'Sid') + { + # Switch the value of the Sid property to be different than the one specified in the call to Test-TargetResource. + [byte[]] -split ('B76150A66B38F64FAE9470091789AA66' -replace '..', '0x$& ') + } + else + { + [byte[]] -split ('5283175DBF354E508FB7582940E87500' -replace '..', '0x$& ') + } } } @@ -1061,7 +1069,7 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { Should -Invoke -CommandName Connect-SQL -Exactly -Times 1 -Scope It Should -Invoke -CommandName New-SQLServerLogin -ParameterFilter { - $Login.Name -eq 'SqlLogin1' -and @(Compare-Object $login.Sid ([byte[]] -split ( '0x17442048803848B58686603376A84216' -replace '^0x','' -replace '..', '0x$& ')) -SyncWindow 0).Length -eq 0 + $Login.Name -eq 'SqlLogin1' -and @(Compare-Object $login.Sid ([byte[]] -split ( '17442048803848B58686603376A84216' -replace '..', '0x$& ')) -SyncWindow 0).Length -eq 0 } -Exactly -Times 1 -Scope It } } From cdc48cf3603f195313649b5b5763535258aee9b8 Mon Sep 17 00:00:00 2001 From: cai-n Date: Mon, 16 Feb 2026 16:19:45 +0100 Subject: [PATCH 08/13] remove unused parameter in example --- source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 | 9 +++++++-- source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 | 2 +- source/Examples/Resources/SqlLogin/1-AddWindowsUser.ps1 | 6 +----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 index 451dd190f..cec1d35c7 100644 --- a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 +++ b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 @@ -127,7 +127,7 @@ function Get-TargetResource Specifies the default language for the login. .PARAMETER Sid - Specifies the login Sid. + Specifies the security identifier (SID) for the login. Only applies to SQL Logins. The value should be a hexadecimal string (e.g. '0x1234...'). #> function Set-TargetResource { @@ -194,6 +194,7 @@ function Set-TargetResource $Language, [Parameter()] + [ValidatePattern('^0x([0-9A-Fa-f]{2})+$')] [System.String] $Sid ) @@ -445,7 +446,7 @@ function Set-TargetResource Specifies the default language for the login. .PARAMETER Sid - Specifies the login Sid. + Specifies the security identifier (SID) for the login. Only applies to SQL Logins. The value should be a hexadecimal string (e.g. '0x1234...'). #> function Test-TargetResource { @@ -512,6 +513,7 @@ function Test-TargetResource $Language, [Parameter()] + [ValidatePattern('^0x([0-9A-Fa-f]{2})+$')] [System.String] $Sid ) @@ -591,6 +593,9 @@ function Test-TargetResource { if ($null -eq $loginInfo.Sid) { + Write-Verbose -Message ( + $script:localizedData.WrongSid -f $Name, $null, $Sid + ) $testPassed = $false } else diff --git a/source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 b/source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 index 56f2eddc3..a40e6dc35 100644 --- a/source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 +++ b/source/Examples/Resources/SqlLogin/1-AddSqlLogin.ps1 @@ -1,7 +1,7 @@ <# .DESCRIPTION This example shows how to ensure that the SQL logins 'SqlLogin' and - 'SqlLogin2' exist, where 'SqlLogin2' is created with an explicit SID. + 'SqlLogin2' exist, where 'SqlLogin2' is created with an explicit SID. #> Configuration Example diff --git a/source/Examples/Resources/SqlLogin/1-AddWindowsUser.ps1 b/source/Examples/Resources/SqlLogin/1-AddWindowsUser.ps1 index 91106c110..3fbc844d5 100644 --- a/source/Examples/Resources/SqlLogin/1-AddWindowsUser.ps1 +++ b/source/Examples/Resources/SqlLogin/1-AddWindowsUser.ps1 @@ -11,11 +11,7 @@ Configuration Example ( [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] - $SqlAdministratorCredential, - - [Parameter(Mandatory = $true)] - [System.Management.Automation.PSCredential] - $LoginCredential + $SqlAdministratorCredential ) Import-DscResource -ModuleName 'SqlServerDsc' From a10e5c743581e23029f4be89b476cc619c8cd9b9 Mon Sep 17 00:00:00 2001 From: cai-n Date: Mon, 16 Feb 2026 16:28:42 +0100 Subject: [PATCH 09/13] fix missing bracket --- tests/Unit/DSC_SqlLogin.Tests.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Unit/DSC_SqlLogin.Tests.ps1 b/tests/Unit/DSC_SqlLogin.Tests.ps1 index a3887e440..87b18dc54 100644 --- a/tests/Unit/DSC_SqlLogin.Tests.ps1 +++ b/tests/Unit/DSC_SqlLogin.Tests.ps1 @@ -543,6 +543,7 @@ Describe 'SqlLogin\Test-TargetResource' -Tag 'Test' { { [byte[]] -split ('5283175DBF354E508FB7582940E87500' -replace '..', '0x$& ') } + } } } From 4ca74cafb0f25bda22540c141fb3e69ac0dff4a6 Mon Sep 17 00:00:00 2001 From: cai-n Date: Tue, 17 Feb 2026 14:25:12 +0100 Subject: [PATCH 10/13] update sqllogin sid test to test for null value --- tests/Unit/DSC_SqlLogin.Tests.ps1 | 48 +++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/tests/Unit/DSC_SqlLogin.Tests.ps1 b/tests/Unit/DSC_SqlLogin.Tests.ps1 index 87b18dc54..a59940a8a 100644 --- a/tests/Unit/DSC_SqlLogin.Tests.ps1 +++ b/tests/Unit/DSC_SqlLogin.Tests.ps1 @@ -534,15 +534,45 @@ Describe 'SqlLogin\Test-TargetResource' -Tag 'Test' { #> LoginPasswordPolicyEnforced = -not $MockPropertyValue LoginPasswordExpirationEnabled = -not $MockPropertyValue - Sid = if ($MockPropertyName -eq 'Sid') - { - # Switch the value of the Sid property to be different than the one specified in the call to Test-TargetResource. - [byte[]] -split ('B76150A66B38F64FAE9470091789AA66' -replace '..', '0x$& ') - } - else - { - [byte[]] -split ('5283175DBF354E508FB7582940E87500' -replace '..', '0x$& ') - } + Sid = [byte[]] -split ('B76150A66B38F64FAE9470091789AA66' -replace '..', '0x$& ') + } + } + } + + It 'Should return $false' { + InModuleScope -Parameters $_ -ScriptBlock { + Set-StrictMode -Version 1.0 + + $mockTestTargetResourceParameters.Name = 'Login1' + $mockTestTargetResourceParameters.LoginType = 'SqlLogin' + $mockTestTargetResourceParameters.$MockPropertyName = $MockPropertyValue + + $result = Test-TargetResource @mockTestTargetResourceParameters + + $result | Should -BeFalse + } + + Should -Invoke -CommandName Get-TargetResource -Exactly -Times 1 -Scope It + } + } + + Context 'When the property Sid is set for a SQL login is not in desired state' -ForEach @( + @{ + MockPropertyName = 'Sid' + MockPropertyValue = '0x5283175DBF354E508FB7582940E87500' + } + ) { + BeforeAll { + Mock -CommandName Get-TargetResource -MockWith { + return @{ + Ensure = 'Present' + <# + Switch the value of the property to the opposite of what + will be specified in the call to Test-TargetResource. + #> + LoginPasswordPolicyEnforced = -not $MockPropertyValue + LoginPasswordExpirationEnabled = -not $MockPropertyValue + Sid = $null } } } From 26cfee44bc3604670d2434aadac7d1ebd1ba6a86 Mon Sep 17 00:00:00 2001 From: cai-n Date: Tue, 17 Feb 2026 19:06:38 +0100 Subject: [PATCH 11/13] remove Sid check in Test-TargetResource --- .../DSC_SqlLogin/DSC_SqlLogin.psm1 | 22 --------- .../en-US/DSC_SqlLogin.strings.psd1 | 1 - tests/Unit/DSC_SqlLogin.Tests.ps1 | 45 +------------------ 3 files changed, 1 insertion(+), 67 deletions(-) diff --git a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 index cec1d35c7..e5b608ab7 100644 --- a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 +++ b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 @@ -589,28 +589,6 @@ function Test-TargetResource $testPassed = $false } - if ( $PSBoundParameters.ContainsKey('Sid') ) - { - if ($null -eq $loginInfo.Sid) - { - Write-Verbose -Message ( - $script:localizedData.WrongSid -f $Name, $null, $Sid - ) - $testPassed = $false - } - else - { - $infoSid = '0x' + [System.BitConverter]::ToString($loginInfo.Sid).Replace('-', '') - if ( $infoSid -ne $Sid ) - { - Write-Verbose -Message ( - $script:localizedData.WrongSid -f $Name, $infoSid, $Sid - ) - $testPassed = $false - } - } - } - if ( $LoginType -eq 'SqlLogin' ) { if ( $PSBoundParameters.ContainsKey('LoginPasswordExpirationEnabled') -and $LoginPasswordExpirationEnabled -ne $loginInfo.LoginPasswordExpirationEnabled ) diff --git a/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 b/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 index bdb33cf1f..f76b737e1 100644 --- a/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 +++ b/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 @@ -20,7 +20,6 @@ ConvertFrom-StringData @' ExpectedEnabled = Expected the login '{0}' to be enabled, but it is disabled. WrongDefaultDatabase = The login '{0}' has the default database '{1}', but expected it to have the default database '{2}'. WrongLanguage = The login '{0}' has the default language '{1}', but expected it to have the default language '{2}'. - WrongSid = The login '{0}' has the Sid '{1}', but expected it to have the Sid '{2}'. ExpectedLoginPasswordExpirationDisabled = The login '{0}' has the password expiration enabled, but expected it to be disabled. ExpectedLoginPasswordExpirationEnabled = The login '{0}' has the password expiration disabled, but expected it to be enabled. ExpectedLoginPasswordPolicyEnforcedDisabled = The login '{0}' has the password policy enforced enabled, but expected it to be disabled. diff --git a/tests/Unit/DSC_SqlLogin.Tests.ps1 b/tests/Unit/DSC_SqlLogin.Tests.ps1 index a59940a8a..765e5d2a3 100644 --- a/tests/Unit/DSC_SqlLogin.Tests.ps1 +++ b/tests/Unit/DSC_SqlLogin.Tests.ps1 @@ -357,7 +357,7 @@ Describe 'SqlLogin\Test-TargetResource' -Tag 'Test' { } } - Context 'When the parmeter Disabled is set to True for a SQL login (and the account is disabled)' { + Context 'When the parameter Disabled is set to True for a SQL login (and the account is disabled)' { BeforeAll { Mock -CommandName Connect-SQL -MockWith { $mockAccountDisabledException = New-Object -TypeName 'System.Exception' -ArgumentList 'Account disabled' @@ -519,48 +519,6 @@ Describe 'SqlLogin\Test-TargetResource' -Tag 'Test' { MockPropertyName = 'LoginPasswordPolicyEnforced' MockPropertyValue = $false } - @{ - MockPropertyName = 'Sid' - MockPropertyValue = '0x5283175DBF354E508FB7582940E87500' - } - ) { - BeforeAll { - Mock -CommandName Get-TargetResource -MockWith { - return @{ - Ensure = 'Present' - <# - Switch the value of the property to the opposite of what - will be specified in the call to Test-TargetResource. - #> - LoginPasswordPolicyEnforced = -not $MockPropertyValue - LoginPasswordExpirationEnabled = -not $MockPropertyValue - Sid = [byte[]] -split ('B76150A66B38F64FAE9470091789AA66' -replace '..', '0x$& ') - } - } - } - - It 'Should return $false' { - InModuleScope -Parameters $_ -ScriptBlock { - Set-StrictMode -Version 1.0 - - $mockTestTargetResourceParameters.Name = 'Login1' - $mockTestTargetResourceParameters.LoginType = 'SqlLogin' - $mockTestTargetResourceParameters.$MockPropertyName = $MockPropertyValue - - $result = Test-TargetResource @mockTestTargetResourceParameters - - $result | Should -BeFalse - } - - Should -Invoke -CommandName Get-TargetResource -Exactly -Times 1 -Scope It - } - } - - Context 'When the property Sid is set for a SQL login is not in desired state' -ForEach @( - @{ - MockPropertyName = 'Sid' - MockPropertyValue = '0x5283175DBF354E508FB7582940E87500' - } ) { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { @@ -572,7 +530,6 @@ Describe 'SqlLogin\Test-TargetResource' -Tag 'Test' { #> LoginPasswordPolicyEnforced = -not $MockPropertyValue LoginPasswordExpirationEnabled = -not $MockPropertyValue - Sid = $null } } } From 28a6de9011d163e17575a045a9fe8cad3173d8f1 Mon Sep 17 00:00:00 2001 From: cai-n Date: Wed, 18 Feb 2026 18:32:25 +0100 Subject: [PATCH 12/13] put Sid check back in resources --- .../DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 | 17 +++++++++++++++++ .../en-US/DSC_SqlLogin.strings.psd1 | 1 + 2 files changed, 18 insertions(+) diff --git a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 index e5b608ab7..a94648797 100644 --- a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 +++ b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 @@ -589,6 +589,23 @@ function Test-TargetResource $testPassed = $false } + if ( $PSBoundParameters.ContainsKey('Sid') ) + { + $infoSid = if ($null -ne $loginInfo.Sid) + { + '0x' + [System.BitConverter]::ToString($loginInfo.Sid).Replace('-', '') + } + + if ($null -eq $infoSid -or $infoSid -ne $Sid) + { + Write-Verbose -Message ( + $script:localizedData.WrongSid -f $Name, $infoSid, $Sid + ) + + $testPassed = $false + } + } + if ( $LoginType -eq 'SqlLogin' ) { if ( $PSBoundParameters.ContainsKey('LoginPasswordExpirationEnabled') -and $LoginPasswordExpirationEnabled -ne $loginInfo.LoginPasswordExpirationEnabled ) diff --git a/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 b/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 index f76b737e1..bdb33cf1f 100644 --- a/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 +++ b/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 @@ -20,6 +20,7 @@ ConvertFrom-StringData @' ExpectedEnabled = Expected the login '{0}' to be enabled, but it is disabled. WrongDefaultDatabase = The login '{0}' has the default database '{1}', but expected it to have the default database '{2}'. WrongLanguage = The login '{0}' has the default language '{1}', but expected it to have the default language '{2}'. + WrongSid = The login '{0}' has the Sid '{1}', but expected it to have the Sid '{2}'. ExpectedLoginPasswordExpirationDisabled = The login '{0}' has the password expiration enabled, but expected it to be disabled. ExpectedLoginPasswordExpirationEnabled = The login '{0}' has the password expiration disabled, but expected it to be enabled. ExpectedLoginPasswordPolicyEnforcedDisabled = The login '{0}' has the password policy enforced enabled, but expected it to be disabled. From 6fc66ae66144baad01771af8acd5a1412f169d50 Mon Sep 17 00:00:00 2001 From: cai-n Date: Thu, 19 Feb 2026 11:28:51 +0100 Subject: [PATCH 13/13] Remove Sid logic in test-target --- .../DSC_SqlLogin/DSC_SqlLogin.psm1 | 19 ++----------------- .../en-US/DSC_SqlLogin.strings.psd1 | 1 - 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 index a94648797..2f0953d92 100644 --- a/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 +++ b/source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1 @@ -447,6 +447,8 @@ function Set-TargetResource .PARAMETER Sid Specifies the security identifier (SID) for the login. Only applies to SQL Logins. The value should be a hexadecimal string (e.g. '0x1234...'). + + Not currently used in Test-TargetResource to enforce Sid. #> function Test-TargetResource { @@ -589,23 +591,6 @@ function Test-TargetResource $testPassed = $false } - if ( $PSBoundParameters.ContainsKey('Sid') ) - { - $infoSid = if ($null -ne $loginInfo.Sid) - { - '0x' + [System.BitConverter]::ToString($loginInfo.Sid).Replace('-', '') - } - - if ($null -eq $infoSid -or $infoSid -ne $Sid) - { - Write-Verbose -Message ( - $script:localizedData.WrongSid -f $Name, $infoSid, $Sid - ) - - $testPassed = $false - } - } - if ( $LoginType -eq 'SqlLogin' ) { if ( $PSBoundParameters.ContainsKey('LoginPasswordExpirationEnabled') -and $LoginPasswordExpirationEnabled -ne $loginInfo.LoginPasswordExpirationEnabled ) diff --git a/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 b/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 index bdb33cf1f..f76b737e1 100644 --- a/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 +++ b/source/DSCResources/DSC_SqlLogin/en-US/DSC_SqlLogin.strings.psd1 @@ -20,7 +20,6 @@ ConvertFrom-StringData @' ExpectedEnabled = Expected the login '{0}' to be enabled, but it is disabled. WrongDefaultDatabase = The login '{0}' has the default database '{1}', but expected it to have the default database '{2}'. WrongLanguage = The login '{0}' has the default language '{1}', but expected it to have the default language '{2}'. - WrongSid = The login '{0}' has the Sid '{1}', but expected it to have the Sid '{2}'. ExpectedLoginPasswordExpirationDisabled = The login '{0}' has the password expiration enabled, but expected it to be disabled. ExpectedLoginPasswordExpirationEnabled = The login '{0}' has the password expiration disabled, but expected it to be enabled. ExpectedLoginPasswordPolicyEnforcedDisabled = The login '{0}' has the password policy enforced enabled, but expected it to be disabled.