Tests/Unit/CertificateDsc.Common.Tests.ps1
#region HEADER $script:moduleName = 'CertificateDsc.Common' # 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 'DSCResource.Tests\TestHelper.psm1') -Force Import-Module -Name (Join-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path -Path 'Modules' -ChildPath $script:ModuleName)) -ChildPath "$script:ModuleName.psm1") -Force Import-Module -Name (Join-Path -Path (Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath 'TestHelpers') -ChildPath 'CommonTestHelper.psm1') -Global #endregion HEADER # Begin Testing InModuleScope 'CertificateDsc.Common' { Describe 'CertificateDsc.Common\Test-DscParameterState' -Tag TestDscParameterState { Context -Name 'When passing values' -Fixture { It 'Should return true for two identical tables' { $mockDesiredValues = @{ Example = 'test' } $testParameters = @{ CurrentValues = $mockDesiredValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $true } It 'Should return false when a value is different for [System.String]' { $mockCurrentValues = @{ Example = [System.String] 'something' } $mockDesiredValues = @{ Example = [System.String] 'test' } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $false } It 'Should return false when a value is different for [System.Int32]' { $mockCurrentValues = @{ Example = [System.Int32] 1 } $mockDesiredValues = @{ Example = [System.Int32] 2 } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $false } It 'Should return false when a value is different for [Int16]' { $mockCurrentValues = @{ Example = [System.Int16] 1 } $mockDesiredValues = @{ Example = [System.Int16] 2 } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $false } It 'Should return false when a value is different for [UInt16]' { $mockCurrentValues = @{ Example = [System.UInt16] 1 } $mockDesiredValues = @{ Example = [System.UInt16] 2 } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $false } It 'Should return false when a value is different for [Boolean]' { $mockCurrentValues = @{ Example = [System.Boolean] $true } $mockDesiredValues = @{ Example = [System.Boolean] $false } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $false } It 'Should return false when a value is missing' { $mockCurrentValues = @{ } $mockDesiredValues = @{ Example = 'test' } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $false } It 'Should return true when only a specified value matches, but other non-listed values do not' { $mockCurrentValues = @{ Example = 'test'; SecondExample = 'true' } $mockDesiredValues = @{ Example = 'test'; SecondExample = 'false' } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues ValuesToCheck = @('Example') } Test-DscParameterState @testParameters | Should -Be $true } It 'Should return false when only specified values do not match, but other non-listed values do ' { $mockCurrentValues = @{ Example = 'test'; SecondExample = 'true' } $mockDesiredValues = @{ Example = 'test'; SecondExample = 'false' } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues ValuesToCheck = @('SecondExample') } Test-DscParameterState @testParameters | Should -Be $false } It 'Should return false when an empty hash table is used in the current values' { $mockCurrentValues = @{ } $mockDesiredValues = @{ Example = 'test'; SecondExample = 'false' } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $false } It 'Should return true when evaluating a table against a CimInstance' { $mockCurrentValues = @{ Handle = '0'; ProcessId = '1000' } $mockWin32ProcessProperties = @{ Handle = 0 ProcessId = 1000 } $mockNewCimInstanceParameters = @{ ClassName = 'Win32_Process' Property = $mockWin32ProcessProperties Key = 'Handle' ClientOnly = $true } $mockDesiredValues = New-CimInstance @mockNewCimInstanceParameters $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues ValuesToCheck = @('Handle', 'ProcessId') } Test-DscParameterState @testParameters | Should -Be $true } It 'Should return false when evaluating a table against a CimInstance and a value is wrong' { $mockCurrentValues = @{ Handle = '1'; ProcessId = '1000' } $mockWin32ProcessProperties = @{ Handle = 0 ProcessId = 1000 } $mockNewCimInstanceParameters = @{ ClassName = 'Win32_Process' Property = $mockWin32ProcessProperties Key = 'Handle' ClientOnly = $true } $mockDesiredValues = New-CimInstance @mockNewCimInstanceParameters $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues ValuesToCheck = @('Handle', 'ProcessId') } Test-DscParameterState @testParameters | Should -Be $false } It 'Should return true when evaluating a hash table containing an array' { $mockCurrentValues = @{ Example = 'test'; SecondExample = @('1', '2') } $mockDesiredValues = @{ Example = 'test'; SecondExample = @('1', '2') } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $true } It 'Should return false when evaluating a hash table containing an array with wrong values' { $mockCurrentValues = @{ Example = 'test'; SecondExample = @('A', 'B') } $mockDesiredValues = @{ Example = 'test'; SecondExample = @('1', '2') } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $false } It 'Should return false when evaluating a hash table containing an array, but the CurrentValues are missing an array' { $mockCurrentValues = @{ Example = 'test' } $mockDesiredValues = @{ Example = 'test'; SecondExample = @('1', '2') } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $false } It 'Should return false when evaluating a hash table containing an array, but the property i CurrentValues is $null' { $mockCurrentValues = @{ Example = 'test'; SecondExample = $null } $mockDesiredValues = @{ Example = 'test'; SecondExample = @('1', '2') } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $false } } Context -Name 'When passing invalid types for DesiredValues' -Fixture { It 'Should throw the correct error when DesiredValues is of wrong type' { $mockCurrentValues = @{ Example = 'something' } $mockDesiredValues = 'NotHashTable' $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } $mockCorrectErrorMessage = ($script:localizedData.PropertyTypeInvalidForDesiredValues -f $testParameters.DesiredValues.GetType().Name) { Test-DscParameterState @testParameters } | Should -Throw $mockCorrectErrorMessage } It 'Should write a warning when DesiredValues contain an unsupported type' { Mock -CommandName Write-Warning -Verifiable # This is a dummy type to test with a type that could never be a correct one. class MockUnknownType { [ValidateNotNullOrEmpty()] [System.String] $Property1 [ValidateNotNullOrEmpty()] [System.String] $Property2 MockUnknownType() { } } $mockCurrentValues = @{ Example = New-Object -TypeName MockUnknownType } $mockDesiredValues = @{ Example = New-Object -TypeName MockUnknownType } $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues } Test-DscParameterState @testParameters | Should -Be $false Assert-MockCalled -CommandName Write-Warning -Exactly -Times 1 } } Context -Name 'When passing an CimInstance as DesiredValue and ValuesToCheck is $null' -Fixture { It 'Should throw the correct error' { $mockCurrentValues = @{ Example = 'something' } $mockWin32ProcessProperties = @{ Handle = 0 ProcessId = 1000 } $mockNewCimInstanceParameters = @{ ClassName = 'Win32_Process' Property = $mockWin32ProcessProperties Key = 'Handle' ClientOnly = $true } $mockDesiredValues = New-CimInstance @mockNewCimInstanceParameters $testParameters = @{ CurrentValues = $mockCurrentValues DesiredValues = $mockDesiredValues ValuesToCheck = $null } $mockCorrectErrorMessage = $script:localizedData.PropertyTypeInvalidForValuesToCheck { Test-DscParameterState @testParameters } | Should -Throw $mockCorrectErrorMessage } } Assert-VerifiableMock } Describe 'CertificateDsc.Common\Get-LocalizedData' { $mockTestPath = { return $mockTestPathReturnValue } $mockImportLocalizedData = { $BaseDirectory | Should -Be $mockExpectedLanguagePath } BeforeEach { Mock -CommandName Test-Path -MockWith $mockTestPath -Verifiable Mock -CommandName Import-LocalizedData -MockWith $mockImportLocalizedData -Verifiable } Context 'When loading localized data for Swedish' { $mockExpectedLanguagePath = 'sv-SE' $mockTestPathReturnValue = $true It 'Should call Import-LocalizedData with sv-SE language' { Mock -CommandName Join-Path -MockWith { return 'sv-SE' } -Verifiable { Get-LocalizedData -ResourceName 'DummyResource' } | Should -Not -Throw Assert-MockCalled -CommandName Join-Path -Exactly -Times 3 -Scope It Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Import-LocalizedData -Exactly -Times 1 -Scope It } $mockExpectedLanguagePath = 'en-US' $mockTestPathReturnValue = $false It 'Should call Import-LocalizedData and fallback to en-US if sv-SE language does not exist' { Mock -CommandName Join-Path -MockWith { return $ChildPath } -Verifiable { Get-LocalizedData -ResourceName 'DummyResource' } | Should -Not -Throw Assert-MockCalled -CommandName Join-Path -Exactly -Times 4 -Scope It Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Import-LocalizedData -Exactly -Times 1 -Scope It } Context 'When $ScriptRoot is set to a path' { $mockExpectedLanguagePath = 'sv-SE' $mockTestPathReturnValue = $true It 'Should call Import-LocalizedData with sv-SE language' { Mock -CommandName Join-Path -MockWith { return 'sv-SE' } -Verifiable { Get-LocalizedData -ResourceName 'DummyResource' -ScriptRoot '.' } | Should -Not -Throw Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Import-LocalizedData -Exactly -Times 1 -Scope It } $mockExpectedLanguagePath = 'en-US' $mockTestPathReturnValue = $false It 'Should call Import-LocalizedData and fallback to en-US if sv-SE language does not exist' { Mock -CommandName Join-Path -MockWith { return $ChildPath } -Verifiable { Get-LocalizedData -ResourceName 'DummyResource' -ScriptRoot '.' } | Should -Not -Throw Assert-MockCalled -CommandName Join-Path -Exactly -Times 2 -Scope It Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Import-LocalizedData -Exactly -Times 1 -Scope It } } } Context 'When loading localized data for English' { Mock -CommandName Join-Path -MockWith { return 'en-US' } -Verifiable $mockExpectedLanguagePath = 'en-US' $mockTestPathReturnValue = $true It 'Should call Import-LocalizedData with en-US language' { { Get-LocalizedData -ResourceName 'DummyResource' } | Should -Not -Throw } } Assert-VerifiableMock } Describe 'CertificateDsc.Common\New-InvalidResultException' { Context 'When calling with Message parameter only' { It 'Should throw the correct error' { $mockErrorMessage = 'Mocked error' { New-InvalidResultException -Message $mockErrorMessage } | Should -Throw $mockErrorMessage } } Context 'When calling with both the Message and ErrorRecord parameter' { It 'Should throw the correct error' { $mockErrorMessage = 'Mocked error' $mockExceptionErrorMessage = 'Mocked exception error message' $mockException = New-Object -TypeName System.Exception -ArgumentList $mockExceptionErrorMessage $mockErrorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList $mockException, $null, 'InvalidResult', $null { New-InvalidResultException -Message $mockErrorMessage -ErrorRecord $mockErrorRecord } | Should -Throw ('System.Exception: {0} ---> System.Exception: {1}' -f $mockErrorMessage, $mockExceptionErrorMessage) } } Assert-VerifiableMock } Describe 'CertificateDsc.Common\New-ObjectNotFoundException' { Context 'When calling with Message parameter only' { It 'Should throw the correct error' { $mockErrorMessage = 'Mocked error' { New-ObjectNotFoundException -Message $mockErrorMessage } | Should -Throw $mockErrorMessage } } Context 'When calling with both the Message and ErrorRecord parameter' { It 'Should throw the correct error' { $mockErrorMessage = 'Mocked error' $mockExceptionErrorMessage = 'Mocked exception error message' $mockException = New-Object -TypeName System.Exception -ArgumentList $mockExceptionErrorMessage $mockErrorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList $mockException, $null, 'InvalidResult', $null { New-ObjectNotFoundException -Message $mockErrorMessage -ErrorRecord $mockErrorRecord } | Should -Throw ('System.Exception: {0} ---> System.Exception: {1}' -f $mockErrorMessage, $mockExceptionErrorMessage) } } Assert-VerifiableMock } Describe 'CertificateDsc.Common\New-InvalidOperationException' { Context 'When calling with Message parameter only' { It 'Should throw the correct error' { $mockErrorMessage = 'Mocked error' { New-InvalidOperationException -Message $mockErrorMessage } | Should -Throw $mockErrorMessage } } Context 'When calling with both the Message and ErrorRecord parameter' { It 'Should throw the correct error' { $mockErrorMessage = 'Mocked error' $mockExceptionErrorMessage = 'Mocked exception error message' $mockException = New-Object -TypeName System.Exception -ArgumentList $mockExceptionErrorMessage $mockErrorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList $mockException, $null, 'InvalidResult', $null { New-InvalidOperationException -Message $mockErrorMessage -ErrorRecord $mockErrorRecord } | Should -Throw ('System.InvalidOperationException: {0} ---> System.Exception: {1}' -f $mockErrorMessage, $mockExceptionErrorMessage) } } Assert-VerifiableMock } Describe 'CertificateDsc.Common\New-NotImplementedException' { Context 'When called with Message parameter only' { It 'Should throw the correct error' { $mockErrorMessage = 'Mocked error' { New-NotImplementedException -Message $mockErrorMessage } | Should -Throw $mockErrorMessage } } Context 'When called with both the Message and ErrorRecord parameter' { It 'Should throw the correct error' { $mockErrorMessage = 'Mocked error' $mockExceptionErrorMessage = 'Mocked exception error message' $mockException = New-Object -TypeName System.Exception -ArgumentList $mockExceptionErrorMessage $mockErrorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList $mockException, $null, 'InvalidResult', $null { New-NotImplementedException -Message $mockErrorMessage -ErrorRecord $mockErrorRecord } | Should -Throw ('System.NotImplementedException: {0} ---> System.Exception: {1}' -f $mockErrorMessage, $mockExceptionErrorMessage) } } Assert-VerifiableMock } Describe 'CertificateDsc.Common\New-InvalidArgumentException' { Context 'When calling with both the Message and ArgumentName parameter' { It 'Should throw the correct error' { $mockErrorMessage = 'Mocked error' $mockArgumentName = 'MockArgument' { New-InvalidArgumentException -Message $mockErrorMessage -ArgumentName $mockArgumentName } | Should -Throw ('Parameter name: {0}' -f $mockArgumentName) } } Assert-VerifiableMock } $invalidThumbprint = 'Zebra' $definedRuntimeTypes = ([System.AppDomain]::CurrentDomain.GetAssemblies() | Where-Object -FilterScript { $null -ne $_.DefinedTypes }).GetTypes() # This thumbprint is valid (but not FIPS valid) $validThumbprint = ( $definedRuntimeTypes | Where-Object -FilterScript { $_.BaseType.BaseType -eq [System.Security.Cryptography.HashAlgorithm] -and ($_.Name -cmatch 'Managed$' -or $_.Name -cmatch 'Provider$') } | Select-Object -First 1 | ForEach-Object -Process { (New-Object $_).ComputeHash([String]::Empty) | ForEach-Object -Process { '{0:x2}' -f $_ } } ) -join '' # This thumbprint is valid for FIPS $validFipsThumbprint = ( $definedRuntimeTypes | Where-Object -FilterScript { $_.BaseType.BaseType -eq [System.Security.Cryptography.HashAlgorithm] -and ($_.Name -cmatch 'Provider$' -and $_.Name -cnotmatch 'MD5') } | Select-Object -First 1 | ForEach-Object -Process { (New-Object $_).ComputeHash([String]::Empty) | ForEach-Object -Process { '{0:x2}' -f $_ } } ) -join '' $testFile = 'test.pfx' $invalidPath = 'TestDrive:' $validPath = "TestDrive:\$testFile" $cerFileWithSan = " -----BEGIN CERTIFICATE----- MIIGJDCCBAygAwIBAgITewAAAAqQ+bxgiZZPtgAAAAAACjANBgkqhkiG9w0BAQsF ADBDMRMwEQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHY29udG9z bzETMBEGA1UEAwwKTGFiUm9vdENBMTAeFw0xNzA1MDkxNTM5NTJaFw0xOTA1MDkx NTM5NTJaMBYxFDASBgNVBAMMC3NvbWVtYWNoaW5lMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA0Id9FC2vq90HPWraZnAouit8MZI/p/DeucFiCb6mieuP 017DPCiQKuMQFQmx5VWvv82mpddxmTPtV6zfda0E5R12a11KHJ2mJrK5oR2iuI/I P2SJBlNAkLTsvd96zUqQcWCCE/Q2nSrK7nx3oBq4Dd5+wLfUvAMKR45RXK58J4z5 h3mLxF+ryKnQzQHKXDC4x92hMIPJVwvPym8C3067Ry6kLHhFOk5IoJjiRmS6P1TT 48aHipWeiK9G/aLgKTS4UEbUMooAPfeHQXGRfS4fIEQmaaeY0wqQAVYGau2oDn6m 31SiNEA+NmAmHZFvM2kXf63L58lJASFqRnXquVCw9QIDAQABo4ICPDCCAjgwIQYJ KwYBBAGCNxQCBBQeEgBXAGUAYgBTAGUAcgB2AGUAcjATBgNVHSUEDDAKBggrBgEF BQcDATAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0OBBYEFGFGkDLulJ3m1Bx3DIa1BosB WpOXMCgGA1UdEQQhMB+CCGZpcnN0c2FugglzZWNvbmRzYW6CCHRoaXJkc2FuMB8G A1UdIwQYMBaAFN75yc566Q03FdJ4ZQ/6Kn8dohYVMIHEBgNVHR8Egbwwgbkwgbag gbOggbCGga1sZGFwOi8vL0NOPUxhYlJvb3RDQTEsQ049Q0ExLENOPUNEUCxDTj1Q dWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0 aW9uLERDPWNvbnRvc28sREM9Y29tP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/ YmFzZT9vYmplY3RDbGFzcz1jUkxEaXN0cmlidXRpb25Qb2ludDCBvAYIKwYBBQUH AQEEga8wgawwgakGCCsGAQUFBzAChoGcbGRhcDovLy9DTj1MYWJSb290Q0ExLENO PUFJQSxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1D b25maWd1cmF0aW9uLERDPWNvbnRvc28sREM9Y29tP2NBQ2VydGlmaWNhdGU/YmFz ZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MA0GCSqGSIb3DQEB CwUAA4ICAQBUkvBdMgZsUHDEaVyBuHzALExcEflkvCq1AmJ1U2nixnfcqc5Wb3df W+gauW+YbOA9EfQrwPqMXvo0dhsjLn3H5tTWe0VVT5H8pgsdcXS/5cYDjoC6N3pd NZGCDN/oHAm8BgcNPPYyG8VDMxR+atp8Iv12nCDGQlpPkANK+nUHR8Nu66l/wDqF G8ftnQ7C3mSu4/baAFOAx91rXDbrs1ewrqfcBWxRQn4CZbZs9LMg+NQjrAM8WtQX DZd96IMY6m8DeVbIQQiHytpjpQr8aJs6s5Cd5XzRWPXb4lDMOe/4KwpyQAHjtFPY mYhUfaInXtna/li9MKLK+j641FnBJv6bjWhw1Jp++wHdjef+1RTtG1hslHQXsH48 +n+jHZ5A5DKgOYUJWq3NhYvQwtQmDlBNe5aJbTmAFz7qpsPFWjoOqX8RXCE3Mt+R EhwMvEGNZHdsgMVXeJsqVssG2FfM7cqcslaUL/vULRWJ6LmJerjmSBRXcEHL6uTe IJPSLdUdPx7uvm+P4qpuIuzZ2bdHXqiFbL6yPyWi8lTaApzT/K7Y0Q3oRWYOuThK P2l4M+F7l346gaIDDZOXdrSsrPghSgkS4Xp3QtE6NnKq+V0pX2YHnns+JO97hEXt 2EvKX3TnKnUPPrsl/CffTBpJEsD7xugu6OAn4KnEzzVTNYqzDbYx6g== -----END CERTIFICATE----- " $cerFileWithoutSan = " -----BEGIN CERTIFICATE----- MIIDBjCCAe6gAwIBAgIQRQyErZRGrolI5DfZCJDaTTANBgkqhkiG9w0BAQsFADAW MRQwEgYDVQQDDAtTb21lU2VydmVyMjAeFw0xNzA1MDkxNjI0MTZaFw0xODA1MDkx NjQ0MTZaMBYxFDASBgNVBAMMC1NvbWVTZXJ2ZXIyMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA2x7gR/yQYSiqszd0+e3ZMX2b/mK3XwwEHhoXARoC/Jv/ rmOmESB6AYabIheGmDv2qUESx6r8KtO4afunVEyoxeThQ8LffgduSo0YIUVgqyg9 o+HUOaV4MX5cGutgov62MCs+HO2AYcl2QvmbJ9CF/nyGOigoLNOX1pLPHHM1vIFQ euBCX8KGK02kgl629QVckiUKrn5bCjboxx7JvSsb2UTcCDjR7x1FcGkxwj069koq VdtmwzC3ibYSxQ2UQo1rShol8FPTMkpf8NIZmApY3RGddnAl+r0fznbqqdwzRPjp 1zXuNwYiG/cL/OOt50TQqCKA7CrD9m8Y3yWKK1ilOQIDAQABo1AwTjAOBgNVHQ8B Af8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMB0GA1UdDgQW BBSfthQiQydgIs0dXquThRhnkj78HTANBgkqhkiG9w0BAQsFAAOCAQEAuaACrNbE clIxVjSsJA4kT7z+ajTD7EmT3iX+h1sOABTuiSjR+fBCF/7AgViK24+xdLzuptCH MnoLW7epdP1tRXjs0vb5xwXRsTruwlIzCbvkH8/xkrc6YGw5LzdvxtFPYV+vSsx3 uUmNlrD7ElllzRVzyGBd2VBm8hCAI0297Ls9zJlWDPYTMpedleO2D9vZBAxg3iY7 yiMbficleMbVEE3LTNjK6iYuENZ4KOBkOJU936+lqfcVnOFTvWhLJKxTEMZ7XW4k pP3LiEhYnnxMfm7OyNHL+MnQhq8OV7tY3pZofPdImEeG13qcV8EBYhefFgsSxQRe JqptPVHBXySjMg== -----END CERTIFICATE----- " $cerFileWithAltTemplateName = " -----BEGIN CERTIFICATE----- MIIDVjCCAj6gAwIBAgIQIA9TO/nfla5FrjJZIiI6nzANBgkqhkiG9w0BAQsFADAW MRQwEgYDVQQDDAtzb21lbWFjaGluZTAeFw0xOTAyMTUxNjI3NDVaFw0yMDAyMTUx NjQ3NDVaMBYxFDASBgNVBAMMC3NvbWVtYWNoaW5lMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAuwr0qT/ekYvp4RIHfEqsZyabdWUIR842P/1+t2b0W5bn LqxER+mUuBOrbdNcekjQjTnq5rYy1WsIwjeuJ7zgmVINvL8KeYna750M5ngAZsqO QoRR9xbQAeht2H1Q9vj/GHbakOKUW45It/0EvZLmF/FJ2+WdIGQMuqQVdr4N+w0f DPIVjDCjRLT5USZOHWJGrKYDSaWSf5tEQAp/6RW3JnFkE2biWsYQ3FGZtVgRxjLS 4+602xnLTyjakQiXBosE0AuW36jiFPeW3WVVF1pdinPpIbtzE0CkoeEwPMfWNJaA BfIVmkEKL8HeQGk4kSEvZ/zfNbPr7RfY3S925SeR5QIDAQABo4GfMIGcMA4GA1Ud DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwKAYDVR0R BCEwH4IIZmlyc3RzYW6CCXNlY29uZHNhboIIdGhpcmRzYW4wIgYJKwYBBAGCNxQC BBUeEgBXAGUAYgBTAGUAcgB2AGUAcgAwHQYDVR0OBBYEFNzXV7OE2NNKgKeLPTbT +YBIcPJXMA0GCSqGSIb3DQEBCwUAA4IBAQBigwVwGdmE/RekuKY++7oxIrnWkQ0L VN+ps5pVLM3+P1XaHdtRUVAHErBuRaqZMTHc4REzSE6PNozrznQJknEnMc6d4y4+ IZ5pfPl8eyuPs6nBAP5aA3KhC9lW72csjXqe+EJNHfCP0k3AOkBb1A6Cja36h8Ef lJiPqE2bRualoz6iqcHftilLCF+8s7q1sW12730PK1BD+gqQo0o8N0fZrXhWU4/I 0nuuz7F7VEaNcpZD7leBPCiNdsyDkLIfkb2cj4R39Fbs0yuuG6Bv1jQ+adXXprCG ZMCE85eAK5et3yur0hVcUHppM6oDPOyoCYnUhDthiO3rwnfRCr/1f3IB -----END CERTIFICATE----- " $cerFileWithAltTemplateInformation = " -----BEGIN CERTIFICATE----- MIIDazCCAlOgAwIBAgIQJx7ZH+jq5YZLy436X4Li3TANBgkqhkiG9w0BAQsFADAW MRQwEgYDVQQDDAtzb21lbWFjaGluZTAeFw0xODA4MDcwOTEwNDVaFw0xOTA4MDcw OTMwNDVaMBYxFDASBgNVBAMMC3NvbWVtYWNoaW5lMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA98nll0sk4LiGTJcbZ+jIY86ongKRNE6CH+LZ0gp4mzUY FRufTwmWqqoTjg6Q/Ri+CvofX1CbeaHCSdvI76/vIzF0ij+Y3wGg4Ot8YljbTjsF aig3hGaWp+/Q345+O+sTlppwipcmdlp8vS8PNWx+FRbPFyPYSNTHbdFQXGjlz7Lu s1gFe9VGbBqditYhvYPJeHjUSBWVDve2vd+E9ECRKssxn3UME74yuRSzEq30ly44 LPZYRYd8maypJERcMAkRz19bXZ1BNYp1kesxoi0KK7LLodSSzPG01Pls/K51KhZA 6NuFe14kA+jsAnstWQ2lIofUZxHrQ4IfykmgmP3NmQIDAQABo4G0MIGxMA4GA1Ud DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwKAYDVR0R BCEwH4IIZmlyc3RzYW6CCXNlY29uZHNhboIIdGhpcmRzYW4wNwYJKwYBBAGCNxUH BCowKAYgKwYBBAGCNxUIgt3/eIL6kR6HjYUJhpmDKIHSoVI+ARACAWQCAQUwHQYD VR0OBBYEFNt1uNJH8KG4/X0Gzh4rnAPR5lBfMA0GCSqGSIb3DQEBCwUAA4IBAQBI MyZvohjsm1wbxJvowp5QrKXvGs8XVl+97zY79h8QqtcZALtIHkZd8rj2Bvkd+qyU o01rPj7+LS7HzkdqfmDRUxbAnDclOkUTCMskzxon9CzEsizomFyTq4khWh/p+7fE mR2Rq/kA95aupS4Dm7HcncHn89nw9BKcP7WLgIzjRC3ZBzplEGCCL7aKDv66+dv/ HM2uI47A8kHCFMvaq6O0bjlJfmXvrX8OgVQlRDItiuM+pu9LMkWc0t8U4ekRRQdj kVIXdpdvNQmud6JHv3OI0HrjtL7Da1dK7Q8qye3qHBzHwva6SMVbMmFC3ACxukBU v+M0WvuaEOEmAQoYaY6K -----END CERTIFICATE----- " $cerBytes = [System.Text.Encoding]::ASCII.GetBytes($cerFileWithSan) $cerBytesWithoutSan = [System.Text.Encoding]::ASCII.GetBytes($cerFileWithoutSan) $cerBytesWithAltTemplateName = [System.Text.Encoding]::ASCII.GetBytes($cerFileWithAltTemplateName) $cerBytesWithAltTemplateInformation = [System.Text.Encoding]::ASCII.GetBytes($cerFileWithAltTemplateInformation) $testCertificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($cerBytes) $testCertificateWithoutSan = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($cerBytesWithoutSan) $testCertificateWithAltTemplateName = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($cerBytesWithAltTemplateName) $testCertificateWithAltTemplateInformation = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($cerBytesWithAltTemplateInformation) Describe 'CertificateDsc.Common\Test-CertificatePath' { $null | Set-Content -Path $validPath Context 'a single existing file by parameter' { $result = Test-CertificatePath -Path $validPath It 'Should return true' { ($result -is [bool]) | Should -Be $true $result | Should -Be $true } } Context 'a single missing file by parameter' { It 'Should throw an exception' { # directories are not valid { Test-CertificatePath -Path $invalidPath } | Should -Throw } } Context 'a single missing file by parameter with -Quiet' { $result = Test-CertificatePath -Path $invalidPath -Quiet It 'Should return false' { ($result -is [bool]) | Should -Be $true $result | Should -Be $false } } Context 'a single existing file by pipeline' { $result = $validPath | Test-CertificatePath It 'Should return true' { ($result -is [bool]) | Should -Be $true $result | Should -Be $true } } Context 'a single missing file by pipeline' { It 'Should throw an exception' { # directories are not valid { $invalidPath | Test-CertificatePath } | Should -Throw } } Context 'a single missing file by pipeline with -Quiet' { $result = $invalidPath | Test-CertificatePath -Quiet It 'Should return false' { ($result -is [bool]) | Should -Be $true $result | Should -Be $false } } } Describe 'CertificateDsc.Common\Test-Thumbprint' { Context 'When FIPS not set' { Context 'When a single valid thumbrpint by parameter is passed' { $result = Test-Thumbprint -Thumbprint $validThumbprint It 'Should return true' { $result | Should -BeOfType [System.Boolean] $result | Should -Be $true } } Context 'When a single invalid thumbprint by parameter is passed' { It 'Should throw an exception' { { Test-Thumbprint -Thumbprint $invalidThumbprint } | Should -Throw } } Context 'When a single invalid thumbprint by parameter with -Quiet is passed' { $result = Test-Thumbprint $invalidThumbprint -Quiet It 'Should return false' { $result | Should -BeOfType [System.Boolean] $result | Should -Be $false } } Context 'When a single valid thumbprint by pipeline is passed' { $result = $validThumbprint | Test-Thumbprint It 'Should return true' { $result | Should -BeOfType [System.Boolean] $result | Should -Be $true } } Context 'When a single invalid thumbprint by pipeline is passed' { It 'Should throw an exception' { { $invalidThumbprint | Test-Thumbprint } | Should -Throw } } Context 'When a single invalid thumbprint by pipeline with -Quiet is passed' { $result = $invalidThumbprint | Test-Thumbprint -Quiet It 'Should return false' { $result | Should -BeOfType [System.Boolean] $result | Should -Be $false } } } Context 'When FIPS is enabled' { Mock -CommandName Get-ItemProperty -MockWith { @{ Enabled = 1 } } Context 'When a single valid FIPS thumbrpint by parameter is passed' { $result = Test-Thumbprint -Thumbprint $validFipsThumbprint It 'Should return true' { $result | Should -BeOfType [System.Boolean] $result | Should -Be $true } } Context 'When a single invalid FIPS thumbprint by parameter is passed' { It 'Should throw an exception' { { Test-Thumbprint -Thumbprint $validThumbprint } | Should -Throw } } Context 'When a single invalid FIPS thumbprint by parameter with -Quiet is passed' { $result = Test-Thumbprint $validThumbprint -Quiet It 'Should return false' { $result | Should -BeOfType [System.Boolean] $result | Should -Be $false } } Context 'When a single valid FIPS thumbprint by pipeline is passed' { $result = $validFipsThumbprint | Test-Thumbprint It 'Should return true' { $result | Should -BeOfType [System.Boolean] $result | Should -Be $true } } Context 'When a single invalid FIPS thumbprint by pipeline is passed' { It 'Should throw an exception' { { $validThumbprint | Test-Thumbprint } | Should -Throw } } Context 'When a single invalid FIPS thumbprint by pipeline with -Quiet is passed' { $result = $validThumbprint | Test-Thumbprint -Quiet It 'Should return false' { $result | Should -BeOfType [System.Boolean] $result | Should -Be $false } } } } Describe 'CertificateDsc.Common\Find-Certificate' { # Download and dot source the New-SelfSignedCertificateEx script . (Install-NewSelfSignedCertificateExScript) # Generate the Valid certificate for testing but remove it from the store straight away $certDNSNames = @('www.fabrikam.com', 'www.contoso.com') $certDNSNamesReverse = @('www.contoso.com', 'www.fabrikam.com') $certDNSNamesNoMatch = $certDNSNames + @('www.nothere.com') $certKeyUsage = @('DigitalSignature', 'DataEncipherment') $certKeyUsageReverse = @('DataEncipherment', 'DigitalSignature') $certKeyUsageNoMatch = $certKeyUsage + @('KeyEncipherment') $certEKU = @('Server Authentication', 'Client authentication') $certEKUReverse = @('Client authentication', 'Server Authentication') $certEKUNoMatch = $certEKU + @('Encrypting File System') $certSubject = 'CN=contoso, DC=com' $certFriendlyName = 'Contoso Test Cert' $validCert = New-SelfSignedCertificateEx ` -Subject $certSubject ` -KeyUsage $certKeyUsage ` -KeySpec 'Exchange' ` -EKU $certEKU ` -SubjectAlternativeName $certDNSNames ` -FriendlyName $certFriendlyName ` -StoreLocation 'CurrentUser' ` -Exportable # Pull the generated certificate from the store so we have the friendlyname $validThumbprint = $validCert.Thumbprint $validCert = Get-Item -Path "cert:\CurrentUser\My\$validThumbprint" Remove-Item -Path $validCert.PSPath -Force # Generate the Expired certificate for testing but remove it from the store straight away $expiredCert = New-SelfSignedCertificateEx ` -Subject $certSubject ` -KeyUsage $certKeyUsage ` -KeySpec 'Exchange' ` -EKU $certEKU ` -SubjectAlternativeName $certDNSNames ` -FriendlyName $certFriendlyName ` -NotBefore ((Get-Date) - (New-TimeSpan -Days 2)) ` -NotAfter ((Get-Date) - (New-TimeSpan -Days 1)) ` -StoreLocation 'CurrentUser' ` -Exportable # Pull the generated certificate from the store so we have the friendlyname $expiredThumbprint = $expiredCert.Thumbprint $expiredCert = Get-Item -Path "cert:\CurrentUser\My\$expiredThumbprint" Remove-Item -Path $expiredCert.PSPath -Force $nocertThumbprint = '1111111111111111111111111111111111111111' # Dynamic mock content for Get-ChildItem $mockGetChildItem = { switch ( $Path ) { 'cert:\LocalMachine\My' { return @( $validCert ) } 'cert:\LocalMachine\NoCert' { return @() } 'cert:\LocalMachine\TwoCerts' { return @( $expiredCert, $validCert ) } 'cert:\LocalMachine\Expired' { return @( $expiredCert ) } default { throw 'mock called with unexpected value {0}' -f $Path } } } BeforeEach { Mock ` -CommandName Test-Path ` -MockWith { $true } Mock ` -CommandName Get-ChildItem ` -MockWith $mockGetChildItem } Context 'Thumbprint only is passed and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -Thumbprint $validThumbprint } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'Thumbprint only is passed and matching certificate does not exist' { It 'Should not throw exception' { { $script:result = Find-Certificate -Thumbprint $nocertThumbprint } | Should -Not -Throw } It 'Should return null' { $script:result | Should -BeNullOrEmpty } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'FriendlyName only is passed and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -FriendlyName $certFriendlyName } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'FriendlyName only is passed and matching certificate does not exist' { It 'Should not throw exception' { { $script:result = Find-Certificate -FriendlyName 'Does Not Exist' } | Should -Not -Throw } It 'Should return null' { $script:result | Should -BeNullOrEmpty } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'Subject only is passed and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -Subject $certSubject } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'Subject only is passed and matching certificate does not exist' { It 'Should not throw exception' { { $script:result = Find-Certificate -Subject 'CN=Does Not Exist' } | Should -Not -Throw } It 'Should return null' { $script:result | Should -BeNullOrEmpty } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'Issuer only is passed and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -Issuer $certSubject } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'Issuer only is passed and matching certificate does not exist' { It 'Should not throw exception' { { $script:result = Find-Certificate -Issuer 'CN=Does Not Exist' } | Should -Not -Throw } It 'Should return null' { $script:result | Should -BeNullOrEmpty } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'DNSName only is passed and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -DnsName $certDNSNames } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'DNSName only is passed in reversed order and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -DnsName $certDNSNamesReverse } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'DNSName only is passed with only one matching DNS name and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -DnsName $certDNSNames[0] } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'DNSName only is passed but an entry is missing and matching certificate does not exist' { It 'Should not throw exception' { { $script:result = Find-Certificate -DnsName $certDNSNamesNoMatch } | Should -Not -Throw } It 'Should return null' { $script:result | Should -BeNullOrEmpty } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'KeyUsage only is passed and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -KeyUsage $certKeyUsage } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'KeyUsage only is passed in reversed order and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -KeyUsage $certKeyUsageReverse } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'KeyUsage only is passed with only one matching DNS name and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -KeyUsage $certKeyUsage[0] } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'KeyUsage only is passed but an entry is missing and matching certificate does not exist' { It 'Should not throw exception' { { $script:result = Find-Certificate -KeyUsage $certKeyUsageNoMatch } | Should -Not -Throw } It 'Should return null' { $script:result | Should -BeNullOrEmpty } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'EnhancedKeyUsage only is passed and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -EnhancedKeyUsage $certEKU } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'EnhancedKeyUsage only is passed in reversed order and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -EnhancedKeyUsage $certEKUReverse } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'EnhancedKeyUsage only is passed with only one matching DNS name and matching certificate exists' { It 'Should not throw exception' { { $script:result = Find-Certificate -EnhancedKeyUsage $certEKU[0] } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'EnhancedKeyUsage only is passed but an entry is missing and matching certificate does not exist' { It 'Should not throw exception' { { $script:result = Find-Certificate -EnhancedKeyUsage $certEKUNoMatch } | Should -Not -Throw } It 'Should return null' { $script:result | Should -BeNullOrEmpty } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'Thumbprint only is passed and matching certificate does not exist in the store' { It 'Should not throw exception' { { $script:result = Find-Certificate -Thumbprint $validThumbprint -Store 'NoCert' } | Should -Not -Throw } It 'Should return null' { $script:result | Should -BeNullOrEmpty } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'FriendlyName only is passed and both valid and expired certificates exist' { It 'Should not throw exception' { { $script:result = Find-Certificate -FriendlyName $certFriendlyName -Store 'TwoCerts' } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $validThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'FriendlyName only is passed and only expired certificates exist' { It 'Should not throw exception' { { $script:result = Find-Certificate -FriendlyName $certFriendlyName -Store 'Expired' } | Should -Not -Throw } It 'Should return expected certificate' { $script:result | Should -BeNullOrEmpty } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } Context 'FriendlyName only is passed and only expired certificates exist but allowexpired passed' { It 'Should not throw exception' { { $script:result = Find-Certificate -FriendlyName $certFriendlyName -Store 'Expired' -AllowExpired:$true } | Should -Not -Throw } It 'Should return expected certificate' { $script:result.Thumbprint | Should -Be $expiredThumbprint } It 'Should call expected mocks' { Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 } } } Describe 'CertificateDsc.Common\Find-CertificateAuthority' { Context 'Function is executed with domain connectivity' { Mock ` -CommandName Get-CdpContainer ` -MockWith { [CmdletBinding()] param ( $DomainName ) return New-Object -TypeName psobject -Property @{ Children = @( @{ distinguishedName = 'CN=CA1,CN=CDP,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com' Children = @{ distinguishedName = 'CN=LabRootCA1,CN=CA1,CN=CDP,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com' } } ) } } Mock ` -CommandName Test-CertificateAuthority ` -ParameterFilter { $CARootName -eq 'LabRootCA1' -and $CAServerFQDN -eq 'CA1' } ` -MockWith { return $true } It 'Should not throw exception' { $script:result = Find-CertificateAuthority -DomainName contoso.com -Verbose } It 'Should return the expected CA' { $script:result.CARootName | Should -Be 'LabRootCA1' $script:result.CAServerFQDN | Should -Be 'CA1' } It 'Should call expected mocks' { Assert-MockCalled -CommandName Get-CdpContainer -Exactly -Times 1 Assert-MockCalled -CommandName Test-CertificateAuthority -Exactly -Times 1 } } Context 'Function is executed with domain connectivity but CA is uncontactable' { Mock ` -CommandName Get-CdpContainer ` -MockWith { [CmdletBinding()] param ( $DomainName ) return New-Object -TypeName psobject -Property @{ Children = @( @{ distinguishedName = 'CN=CA1,CN=CDP,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com' Children = @{ distinguishedName = 'CN=LabRootCA1,CN=CA1,CN=CDP,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=com' } } ) } } Mock ` -CommandName Test-CertificateAuthority ` -ParameterFilter { $CARootName -eq 'LabRootCA1' -and $CAServerFQDN -eq 'CA1' } ` -MockWith { return $false } $errorRecord = Get-InvalidOperationRecord ` -Message ($LocalizedData.NoCaFoundError) It 'Should throw NoCaFoundError exception' { { Find-CertificateAuthority -DomainName contoso.com -Verbose } | Should -Throw $errorRecord } It 'Should call expected mocks' { Assert-MockCalled -CommandName Get-CdpContainer -Exactly -Times 1 Assert-MockCalled -CommandName Test-CertificateAuthority -Exactly -Times 1 } } Context 'Function is executed without domain connectivity' { Mock ` -CommandName Get-CdpContainer ` -MockWith { [CmdletBinding()] param ( $DomainName ) New-InvalidOperationException ` -Message ($LocalizedData.DomainNotJoinedError) } Mock ` -CommandName Test-CertificateAuthority ` -ParameterFilter { $CARootName -eq 'LabRootCA1' -and $CAServerFQDN -eq 'CA1' } ` -MockWith { return $false } $errorRecord = Get-InvalidOperationRecord ` -Message ($LocalizedData.DomainNotJoinedError) It 'Should throw DomainNotJoinedError exception' { { Find-CertificateAuthority -DomainName 'somewhere.overtherainbow' -Verbose } | Should -Throw $errorRecord } It 'Should call expected mocks' { Assert-MockCalled -CommandName Get-CdpContainer -Exactly -Times 1 Assert-MockCalled -CommandName Test-CertificateAuthority -Exactly -Times 0 } } } Describe 'CertificateDsc.Common\Test-CertificateAuthority' { Mock ` -CommandName New-Object ` -ParameterFilter { $TypeName -eq 'System.Diagnostics.ProcessStartInfo' } ` -MockWith { $retObj = New-Object -TypeName psobject -Property @{ FileName = '' Arguments = '' RedirectStandardError = $false RedirectStandardOutput = $true UseShellExecute = $false CreateNoWindow = $true } return $retObj } Context 'Function is executed with CA online' { Mock ` -CommandName New-Object ` -ParameterFilter { $TypeName -eq 'System.Diagnostics.Process' } ` -MockWith { $retObj = New-Object -TypeName psobject -Property @{ StartInfo = $null ExitCode = 0 StandardOutput = New-Object -TypeName psobject | Add-Member -MemberType ScriptMethod -Name ReadToEnd -Value { return @" Connecting to LabRootCA1\CA1 ... Server "CA1" ICertRequest2 interface is alive (32ms) CertUtil: -ping command completed successfully. "@ } -PassThru } $retObj | Add-Member -MemberType ScriptMethod -Name Start -Value { } -PassThru | Add-Member -MemberType ScriptMethod -Name WaitForExit -Value { } return $retObj } It 'Should not throw exception' { $script:result = Test-CertificateAuthority ` -CARootName 'LabRootCA1' ` -CAServerFQDN 'CA1' ` -Verbose } It 'Should return true' { $script:result | Should -Be $True } It 'Should call expected mocks' { Assert-MockCalled ` -CommandName New-Object ` -ParameterFilter { $TypeName -eq 'System.Diagnostics.ProcessStartInfo' } ` -Exactly -Times 1 Assert-MockCalled ` -CommandName New-Object ` -ParameterFilter { $TypeName -eq 'System.Diagnostics.Process' } ` -Exactly -Times 1 } } Context 'Function is executed with CA offline' { Mock ` -CommandName New-Object ` -ParameterFilter { $TypeName -eq 'System.Diagnostics.Process' } ` -MockWith { $retObj = New-Object -TypeName psobject -Property @{ StartInfo = $null ExitCode = -2147024809 StandardOutput = New-Object -TypeName psobject | Add-Member -MemberType ScriptMethod -Name ReadToEnd -Value { return @" Connecting to LabRootCA1\CA2 ... Server could not be reached: The parameter is incorrect. 0x80070057 (WIN32: 87 ERROR_INVALID_PARAMETER) -- (31ms) CertUtil: -ping command FAILED: 0x80070057 (WIN32: 87 ERROR_INVALID_PARAMETER) CertUtil: The parameter is incorrect. "@ } -PassThru } $retObj | Add-Member -MemberType ScriptMethod -Name Start -Value { } -PassThru | Add-Member -MemberType ScriptMethod -Name WaitForExit -Value { } return $retObj } It 'Should not throw exception' { $script:result = Test-CertificateAuthority ` -CARootName 'LabRootCA1' ` -CAServerFQDN 'CA2' ` -Verbose } It 'Should return false' { $script:result | Should -Be $false } It 'Should call expected mocks' { Assert-MockCalled ` -CommandName New-Object ` -ParameterFilter { $TypeName -eq 'System.Diagnostics.ProcessStartInfo' } ` -Exactly -Times 1 Assert-MockCalled ` -CommandName New-Object ` -ParameterFilter { $TypeName -eq 'System.Diagnostics.Process' } ` -Exactly -Times 1 } } } Describe 'CertificateDsc.Common\Get-CertificateTemplateName' { Mock -CommandName Get-CertificateTemplatesFromActiveDirectory -MockWith { @( [PSCustomObject] @{ 'Name' = 'WebServer' 'DisplayName' = 'Web Server' 'mspki-cert-template-oid' = '1.3.6.1.4.1.311.21.8.5734392.6195358.14893705.12992936.3444946.62.1.16' } ) } Context 'When a certificate with the extension "Certificate Template Name" is used' { It 'Should return the template name' { Get-CertificateTemplateName -Certificate $testCertificate | Should -Be 'WebServer' } } Context 'When a certificate with the extension "Certificate Template Information" is used.' { It 'Should return the template name when there is no display name' { Get-CertificateTemplateName -Certificate $testCertificateWithAltTemplateInformation | Should -Be 'WebServer' } Mock -CommandName Get-CertificateTemplateExtensionText -MockWith { @' Template=Web Server(1.3.6.1.4.1.311.21.8.5734392.6195358.14893705.12992936.3444946.62.1.16) Major Version Number=100 Minor Version Number=5 '@ } It 'Should return the template name when there is a display name' { Get-CertificateTemplateName -Certificate $testCertificateWithAltTemplateInformation | Should -Be 'WebServer' } } Context 'When a certificate with no template name is used' { It 'Should return null' { Get-CertificateTemplateName -Certificate $testCertificateWithoutSan | Should -BeNullOrEmpty } } } Describe 'CertificateDsc.Common\Get-CertificateTemplatesFromActiveDirectory' { $MockSearchResults = @( @{ Properties = @( @{ Name = 'name' Value = 'MockData1' } @{ Name = 'displayName' Value = 'Mock Data 1' } ) } @{ Properties = @( @{ Name = 'name' Value = 'MockData2' } @{ Name = 'displayName' Value = 'Mock Data 2' } ) } @{ Properties = @( @{ Name = 'name' Value = 'MockData3' } @{ Name = 'displayName' Value = 'Mock Data 3' } ) } ) $newObject_parameterFilter = { $TypeName -eq 'DirectoryServices.DirectorySearcher' } $newObject_mock = { [PSCustomObject] @{ Filter = $null SearchRoot = $null } | Add-Member -MemberType ScriptMethod -Name FindAll -Value { $MockSearchResults } -PassThru } Mock -CommandName New-Object -ParameterFilter $newObject_parameterFilter -MockWith $newObject_mock Mock -CommandName Get-DirectoryEntry Context 'When certificate templates are retrieved from Active Directory successfully' { It 'Should get 3 mocked search results' { $SearchResults = Get-CertificateTemplatesFromActiveDirectory Assert-MockCalled -CommandName Get-DirectoryEntry -Exactly -Times 1 Assert-MockCalled -CommandName New-Object -Exactly -Times 1 $SearchResults.Count | Should -Be 3 } } Context 'When certificate templates are not retrieved from Active Directory successfully' { Mock -CommandName Get-DirectoryEntry -MockWith { throw 'Mock Function Failure' } It 'Should display a warning message' { $Message = 'Failed to get the certificate templates from Active Directory.' (Get-CertificateTemplatesFromActiveDirectory -Verbose 3>&1).Message | Should -Be $Message } It 'Should display a verbose message' { $Message = 'Mock Function Failure' (Get-CertificateTemplatesFromActiveDirectory -Verbose 4>&1).Message | Should -Be $Message } } } Describe 'CertificateDsc.Common\Get-CertificateTemplateInformation' { $mockADTemplates = @( @{ 'Name' = 'DisplayName1' 'DisplayName' = 'Display Name 1' 'msPKI-Cert-Template-OID' = '1.3.6.1.4.1.311.21.8.5734392.6195358.14893705.12992936.3444946.62.3384218.1234567' } @{ 'Name' = 'DisplayName2' 'DisplayName' = 'Display Name 2' 'msPKI-Cert-Template-OID' = '1.3.6.1.4.1.311.21.8.5734392.6195358.14893705.12992936.3444946.62.3384218.2345678' } ) $certificateTemplateExtensionFormattedText1 = @' Template=Display Name 1(1.3.6.1.4.1.311.21.8.5734392.6195358.14893705.12992936.3444946.62.3384218.1234567) Major Version Number=100 Minor Version Number=5 '@ $certificateTemplateExtensionFormattedText1NoDisplayName = @' Template=1.3.6.1.4.1.311.21.8.5734392.6195358.14893705.12992936.3444946.62.3384218.1234567 Major Version Number=100 Minor Version Number=5 '@ $certificateTemplateExtensionFormattedText2 = @' Template=Display Name 2(1.3.6.1.4.1.311.21.8.5734392.6195358.14893705.12992936.3444946.62.3384218.2345678) Major Version Number=100 Minor Version Number=5 '@ $certificateTemplateExtensionFormattedText2NoDisplayName = @' Template=1.3.6.1.4.1.311.21.8.5734392.6195358.14893705.12992936.3444946.62.3384218.2345678 Major Version Number=100 Minor Version Number=5 '@ $certificateTemplateExtensionFormattedText3 = @' Template=Display Name 3(1.3.6.1.4.1.311.21.8.5734392.6195358.14893705.12992936.3444946.62.3384218.3456789) Major Version Number=100 Minor Version Number=5 '@ $certificateTemplateExtensionFormattedText3NoDisplayName = @' Template=1.3.6.1.4.1.311.21.8.5734392.6195358.14893705.12992936.3444946.62.3384218.3456789 Major Version Number=100 Minor Version Number=5 '@ $RegexTemplatePattern = '^\w+=(?<Name>.*)\((?<Oid>[\.\d]+)\)' Mock -CommandName Get-CertificateTemplatesFromActiveDirectory -MockWith { $mockADTemplates } Context 'When FormattedTemplate contains a Template OID with a Template Display Name' { It 'Should return the Template Name "DisplayName1"' { $params = @{ FormattedTemplate = $certificateTemplateExtensionFormattedText1 } (Get-CertificateTemplateInformation @params).Name | Should -Be 'DisplayName1' } It 'Should return the Template Name "DisplayName2"' { $params = @{ FormattedTemplate = $certificateTemplateExtensionFormattedText2 } (Get-CertificateTemplateInformation @params).Name | Should -Be 'DisplayName2' } It 'Should write a warning when there is no match in Active Directory' { $templateValues = [Regex]::Match($certificateTemplateExtensionFormattedText3, $RegexTemplatePattern) $templateText = '{0}({1})' -f $templateValues.Groups['Name'].Value, $templateValues.Groups['Oid'].Value $warningMessage = $localizedData.TemplateNameResolutionError -f $templateText $params = @{ FormattedTemplate = $certificateTemplateExtensionFormattedText3 } (Get-CertificateTemplateInformation @params 3>&1)[0].Message | Should -Be $warningMessage } } Context 'When FormattedTemplate contains a Template OID without a Template Display Name' { It 'Should return the Template Name "DisplayName1"' { $params = @{ FormattedTemplate = $certificateTemplateExtensionFormattedText1NoDisplayName } (Get-CertificateTemplateInformation @params).Name | Should -Be 'DisplayName1' } It 'Should return the Template Name "DisplayName2"' { $params = @{ FormattedTemplate = $certificateTemplateExtensionFormattedText2NoDisplayName } (Get-CertificateTemplateInformation @params).Name | Should -Be 'DisplayName2' } It 'Should write a warning when there is no match in Active Directory' { $templateValues = [Regex]::Match($certificateTemplateExtensionFormattedText3, $RegexTemplatePattern) $templateText = '{0}({1})' -f $templateValues.Groups['Name'].Value, $templateValues.Groups['Oid'].Value $warningMessage = $localizedData.TemplateNameResolutionError -f $templateText $params = @{ FormattedTemplate = $certificateTemplateExtensionFormattedText3 } (Get-CertificateTemplateInformation @params 3>&1)[0].Message | Should -Be $warningMessage } } Context 'When FormattedTemplate contains a the Template Name' { It 'Should return the FormattedText' { $templateName = 'TemplateName' (Get-CertificateTemplateInformation -FormattedTemplate $templateName).Name | Should -Be $templateName } It 'Should return the FormattedText Without a Trailing Carriage Return' { $templateName = 'TemplateName' + [Char]13 (Get-CertificateTemplateInformation -FormattedTemplate $templateName).Name | Should -Be $templateName.TrimEnd([Char]13) } } Context 'When FormattedTemplate does not contain a recognised format' { It 'Should write a warning when there is no match in Active Directory' { $formattedTemplate = 'Unrecognized Format' $warningMessage = $localizedData.TemplateNameNotFound -f $formattedTemplate (Get-CertificateTemplateInformation -FormattedTemplate $formattedTemplate 3>&1)[0].Message | Should -Be $warningMessage } } } Describe 'CertificateDsc.Common\Get-CertificateExtension' { Context 'When a certificate contains an extension that matches the Oid parameter and First is not specified' { It 'Should return the extension with Oid ''2.5.29.17''' { $extension = Get-CertificateExtension -Certificate $testCertificate -Oid '2.5.29.17' $extension | Should -BeOfType [System.Security.Cryptography.X509Certificates.X509Extension] $extension | Should -HaveCount 1 $extension.Oid.Value | Should -Be '2.5.29.17' } } Context 'When a certificate does not contain an extension that matches the Oid parameter and First is not specified' { It 'Should return no extension' { $extension = Get-CertificateExtension -Certificate $testCertificate -Oid '2.9.9.9' $extension | Should -BeNullOrEmpty } } Context 'When a certificate does not contain an extension that matches the Oid parameter and First is set to 2' { It 'Should return no extension' { $extension = Get-CertificateExtension -Certificate $testCertificate -Oid '2.9.9.9' -First 2 $extension | Should -BeNullOrEmpty } } Context 'When a certificate contains an extension that matches only one of the Oid parameter values and First is not specified' { It 'Should return the extension with Oid ''2.5.29.17''' { $extension = Get-CertificateExtension -Certificate $testCertificate -Oid '2.5.29.17', '2.9.9.9' $extension | Should -BeOfType [System.Security.Cryptography.X509Certificates.X509Extension] $extension | Should -HaveCount 1 $extension.Oid.Value | Should -Be '2.5.29.17' } } Context 'When a certificate contains an extension that matches both of the Oid parameter values and First is not specified' { It 'Should return the extension with Oid ''2.5.29.17''' { $extension = Get-CertificateExtension -Certificate $testCertificate -Oid '2.5.29.17', '2.5.29.31' $extension | Should -BeOfType [System.Security.Cryptography.X509Certificates.X509Extension] $extension | Should -HaveCount 1 $extension.Oid.Value | Should -Contain '2.5.29.17' } } Context 'When a certificate contains an extension that matches both of the Oid parameter values but First is set to 2' { It 'Should return the extension with Oid ''2.5.29.17'' and ''2.5.29.31''' { $extension = Get-CertificateExtension -Certificate $testCertificate -Oid '2.5.29.17', '2.5.29.31' -First 2 $extension | Should -BeOfType [System.Security.Cryptography.X509Certificates.X509Extension] $extension | Should -HaveCount 2 $extension.Oid.Value | Should -Contain '2.5.29.17' $extension.Oid.Value | Should -Contain '2.5.29.31' } } Context 'When a certificate contains an extension that matches both of the Oid parameter values but First is set to 3' { It 'Should return the extension with Oid ''2.5.29.17'' and ''2.5.29.31''' { $extension = Get-CertificateExtension -Certificate $testCertificate -Oid '2.5.29.17', '2.5.29.31' -First 3 $extension | Should -BeOfType [System.Security.Cryptography.X509Certificates.X509Extension] $extension | Should -HaveCount 2 $extension.Oid.Value | Should -Contain '2.5.29.17' $extension.Oid.Value | Should -Contain '2.5.29.31' } } } Describe 'CertificateDsc.Common\Get-CertificateTemplateExtensionText' { Context 'When a certificate contains Certificate Template Name extension' { It 'Should return the Name of the Certificate Template' { $params = @{ Certificate = $testCertificateWithAltTemplateName } # Template Names have a trailing carriage return and linefeed. Get-CertificateTemplateExtensionText @params | Should -Be ('WebServer' + [Char]13 + [Char]10) } } Context 'When a certificate contains Certificate Template Information extension' { It 'Should return the Oid, Major and Minor Version of the Certificate Template' { $CertificateTemplateInformation = @' Template=1.3.6.1.4.1.311.21.8.5734392.6195358.14893705.12992936.3444946.62.1.16 Major Version Number=100 Minor Version Number=5 '@ $params = @{ Certificate = $testCertificateWithAltTemplateInformation } # Template Names have a trailing carriage return and linefeed. Get-CertificateTemplateExtensionText @params | Should -Be $CertificateTemplateInformation } } Context 'When a certificate does not contain a Certificate Template extension' { It 'Should not return anything' { $params = @{ Certificate = $testCertificateWithoutSan } # Template Names have a trailing carriage return and linefeed. Get-CertificateTemplateExtensionText @params | Should -Be $null } } } Describe 'CertificateDsc.Common\Get-CertificateSubjectAlternativeName' { Context 'When a certificate with a SAN is used' { It 'Should return the SAN' { Get-CertificateSubjectAlternativeName -Certificate $testCertificate | Should -Be 'firstsan' } } Context 'When a certificate without SAN is used' { It 'Should return null' { Get-CertificateSubjectAlternativeName -Certificate $testCertificateWithoutSan | Should -BeNullOrEmpty } } } Describe 'CertificateDsc.Common\Get-CertificateSubjectAlternativeNameList' { Context 'When a certificate with a Subject Alternative Name is used' { It 'Should return the list of Subject Alternative Name entries' { $global:certificate = $testCertificate $result = Get-CertificateSubjectAlternativeNameList -Certificate $testCertificate $result | Should -HaveCount 3 $result | Should -Contain 'DNS Name=firstsan' $result | Should -Contain 'DNS Name=secondsan' $result | Should -Contain 'DNS Name=thirdsan' } } Context 'When a certificate without Subject Alternative Name is used' { It 'Should return null' { $result = Get-CertificateSubjectAlternativeNameList -Certificate $testCertificateWithoutSan $result | Should -BeNullOrEmpty } } } Describe 'CertificateDsc.Common\Test-CommandExists' { $testCommandName = 'TestCommandName' Mock -CommandName 'Get-Command' -MockWith { return $Name } Context 'When Get-Command returns' { It 'Should not throw exception' { { $null = Test-CommandExists -Name $testCommandName } | Should -Not -Throw } It 'Should retrieve the command with the specified name' { $getCommandParameterFilter = { return $Name -eq $testCommandName } Assert-MockCalled -CommandName 'Get-Command' -ParameterFilter $getCommandParameterFilter -Exactly -Times 1 -Scope 'Context' } It 'Should return true' { Test-CommandExists -Name $testCommandName | Should -Be $true } } Context 'When Get-Command returns null' { Mock -CommandName 'Get-Command' -MockWith { return $null } It 'Should not throw exception' { { $null = Test-CommandExists -Name $testCommandName } | Should -Not -Throw } It 'Should retrieve the command with the specified name' { $getCommandParameterFilter = { return $Name -eq $testCommandName } Assert-MockCalled -CommandName 'Get-Command' -ParameterFilter $getCommandParameterFilter -Exactly -Times 1 -Scope 'Context' } It 'Should return false' { Test-CommandExists -Name $testCommandName | Should -Be $false } } } Describe 'CertificateDsc.Common\Get-CertificateStorePath' { Context 'When called with a Store and Location that exists' { Mock -CommandName Test-Path -MockWith { $true } It 'Should not throw exception' { { $script:getCertificateStorePathResult = Get-CertificateStorePath ` -Location 'LocalMachine' ` -Store 'TestStore' } | Should -Not -Throw } It 'Should return the expected path' { $script:getCertificateStorePathResult = 'Cert:\LocalMachine\TestStore' } } Context 'When called with a Store and Location that does not exist' { Mock -CommandName Test-Path -MockWith { $false } It 'Should throw expected exception' { { Get-CertificateStorePath ` -Location 'LocalMachine' ` -Store 'TestStore' } | Should -Throw ($script:localizedData.CertificateStoreNotFoundError -f 'Cert:\LocalMachine\TestStore') } } } Describe 'CertificateDsc.Common\Get-CertificatePath' { Context 'When called with Thumbprint, Store and Location' { Mock -CommandName Test-Path -MockWith { $true } It 'Should not throw exception' { { $script:getCertificatePathResult = Get-CertificatePath ` -Thumbprint '627b268587e95099e72aab831a81f887d7a20578' ` -Location 'LocalMachine' ` -Store 'TestStore' } | Should -Not -Throw } It 'Should return the expected path' { $script:getCertificateStorePathResult = 'Cert:\LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a2057' } } } Describe 'CertificateDsc.Common\Get-CertificateFromCertificateStore' { Context 'When the certificate exists in the store' { Mock -CommandName Test-Path -MockWith { $true } Mock -CommandName Get-ChildItem -MockWith { @( [PSCustomObject] @{ PSPath = 'Microsoft.PowerShell.Security\Certificate::LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' } ) } It 'Should not throw exception' { { $script:getCertificateFromCertificateStoreResult = Get-CertificateFromCertificateStore ` -Thumbprint '627b268587e95099e72aab831a81f887d7a20578' ` -Location 'LocalMachine' ` -Store 'TestStore' ` -Verbose } | Should -Not -Throw } It 'Should return the expected certificate' { $script:getCertificateFromCertificateStoreResult.PSPath | Should -Be 'Microsoft.PowerShell.Security\Certificate::LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' } It 'Should call expected mocks' { Assert-MockCalled -CommandName Get-ChildItem -ParameterFilter { $Path -eq 'Cert:\LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' } -Exactly -Times 1 } } Context 'When the certificate does not exist in the store' { Mock -CommandName Test-Path -MockWith { $true } Mock -CommandName Get-ChildItem It 'Should not throw exception' { { $script:getCertificateFromCertificateStoreResult = Get-CertificateFromCertificateStore ` -Thumbprint '627b268587e95099e72aab831a81f887d7a20578' ` -Location 'LocalMachine' ` -Store 'TestStore' ` -Verbose } | Should -Not -Throw } It 'Should not return any certificates' { $script:getCertificateFromCertificateStoreResult.PSPath | Should -BeNullOrEmpty } It 'Should call expected mocks' { Assert-MockCalled -CommandName Get-ChildItem -ParameterFilter { $Path -eq 'Cert:\LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' } -Exactly -Times 1 } } } Describe 'CertificateDsc.Common\Remove-CertificateFromCertificateStore' { Context 'When the certificate exists in the store' { Mock -CommandName Test-Path -MockWith { $true } Mock -CommandName Get-ChildItem -MockWith { @( [PSCustomObject] @{ PSPath = 'Microsoft.PowerShell.Security\Certificate::LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' } ) } Mock -CommandName Remove-Item It 'Should not throw exception' { { Remove-CertificateFromCertificateStore ` -Thumbprint '627b268587e95099e72aab831a81f887d7a20578' ` -Location 'LocalMachine' ` -Store 'TestStore' ` -Verbose } | Should -Not -Throw } It 'Should call expected mocks' { Assert-MockCalled -CommandName Get-ChildItem -ParameterFilter { $Path -eq 'Cert:\LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' } -Exactly -Times 1 Assert-MockCalled -CommandName Remove-Item -ParameterFilter { $Path -eq 'Microsoft.PowerShell.Security\Certificate::LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' ` -and $Force -eq $true } -Exactly -Times 1 } } Context 'When the certificate exists in the store twice' { Mock -CommandName Test-Path -MockWith { $true } Mock -CommandName Get-ChildItem -MockWith { @( [PSCustomObject] @{ PSPath = 'Microsoft.PowerShell.Security\Certificate::LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' }, [PSCustomObject] @{ PSPath = 'Microsoft.PowerShell.Security\Certificate::LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' } ) } Mock -CommandName Remove-Item It 'Should not throw exception' { { Remove-CertificateFromCertificateStore ` -Thumbprint '627b268587e95099e72aab831a81f887d7a20578' ` -Location 'LocalMachine' ` -Store 'TestStore' ` -Verbose } | Should -Not -Throw } It 'Should call expected mocks' { Assert-MockCalled -CommandName Get-ChildItem -ParameterFilter { $Path -eq 'Cert:\LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' } -Exactly -Times 1 Assert-MockCalled -CommandName Remove-Item -ParameterFilter { $Path -eq 'Microsoft.PowerShell.Security\Certificate::LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' ` -and $Force -eq $true } -Exactly -Times 2 } } Context 'When the certificate does not exist in the store' { Mock -CommandName Test-Path -MockWith { $true } Mock -CommandName Get-ChildItem Mock -CommandName Remove-Item It 'Should not throw exception' { { Remove-CertificateFromCertificateStore ` -Thumbprint '627b268587e95099e72aab831a81f887d7a20578' ` -Location 'LocalMachine' ` -Store 'TestStore' ` -Verbose } | Should -Not -Throw } It 'Should call expected mocks' { Assert-MockCalled -CommandName Get-ChildItem -ParameterFilter { $Path -eq 'Cert:\LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' } -Exactly -Times 1 Assert-MockCalled -CommandName Remove-Item -Exactly -Times 0 } } } Describe 'CertificateDsc.Common\Set-CertificateFriendlyNameInCertificateStore' { Context 'When the certificate exists in the store' { Mock -CommandName Test-Path -MockWith { $true } Mock -CommandName Get-ChildItem -MockWith { @( [PSCustomObject] @{ PSPath = 'Microsoft.PowerShell.Security\Certificate::LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' FriendlyName = 'Nothing' } ) } It 'Should not throw exception' { { Set-CertificateFriendlyNameInCertificateStore ` -Thumbprint '627b268587e95099e72aab831a81f887d7a20578' ` -Location 'LocalMachine' ` -Store 'TestStore' ` -FriendlyName 'New Name' ` -Verbose } | Should -Not -Throw } It 'Should call expected mocks' { Assert-MockCalled -CommandName Get-ChildItem -ParameterFilter { $Path -eq 'Cert:\LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' } -Exactly -Times 1 } } Context 'When the certificate does not exist in the store' { Mock -CommandName Test-Path -MockWith { $true } Mock -CommandName Get-ChildItem It 'Should not throw exception' { { Set-CertificateFriendlyNameInCertificateStore ` -Thumbprint '627b268587e95099e72aab831a81f887d7a20578' ` -Location 'LocalMachine' ` -Store 'TestStore' ` -FriendlyName 'New Name' ` -Verbose } | Should -Not -Throw } It 'Should call expected mocks' { Assert-MockCalled -CommandName Get-ChildItem -ParameterFilter { $Path -eq 'Cert:\LocalMachine\TestStore\627b268587e95099e72aab831a81f887d7a20578' } -Exactly -Times 1 } } } } |