Tests/Unit/MSFT_ADKDSKey.Tests.ps1
Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\ActiveDirectoryDsc.TestHelper.psm1') if (-not (Test-RunForCITestCategory -Type 'Unit' -Category 'Tests')) { return } $script:dscModuleName = 'ActiveDirectoryDsc' $script:dscResourceName = 'MSFT_ADKDSKey' #region HEADER # Unit Test Template Version: 1.2.4 $script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) { & git @('clone', 'https://github.com/PowerShell/DscResource.Tests.git', (Join-Path -Path $script:moduleRoot -ChildPath 'DscResource.Tests')) } Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path -Path 'DSCResource.Tests' -ChildPath 'TestHelper.psm1')) -Force $TestEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:dscModuleName ` -DSCResourceName $script:dscResourceName ` -ResourceType 'Mof' ` -TestType Unit #endregion HEADER function Invoke-TestSetup { } function Invoke-TestCleanup { Restore-TestEnvironment -TestEnvironment $TestEnvironment } # Begin Testing try { Invoke-TestSetup InModuleScope $script:dscResourceName { # Load stub cmdlets and classes. Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'Stubs\ActiveDirectory_2019.psm1') -Force # Need to do a deep copy of the Array of objects that compare returns function Copy-ArrayObjects { param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Array] $DeepCopyObject ) $memStream = New-Object -TypeName 'IO.MemoryStream' $formatter = New-Object -TypeName 'Runtime.Serialization.Formatters.Binary.BinaryFormatter' $formatter.Serialize($memStream,$DeepCopyObject) $memStream.Position = 0 $formatter.Deserialize($memStream) } $mockADDomain = 'OU=Fake,DC=contoso,DC=com' $mockKDSServerConfiguration = [pscustomobject] @{ AttributeOfWrongFormat = $null KdfParameters = $null #Byte[], not currently needed SecretAgreementParameters = $null #Byte[], not currently needed IsValidFormat = $true SecretAgreementAlgorithm = 'DH' KdfAlgorithm = 'SP800_108_CTR_HMAC' SecretAgreementPublicKeyLength = 2048 SecretAgreementPrivateKeyLength = 512 VersionNumber = 1 } $mockKDSRootKeyFuture = [pscustomobject] @{ AttributeOfWrongFormat = $null KeyValue = $null #Byte[], not currently needed EffectiveTime = [DateTime]::Parse('1/1/3000 13:00') CreationTime = [DateTime]::Parse('1/1/3000 08:00') IsFormatValid = $true DomainController = 'CN=MockDC,{0}' -f $mockADDomain ServerConfiguration = $mockKDSServerConfiguration KeyId = '92051014-f6c5-4a09-8f7a-f747728d1b9a' VersionNumber = 1 } $mockKDSRootKeyPast = [pscustomobject] @{ AttributeOfWrongFormat = $null KeyValue = $null #Byte[], not currently needed EffectiveTime = [DateTime]::Parse('1/1/2000 13:00') CreationTime = [DateTime]::Parse('1/1/2000 08:00') IsFormatValid = $true DomainController = 'CN=MockDC,{0}' -f $mockADDomain ServerConfiguration = $mockKDSServerConfiguration KeyId = '92051014-f6c5-4a09-8f7a-f747728d1b9a' VersionNumber = 1 } $mockKDSRootKeyFutureGet = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() CreationTime = $mockKDSRootKeyFuture.CreationTime KeyId = $mockKDSRootKeyFuture.KeyId Ensure = 'Present' DistinguishedName = 'CN={0},CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services,CN=Configuration,{1}' -f $mockKDSRootKeyFuture.KeyId, $mockADDomain } $mockKDSRootKeyPastGet = @{ EffectiveTime = ($mockKDSRootKeyPast.EffectiveTime).ToString() CreationTime = $mockKDSRootKeyPast.CreationTime KeyId = $mockKDSRootKeyPast.KeyId Ensure = 'Present' DistinguishedName = 'CN={0},CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services,CN=Configuration,{1}' -f $mockKDSRootKeyPast.KeyId, $mockADDomain } $mockKDSRootKeyFutureCompare = @( [pscustomobject] @{ Parameter = 'EffectiveTime' Expected = $mockKDSRootKeyFutureGet.EffectiveTime Actual = $mockKDSRootKeyFutureGet.EffectiveTime Pass = $true } [pscustomobject] @{ Parameter = 'Ensure' Expected = $mockKDSRootKeyFutureGet.Ensure Actual = $mockKDSRootKeyFutureGet.Ensure Pass = $true } [pscustomobject] @{ Parameter = 'DistinguishedName' Expected = $mockKDSRootKeyFutureGet.DistinguishedName Actual = $mockKDSRootKeyFutureGet.DistinguishedName Pass = $true } ) $mockKDSRootKeyPastCompare = @( [pscustomobject] @{ Parameter = 'EffectiveTime' Expected = $mockKDSRootKeyPastGet.EffectiveTime Actual = $mockKDSRootKeyPastGet.EffectiveTime Pass = $true } [pscustomobject] @{ Parameter = 'Ensure' Expected = $mockKDSRootKeyPastGet.Ensure Actual = $mockKDSRootKeyPastGet.Ensure Pass = $true } [pscustomobject] @{ Parameter = 'DistinguishedName' Expected = $mockKDSRootKeyPastGet.DistinguishedName Actual = $mockKDSRootKeyPastGet.DistinguishedName Pass = $true } ) #region Function Assert-HasDomainAdminRights Describe -Name 'MSFT_ADKDSKey\Assert-HasDomainAdminRights' { Context 'When Assert-HasDomainAdminRights returns true' { Context 'When the user has proper permissions' { BeforeAll { Mock -CommandName New-Object -MockWith { $object = New-MockObject -Type 'System.Security.Principal.WindowsPrincipal' $object | Add-Member -MemberType ScriptMethod -Name 'IsInRole' -Force -Value { return $true } return $object } Mock -CommandName Get-CimInstance -MockWith { return @{ProductType = 0} } } It "Should Call 'New-Object' and 'Get-CimInstance'" { $currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent() Assert-HasDomainAdminRights -User $currentUser | Should -BeTrue Assert-MockCalled -CommandName New-Object -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Get-CimInstance -Scope It -Exactly -Times 1 } } Context 'When the resource is run on a domain controller' { BeforeAll { Mock -CommandName New-Object -MockWith { $object = New-MockObject -Type 'System.Security.Principal.WindowsPrincipal' $object | Add-Member -MemberType ScriptMethod -Name 'IsInRole' -Force -Value { return $false } return $object } Mock -CommandName Get-CimInstance -MockWith { return @{ProductType = 2} } } It "Should Call 'New-Object' and 'Get-CimInstance'" { $currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent() Assert-HasDomainAdminRights -User $currentUser | Should -BeTrue Assert-MockCalled -CommandName New-Object -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Get-CimInstance -Scope It -Exactly -Times 1 } } } Context 'When Assert-HasDomainAdminRights returns false' { Context 'When the user does NOT have proper permissions' { BeforeAll { Mock -CommandName New-Object -MockWith { $object = New-MockObject -Type 'System.Security.Principal.WindowsPrincipal' $object | Add-Member -MemberType ScriptMethod -Name 'IsInRole' -Force -Value { return $false } return $object } Mock -CommandName Get-CimInstance -MockWith { return @{ProductType = 0} } } It "Should Call 'New-Object' and 'Get-CimInstance'" { $currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent() Assert-HasDomainAdminRights -User $currentUser | Should -BeFalse Assert-MockCalled -CommandName New-Object -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Get-CimInstance -Scope It -Exactly -Times 1 } } Context 'When the resource is NOT run on a domain controller' { BeforeAll { Mock -CommandName New-Object -MockWith { $object = New-MockObject -Type 'System.Security.Principal.WindowsPrincipal' $object | Add-Member -MemberType ScriptMethod -Name 'IsInRole' -Force -Value { return $false } return $object } Mock -CommandName Get-CimInstance -MockWith { return @{ProductType = 0} } } It "Should Call 'New-Object' and 'Get-CimInstance'" { $currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent() Assert-HasDomainAdminRights -User $currentUser | Should -BeFalse Assert-MockCalled -CommandName New-Object -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Get-CimInstance -Scope It -Exactly -Times 1 } } } } #endregion Function Assert-HasDomainAdminRights #region Function Get-ADRootDomainDN Describe -Name 'MSFT_ADKDSKey\Get-ADRootDomainDN' { BeforeAll { Mock -CommandName New-Object -MockWith { $object = [PSCustomObject] @{} $object | Add-Member -MemberType ScriptMethod -Name 'Get' -Value { return $mockADDomain } return $object } } It 'Should return domain distinguished name' { Get-ADRootDomainDN | Should -Be $mockADDomain } } #endregion Function Get-ADRootDomainDN #region Function Get-TargetResource Describe -Name 'MSFT_ADKDSKey\Get-TargetResource' -Tag 'Get' { BeforeAll { Mock -CommandName Assert-Module -ParameterFilter { $ModuleName -eq 'ActiveDirectory' } Mock -CommandName Get-ADRootDomainDN -MockWith { return $mockADDomain } Mock -CommandName Assert-HasDomainAdminRights -MockWith { return $true } Mock -CommandName Get-KdsRootKey } Context -Name 'When the system uses specific parameters' { It 'Should call "Assert-Module" to check AD module is installed' { $getTargetResourceParameters = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() } { Get-TargetResource @getTargetResourceParameters } | Should -Not -Throw Assert-MockCalled -CommandName Assert-Module -Scope It -Exactly -Times 1 } } Context -Name "When 'EffectiveTime' is not parsable by DateTime" { It 'Should call throw an error if EffectiveTime cannot be parsed' { $getTargetResourceParameters = @{ EffectiveTime = 'Useless Time' } { Get-TargetResource @getTargetResourceParameters -ErrorAction 'SilentlyContinue' } | Should -Throw ($script:localizedData.EffectiveTimeInvalid -f $getTargetResourceParameters.EffectiveTime) } Assert-MockCalled -CommandName Assert-HasDomainAdminRights -Scope It -Exactly -Times 0 Assert-MockCalled -CommandName Get-KdsRootKey -Scope It -Exactly -Times 0 } Context -Name "When the Current User does not have proper permissions" { Mock -CommandName Assert-HasDomainAdminRights -MockWith { return $false } It 'Should call throw an error if Context User does not have correct permissions' { $getTargetResourceParameters = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() } $currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent() { Get-TargetResource @getTargetResourceParameters -ErrorAction 'SilentlyContinue' } | Should -Throw ($script:localizedData.IncorrectPermissions -f $currentUser.Name) Assert-MockCalled -CommandName Assert-HasDomainAdminRights -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Get-KdsRootKey -Scope It -Exactly -Times 0 } } Context -Name "When 'Get-KdsRootKey' throws an error" { Mock -CommandName Get-KdsRootKey -MockWith { throw 'Microsoft.ActiveDirectory.Management.ADServerDownException' } It "Should call 'Get-KdsRootKey' and throw an error when catching any errors" { $getTargetResourceParameters = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() } { Get-TargetResource @getTargetResourceParameters -ErrorAction 'SilentlyContinue' } | Should -Throw ($script:localizedData.RetrievingKDSRootKeyError -f $getTargetResourceParameters.EffectiveTime) Assert-MockCalled -CommandName Assert-HasDomainAdminRights -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Get-KdsRootKey -Scope It -Exactly -Times 1 } } Context -Name 'When the system is in desired state' { Mock -CommandName Get-KdsRootKey -MockWith { return ,@($mockKDSRootKeyFuture) } It 'Should mock call to Get-KdsRootKey and return identical information' { $getTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() } $getTargetResourceResult = Get-TargetResource @getTargetResourceParametersFuture $getTargetResourceResult.EffectiveTime | Should -Be $mockKDSRootKeyFuture.EffectiveTime $getTargetResourceResult.CreationTime | Should -Be $mockKDSRootKeyFuture.CreationTime $getTargetResourceResult.KeyId | Should -Be $mockKDSRootKeyFuture.KeyId $getTargetResourceResult.Ensure | Should -Be 'Present' $dn = 'CN={0},CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services,CN=Configuration,{1}' -f $mockKDSRootKeyFuture.KeyId, $mockADDomain $getTargetResourceResult.DistinguishedName | Should -Be $dn Assert-MockCalled -CommandName Assert-HasDomainAdminRights -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Get-KdsRootKey -Scope It -Exactly -Times 1 } Context -Name 'When system has two or more KDS keys with the same effective date' { Mock -CommandName Write-Warning Mock -CommandName Get-KdsRootKey -MockWith { return @($mockKDSRootKeyFuture,$mockKDSRootKeyFuture) } It 'Should return Warning that more than one key exists and Error that two keys exist with the same dates' { $getTargetResourceParameters = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() } { Get-TargetResource @getTargetResourceParameters -ErrorAction 'SilentlyContinue' } | Should -Throw ($script:localizedData.FoundKDSRootKeySameEffectiveTime -f $getTargetResourceParameters.EffectiveTime) Assert-MockCalled -CommandName Write-Warning -Scope It -Times 1 Assert-MockCalled -CommandName Assert-HasDomainAdminRights -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Get-KdsRootKey -Scope It -Exactly -Times 1 } } } Context -Name 'When the system is NOT in the desired state' { Context -Name 'When no KDS root keys exists' { Mock -CommandName Get-KdsRootKey -MockWith { return $null } It "Should return 'Ensure' is 'Absent'" { $getTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() } $getTargetResourceResult = Get-TargetResource @getTargetResourceParametersFuture $getTargetResourceResult.Ensure | Should -Be 'Absent' Assert-MockCalled -CommandName Assert-HasDomainAdminRights -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Get-KdsRootKey -Scope It -Exactly -Times 1 } } Context -Name 'When the KDS root key does not exist' { Mock -CommandName Get-KdsRootKey -MockWith { return ,@($mockKDSRootKeyPast) } It "Should return 'Ensure' is 'Absent'" { $getTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() } $getTargetResourceResult = Get-TargetResource @getTargetResourceParametersFuture $getTargetResourceResult.Ensure | Should -Be 'Absent' Assert-MockCalled -CommandName Assert-HasDomainAdminRights -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Get-KdsRootKey -Scope It -Exactly -Times 1 } } } } #endregion Function Get-TargetResource #region Function Compare-TargetResourceState Describe -Name 'MSFT_ADKDSKey\Compare-TargetResourceState' -Tag 'Compare' { BeforeAll { Mock -CommandName Get-TargetResource -ParameterFilter { $mockKDSRootKeyFuture.EffectiveTime -eq $EffectiveTime } -MockWith { return $mockKDSRootKeyFutureGet } } Context -Name 'When the system is in the desired state' { $compareTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() } $compareTargetResourceResult = Compare-TargetResourceState @compareTargetResourceParametersFuture $testCases = @() $compareTargetResourceResult | ForEach-Object { $testCases += @{ Parameter = $_.Parameter Expected = $_.Expected Actual = $_.Actual Pass = $_.Pass } } It "Should return identical information for <Parameter>" -TestCases $testCases { param ( [Parameter()] $Parameter, [Parameter()] $Expected, [Parameter()] $Actual, [Parameter()] $Pass ) $Expected | Should -BeExactly $Actual $Pass | Should -BeTrue } } Context -Name 'When the system is NOT in the desired state' { $compareTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() Ensure = 'Absent' } $compareTargetResourceResult = Compare-TargetResourceState @compareTargetResourceParametersFuture $testCases = @() # Need to remove parameters that will always be true $compareTargetResourceResult = $compareTargetResourceResult | Where-Object -FilterScript { $_.Parameter -ne 'EffectiveTime' -and $_.Parameter -ne 'DistinguishedName' } $compareTargetResourceResult | ForEach-Object { $testCases += @{ Parameter = $_.Parameter Expected = $_.Expected Actual = $_.Actual Pass = $_.Pass } } It "Should return false for <Parameter>" -TestCases $testCases { param ( [Parameter()] $Parameter, [Parameter()] $Expected, [Parameter()] $Actual, [Parameter()] $Pass ) $Expected | Should -Not -Be $Actual $Pass | Should -BeFalse } } } #endregion Function Compare-TargetResourceState #region Function Test-TargetResource Describe -Name 'MSFT_ADKDSKey\Test-TargetResource' -Tag 'Test' { Context -Name "When the system is in the desired state and 'Ensure' is 'Present'" { It "Should pass when the Parameters are properly set" { Mock -CommandName Compare-TargetResourceState -MockWith { return $mockKDSRootKeyFutureCompare } $testTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() } Test-TargetResource @testTargetResourceParametersFuture | Should -BeTrue Assert-MockCalled -CommandName Compare-TargetResourceState -ParameterFilter { $mockKDSRootKeyFuture.EffectiveTime -eq $EffectiveTime } -Scope It -Exactly -Times 1 } } Context -Name "When the system is in the desired state and 'Ensure' is 'Absent'" { It "Should pass when 'Ensure' is set to 'Absent" { $mockKDSRootKeyFutureCompareEnsureAbsent = Copy-ArrayObjects $mockKDSRootKeyFutureCompare $objectEnsure = $mockKDSRootKeyFutureCompareEnsureAbsent | Where-Object -FilterScript {$_.Parameter -eq 'Ensure'} $objectEnsure.Actual = 'Absent' $objectEnsure.Pass = $true Mock -CommandName Compare-TargetResourceState -MockWith { return $mockKDSRootKeyFutureCompareEnsureAbsent } $testTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() Ensure = 'Absent' } Test-TargetResource @testTargetResourceParametersFuture | Should -BeTrue Assert-MockCalled -CommandName Compare-TargetResourceState -ParameterFilter { $mockKDSRootKeyFuture.EffectiveTime -eq $EffectiveTime } -Scope It -Exactly -Times 1 } } Context -Name "When the system is NOT in the desired state and 'Ensure' is 'Absent'" { $mockKDSRootKeyFutureCompareNotCompliant = Copy-ArrayObjects $mockKDSRootKeyFutureCompare $testIncorrectParameters = @{ Ensure = 'Absent' } $testCases = @() foreach($incorrectParameter in $testIncorrectParameters.GetEnumerator()) { $objectParameter = $mockKDSRootKeyFutureCompareNotCompliant | Where-Object -FilterScript { $_.Parameter -eq $incorrectParameter.Name } $objectParameter.Expected = $incorrectParameter.Value $objectParameter.Pass = $false $testCases += @{ Parameter = $incorrectParameter.Name; Value = $incorrectParameter.Value } } Mock -CommandName Compare-TargetResourceState -MockWith { return $mockKDSRootKeyFutureCompareNotCompliant } It "Should return $false when <Parameter> is incorrect" -TestCases $testCases { param ( [Parameter()] $Parameter, [Parameter()] $Value ) $testTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() Ensure = 'Present' } $testTargetResourceParametersFuture[$Parameter] = $value Test-TargetResource @testTargetResourceParametersFuture | Should -BeFalse Assert-MockCalled -CommandName Compare-TargetResourceState -ParameterFilter { $mockKDSRootKeyFuture.EffectiveTime -eq $EffectiveTime } -Scope It -Exactly -Times 1 } } } #endregion Function Test-TargetResource #region Function Set-TargetResource Describe -Name 'MSFT_ADKDSKey\Set-TargetResource' -Tag 'Set' { BeforeAll { Mock -CommandName Add-KDSRootKey Mock -CommandName Remove-ADObject Mock -CommandName Write-Warning } Context -Name 'When the system is in the desired state and KDS Root Key is Present' { Mock -CommandName Compare-TargetResourceState -MockWith { return $mockKDSRootKeyFutureCompare } $setTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() } It 'Should NOT take any action when all parameters are correct' { Set-TargetResource @setTargetResourceParametersFuture Assert-MockCalled -CommandName Add-KDSRootKey -Scope It -Times 0 Assert-MockCalled -CommandName Remove-ADObject -Scope It -Times 0 Assert-MockCalled -CommandName Write-Warning -Scope It -Exactly -Times 0 Assert-MockCalled -CommandName Compare-TargetResourceState -ParameterFilter { $mockKDSRootKeyFuture.EffectiveTime -eq $EffectiveTime } -Scope It -Exactly -Times 1 } } Context -Name 'When the system is in the desired state and KDS Root Key is Absent' { $mockKDSRootKeyFutureCompareEnsureAbsent = Copy-ArrayObjects $mockKDSRootKeyFutureCompare $objectEnsure = $mockKDSRootKeyFutureCompareEnsureAbsent | Where-Object -FilterScript {$_.Parameter -eq 'Ensure'} $objectEnsure.Expected = 'Absent' $objectEnsure.Pass = $false Mock -CommandName Compare-TargetResourceState -MockWith { return $mockKDSRootKeyFutureCompareEnsureAbsent } $setTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() Ensure = 'Present' } It 'Should NOT take any action when all parameters are correct' { Set-TargetResource @setTargetResourceParametersFuture Assert-MockCalled -CommandName Add-KDSRootKey -Scope It -Times 1 Assert-MockCalled -CommandName Remove-ADObject -Scope It -Times 0 Assert-MockCalled -CommandName Write-Warning -Scope It -Exactly -Times 0 Assert-MockCalled -CommandName Compare-TargetResourceState -ParameterFilter { $mockKDSRootKeyFuture.EffectiveTime -eq $EffectiveTime } -Scope It -Exactly -Times 1 } } Context -Name 'When the system is NOT in the desired state and need to remove KDS Root Key' { BeforeEach { $mockKDSRootKeyFutureCompareEnsureAbsent = Copy-ArrayObjects $mockKDSRootKeyFutureCompare $objectEnsure = $mockKDSRootKeyFutureCompareEnsureAbsent | Where-Object -FilterScript {$_.Parameter -eq 'Ensure'} $objectEnsure.Actual = 'Present' $objectEnsure.Pass = $false Mock -CommandName Compare-TargetResourceState -MockWith { return $mockKDSRootKeyFutureCompareEnsureAbsent } $setTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() Ensure = 'Absent' } } Context -Name 'When more than one KDS root key exists' { Mock -CommandName Get-KdsRootKey -MockWith { return @($mockKDSRootKeyFuture, $mockKDSRootKeyPast) } It "Should call 'Remove-ADObject' when 'Ensure' is set to 'Present'" { Set-TargetResource @setTargetResourceParametersFuture Assert-MockCalled -CommandName Add-KDSRootKey -Scope It -Times 0 Assert-MockCalled -CommandName Remove-ADObject -Scope It -Times 1 Assert-MockCalled -CommandName Write-Warning -Scope It -Exactly -Times 0 Assert-MockCalled -CommandName Get-KdsRootKey -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Compare-TargetResourceState -ParameterFilter { $mockKDSRootKeyFuture.EffectiveTime -eq $EffectiveTime } -Scope It -Exactly -Times 1 } } Context -Name 'When only one KDS root key exists' { Mock -CommandName Get-KdsRootKey -MockWith { return ,@($mockKDSRootKeyFuture) } It "Should call NOT 'Remove-ADObject' when 'Ensure' is set to 'Present' and 'ForceRemove' is 'False'" { { Set-TargetResource @setTargetResourceParametersFuture -ErrorAction 'SilentlyContinue' } | Should -Throw ($script:localizedData.NotEnoughKDSRootKeysPresentNoForce -f $setTargetResourceParametersFuture.EffectiveTime) Assert-MockCalled -CommandName Add-KDSRootKey -Scope It -Times 0 Assert-MockCalled -CommandName Remove-ADObject -Scope It -Times 0 Assert-MockCalled -CommandName Write-Warning -Scope It -Exactly -Times 0 Assert-MockCalled -CommandName Get-KdsRootKey -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Compare-TargetResourceState -ParameterFilter { $mockKDSRootKeyFuture.EffectiveTime -eq $EffectiveTime } -Scope It -Exactly -Times 1 } $setTargetResourceParametersFutureForce = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() Ensure = 'Absent' ForceRemove = $true } It "Should call 'Remove-ADObject' when 'Ensure' is set to 'Present' and 'ForceRemove' is 'True'" { Set-TargetResource @setTargetResourceParametersFutureForce Assert-MockCalled -CommandName Add-KDSRootKey -Scope It -Times 0 Assert-MockCalled -CommandName Remove-ADObject -Scope It -Times 1 Assert-MockCalled -CommandName Write-Warning -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Get-KdsRootKey -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Compare-TargetResourceState -ParameterFilter { $mockKDSRootKeyFuture.EffectiveTime -eq $EffectiveTime } -Scope It -Exactly -Times 1 } } Context -Name 'When calling Remove-ADObject fails' { Mock -CommandName Get-KdsRootKey -MockWith { return @($mockKDSRootKeyFuture, $mockKDSRootKeyPast) } Mock -CommandName Remove-ADObject -MockWith { throw 'Microsoft.ActiveDirectory.Management.ADServerDownException' } It "Should call 'Remove-ADObject' and throw an error when catching any errors" { { Set-TargetResource @setTargetResourceParametersFuture -ErrorAction 'SilentlyContinue' } | Should -Throw ($script:localizedData.KDSRootKeyRemoveError -f $setTargetResourceParametersFuture.EffectiveTime) Assert-MockCalled -CommandName Remove-ADObject -Scope It -Exactly -Times 1 } } } Context -Name 'When the system is NOT in the desired state and need to add KDS Root Key' { BeforeEach { $mockKDSRootKeyCompareEnsureAbsent = Copy-ArrayObjects $mockKDSRootKeyFutureCompare $objectEnsure = $mockKDSRootKeyCompareEnsureAbsent | Where-Object -FilterScript {$_.Parameter -eq 'Ensure'} $objectEnsure.Actual = 'Absent' $objectEnsure.Pass = $false Mock -CommandName Compare-TargetResourceState -MockWith { return $mockKDSRootKeyCompareEnsureAbsent } } It "Should call 'Add-KDSRootKey' when 'Ensure' is set to 'Present'" { $setTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() Ensure = 'Present' } Set-TargetResource @setTargetResourceParametersFuture Assert-MockCalled -CommandName Add-KDSRootKey -Scope It -Times 1 Assert-MockCalled -CommandName Remove-ADObject -Scope It -Times 0 Assert-MockCalled -CommandName Write-Warning -Scope It -Exactly -Times 0 Assert-MockCalled -CommandName Compare-TargetResourceState -ParameterFilter { $mockKDSRootKeyFuture.EffectiveTime -eq $EffectiveTime } -Scope It -Exactly -Times 1 } It "Should NOT call 'Add-KDSRootKey' when 'EffectiveTime' is past date and 'AllowUnsafeEffectiveTime' is 'False'" { $setTargetResourceParametersPast = @{ EffectiveTime = ($mockKDSRootKeyPast.EffectiveTime).ToString() Ensure = 'Present' } { Set-TargetResource @setTargetResourceParametersPast -ErrorAction 'SilentlyContinue' } | Should -Throw ($script:localizedData.AddingKDSRootKeyError -f $setTargetResourceParametersPast.EffectiveTime) Assert-MockCalled -CommandName Add-KDSRootKey -Scope It -Times 0 Assert-MockCalled -CommandName Remove-ADObject -Scope It -Times 0 Assert-MockCalled -CommandName Write-Warning -Scope It -Exactly -Times 0 Assert-MockCalled -CommandName Compare-TargetResourceState -ParameterFilter { $mockKDSRootKeyPast.EffectiveTime } -Scope It -Exactly -Times 1 } It "Should call 'Add-KDSRootKey' when 'EffectiveTime' is past date and 'AllowUnsafeEffectiveTime' is 'True'" { $setTargetResourceParametersPast = @{ EffectiveTime = ($mockKDSRootKeyPast.EffectiveTime).ToString() Ensure = 'Present' AllowUnsafeEffectiveTime = $true } Set-TargetResource @setTargetResourceParametersPast Assert-MockCalled -CommandName Add-KDSRootKey -Scope It -Times 1 Assert-MockCalled -CommandName Remove-ADObject -Scope It -Times 0 Assert-MockCalled -CommandName Write-Warning -Scope It -Exactly -Times 1 Assert-MockCalled -CommandName Compare-TargetResourceState -ParameterFilter { $mockKDSRootKeyPast.EffectiveTime } -Scope It -Exactly -Times 1 } It 'Should call throw an error if EffectiveTime cannot be parsed' { $setTargetResourceParametersFuture = @{ EffectiveTime = 'Useless Time' } { Set-TargetResource @setTargetResourceParametersFuture -ErrorAction 'SilentlyContinue' } | Should -Throw ($script:localizedData.EffectiveTimeInvalid -f $setTargetResourceParametersFuture.EffectiveTime) Assert-MockCalled -CommandName Compare-TargetResourceState -ParameterFilter { $mockKDSRootKeyFuture.EffectiveTime } -Scope It -Exactly -Times 1 } Context -Name 'When calling Add-KDSRootKey fails' { Mock -CommandName Add-KDSRootKey -MockWith { throw 'Microsoft.ActiveDirectory.Management.ADServerDownException' } It "Should call 'Add-KdsRootKey' and throw an error when catching any errors" { $setTargetResourceParametersFuture = @{ EffectiveTime = ($mockKDSRootKeyFuture.EffectiveTime).ToString() Ensure = 'Present' } { Set-TargetResource @setTargetResourceParametersFuture -ErrorAction 'SilentlyContinue' } | Should -Throw ($script:localizedData.KDSRootKeyAddError -f $setTargetResourceParametersFuture.EffectiveTime) Assert-MockCalled -CommandName Add-KdsRootKey -Scope It -Exactly -Times 1 } } } } #endregion Function Set-TargetResource } } finally { Invoke-TestCleanup } |