Tests/Unit/MSFT_CertReq.Tests.ps1

[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')]
[CmdletBinding()]
param ()

#region HEADER
$script:dscModuleName = 'CertificateDsc'
$script:dscResourceName = 'MSFT_CertReq'

# 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

# Begin Testing
try
{
    InModuleScope $script:DSCResourceName {
        $definedRuntimeTypes = ([System.AppDomain]::CurrentDomain.GetAssemblies() | Where-Object -FilterScript { $null -ne $_.DefinedTypes }).GetTypes()
        $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 ''
        $invalidThumbprint = $validThumbprint + 1
        $caServerFQDN = 'rootca.contoso.com'
        $caRootName = 'contoso-CA'
        $validSubject = 'Test Subject'
        $invalidSubject = 'Invalid Test Subject'
        $validIssuer = "CN=$caRootName, DC=contoso, DC=com"
        $invalidIssuer = 'CN=InvalidTest, DC=invalid, DC=com'
        $keyLength = '2048'
        $exportable = $true
        $providerName = 'Microsoft RSA SChannel Cryptographic Provider'
        $providerNameWithQuotes = ('"{0}"' -f $providerName)
        $oid = '1.3.6.1.5.5.7.3.1'
        $keyUsage = '0xa0'
        $certificateTemplate = 'WebServer'
        $certificateDCTemplate = 'DomainControllerAuthentication'
        $invalidCertificateTemplate = 'Invalid Template'
        $subjectAltUrl = 'contoso.com'
        $subjectAltName = "dns=$subjectAltUrl"
        $friendlyName = "Test Certificate"
        $invalidFriendlyName = 'Invalid Certificate'

        $validCert = New-Object -TypeName PSObject -Property @{
            Thumbprint   = $validThumbprint
            Subject      = "CN=$validSubject"
            Issuer       = $validIssuer
            NotBefore    = (Get-Date).AddDays(-30) # Issued on
            NotAfter     = (Get-Date).AddDays(31) # Expires after
            FriendlyName = $friendlyName
        }

        $validCertWithoutSubject = New-Object -TypeName PSObject -Property @{
            Thumbprint   = $validThumbprint
            Subject      = ''
            Issuer       = $validIssuer
            NotBefore    = (Get-Date).AddDays(-30) # Issued on
            NotAfter     = (Get-Date).AddDays(31) # Expires after
            FriendlyName = $friendlyName
        }

        $invalidCert = New-Object -TypeName PSObject -Property @{
            Thumbprint   = $invalidThumbprint
            Subject      = "CN=$invalidSubject"
            Issuer       = $invalidIssuer
            NotBefore    = (Get-Date).AddDays(-30) # Issued on
            NotAfter     = (Get-Date).AddDays(31) # Expires after
            FriendlyName = $invalidFriendlyName
        }

        Add-Member -InputObject $validCert -MemberType ScriptMethod -Name Verify -Value {
            return $true
        }

        $expiringCert = New-Object -TypeName PSObject -Property @{
            Thumbprint   = $validThumbprint
            Subject      = "CN=$validSubject"
            Issuer       = $validIssuer
            NotBefore    = (Get-Date).AddDays(-30) # Issued on
            NotAfter     = (Get-Date).AddDays(30) # Expires after
            FriendlyName = $friendlyName
        }

        Add-Member -InputObject $expiringCert -MemberType ScriptMethod -Name Verify -Value {
            return $true
        }

        $expiredCert = New-Object -TypeName PSObject -Property @{
            Thumbprint   = $validThumbprint
            Subject      = "CN=$validSubject"
            Issuer       = $validIssuer
            NotBefore    = (Get-Date).AddDays(-30) # Issued on
            NotAfter     = (Get-Date).AddDays(-1) # Expires after
            FriendlyName = $friendlyName
        }
        Add-Member -InputObject $expiredCert -MemberType ScriptMethod -Name Verify -Value {
            return $true
        }

        $sanOid = New-Object -TypeName System.Security.Cryptography.Oid -Property @{FriendlyName = 'Subject Alternative Name' }
        $sanExt = [PSCustomObject] @{
            Oid      = $sanOid
            Critical = $false
        }
        Add-Member -InputObject $sanExt -MemberType ScriptMethod -Name Format -Force -Value {
            return "DNS Name=$subjectAltUrl"
        }

        $validCertSubjectDifferentOrder = New-Object -TypeName PSObject -Property @{
            Thumbprint   = $validThumbprint
            Subject      = 'E=xyz@contoso.com, CN=xyz.contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, S=State, C=country'
            Issuer       = $validIssuer
            NotBefore    = (Get-Date).AddDays(-30) # Issued on
            NotAfter     = (Get-Date).AddDays(31) # Expires after
            FriendlyName = $friendlyName
        }
        Add-Member -InputObject $validCertSubjectDifferentOrder -MemberType ScriptMethod -Name Verify -Value {
            return $true
        }

        $validSANCert = New-Object -TypeName PSObject -Property @{
            Thumbprint   = $validThumbprint
            Subject      = "CN=$validSubject"
            Issuer       = $validIssuer
            NotBefore    = (Get-Date).AddDays(-30) # Issued on
            NotAfter     = (Get-Date).AddDays(31) # Expires after
            Extensions   = @($sanExt)
            FriendlyName = $friendlyName
        }
        Add-Member -InputObject $validSANCert -MemberType ScriptMethod -Name Verify -Value {
            return $true
        }

        $incorrectSanExt = [PSCustomObject] @{
            Oid      = $sanOid
            Critical = $false
        }
        Add-Member -InputObject $incorrectSanExt -MemberType ScriptMethod -Name Format -Force -Value {
            return "DNS Name=incorrect.com"
        }

        $incorrectSANCert = New-Object -TypeName PSObject -Property @{
            Thumbprint   = $validThumbprint
            Subject      = "CN=$validSubject"
            Issuer       = $validIssuer
            NotBefore    = (Get-Date).AddDays(-30) # Issued on
            NotAfter     = (Get-Date).AddDays(31) # Expires after
            Extensions   = @($incorrectSanExt)
            FriendlyName = $friendlyName
        }
        Add-Member -InputObject $incorrectSANCert -MemberType ScriptMethod -Name Verify -Value {
            return $true
        }

        $emptySANCert = New-Object -TypeName PSObject -Property @{
            Thumbprint   = $validThumbprint
            Subject      = "CN=$validSubject"
            Issuer       = $validIssuer
            NotBefore    = (Get-Date).AddDays(-30) # Issued on
            NotAfter     = (Get-Date).AddDays(31) # Expires after
            Extensions   = @()
            FriendlyName = $friendlyName
        }
        Add-Member -InputObject $emptySANCert -MemberType ScriptMethod -Name Verify -Value {
            return $true
        }

        $incorrectFriendlyName = New-Object -TypeName PSObject -Property @{
            Thumbprint   = $validThumbprint
            Subject      = "CN=$validSubject"
            Issuer       = $validIssuer
            NotBefore    = (Get-Date).AddDays(-30) # Issued on
            NotAfter     = (Get-Date).AddDays(31) # Expires after
            FriendlyName = 'This name will not match'
        }
        Add-Member -InputObject $incorrectFriendlyName -MemberType ScriptMethod -Name Verify -Value {
            return $true
        }

        $caType = 'Enterprise'
        $cepURL = 'DummyURL'
        $cesURL = 'DummyURL'

        $testUsername = 'DummyUsername'
        $testPassword = 'DummyPassword'
        $testCredential = New-Object System.Management.Automation.PSCredential $testUsername, (ConvertTo-SecureString $testPassword -AsPlainText -Force)

        $mock_getCertificateTemplateName_validCertificateTemplate = { $certificateTemplate }
        $mock_getCertificateTemplateName_invalidCertificateTemplate = { $invalidCertificateTemplate }
        $mock_getCertificateTemplateName_validDCCertificateTemplate = { $certificateDCTemplate }
        $mock_GetChildItem_validCertWithoutSubject = { $validCertWithoutSubject }
        $mock_getChildItem_validCert = { $validCert }
        $mock_getChildItem_expiredCert = { $expiredCert }
        $mock_getChildItem_expiringCert = { $expiringCert }
        $mock_getChildItem_validSANCert = { $validSANCert }
        $mock_getChildItem_validCertSubjectDifferentOrder = { $validCertSubjectDifferentOrder }
        $mock_getChildItem_incorrectSANCert = { $incorrectSANCert }
        $mock_getChildItem_emptySANCert = { $emptySANCert }
        $mock_getChildItem_incorrectFriendlyName = { $incorrectFriendlyName }
        $mock_getCertificateSan_subjectAltName = { $subjectAltName }

        $paramsStandard = @{
            Subject             = $validSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $testCredential
            AutoRenew           = $false
            FriendlyName        = $friendlyName
            KeyType             = 'RSA'
        }

        $paramsStandardProviderNameWithQuotes = @{
            Subject             = $validSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerNameWithQuotes
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $testCredential
            AutoRenew           = $false
            FriendlyName        = $friendlyName
            KeyType             = 'RSA'
        }

        $paramsStandardDomainController = @{
            Subject             = $validSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateDCTemplate
            Credential          = $testCredential
            AutoRenew           = $false
            FriendlyName        = $friendlyName
        }

        $paramsInvalid = @{
            Subject             = $invalidSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $testCredential
            AutoRenew           = $false
            FriendlyName        = $invalidFriendlyName
        }

        $paramsAutoDiscovery = @{
            Subject             = $validSubject
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $testCredential
            AutoRenew           = $false
            FriendlyName        = $friendlyName
        }

        $paramsAutoRenew = @{
            Subject             = $validSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $testCredential
            AutoRenew           = $true
            FriendlyName        = $friendlyName
        }

        $paramsNoCred = @{
            Subject             = $validSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $null
            AutoRenew           = $false
            FriendlyName        = $friendlyName
        }

        $paramsStandardMachineContext = @{
            Subject             = $validSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $testCredential
            AutoRenew           = $false
            FriendlyName        = $friendlyName
            UseMachineContext   = $true
        }

        $paramsAutoRenewNoCred = @{
            Subject             = $validSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $null
            AutoRenew           = $true
            FriendlyName        = $friendlyName
        }

        $paramsKeyLength4096AutoRenewNoCred = @{
            Subject             = $validSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = '4096'
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $null
            AutoRenew           = $true
            FriendlyName        = $friendlyName
        }

        $paramsSubjectDifferentOrder = @{
            Subject             = 'CN=xyz.contoso.com, E=xyz@contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, S=State, C=country'
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $testCredential
            AutoRenew           = $True
            FriendlyName        = $friendlyName
        }

        $paramsSubjectAltName = @{
            Subject             = $validSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $testCredential
            SubjectAltName      = $subjectAltName
            AutoRenew           = $false
            FriendlyName        = $friendlyName
        }

        $paramsSubjectAltNameNoCred = @{
            Subject             = $validSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $null
            SubjectAltName      = $subjectAltName
            AutoRenew           = $false
            FriendlyName        = $friendlyName
        }

        $paramsStandaloneWebEnrollment = @{
            Subject             = $validSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $testCredential
            AutoRenew           = $false
            CAType              = 'Standalone'
            CepURL              = $cepURL
            CesURL              = $cesURL
            FriendlyName        = $friendlyName
        }

        $paramsEnterpriseWebEnrollment = @{
            Subject             = $validSubject
            CAServerFQDN        = $caServerFQDN
            CARootName          = $caRootName
            KeyLength           = $keyLength
            Exportable          = $exportable
            ProviderName        = $providerName
            OID                 = $oid
            KeyUsage            = $keyUsage
            CertificateTemplate = $certificateTemplate
            Credential          = $testCredential
            AutoRenew           = $false
            CAType              = $caType
            CepURL              = $cepURL
            CesURL              = $cesURL
            FriendlyName        = $friendlyName
        }

        $paramRsaValid = @{
            KeyType   = 'RSA'
            KeyLength = '2048'
        }

        $paramRsaInvalid = @{
            KeyType   = 'RSA'
            KeyLength = '384'
        }

        $paramEcdhValid = @{
            KeyType   = 'ECDH'
            KeyLength = '384'
        }

        $paramEcdhInvalid = @{
            KeyType   = 'ECDH'
            KeyLength = '2048'
        }

        $certInf = @"
[NewRequest]
Subject = "CN=$validSubject"
KeySpec = 1
KeyLength = $keyLength
Exportable = $($exportable.ToString().ToUpper())
MachineKeySet = TRUE
SMIME = FALSE
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = $providerNameWithQuotes
ProviderType = 12
RequestType = CMC
KeyUsage = $keyUsage
FriendlyName = "$friendlyName"
[RequestAttributes]
CertificateTemplate = "$certificateTemplate"
[EnhancedKeyUsageExtension]
OID = $oid
"@


        $certInfNoTemplate = @"
[NewRequest]
Subject = "CN=$validSubject"
KeySpec = 1
KeyLength = $keyLength
Exportable = $($exportable.ToString().ToUpper())
MachineKeySet = TRUE
SMIME = FALSE
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = $providerNameWithQuotes
ProviderType = 12
RequestType = CMC
KeyUsage = $keyUsage
FriendlyName = "$friendlyName"
[EnhancedKeyUsageExtension]
OID = $oid
"@


        $certInfRenew = @"
[NewRequest]
Subject = "CN=$validSubject"
KeySpec = 1
KeyLength = $keyLength
Exportable = $($exportable.ToString().ToUpper())
MachineKeySet = TRUE
SMIME = FALSE
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = $providerNameWithQuotes
ProviderType = 12
RequestType = CMC
KeyUsage = $keyUsage
FriendlyName = "$friendlyName"
RenewalCert = $validThumbprint
[RequestAttributes]
CertificateTemplate = "$certificateTemplate"
[EnhancedKeyUsageExtension]
OID = $oid
"@


        $certInfKeyRenew = @"
[NewRequest]
Subject = "CN=$validSubject"
KeySpec = 1
KeyLength = 4096
Exportable = $($exportable.ToString().ToUpper())
MachineKeySet = TRUE
SMIME = FALSE
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = $providerNameWithQuotes
ProviderType = 12
RequestType = CMC
KeyUsage = $keyUsage
FriendlyName = "$friendlyName"
RenewalCert = $validThumbprint
[RequestAttributes]
CertificateTemplate = "$certificateTemplate"
[EnhancedKeyUsageExtension]
OID = $oid
"@


        $certInfSubjectAltName = @"
[NewRequest]
Subject = "CN=$validSubject"
KeySpec = 1
KeyLength = $keyLength
Exportable = $($exportable.ToString().ToUpper())
MachineKeySet = TRUE
SMIME = FALSE
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = $providerNameWithQuotes
ProviderType = 12
RequestType = CMC
KeyUsage = $keyUsage
FriendlyName = "$friendlyName"
[RequestAttributes]
CertificateTemplate = "$certificateTemplate"
[EnhancedKeyUsageExtension]
OID = $oid
[Extensions]
2.5.29.17 = "{text}$subjectAltName"
"@


        $pathCertLocalMachineMy_parameterFilter = {
            $Path -eq 'Cert:\LocalMachine\My'
        }
        $pathCertReqTestOut_parameterFilter = {
            $Path -eq 'CertReq-Test.out'
        }
        $pathCertReqTestReq_parameterFilter = {
            $Path -eq 'CertReq-Test.req'
        }
        $pathCertReqTestCer_parameterFilter = {
            $Path -eq 'CertReq-Test.cer'
        }
        $pathTemp_parameterFilter = {
            $Path -eq $env:Temp
        }

        function Start-Win32Process
        {
            param
            (
                [Parameter()]
                $Path,

                [Parameter()]
                $Arguments,

                [Parameter()]
                [System.Management.Automation.PSCredential]
                $Credential
            )
        }

        function Wait-Win32ProcessStop
        {
            param
            (
                [Parameter()]
                $Path,

                [Parameter()]
                $Arguments,

                [Parameter()]
                [System.Management.Automation.PSCredential]
                $Credential
            )
        }

        Describe 'MSFT_CertReq\Get-TargetResource' -Tag 'Get' {
            BeforeAll {
                Mock -CommandName Get-ChildItem `
                    -Mockwith { $validCert } `
                    -ParameterFilter $pathCertLocalMachineMy_parameterFilter

                Mock -CommandName Get-CertificateTemplateName `
                    -MockWith $mock_getCertificateTemplateName_validCertificateTemplate

                Mock -CommandName Get-CertificateSubjectAlternativeName `
                    -MockWith { $subjectAltName }

                Mock -CommandName Find-CertificateAuthority -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CAServerFQDN = 'rootca.contoso.com'
                        CARootName   = 'contoso-CA'
                    }
                }
            }

            Context 'When called without auto discovery' {
                $result = Get-TargetResource @paramsStandard -Verbose

                It 'Should return a hashtable' {
                    $result | Should -BeOfType System.Collections.Hashtable
                }

                It 'Should contain the input values' {
                    $result.Subject | Should -BeExactly $validSubject
                    $result.CAServerFQDN | Should -BeNullOrEmpty
                    $result.CARootName | Should -BeExactly $caRootName
                    $result.KeyLength | Should -BeNullOrEmpty
                    $result.Exportable | Should -BeNullOrEmpty
                    $result.ProviderName | Should -BeNullOrEmpty
                    $result.OID | Should -BeNullOrEmpty
                    $result.KeyUsage | Should -BeNullOrEmpty
                    $result.CertificateTemplate | Should -BeExactly $certificateTemplate
                    $result.SubjectAltName | Should -BeNullOrEmpty
                    $result.FriendlyName | Should -BeExactly $friendlyName
                }
            }

            Context 'When called with auto discovery' {
                $result = Get-TargetResource @paramsAutoDiscovery -Verbose

                It 'Should return a hashtable' {
                    $result | Should -BeOfType System.Collections.Hashtable
                }

                It 'Should contain the input values and the CA should be auto-discovered' {
                    $result.Subject | Should -BeExactly $validSubject
                    $result.CAServerFQDN | Should -BeExactly $caServerFQDN
                    $result.CARootName | Should -BeExactly $caRootName
                    $result.KeyLength | Should -BeNullOrEmpty
                    $result.Exportable | Should -BeNullOrEmpty
                    $result.ProviderName | Should -BeNullOrEmpty
                    $result.OID | Should -BeNullOrEmpty
                    $result.KeyUsage | Should -BeNullOrEmpty
                    $result.CertificateTemplate | Should -BeExactly $certificateTemplate
                    $result.SubjectAltName | Should -BeNullOrEmpty
                    $result.FriendlyName | Should -BeExactly $friendlyName
                }

                It 'Should call the mocked function Find-CertificateAuthority once' {
                    Assert-MockCalled -CommandName Find-CertificateAuthority -Exactly -Times 1
                }
            }

            Mock -CommandName Get-ChildItem -ParameterFilter { $Path -eq 'Cert:\LocalMachine\My' } `
                -Mockwith { $invalidCert }

            Context 'When called without valid cert' {
                $results = Get-TargetResource @paramsInvalid -Verbose

                It 'Should return null' {
                    $results | Should -BeNullOrEmpty
                }
            }
        }

        Describe 'MSFT_CertReq\Set-TargetResource' -Tag 'Set' {
            BeforeAll {
                Mock -CommandName Test-Path -MockWith { $true } `
                    -ParameterFilter $pathCertReqTestReq_parameterFilter

                Mock -CommandName Test-Path -MockWith { $true } `
                    -ParameterFilter $pathCertReqTestCer_parameterFilter

                Mock -CommandName Test-Path -MockWith { $true } `
                    -ParameterFilter $pathCertReqTestOut_parameterFilter

                Mock -CommandName Join-Path -MockWith { 'CertReq-Test' }

                Mock -CommandName CertReq.exe
            }

            Context 'When autorenew is false, credentials not passed' {
                Mock -CommandName Set-Content `
                    -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf' -and `
                        $Value -eq $certInf
                }

                It 'Should not throw' {
                    { Set-TargetResource @paramsNoCred -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path  -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 3

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInf
                    }
                }
            }

            Context 'When autorenew is true, credentials not passed and certificate does not exist' {
                Mock -CommandName Set-Content `
                    -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf' -and `
                        $Value -eq $certInf
                }

                Mock -CommandName Get-ChildItem

                It 'Should not throw' {
                    { Set-TargetResource @paramsAutoRenewNoCred -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInf
                    }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 3

                    Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter
                }
            }

            Context 'When autorenew is true, credentials not passed and valid certificate exists' {
                Mock -CommandName Set-Content `
                    -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf' -and `
                        $Value -eq $certInf
                }

                Mock -CommandName Get-ChildItem -Mockwith { $validCert }

                It 'Should not throw' {
                    { Set-TargetResource @paramsAutoRenewNoCred -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInf
                    }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 3

                    Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter
                }
            }

            Context 'When autorenew is true, credentials not passed and expiring certificate exists' {
                Mock -CommandName Set-Content `
                    -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf' -and `
                        $Value -eq $certInfRenew
                }

                Mock -CommandName Get-ChildItem -Mockwith { $expiringCert }

                It 'Should not throw' {
                    { Set-TargetResource @paramsAutoRenewNoCred -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInfRenew
                    }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 3
                }
            }

            Context 'When autorenew is true, credentials not passed and expired certificate exists' {
                Mock -CommandName Set-Content `
                    -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf' -and `
                        $Value -eq $certInfRenew
                }

                Mock -CommandName Get-ChildItem -Mockwith { $expiredCert }

                It 'Should not throw' {
                    { Set-TargetResource @paramsAutoRenewNoCred -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInfRenew
                    }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 3

                    Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter
                }
            }

            Context 'When autorenew is true, credentials not passed, keylength passed and expired certificate exists' {
                Mock -CommandName Set-Content `
                    -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf' -and `
                        $Value -eq $certInfKeyRenew
                }

                Mock -CommandName Get-ChildItem -Mockwith { $expiredCert }

                It 'Should not throw' {
                    { Set-TargetResource @paramsKeyLength4096AutoRenewNoCred -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 3

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInfKeyRenew
                    }

                    Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 1 `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter
                }
            }

            Context 'When autorenew is false, credentials not passed, certificate request creation failed' {
                Mock -CommandName Test-Path -MockWith { $false } `
                    -ParameterFilter $pathCertReqTestReq_parameterFilter

                Mock -CommandName Test-Path -MockWith { $false } `
                    -ParameterFilter $pathCertReqTestCer_parameterFilter

                Mock -CommandName Set-Content `
                    -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf' -and `
                        $Value -eq $certInf
                }

                Mock -CommandName Get-ChildItem

                $errorRecord = Get-InvalidOperationRecord `
                    -Message ($LocalizedData.CertificateReqNotFoundError -f 'CertReq-Test.req')

                It 'Should throw CertificateReqNotFoundError exception' {
                    { Set-TargetResource @paramsNoCred -Verbose } | Should -Throw $errorRecord
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 0 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInf
                    }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 1

                    Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 0 `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter
                }
            }

            Context 'When autorenew is false, credentials not passed, certificate creation failed' {
                Mock -CommandName Test-Path -MockWith { $false } `
                    -ParameterFilter $pathCertReqTestCer_parameterFilter

                Mock -CommandName Set-Content `
                    -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf'
                }

                Mock -CommandName Get-ChildItem

                $errorRecord = Get-InvalidOperationRecord `
                    -Message ($LocalizedData.CertificateCerNotFoundError -f 'CertReq-Test.cer')

                It 'Should throw CertificateCerNotFoundError exception' {
                    { Set-TargetResource @paramsNoCred -Verbose } | Should -Throw $errorRecord
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInf
                    }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 2

                    Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 0 `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter
                }
            }

            Context 'When autorenew is false, credentials passed' {
                Mock -CommandName Set-Content `
                    -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf'
                }

                Mock -CommandName Get-ChildItem

                Mock -CommandName Get-Content -Mockwith { 'Output' } `
                    -ParameterFilter $pathCertReqTestOut_parameterFilter

                Mock -CommandName Remove-Item `
                    -ParameterFilter $pathCertReqTestOut_parameterFilter

                Mock -CommandName Import-Module

                Mock -CommandName Start-Win32Process -ModuleName MSFT_CertReq

                Mock -CommandName Wait-Win32ProcessStop -ModuleName MSFT_CertReq

                It 'Should not throw' {
                    { Set-TargetResource @paramsStandard -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestOut_parameterFilter

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInf
                    }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 2

                    Assert-MockCalled -CommandName Get-Content -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestOut_parameterFilter

                    Assert-MockCalled -CommandName Remove-Item -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestOut_parameterFilter

                    Assert-MockCalled -CommandName Start-Win32Process -ModuleName MSFT_CertReq -Exactly -Times 1

                    Assert-MockCalled -CommandName Wait-Win32ProcessStop -ModuleName MSFT_CertReq -Exactly -Times 1

                    Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 0 `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter
                }
            }

            Context 'When autorenew is false, credentials passed and provider name encapsulated in quotes' {
                Mock -CommandName Set-Content `
                    -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf'
                }

                Mock -CommandName Get-ChildItem

                Mock -CommandName Get-Content -Mockwith { 'Output' } `
                    -ParameterFilter $pathCertReqTestOut_parameterFilter

                Mock -CommandName Remove-Item `
                    -ParameterFilter $pathCertReqTestOut_parameterFilter

                Mock -CommandName Import-Module

                Mock -CommandName Start-Win32Process -ModuleName MSFT_CertReq

                Mock -CommandName Wait-Win32ProcessStop -ModuleName MSFT_CertReq

                It 'Should not throw' {
                    { Set-TargetResource @paramsStandardProviderNameWithQuotes -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestOut_parameterFilter

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInf
                    }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 2

                    Assert-MockCalled -CommandName Get-Content -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestOut_parameterFilter

                    Assert-MockCalled -CommandName Remove-Item -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestOut_parameterFilter

                    Assert-MockCalled -CommandName Start-Win32Process -ModuleName MSFT_CertReq -Exactly -Times 1

                    Assert-MockCalled -CommandName Wait-Win32ProcessStop -ModuleName MSFT_CertReq -Exactly -Times 1

                    Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 0 `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter
                }
            }

            Context 'When autorenew is false, credentials passed and machine context specified' {
                Mock -CommandName Get-ChildItem -Mockwith { } `
                    -ParameterFilter { $Path -eq 'Cert:\LocalMachine\My' }

                Mock -CommandName Get-Content -Mockwith { 'Output' } `
                    -ParameterFilter { $Path -eq 'CertReq-Test.out' }

                Mock -CommandName Remove-Item `
                    -ParameterFilter { $Path -eq 'CertReq-Test.out' }

                Mock -CommandName Import-Module

                Mock -CommandName Start-Win32Process -ModuleName MSFT_CertReq

                Mock -CommandName Wait-Win32ProcessStop -ModuleName MSFT_CertReq

                It 'Should not throw' {
                    { Set-TargetResource @paramsStandardMachineContext -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter { $Path -eq 'CertReq-Test.req' }

                    Assert-MockCalled -CommandName Test-Path  -Exactly -Times 1 `
                        -ParameterFilter { $Path -eq 'CertReq-Test.cer' }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly 2

                    Assert-MockCalled -CommandName Start-Win32Process -ModuleName MSFT_CertReq -Exactly 1 `
                        -ParameterFilter { $Arguments -like "*-adminforcemachine*" }

                    Assert-MockCalled -CommandName Wait-Win32ProcessStop -ModuleName MSFT_CertReq -Exactly -Times 1

                    Assert-MockCalled -CommandName Test-Path  -Exactly -Times 1 `
                        -ParameterFilter { $Path -eq 'CertReq-Test.out' }

                    Assert-MockCalled -CommandName Get-Content -Exactly -Times 1 `
                        -ParameterFilter { $Path -eq 'CertReq-Test.out' }

                    Assert-MockCalled -CommandName Remove-Item -Exactly -Times 1 `
                        -ParameterFilter { $Path -eq 'CertReq-Test.out' }
                }
            }

            Context 'When autorenew is false, credeintals passed, no .out file' {
                Mock -CommandName Test-Path -MockWith { $false } `
                    -ParameterFilter { $Path -eq 'CertReq-Test.out' }

                Mock -CommandName Get-ChildItem -Mockwith { } `
                    -ParameterFilter { $Path -eq 'Cert:\LocalMachine\My' }

                Mock -CommandName Get-Content -Mockwith { 'Output' } `
                    -ParameterFilter { $Path -eq 'CertReq-Test.out' }

                Mock -CommandName Remove-Item `
                    -ParameterFilter { $Path -eq 'CertReq-Test.out' }

                Mock -CommandName Import-Module

                Mock -CommandName New-InvalidOperationException

                Mock -CommandName Start-Win32Process -ModuleName MSFT_CertReq

                Mock -CommandName Wait-Win32ProcessStop -ModuleName MSFT_CertReq

                It 'Should not throw' {
                    { Set-TargetResource @paramsStandard -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter { $Path -eq 'CertReq-Test.req' }

                    Assert-MockCalled -CommandName Test-Path  -Exactly -Times 1 `
                        -ParameterFilter { $Path -eq 'CertReq-Test.cer' }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly 2

                    Assert-MockCalled -CommandName Start-Win32Process -ModuleName MSFT_CertReq -Exactly -Times 1

                    Assert-MockCalled -CommandName Wait-Win32ProcessStop -ModuleName MSFT_CertReq -Exactly -Times 1

                    Assert-MockCalled -CommandName Test-Path  -Exactly -Times 1 `
                        -ParameterFilter { $Path -eq 'CertReq-Test.out' }

                    Assert-MockCalled -CommandName Get-Content -Exactly 0 `
                        -ParameterFilter { $Path -eq 'CertReq-Test.out' }

                    Assert-MockCalled -CommandName Remove-Item -Exactly 0 `
                        -ParameterFilter { $Path -eq 'CertReq-Test.out' }

                    Assert-MockCalled -CommandName New-InvalidOperationException -Exactly 1
                }
            }

            Mock -CommandName Set-Content `
                -ParameterFilter {
                $Path -eq 'CertReq-Test.inf' -and `
                    $Value -eq $certInfSubjectAltName
            }

            Context 'When autorenew is false, subject alt name passed, credentials not passed' {
                Mock -CommandName Set-Content `
                    -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf' -and `
                        $Value -eq $certInfSubjectAltName
                }

                Mock -CommandName Get-ChildItem

                It 'Should not throw' {
                    { Set-TargetResource @paramsSubjectAltNameNoCred -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInfSubjectAltName
                    }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 3

                    Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 0 `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter
                }
            }

            Context 'When standalone CA, URL for CEP and CES passed, credentials passed, inf not containing template' {
                Mock -CommandName Set-Content -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf'
                }

                Mock -CommandName Get-ChildItem

                It 'Should not throw' {
                    { Set-TargetResource @paramsStandaloneWebEnrollment -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInfNoTemplate
                    }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 3

                    Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 0 `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter
                }
            }

            Context 'When enterprise CA, URL for CEP and CES passed, credentials passed' {
                Mock -CommandName Set-Content -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf'
                }

                Mock -CommandName Get-ChildItem

                It 'Should not throw' {
                    { Set-TargetResource @paramsEnterpriseWebEnrollment -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInf
                    }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 3

                    Assert-MockCalled -CommandName Get-ChildItem -Exactly -Times 0 `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter
                }
            }

            Context 'When auto-discovered CA, autorenew is false, credentials passed' {
                Mock -CommandName Set-Content -ParameterFilter {
                    $Path -eq 'CertReq-Test.inf'
                }

                Mock -CommandName Get-ChildItem

                Mock -CommandName Get-Content -Mockwith { 'Output' } `
                    -ParameterFilter $pathCertReqTestOut_parameterFilter

                Mock -CommandName Remove-Item `
                    -ParameterFilter $pathCertReqTestOut_parameterFilter

                Mock -CommandName Import-Module

                Mock -CommandName Start-Win32Process

                Mock -CommandName Wait-Win32ProcessStop

                Mock -CommandName Find-CertificateAuthority -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CARootName   = "ContosoCA"
                        CAServerFQDN = "ContosoVm.contoso.com"
                    }
                }

                It 'Should not throw' {
                    { Set-TargetResource @paramsAutoDiscovery -Verbose } | Should -Not -Throw
                }

                It 'Should call expected mocks' {
                    Assert-MockCalled -CommandName Join-Path -Exactly -Times 1 `
                        -ParameterFilter $pathTemp_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestReq_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestCer_parameterFilter

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestOut_parameterFilter

                    Assert-MockCalled -CommandName Set-Content -Exactly -Times 1 `
                        -ParameterFilter {
                        $Path -eq 'CertReq-Test.inf' -and `
                            $Value -eq $certInf
                    }

                    Assert-MockCalled -CommandName CertReq.exe -Exactly -Times 2

                    Assert-MockCalled -CommandName Start-Win32Process -ModuleName MSFT_CertReq -Exactly -Times 1

                    Assert-MockCalled -CommandName Wait-Win32ProcessStop -ModuleName MSFT_CertReq -Exactly -Times 1

                    Assert-MockCalled -CommandName Test-Path -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestOut_parameterFilter

                    Assert-MockCalled -CommandName Get-Content -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestOut_parameterFilter

                    Assert-MockCalled -CommandName Remove-Item -Exactly -Times 1 `
                        -ParameterFilter $pathCertReqTestOut_parameterFilter

                    Assert-MockCalled -CommandName Find-CertificateAuthority -Exactly -Times 1
                }
            }
        }

        Describe 'MSFT_CertReq\Test-TargetResource' -Tag 'Test' {
            Context 'When a valid certificate does not exist and a certificate with an empty Subject exists in the Store' {
                Mock -CommandName Find-CertificateAuthority `
                    -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CARootName   = "ContosoCA"
                        CAServerFQDN = "ContosoVm.contoso.com"
                    }
                }

                Mock -CommandName Get-ChildItem `
                    -ParameterFilter $pathCertLocalMachineMy_parameterFilter `
                    -Mockwith $mock_GetChildItem_validCertWithoutSubject

                It 'Should return false' {
                    Test-TargetResource @paramsStandard -Verbose | Should -Be $false
                }
            }

            Context 'When a valid certificate does not exist' {
                Mock -CommandName Find-CertificateAuthority `
                    -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CARootName   = "ContosoCA"
                        CAServerFQDN = "ContosoVm.contoso.com"
                    }
                }

                Mock -CommandName Get-ChildItem `
                    -ParameterFilter $pathCertLocalMachineMy_parameterFilter

                It 'Should return false' {
                    Test-TargetResource @paramsStandard -Verbose | Should -Be $false
                }
            }

            Context 'When a valid certificate already exists' {
                Mock -CommandName Find-CertificateAuthority `
                    -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CARootName   = "ContosoCA"
                        CAServerFQDN = "ContosoVm.contoso.com"
                    }
                }

                Mock `
                    -CommandName Get-ChildItem `
                    -ParameterFilter $pathCertLocalMachineMy_parameterFilter

                It 'Should return false' {
                    Test-TargetResource @paramsStandard -Verbose | Should -Be $false
                }
            }

            Context 'When a valid certificate already exists and is not about to expire' {
                Mock -CommandName Find-CertificateAuthority `
                    -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CARootName   = "ContosoCA"
                        CAServerFQDN = "ContosoVm.contoso.com"
                    }
                }

                Mock -CommandName Get-ChildItem `
                    -ParameterFilter $pathCertLocalMachineMy_parameterFilter `
                    -Mockwith $mock_getChildItem_validCert

                Mock -CommandName Get-CertificateTemplateName `
                    -MockWith $mock_getCertificateTemplateName_validCertificateTemplate

                Mock -CommandName Get-CertificateSubjectAlternativeName `
                    -MockWith $mock_getCertificateSan_subjectAltName

                It 'Should return true' {
                    Test-TargetResource @paramsStandard -Verbose | Should -Be $true
                }
            }

            Context 'When an expired certificate exists and autorenew set' {
                It 'Should return true' {
                    Mock -CommandName Get-ChildItem `
                        -ParameterFilter {
                        $Path -eq 'Cert:\LocalMachine\My'
                    } `
                        -Mockwith $mock_getChildItem_expiredCert

                    Mock -CommandName Get-CertificateTemplateName `
                        -MockWith $mock_getCertificateTemplateName_validCertificateTemplate

                    Mock -CommandName Get-CertificateSubjectAlternativeName `
                        -MockWith $mock_getCertificateSan_subjectAltName

                    Test-TargetResource @paramsStandard -Verbose | Should -Be $false
                }
            }

            Context 'When a valid certificate already exists and is about to expire and autorenew set' {
                Mock -CommandName Find-CertificateAuthority `
                    -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CARootName   = "ContosoCA"
                        CAServerFQDN = "ContosoVm.contoso.com"
                    }
                }

                Mock -CommandName Get-ChildItem `
                    -ParameterFilter $pathCertLocalMachineMy_parameterFilter `
                    -Mockwith $mock_getChildItem_expiringCert

                Mock -CommandName Get-CertificateTemplateName `
                    -MockWith $mock_getCertificateTemplateName_validCertificateTemplate

                Test-TargetResource @paramsAutoRenew -Verbose | Should -Be $false
            }

            Context 'When a valid certificate already exists and X500 subjects are in a different order but match' {
                Mock -CommandName Find-CertificateAuthority `
                    -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CARootName   = "ContosoCA"
                        CAServerFQDN = "ContosoVm.contoso.com"
                    }
                }

                Mock -CommandName Get-ChildItem `
                    -ParameterFilter $pathCertLocalMachineMy_parameterFilter `
                    -Mockwith $mock_getChildItem_validCertSubjectDifferentOrder

                Mock -CommandName Get-CertificateTemplateName `
                    -MockWith $mock_getCertificateTemplateName_validCertificateTemplate

                It 'Should return true' {
                    Test-TargetResource @paramsSubjectDifferentOrder -Verbose | Should -Be $true
                }
            }

            Context 'When a valid certificate already exists and DNS SANs match' {
                Mock -CommandName Find-CertificateAuthority `
                    -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CARootName   = "ContosoCA"
                        CAServerFQDN = "ContosoVm.contoso.com"
                    }
                }

                Mock -CommandName Get-ChildItem `
                    -ParameterFilter $pathCertLocalMachineMy_parameterFilter `
                    -Mockwith $mock_getChildItem_validSANCert

                Mock -CommandName Get-CertificateTemplateName `
                    -MockWith $mock_getCertificateTemplateName_validCertificateTemplate

                It 'Should return true' {
                    Test-TargetResource @paramsSubjectAltName -Verbose | Should -Be $true
                }
            }

            Context 'When a certificate exists but contains incorrect DNS SANs' {
                Mock -CommandName Find-CertificateAuthority `
                    -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CARootName   = "ContosoCA"
                        CAServerFQDN = "ContosoVm.contoso.com"
                    }
                }

                Mock -CommandName Get-ChildItem `
                    -ParameterFilter $pathCertLocalMachineMy_parameterFilter `
                    -Mockwith $mock_getChildItem_incorrectSANCert

                Mock -CommandName Get-CertificateTemplateName `
                    -MockWith $mock_getCertificateTemplateName_validCertificateTemplate

                It 'Should return false' {
                    Test-TargetResource @paramsSubjectAltName -Verbose | Should -Be $false
                }
            }

            Context 'When a certificate exists but does not contain specified DNS SANs' {
                Mock -CommandName Find-CertificateAuthority -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CARootName   = "ContosoCA"
                        CAServerFQDN = "ContosoVm.contoso.com"
                    }
                }

                Mock -CommandName Get-ChildItem `
                    -ParameterFilter $pathCertLocalMachineMy_parameterFilter `
                    -Mockwith $mock_getChildItem_emptySANCert

                Mock -CommandName Get-CertificateTemplateName `
                    -MockWith $mock_getCertificateTemplateName_validCertificateTemplate

                It 'Should return false' {
                    Test-TargetResource @paramsSubjectAltName -Verbose | Should -Be $false
                }
            }

            Context 'When a certificate exists but does not match the Friendly Name' {
                Mock -CommandName Find-CertificateAuthority `
                    -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CARootName   = "ContosoCA"
                        CAServerFQDN = "ContosoVm.contoso.com"
                    }
                }

                Mock -CommandName Get-ChildItem `
                    -ParameterFilter $pathCertLocalMachineMy_parameterFilter `
                    -Mockwith $mock_getChildItem_incorrectFriendlyName

                Mock -CommandName Get-CertificateTemplateName `
                    -MockWith $mock_getCertificateTemplateName_validCertificateTemplate

                It 'Should return false' {
                    Test-TargetResource @paramsStandard -Verbose | Should -Be $false
                }
            }


            Context 'When a certificate exists but does not match the Certificate Template' {
                It 'Should return false' {
                    Mock -CommandName Get-ChildItem `
                        -ParameterFilter {
                        $Path -eq 'Cert:\LocalMachine\My'
                    } `
                        -Mockwith $mock_getChildItem_validCert

                    Mock -CommandName Get-CertificateTemplateName `
                        -MockWith $mock_getCertificateTemplateName_invalidCertificateTemplate

                    Test-TargetResource @paramsStandard -Verbose | Should -Be $false
                }
            }

            Context 'When a Domain Controller certificate template is used, A valid certificate already exists and is not about to expire' {
                It 'Should return true' {
                    Mock -CommandName Get-ChildItem `
                        -ParameterFilter $pathCertLocalMachineMy_parameterFilter `
                        -Mockwith $mock_getChildItem_validCert

                    Mock -CommandName Get-CertificateTemplateName `
                        -MockWith $mock_getCertificateTemplateName_validDCCertificateTemplate

                    Mock -CommandName Get-CertificateSubjectAlternativeName `
                        -MockWith $mock_getCertificateSan_subjectAltName

                    Test-TargetResource @paramsStandardDomainController -Verbose | Should -Be $true
                }
            }

            Context 'When auto-discover of the CA is enabled' {
                Mock -CommandName Find-CertificateAuthority `
                    -MockWith {
                    return New-Object -TypeName psobject -Property @{
                        CARootName   = "ContosoCA"
                        CAServerFQDN = "ContosoVm.contoso.com"
                    }
                }

                Mock -CommandName Get-ChildItem `
                    -ParameterFilter $pathCertLocalMachineMy_parameterFilter

                It 'Should return false' {
                    Test-TargetResource @paramsAutoDiscovery -Verbose | Should -Be $false
                }

                It 'Should execute the auto-discovery function' {
                    Assert-MockCalled -CommandName Find-CertificateAuthority -Exactly -Times 1
                }
            }
        }

        Describe 'MSFT_CertReq\Assert-ResourceProperty' {
            Context 'When RSA key type and key length is valid' {
                It 'Should not throw' {
                    { Assert-ResourceProperty @paramRsaValid -Verbose } | Should -Not -Throw
                }
            }

            Context 'When RSA key type and key length is invalid' {
                $errorRecord = Get-InvalidArgumentRecord `
                    -Message (($LocalizedData.InvalidKeySize) -f '384', 'RSA') -ArgumentName 'KeyLength'

                It 'Should not throw' {
                    { Assert-ResourceProperty @paramRsaInvalid -Verbose } | Should -Throw $errorRecord
                }
            }

            Context 'When ECDH key type and key length is valid' {
                It 'Should not throw' {
                    { Assert-ResourceProperty @paramEcdhValid -Verbose } | Should -Not -Throw
                }
            }

            Context 'When ECDH key type and key length is invalid' {
                $errorRecord = Get-InvalidArgumentRecord `
                    -Message (($LocalizedData.InvalidKeySize) -f '2048', 'ECDH') -ArgumentName 'KeyLength'

                It 'Should not throw' {
                    { Assert-ResourceProperty @paramEcdhInvalid -Verbose } | Should -Throw $errorRecord
                }
            }
        }

        Describe 'MSFT_CertReq\Compare-CertificateSubject' {
            Context 'When called with matching subjects containing with single X500 paths' {
                It 'Should return a true' {
                    Compare-CertificateSubject `
                        -ReferenceSubject 'CN=TestSubject' `
                        -DifferenceSubject 'CN=TestSubject' | Should -Be $true
                }
            }

            Context 'When called without matching subjects containing with single X500 paths' {
                It 'Should return a false' {
                    Compare-CertificateSubject `
                        -ReferenceSubject 'CN=TestSubject' `
                        -DifferenceSubject 'CN=SubjectTest' | Should -Be $false
                }
            }

            Context 'When called with matching subjects containing with X500 paths in the same order' {
                It 'Should return a true' {
                    Compare-CertificateSubject `
                        -ReferenceSubject 'CN=xyz.contoso.com, E=xyz@contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, S=State, C=country' `
                        -DifferenceSubject 'CN=xyz.contoso.com, E=xyz@contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, S=State, C=country' | Should -Be $true
                }
            }

            Context 'When called with matching subjects containing with X500 paths in different order' {
                It 'Should return a true' {
                    Compare-CertificateSubject `
                        -ReferenceSubject 'CN=xyz.contoso.com, E=xyz@contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, S=State, C=country' `
                        -DifferenceSubject 'E=xyz@contoso.com, CN=xyz.contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, S=State, C=country' | Should -Be $true
                }
            }

            Context 'When called with different subjects containing with X500 paths in the same order' {
                It 'Should return a false' {
                    Compare-CertificateSubject `
                        -ReferenceSubject 'CN=xyz.contoso.com, E=xyz@contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, S=State, C=country' `
                        -DifferenceSubject 'CN=xyz.contoso.com, E=test@contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, S=State, C=country' | Should -Be $false
                }
            }

            Context 'When called with different subjects containing with X500 paths in the same order but missing element' {
                It 'Should return a false' {
                    Compare-CertificateSubject `
                        -ReferenceSubject 'CN=xyz.contoso.com, E=xyz@contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, S=State, C=country' `
                        -DifferenceSubject 'CN=xyz.contoso.com, E=xyz@contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, C=country' | Should -Be $false
                }
            }

            Context 'When called with a null ReferenceSubject' {
                It 'Should return a false' {
                    Compare-CertificateSubject `
                        -ReferenceSubject $null `
                        -DifferenceSubject 'CN=xyz.contoso.com, E=xyz@contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, C=country' | Should -Be $false
                }
            }

            Context 'When called with an empty ReferenceSubject' {
                It 'Should return a false' {
                    Compare-CertificateSubject `
                        -ReferenceSubject '' `
                        -DifferenceSubject 'CN=xyz.contoso.com, E=xyz@contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, C=country' | Should -Be $false
                }
            }
        }

        Describe 'MSFT_CertReq\Compare-CertificateIssuer' {
            Context 'When called with certificate issuer with single X500 paths matching the CA root name' {
                It 'Should return a true' {
                    Compare-CertificateIssuer `
                        -Issuer 'CN=xyz.contoso.com' `
                        -CARootName 'xyz.contoso.com' | Should -Be $true
                }
            }

            Context 'When called with certificate issuer with multiple X500 paths matching the CA root name' {
                It 'Should return a true' {
                    Compare-CertificateIssuer `
                        -Issuer 'CN=xyz.contoso.com, E=xyz@contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, S=State, C=country' `
                        -CARootName 'xyz.contoso.com' | Should -Be $true
                }
            }

            Context 'When called with certificate issuer with single X500 paths not matching the CA root name' {
                It 'Should return a false' {
                    Compare-CertificateIssuer `
                        -Issuer 'CN=abc.contoso.com' `
                        -CARootName 'xyz.contoso.com' | Should -Be $false
                }
            }

            Context 'When called with certificate issuer with multiple X500 paths not matching the CA root name' {
                It 'Should return a true' {
                    Compare-CertificateIssuer `
                        -Issuer 'CN=abc.contoso.com, E=xyz@contoso.com, OU=Organisation Unit, O=Organisation, L=Locality, S=State, C=country' `
                        -CARootName 'xyz.contoso.com' | Should -Be $false
                }
            }
        }

        Describe 'MSFT_CertReq\ConvertTo-StringEnclosedInDoubleQuotes' {
            Context 'When called with test values' {
                $testValues = @(
                    @{ Value = 'test' },
                    @{ Value = '"test' },
                    @{ Value = 'test"' },
                    @{ Value = '"test"' }
                )

                It 'Should return ''"test"'' when called with ''<Value>''' -TestCases $testValues {
                    param
                    (
                        [Parameter()]
                        [System.String]
                        $Value
                    )

                    ConvertTo-StringEnclosedInDoubleQuotes -Value $Value | Should -Be '"test"'
                }
            }
        }
    }
}
finally
{
    Restore-TestEnvironment -TestEnvironment $testEnvironment
}