diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c99fd621..d3966a1cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,6 +84,8 @@ - Added PasswordNotRequired property - Added SmartcardLogonRequired property - Added ProxyAddresses property ([Issue #254](https://github.com/PowerShell/xActiveDirectory/issues/254)). + - Fix Password property being updated whenever another property is changed + ([issue #384](https://github.com/PowerShell/xActiveDirectory/issues/384)). - Changes to xADDomainController - Change the `#Requires` statement in the Examples to require the correct module. diff --git a/DSCResources/MSFT_xADUser/MSFT_xADUser.psm1 b/DSCResources/MSFT_xADUser/MSFT_xADUser.psm1 index f1c2a2cf5..a90720703 100644 --- a/DSCResources/MSFT_xADUser/MSFT_xADUser.psm1 +++ b/DSCResources/MSFT_xADUser/MSFT_xADUser.psm1 @@ -1523,10 +1523,24 @@ function Set-TargetResource elseif ($parameter -eq 'Password' -and $PasswordNeverResets -eq $false) { $adCommonParameters = Get-ADCommonParameters @PSBoundParameters + $testPasswordParams = @{ + Username = $UserName + Password = $Password + DomainName = $DomainName + PasswordAuthentication = $PasswordAuthentication + } + + if ($DomainAdministratorCredential) + { + $testPasswordParams['DomainAdministratorCredential'] = $DomainAdministratorCredential + } - Write-Verbose -Message ($script:localizedData.SettingADUserPassword -f $UserName) + if (-not (Test-Password @testPasswordParams)) + { + Write-Verbose -Message ($script:localizedData.SettingADUserPassword -f $UserName) - Set-ADAccountPassword @adCommonParameters -Reset -NewPassword $Password.Password + Set-ADAccountPassword @adCommonParameters -Reset -NewPassword $Password.Password + } } elseif ($parameter -eq 'Enabled' -and ($PSBoundParameters.$parameter -ne $targetResource.$parameter)) { diff --git a/Tests/Unit/MSFT_xADUser.Tests.ps1 b/Tests/Unit/MSFT_xADUser.Tests.ps1 index ff0ebb28a..bf584394d 100644 --- a/Tests/Unit/MSFT_xADUser.Tests.ps1 +++ b/Tests/Unit/MSFT_xADUser.Tests.ps1 @@ -490,6 +490,7 @@ try Mock -CommandName Get-ADUser -MockWith { return $fakeADUser } Mock -CommandName Set-ADUser Mock -CommandName Set-ADAccountPassword -ParameterFilter { $NewPassword -eq $testCredential.Password } + Mock -CommandName Test-Password -MockWith { $false } Set-TargetResource @testPresentParams -Password $testCredential @@ -506,6 +507,28 @@ try Assert-MockCalled -CommandName Set-ADAccountPassword -Scope It -Times 0 } + It "Does not call 'Set-ADAccountPassword' when 'Password' parameter is specified and is in the desired state" { + Mock -CommandName Get-ADUser -MockWith { return $fakeADUser } + Mock -CommandName Set-ADUser + Mock -CommandName Set-ADAccountPassword + Mock -CommandName Test-Password -MockWith { $true } + + Set-TargetResource @testPresentParams -Password $testCredential + + Assert-MockCalled -CommandName Set-ADAccountPassword -Scope It -Times 0 + } + + It "Calls 'Test-Password' with the correct parameters when 'DomainAdministratorCredential' is specified" { + Mock -CommandName Get-ADUser -MockWith { return $fakeADUser } + Mock -CommandName Set-ADUser + Mock -CommandName Set-ADAccountPassword -ParameterFilter { $NewPassword -eq $testCredential.Password } + Mock -CommandName Test-Password -ParameterFilter { $DomainAdministratorCredential -eq $testCredential } -MockWith { $true } + + Set-TargetResource @testPresentParams -Password $testCredential -DomainAdministratorCredential $testCredential + + Assert-MockCalled -CommandName Test-Password -ParameterFilter { $DomainAdministratorCredential -eq $testCredential } -Scope It -Exactly 1 + } + It "Should call 'Set-ADUser' with 'Replace' when existing mismatched AD property is null" { $testADPropertyName = 'Description' Mock -CommandName Get-ADUser -MockWith {