Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated Pester test guidance in AI instructions in community style guidelines.
- Added SChannelDsc as a required module for integration tests and enabled the
prerequisites tests `Ensure TLS 1.2 is enabled` ([issue #2441](https://github.com/dsccommunity/SqlServerDsc/issues/2441)).
- `SqlLogin`
- Added parameter `Language` to allow setting the default language used by the login.
Comment thread
johlju marked this conversation as resolved.

## [17.5.0] - 2026-01-30

Expand Down
57 changes: 50 additions & 7 deletions source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ function Get-TargetResource
InstanceName = $InstanceName
Disabled = $login.IsDisabled
DefaultDatabase = $login.DefaultDatabase
Language = $login.Language
}

if ($login.LoginType -eq 'SqlLogin')
Expand Down Expand Up @@ -120,6 +121,9 @@ function Get-TargetResource

.PARAMETER DefaultDatabase
Specifies the default database for the login.

.PARAMETER Language
Specifies the default language for the login.
#>
function Set-TargetResource
{
Expand Down Expand Up @@ -179,7 +183,11 @@ function Set-TargetResource

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

[Parameter()]
[System.String]
$Language
)

$serverObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName -ErrorAction 'Stop'
Expand Down Expand Up @@ -263,9 +271,18 @@ function Set-TargetResource
}
}

if ( $PSBoundParameters.ContainsKey('DefaultDatabase') -and ($login.DefaultDatabase -ne $DefaultDatabase) )
if ( ( $PSBoundParameters.ContainsKey('DefaultDatabase') -and ($login.DefaultDatabase -ne $DefaultDatabase) ) -or
( $PSBoundParameters.ContainsKey('Language') -and $login.Language -ne $Language ) )
{
$login.DefaultDatabase = $DefaultDatabase
if ( $PSBoundParameters.ContainsKey('DefaultDatabase') )
{
$login.DefaultDatabase = $DefaultDatabase
}

if ( $PSBoundParameters.ContainsKey('Language') )
{
$login.Language = $Language
}
Update-SQLServerLogin -Login $login
}
}
Expand Down Expand Up @@ -338,10 +355,20 @@ function Set-TargetResource
$login.Disable()
}

# Set the default database if specified
if ( $PSBoundParameters.ContainsKey('DefaultDatabase') )
if ( ( $PSBoundParameters.ContainsKey('DefaultDatabase') -and ($login.DefaultDatabase -ne $DefaultDatabase) ) -or
( $PSBoundParameters.ContainsKey('Language') -and $login.Language -ne $Language ) )
{
$login.DefaultDatabase = $DefaultDatabase
# Set the default database if specified
if ( $PSBoundParameters.ContainsKey('DefaultDatabase') )
{
$login.DefaultDatabase = $DefaultDatabase
}

# Set the language if specified
if ( $PSBoundParameters.ContainsKey('Language') )
{
$login.Language = $Language
}
Update-SQLServerLogin -Login $login
}
}
Expand Down Expand Up @@ -398,6 +425,9 @@ function Set-TargetResource

.PARAMETER DefaultDatabase
Specifies the default database for the login.

.PARAMETER Language
Specifies the default language for the login.
#>
function Test-TargetResource
{
Expand Down Expand Up @@ -457,7 +487,11 @@ function Test-TargetResource

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

[Parameter()]
[System.String]
$Language
Comment thread
coderabbitai[bot] marked this conversation as resolved.
)

Write-Verbose -Message (
Expand Down Expand Up @@ -522,6 +556,15 @@ function Test-TargetResource
$testPassed = $false
}

if ( $PSBoundParameters.ContainsKey('Language') -and ($loginInfo.Language -ne $Language) )
{
Write-Verbose -Message (
$script:localizedData.WrongLanguage -f $Name, $loginInfo.Language, $Language
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

$testPassed = $false
}

if ( $LoginType -eq 'SqlLogin' )
{
if ( $PSBoundParameters.ContainsKey('LoginPasswordExpirationEnabled') -and $LoginPasswordExpirationEnabled -ne $loginInfo.LoginPasswordExpirationEnabled )
Expand Down
1 change: 1 addition & 0 deletions source/DSCResources/DSC_SqlLogin/DSC_SqlLogin.schema.mof
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ class DSC_SqlLogin : OMI_BaseResource
[Write, Description("Specifies if the login password is required to conform to the password policy specified in the system security policy. Only applies to _SQL Logins_.")] Boolean LoginPasswordPolicyEnforced;
[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;
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ ConvertFrom-StringData @'
ExpectedDisabled = Expected the login '{0}' to be disabled, but it is enabled.
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}'.
Comment thread
johlju marked this conversation as resolved.
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.
Expand Down
88 changes: 88 additions & 0 deletions tests/Unit/DSC_SqlLogin.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ Describe 'SqlLogin\Get-TargetResource' -Tag 'Get' {
Add-Member -MemberType NoteProperty -Name 'Name' -Value $MockLoginName -PassThru |
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 'IsDisabled' -Value $true -PassThru |
Add-Member -MemberType NoteProperty -Name 'MustChangePassword' -Value $true -PassThru |
Add-Member -MemberType NoteProperty -Name 'PasswordExpirationEnabled' -Value $true -PassThru |
Expand Down Expand Up @@ -145,6 +146,7 @@ Describe 'SqlLogin\Get-TargetResource' -Tag 'Get' {
$result.LoginType | Should -Be $MockLoginType
$result.Disabled | Should -BeTrue
$result.DefaultDatabase | Should -Be 'master'
$result.Language | Should -Be 'us_english'

if ($MockLoginType -eq 'SqlLogin')
{
Expand Down Expand Up @@ -197,6 +199,7 @@ Describe 'SqlLogin\Get-TargetResource' -Tag 'Get' {
Add-Member -MemberType NoteProperty -Name 'Name' -Value 'Login1' -PassThru |
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 'IsDisabled' -Value $true -PassThru |
Add-Member -MemberType NoteProperty -Name 'MustChangePassword' -Value $true -PassThru |
Add-Member -MemberType NoteProperty -Name 'PasswordExpirationEnabled' -Value $true -PassThru |
Expand Down Expand Up @@ -226,6 +229,7 @@ Describe 'SqlLogin\Get-TargetResource' -Tag 'Get' {
$result.LoginType | Should -BeNullOrEmpty
$result.Disabled | Should -BeFalse
$result.DefaultDatabase | Should -BeNullOrEmpty
$result.Language | Should -BeNullOrEmpty

if ($MockLoginType -eq 'SqlLogin')
{
Expand Down Expand Up @@ -456,12 +460,17 @@ Describe 'SqlLogin\Test-TargetResource' -Tag 'Test' {
MockPropertyName = 'DefaultDatabase'
MockPropertyValue = 'database1'
}
@{
MockPropertyName = 'Language'
MockPropertyValue = 'Français'
}
) {
BeforeAll {
Mock -CommandName Get-TargetResource -MockWith {
return @{
Ensure = 'Present'
DefaultDatabase = 'master'
Language = 'us_english'
<#
Switch the value of the property to the opposite of what
will be specified in the call to Test-TargetResource.
Expand Down Expand Up @@ -756,6 +765,42 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' {
}
}

Context 'When creating a new login of type WindowsUser and specifying a language' {
BeforeAll {
$mockConnectSQL = {
return New-Object -TypeName Object |
Add-Member -MemberType 'NoteProperty' -Name 'LoginMode' -Value 'Integrated' -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
Mock -CommandName Update-SQLServerLogin
}

It 'Should not throw and call the correct mocks' {
InModuleScope -ScriptBlock {
Set-StrictMode -Version 1.0

$mockSetTargetResourceParameters.Name = 'Windows\Login1'
$mockSetTargetResourceParameters.LoginType = 'WindowsUser'
$mockSetTargetResourceParameters.Language = 'Français'

$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 'Windows\Login1' } -Exactly -Times 1 -Scope It
Should -Invoke -CommandName Update-SQLServerLogin -ParameterFilter {
$Login.Name -eq 'Windows\Login1' -and $Login.Language -eq 'Français'
} -Exactly -Times 1 -Scope It
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Context 'When creating a new login of type WindowsUser and specifying that it should be disabled' {
BeforeAll {
$mockConnectSQL = {
Expand Down Expand Up @@ -941,6 +986,42 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' {
}
}

Context 'When creating a new login of type SqlLogin and specifying a language' {
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.Language = 'Français'
$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 $Login.Language -eq 'Français'
} -Exactly -Times 1 -Scope It
}
}

Context 'When creating a new login of type SqlLogin and specifying that it should be disabled' {
BeforeAll {
$mockConnectSQL = {
Expand Down Expand Up @@ -1226,6 +1307,7 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' {
# Using the stub class Login from the SMO.cs file.
$mockLoginObject = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Login' -ArgumentList ($null, 'Windows\Login1')
$mockLoginObject.DefaultDatabase = 'master'
$mockLoginObject.Language = 'us_english'

return @{
'Windows\Login1' = $mockLoginObject
Expand Down Expand Up @@ -1283,6 +1365,7 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' {
$mockLoginObject = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Login' -ArgumentList ($null, 'SqlLogin1')
$mockLoginObject.LoginType = 'SqlLogin'
$mockLoginObject.DefaultDatabase = 'master'
$mockLoginObject.Language = 'us_english'
# Switch the mock value to the opposite of what should be the desired state.
$mockLoginObject.PasswordPolicyEnforced = -not $MockPropertyValue
$mockLoginObject.PasswordExpirationEnabled = -not $MockPropertyValue
Expand Down Expand Up @@ -1386,6 +1469,10 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' {
MockPropertyName = 'DefaultDatabase'
MockPropertyValue = 'Database1'
}
@{
MockPropertyName = 'Language'
MockPropertyValue = 'Français'
}
) {
BeforeAll {
$mockConnectSQL = {
Expand All @@ -1395,6 +1482,7 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' {
$mockLoginObject = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Login' -ArgumentList ($null, 'SqlLogin1')
$mockLoginObject.LoginType = 'SqlLogin'
$mockLoginObject.DefaultDatabase = 'master'
$mockLoginObject.Language = 'us_english'

return @{
'SqlLogin1' = $mockLoginObject
Expand Down
Loading