Functions/Get-NDESCertificate.ps1

<#
    .SYNOPSIS
    Requests a Certificate from an NDES Server via the SCEP Protocol.
    This works on Windows 8.1 and newer Operating Systems.
 
    .PARAMETER ComputerName
    Specifies the Host Name or IP Address of the NDES Server.
    If using SSL, this must match the NDES Server's identity as specified in its SSL Server Certificate.
 
    .PARAMETER MachineContext
    By default, the Key for Certificate Request gets created in the current User's Context.
    By specifying this Parameter, it will be created as a Machine Key.
    You must execute the Command with Elevation (Run as Administrator) then.
 
    .PARAMETER Subject
    Specifies the Subject DN for the Certificate.
    May be left empty if you specify a DnsName, Upn or IP instead.
 
    .PARAMETER Dns
    Specifies one or more DNS Names to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request.
    May be left Empty if you specify a Subject, Upn or IP instead.
 
    .PARAMETER Upn
    Specifies one or more User Principal Names to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request.
    May be left Empty if you specify a Subject, DnsName or IP instead.
 
    .PARAMETER Email
    Specifies one or more E-Mail addresses (RFC 822) to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request.
    May be left Empty if you specify a Subject, DnsName, Upn or IP instead.
 
    .PARAMETER IP
    Specifies or more IP Addresses to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request.
    May be left Empty if you specify a Subject, DnsName or Upn instead.
 
    .PARAMETER ChallengePassword
    Specifies the Challenge Password used to authenticate to the NDES Server.
    Not necessary if the NDES Server doesn't require a Password, or if you specify a SigningCert.
 
    .PARAMETER SigningCert
    Specifies the Signing Certificate used to sign the SCEP Certificate Request.
    Can be passed to the Command via the Pipeline.
    Use this when you already have a Certificate issued by the NDES Server and just want to renew it.
    Subject Information will be taken from this Certificate as otherwise NDES would deny the Request if there is a mismatch.
 
    .PARAMETER Ksp
    Specifies the Cryptographic Service Provider (CSP) or Key Storage Provider (KSP) to be used for the Private Key of the Certificate.
    You can specify any CSP or KSP that is installed on the System.
    Defaults to the Microsoft Software Key Storage Provider.
 
    .PARAMETER KeyAlgorithm
    Specifies the Algorithm to be used when creating the Key Pair.
    Defaults to "RSA".
 
    .PARAMETER KeyLength
    Specifies the Key Length for the Key pair of the Certificate.
    Gets applied only when KeyAlgorithm is "RSA".
    Defaults to 3072 Bits.
 
    .PARAMETER PrivateKeyExportable
    Specifies if the Private Key of the Certificate shall be marked as exportable.
    Defaults to the Key being not marked as exportable.
 
    .PARAMETER UseSSL
    Forces the connection to use SSL Encryption. Not necessary from a security perspective,
    as the SCEP Message's confidential partsd are encrypted with the NDES RA Certificates anyway.
 
    .PARAMETER Port
    Specifies the Network Port of the NDES Server to be used.
    Only necessary if your NDES Server is running on a non-default Port for some reason.
    Defaults to Port 80 without SSL and 443 with SSL.
 
    .PARAMETER Method
    Specifies if the Certificate Submission shall be done with HTTP "GET" or "POST".
    Defaults to "POST".
 
    .OUTPUTS
    System.Security.Cryptography.X509Certificates.X509Certificate. Returns the issued Certificate returned by the NDES Server.
#>

Function Get-NDESCertificate {

    [cmdletbinding()]
    param(
        [Parameter(Mandatory=$True)]
        [String]
        $ComputerName,

        [Alias("Machine")]
        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [Switch]
        $MachineContext = $False,

        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [ValidateNotNullOrEmpty()]
        [String]
        $Subject,

        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [Alias("DnsName")]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({
            $_ | ForEach-Object -Process {
            [System.Uri]::CheckHostName($_) -eq [System.UriHostnameType]::Dns
            }
        })]
        [String[]]
        $Dns,

        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [Alias("UserPrincipalName")]
        [ValidateNotNullOrEmpty()]
        [mailaddress[]]
        $Upn,

        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [Alias("RFC822Name")]
        [Alias("E-Mail")]
        [ValidateNotNullOrEmpty()]
        [mailaddress[]]
        $Email,

        [Alias("IPAddress")]
        [Parameter(Mandatory=$False)]
        [ValidateNotNullOrEmpty()]
        [System.Net.IPAddress[]]
        $IP,

        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [ValidateNotNullOrEmpty()]
        [String]
        $ChallengePassword,

        [Parameter(
            ParameterSetName="RenewalRequest",
            ValuefromPipeline = $True,
            Mandatory=$False
            )]
        [ValidateScript({($_.HasPrivateKey) -and ($null -ne $_.PSParentPath)})]
        [System.Security.Cryptography.X509Certificates.X509Certificate2]
        $SigningCert,

        [Alias("KeyStorageProvider")]
        [Parameter(Mandatory=$False)]
        [ValidateScript({
            $Ksp = $_
            [bool](Get-KeyStorageProvider | Where-Object { $_.Name -eq $Ksp })}
        )]
        [String]
        $Ksp = "Microsoft Software Key Storage Provider",

        [Parameter(Mandatory=$False)]
        [ValidateSet(
            "RSA",
            "ECDSA_P256",
            "ECDSA_P384",
            "ECDSA_P521",
            "ECDH_P256",
            "ECDH_P384",
            "ECDH_P521"
            )]
        [String]
        $KeyAlgorithm = "RSA",

        [Alias("KeySize")]
        [Parameter(Mandatory=$False)]
        [ValidateSet(512,1024,2048,3072,4096,8192)]
        [Int]
        $KeyLength = 3072,

        [Alias("Exportable")]
        [Parameter(Mandatory=$False)]
        [Switch]
        $PrivateKeyExportable = $False,

        [Alias("SSL")]
        [Parameter(Mandatory=$False)]
        [Switch]
        $UseSSL = $False,

        [Parameter(Mandatory=$False)]
        [ValidateRange(1,65535)]
        [Int]
        $Port,

        [Parameter(Mandatory=$False)]
        [ValidateSet("GET","POST")]
        [String]
        $Method = "POST",

        [Parameter(Mandatory=$False)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Suffix = "certsrv/mscep/mscep.dll"
    )

    begin  {

        Add-Type -AssemblyName System.Security

        # This hides the Status Indicators of the Invoke-WebRequest Calls later on
        $ProgressPreference = 'SilentlyContinue'

        # Assembling the Configuration String, which is the SCEP URL in this Case
        If ($UseSSL)
            { $Protocol = "https" }
        Else 
            { $Protocol = "http" }

        If ($Port)
            { $PortString = ":$($Port)" }
        Else
            { $PortString = [String]::Empty }

        $ConfigString = "$($Protocol)://$($ComputerName)$($PortString)/$($Suffix)/pkiclient.exe"

        Write-Verbose -Message "Configuration String: $ConfigString"

        # SCEP GetCACaps Operation
        Try {
            $GetCACaps = (Invoke-WebRequest -uri "$($ConfigString)?operation=GetCACaps").Content
        }
        Catch {
            Write-Error -Message $PSItem.Exception.Message
            return
        }

        # SCEP GetCACert Operation
        Try {
            $GetCACert = (Invoke-WebRequest -uri "$($ConfigString)?operation=GetCACert").Content

            # Decoding the CMS (PKCS#7 Message that was returned from the NDES Server)
            $Pkcs7CaCert = New-Object System.Security.Cryptography.Pkcs.SignedCms
            $Pkcs7CaCert.Decode($GetCACert)
        }
        Catch {
            Write-Error -Message $PSItem.Exception.Message
            return
        }

    }

    process {

        # Skip pipeline processing if the preparation steps failed
        If (-not $GetCACaps) { return }
        If (-not $Pkcs7CaCert.Certificates) { return }

        # Ensuring the Code will be executed on a supported Operating System
        # Operating Systems prior to Windows 8.1 don't contain the IX509SCEPEnrollment Interface
        If ([int32](Get-WmiObject Win32_OperatingSystem).BuildNumber -lt $BUILD_NUMBER_WINDOWS_8_1) {
            Write-Error -Message "This must be executed on Windows 8.1/Windows Server 2012 R2 or newer!"
            return 
        }

        # Ensuring we work with Elevation when messing with the Computer Certificate Store
        # As we want to inherit Key Settings from the Signing Certificate, we must also check its Certificate Store
        If ($MachineContext.IsPresent -or ($SigningCert -and ($SigningCert.PSParentPath -match "Machine"))) {

            If (-not (
                [Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
                ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
                Write-Error -Message "This must be run with Elevation (Run as Administrator) when using the Machine Context!" 
                return
            }
        }

        $CertificateRequestPkcs10 = New-Object -ComObject "X509Enrollment.CX509CertificateRequestPkcs10"

        # Determining if we create an entirely new Certificate Request or inherit Settings from an old one
        If ($SigningCert) {

            # Certificate Renewal Request

            If ($GetCACaps -match "Renewal") {

                $InheritOptions =  $X509RequestInheritOptions.InheritDefault
                $InheritOptions += $X509RequestInheritOptions.InheritSubjectAltNameFlag
                $InheritOptions += $X509RequestInheritOptions.InheritExtensionsFlag
                $InheritOptions += $X509RequestInheritOptions.InheritSubjectFlag

                $CertificateRequestPkcs10.InitializeFromCertificate(
                    [int]($SigningCert.PSParentPath -match "Machine")+1,
                    [Convert]::ToBase64String($SigningCert.RawData),
                    $EncodingType.XCN_CRYPT_STRING_BASE64,
                    $InheritOptions
                )

                
                # Configuring the private Key of the Certificate
                $CertificateRequestPkcs10.PrivateKey.Length = $KeyLength
                $CertificateRequestPkcs10.PrivateKey.ExportPolicy = [int]($PrivateKeyExportable.IsPresent)
                $CertificateRequestPkcs10.PrivateKey.ProviderName = $Ksp

                <#
                    https://tools.ietf.org/html/draft-nourse-scep-23#section-2.3
                    A client that is performing certificate renewal as per Appendix D
                    SHOULD send an empty challenge password (i.e. use the empty string as
                    the challenge password) but MAY send the originally distributed
                    challenge password in the challengePassword attribute.
                #>

                $CertificateRequestPkcs10.ChallengePassword = [String]::Empty

            }
            Else {
                Write-Error -Message "The Server does not support Renewal!"
                return
            }

        }
        Else {

            # New Certificate Request

            If ((-not $Dns) -and (-not $Upn) -and (-not $Email) -and (-not $IP) -and (-not $Subject)) {
                Write-Error -Message "You must provide an Identity, either in Form ob a Subject or Subject Alternative Name!"
                return
            }


            # We first create the Private Key
            # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-ix509privatekey
            # Setting the Provider Attribute on the CertRequest Object afterwards seems not to work with Key Storage Providers...why?
            $PrivateKey = New-Object -ComObject 'X509Enrollment.CX509PrivateKey'
            
            $PrivateKey.ProviderName = $Ksp

            $PrivateKey.MachineContext = [int]($MachineContext.IsPresent)
            $PrivateKey.ExportPolicy = [int]($PrivateKeyExportable.IsPresent)

            If ($KeyAlgorithm -ne "RSA") {

                $Algorithm = New-Object -ComObject 'X509Enrollment.CObjectId'
    
                # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-iobjectid-initializefromalgorithmname
                $Algorithm.InitializeFromAlgorithmName(
                    $ObjectIdGroupId.XCN_CRYPT_PUBKEY_ALG_OID_GROUP_ID,
                    $ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY,
                    $AlgorithmFlags.AlgorithmFlagsNone,
                    $KeyAlgorithm
                )
    
                # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509privatekey-put_algorithm
                $PrivateKey.Algorithm = $Algorithm
    
                [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($Algorithm))
            }
    
            # Key Length is only relevant when Key Type is "RSA"
            If ($KeyAlgorithm -eq "RSA") {
    
                $PrivateKey.Length = $KeyLength
            }
    
            Try {
                $PrivateKey.Create()
            }
            Catch {
                [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($PrivateKey))
                Write-Error -Message $PSItem.Exception.Message
                return
            }

            $CertificateRequestPkcs10.InitializeFromPrivateKey(
                [int]($MachineContext.IsPresent)+1,
                $PrivateKey, 
                [String]::Empty
            )

            Try {
                # To Do: implement Validation of the Subject RDN
                $SubjectDnObject = New-Object -ComObject "X509Enrollment.CX500DistinguishedName"
                $SubjectDnObject.Encode($Subject)
                $CertificateRequestPkcs10.Subject = $SubjectDnObject
            }
            Catch {
                Write-Error -Message "Invalid Subject DN supplied!"
                return
            }

            # Set the Subject Alternative Names Extension if specified as Argument
            If ($Upn -or $Email -or $Dns -or $IP) {

                $SubjectAlternativeNamesExtension = New-Object -ComObject X509Enrollment.CX509ExtensionAlternativeNames
                $Sans = New-Object -ComObject X509Enrollment.CAlternativeNames
        
                # https://msdn.microsoft.com/en-us/library/aa374981(VS.85).aspx

                Foreach ($Entry in $Upn) {

                    $AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName
                    $AlternativeNameObject.InitializeFromString(
                        $AlternativeNameType.XCN_CERT_ALT_NAME_USER_PRINCIPLE_NAME, 
                        $Entry
                    )
                    $Sans.Add($AlternativeNameObject)
                    [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject))
    
                }

                Foreach ($Entry in $Email) {
            
                    $AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName
                    $AlternativeNameObject.InitializeFromString(
                        $AlternativeNameType.XCN_CERT_ALT_NAME_RFC822_NAME, 
                        $Entry
                    )
                    $Sans.Add($AlternativeNameObject)
                    [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject))
    
                }
    
                Foreach ($Entry in $Dns) {

                    $AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName
                    $AlternativeNameObject.InitializeFromString(
                        $AlternativeNameType.XCN_CERT_ALT_NAME_DNS_NAME,
                        $Entry
                    )
                    $Sans.Add($AlternativeNameObject)
                    [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject))
    
                }

                Foreach ($Entry in $IP) {

                    $AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName
                    $AlternativeNameObject.InitializeFromRawData(
                        $AlternativeNameType.XCN_CERT_ALT_NAME_IP_ADDRESS,
                        $EncodingType.XCN_CRYPT_STRING_BASE64,
                        [Convert]::ToBase64String($Entry.GetAddressBytes())
                    )
                    $Sans.Add($AlternativeNameObject)
                    [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject))
    
                }
                
                $SubjectAlternativeNamesExtension.Critical = $True
                $SubjectAlternativeNamesExtension.InitializeEncode($Sans)
        
                # Adding the Extension to the Certificate
                $CertificateRequestPkcs10.X509Extensions.Add($SubjectAlternativeNamesExtension)
        
            }

            If ($ChallengePassword) {
                <#
                    https://tools.ietf.org/html/draft-nourse-scep-23#section-2.2
                    PKCS#10 [RFC2986] specifies a PKCS#9 [RFC2985] challengePassword
                    attribute to be sent as part of the enrollment request. Inclusion of
                    the challengePassword by the SCEP client is OPTIONAL and allows for
                    unauthenticated authorization of enrollment requests.
                #>

                $CertificateRequestPkcs10.ChallengePassword = $ChallengePassword
            }

        }

        <#
            Identify the Root CA Certificate that was delivered with the Chain
            https://tools.ietf.org/html/rfc5280#section-6.1
            A certificate is self-issued if the same DN appears in the subject and issuer fields
        #>

        $RootCaCert = $Pkcs7CaCert.Certificates | Where-Object { $_.Subject -eq $_.Issuer }

        # Initialize the IX509SCEPEnrollment Interface
        # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-ix509scepenrollment
        $SCEPEnrollmentInterface = New-Object -ComObject "X509Enrollment.CX509SCEPEnrollment"

        # Let's try to build a SCEP Enrollment Message now...

        Try {

            # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509scepenrollment-initialize
            $SCEPEnrollmentInterface.Initialize(
                $CertificateRequestPkcs10,
                (Get-CertificateHash -Bytes $RootCaCert.RawData -HashAlgorithm "MD5"),
                $EncodingType.XCN_CRYPT_STRING_HEX,
                [Convert]::ToBase64String($GetCACert),
                $EncodingType.XCN_CRYPT_STRING_BASE64
            )

        }
        Catch {
            Write-Error -Message $PSItem.Exception.Message
            return
        }

        # Sets the preferred hash and encryption algorithms for the request.
        # If you do not set this property, then the default hash and encryption algorithms will be used.
        # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509scepenrollment-put_servercapabilities
        $SCEPEnrollmentInterface.ServerCapabilities = $GetCACaps

        <#
            https://tools.ietf.org/html/draft-nourse-scep-23#section-2.2
            If the requester does not have an appropriate existing
            certificate, then a locally generated self-signed certificate
            MUST be used instead. The self-signed certificate MUST use the
            same subject name as in the PKCS#10 request.
 
            https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509scepenrollment-put_signercertificate
            To create a renewal request, you must set this property prior to calling the CreateRequestMessage method.
            Otherwise, the CreateRequestMessage method will create a new request and generate a self-signed certificate
            using the same private key as the inner PKCSV10 reqeust.
        #>

        If ($SigningCert) {

            $SignerCertificate = New-Object -ComObject 'X509Enrollment.CSignerCertificate'

            # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-isignercertificate-initialize
            $SignerCertificate.Initialize(
                [int]($SigningCert.PSParentPath -match "Machine"),
                $X509PrivateKeyVerify.VerifyNone, # We did this already during Parameter Validation
                $EncodingType.XCN_CRYPT_STRING_BASE64,
                [Convert]::ToBase64String($SigningCert.RawData)
            )
            $SCEPEnrollmentInterface.SignerCertificate = $SignerCertificate
        }

        # Building the PKCS7 Message for the SCEP Enrollment
        # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509scepenrollment-createrequestmessage
        $SCEPRequestMessage = $SCEPEnrollmentInterface.CreateRequestMessage(
            $EncodingType.XCN_CRYPT_STRING_BASE64
            )
        
        # Submission to the NDES Server
        Try {

            If ($Method -eq "POST") {

                If ($GetCACaps -match "POSTPKIOperation") {
                    $SCEPResponse = Invoke-WebRequest `
                        -Body ([Convert]::FromBase64String($SCEPRequestMessage)) `
                        -Method 'POST' `
                        -Uri "$($ConfigString)?operation=PKIOperation" `
                        -Headers @{'Content-Type' = 'application/x-pki-message'}
                }
                Else {
                    Write-Warning -Message "The Server indicates that it doesnt support the 'POST' Method. Falling back to 'GET'."
                    $Method = "GET"
                }
            }

            If ($Method -eq "GET") {
                $SCEPResponse = Invoke-WebRequest `
                    -Method 'GET' `
                    -Uri "$($ConfigString)?operation=PKIOperation&message=$([uri]::EscapeDataString($SCEPRequestMessage))" `
                    -Headers @{'Content-Type' = 'application/x-pki-message'}
            }

            $SCEPResponse = [Convert]::ToBase64String($ScepResponse.Content)

        }
        Catch {
            Write-Error -Message $PSItem.Exception.Message
            return
        }
        
        Try {

            # Process a response message and return the disposition of the message.
            # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509scepenrollment-processresponsemessage
            $Disposition = $SCEPEnrollmentInterface.ProcessResponseMessage(
                $SCEPResponse,
                $EncodingType.XCN_CRYPT_STRING_BASE64
                )

            # https://docs.microsoft.com/en-us/windows/win32/api/certpol/ne-certpol-x509scepdisposition
            Switch ($Disposition) {

                $X509SCEPDisposition.SCEPDispositionFailure {

                    $ErrorMessage = ''
                    $ErrorMessage += "The NDES Server rejected the Certificate Request!`n"

                    # The Failinfo Method is only present in Windows 10
                    # Windows 8.1 / 2012 R2 Users therefore won't get any fancy error message, sadly
                    If ([int32](Get-WmiObject Win32_OperatingSystem).BuildNumber -ge $BUILD_NUMBER_WINDOWS_10) {

                        $FailInfo = ($SCEPFailInfo | Where-Object { $_.Code -eq $SCEPEnrollmentInterface.FailInfo() })

                        $ErrorMessage += "SCEP Failure Information: $($FailInfo.Message) ($($FailInfo.Code)) $($FailInfo.Description)`n"
                        $ErrorMessage += "Additional Information returned by the Server: $($SCEPEnrollmentInterface.Status().Text)`n"

                        If ($SCEPEnrollmentInterface.Status().Text -match $NDESErrorCode.CERT_E_WRONG_USAGE) {
                            $ErrorMessage += "Possible reason(s): The Challenge Password has been used already."
                        }

                        If ($SCEPEnrollmentInterface.Status().Text -match $NDESErrorCode.TRUST_E_CERT_SIGNATURE) {
                            $ErrorMessage += "Possible reason(s): The NDES Server requires a Challenge Password but none was supplied."
                        }

                        If ($SCEPEnrollmentInterface.Status().Text -match $NDESErrorCode.ERROR_NOT_FOUND) {
                            $ErrorMessage += "Possible reason(s): The Challenge Password supplied is unknown to the NDES Server, or it has been used already."
                        }

                        If ($SCEPEnrollmentInterface.Status().Text -match $NDESErrorCode.CERTSRV_E_BAD_REQUESTSUBJECT) {
                            $ErrorMessage += "Possible reason(s): The CA denied your request because an invalid Subject was requested."
                        }

                        If ($SCEPEnrollmentInterface.Status().Text -match $NDESErrorCode.RPC_S_SERVER_UNAVAILABLE) {
                            $ErrorMessage += "Possible reason(s): The NDES Server was unable to contact the Certification Authority."
                        }
                    }

                    Write-Error -Message $ErrorMessage

                }

                $X509SCEPDisposition.SCEPDispositionPending {
                    Write-Warning -Message "The Enrollment was successful with Status ScepDispositionPending, which is not yet implemented!"
                }

                $X509SCEPDisposition.SCEPDispositionPendingChallenge {
                    Write-Warning -Message  "The Enrollment was successful with Status ScepDispositionPendingChallenge, which is not yet implemented!"
                }

                $X509SCEPDisposition.SCEPDispositionUnknown {
                    Write-Error -Message "The Enrollment failed for an unknown Reason."
                }

                $X509SCEPDisposition.SCEPDispositionSuccess {

                    # We load the Certificate into an X509Certificate2 Object
                    # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509scepenrollment-get_certificate
                    $CertificateObject = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
                    $CertificateObject.Import(
                        [Convert]::FromBase64String(
                            $SCEPEnrollmentInterface.Certificate($EncodingType.XCN_CRYPT_STRING_BASE64)
                            )
                        )

                    # Return the resulting Certificate
                    If ($MachineContext.IsPresent -or ($SigningCert -and ($SigningCert.PSParentPath -match "Machine"))) {
                        Get-ChildItem -Path "Cert:\LocalMachine\My\$($CertificateObject.Thumbprint)"
                    }
                    Else {
                        Get-ChildItem -Path "Cert:\CurrentUser\My\$($CertificateObject.Thumbprint)"
                    }
                }

            }

        }
        Catch {
            Write-Error -Message $PSItem.Exception.Message
            return  
        }

        # Cleaning up the COM Objects, avoiding any User Errors to be reported
        $CertificateRequestPkcs10,
        $SubjectDnObject,
        $SubjectAlternativeNamesExtension,
        $Sans,
        $SCEPEnrollmentInterface,
        $SignerCertificate | ForEach-Object -Process {

            Try {
                [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($_))
            }
            Catch {
                # we don't want to return anything here
            }
        }
    }

    end {}
}
# SIG # Begin signature block
# MIIk6gYJKoZIhvcNAQcCoIIk2zCCJNcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCHrM1ZqWq2FG1d
# FBhhsGjuVBHRzdsmtOmeKVNU2GuFz6CCHqwwggVAMIIEKKADAgECAhEAjyqX/F4u
# bPBaKM2QGtlbKTANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJHQjEbMBkGA1UE
# CBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQK
# Ew9TZWN0aWdvIExpbWl0ZWQxJDAiBgNVBAMTG1NlY3RpZ28gUlNBIENvZGUgU2ln
# bmluZyBDQTAeFw0yMDExMjAwMDAwMDBaFw0yMzExMjAyMzU5NTlaMIGHMQswCQYD
# VQQGEwJERTEOMAwGA1UEEQwFOTE2MDIxHTAbBgNVBAcMFETDvHJyd2FuZ2VuIEhh
# bHNiYWNoMRUwEwYDVQQJDAxXZWloZXJ3ZWcgMTUxGDAWBgNVBAoMD1V3ZSBHcmFk
# ZW5lZ2dlcjEYMBYGA1UEAwwPVXdlIEdyYWRlbmVnZ2VyMIIBIjANBgkqhkiG9w0B
# AQEFAAOCAQ8AMIIBCgKCAQEA53wYl/2oLVZBtzGBVrhekovOH+jLXaqR8bcrXUEt
# GzZS5mhld6V58oliKsdanM2WGRtGga/ew1QKAqlEO3LPWQd/6O+T6ewH1IJy0xxy
# Zv3zsEDySr+2iAZaOqUdxAV8ROuW/fPGJCR3nrRO2vH047z+aAi9S5sZbiO21634
# BRXw94cl4JArB62gSfehtyCqO5oBLjWdz9/41pfrCQPyIoalfL4Ksdt+WEAJqy9T
# JyEF/8GWbGxko/yx/p1k03QjtNT2SM7kDw2JYCnsn2hPPS18q4ca6sZqqUAxBQl0
# P1E0POzP4I3XD8uNuSF8lrCegjxdHuDycgE4fZ1/5giY9QIDAQABo4IBrzCCAasw
# HwYDVR0jBBgwFoAUDuE6qFM6MdWKvsG7rWcaA4WtNA4wHQYDVR0OBBYEFCmcAsJF
# JdY/qAsyvvsYLFw96N2aMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBMG
# A1UdJQQMMAoGCCsGAQUFBwMDMBEGCWCGSAGG+EIBAQQEAwIEEDBKBgNVHSAEQzBB
# MDUGDCsGAQQBsjEBAgEDAjAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28u
# Y29tL0NQUzAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5z
# ZWN0aWdvLmNvbS9TZWN0aWdvUlNBQ29kZVNpZ25pbmdDQS5jcmwwcwYIKwYBBQUH
# AQEEZzBlMD4GCCsGAQUFBzAChjJodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3Rp
# Z29SU0FDb2RlU2lnbmluZ0NBLmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29jc3Au
# c2VjdGlnby5jb20wHQYDVR0RBBYwFIESdXdlQGdyYWRlbmVnZ2VyLmV1MA0GCSqG
# SIb3DQEBCwUAA4IBAQCEQ6MLH2xJoylM/1EVGcnHx1yfR4N0KTpMZmUHeDKHbhVa
# 75UQJRd3/Wy9knpqk8NGnPaS8XNOUgR8A5EoO5djvZfp4JLtUVOM28TI0U+avrtP
# olQHtCRrpb12kCqG5/E5DQNFL9qTK0/cngkXQFiJncjF+AAfWOL+5e4zIPWMVJaw
# PKFIyT47S6BjD5NopviPxcJY3uQ3y5WFqpeYMWL1cpMpC26tvEQbecJLGW51m3l8
# MiaPtxieiuEje8YplJdBOOBDVO+NTJvhiOhOhM2Nnp/PcdqYAuiLpAcv2ekcHp6Q
# svBWxRbwb23mjni1DipueBqn98FCTQkNDQLb6KRuMIIFgTCCBGmgAwIBAgIQOXJE
# Ovkit1HX02wQ3TE1lTANBgkqhkiG9w0BAQwFADB7MQswCQYDVQQGEwJHQjEbMBkG
# A1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYD
# VQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRl
# IFNlcnZpY2VzMB4XDTE5MDMxMjAwMDAwMFoXDTI4MTIzMTIzNTk1OVowgYgxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJzZXkg
# Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQDEyVV
# U0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG
# 9w0BAQEFAAOCAg8AMIICCgKCAgEAgBJlFzYOw9sIs9CsVw127c0n00ytUINh4qog
# TQktZAnczomfzD2p7PbPwdzx07HWezcoEStH2jnGvDoZtF+mvX2do2NCtnbyqTsr
# kfjib9DsFiCQCT7i6HTJGLSR1GJk23+jBvGIGGqQIjy8/hPwhxR79uQfjtTkUcYR
# Z0YIUcuGFFQ/vDP+fmyc/xadGL1RjjWmp2bIcmfbIWax1Jt4A8BQOujM8Ny8nkz+
# rwWWNR9XWrf/zvk9tyy29lTdyOcSOk2uTIq3XJq0tyA9yn8iNK5+O2hmAUTnAU5G
# U5szYPeUvlM3kHND8zLDU+/bqv50TmnHa4xgk97Exwzf4TKuzJM7UXiVZ4vuPVb+
# DNBpDxsP8yUmazNt925H+nND5X4OpWaxKXwyhGNVicQNwZNUMBkTrNN9N6frXTps
# NVzbQdcS2qlJC9/YgIoJk2KOtWbPJYjNhLixP6Q5D9kCnusSTJV882sFqV4Wg8y4
# Z+LoE53MW4LTTLPtW//e5XOsIzstAL81VXQJSdhJWBp/kjbmUZIO8yZ9HE0XvMns
# QybQv0FfQKlERPSZ51eHnlAfV1SoPv10Yy+xUGUJ5lhCLkMaTLTwJUdZ+gQek9Qm
# RkpQgbLevni3/GcV4clXhB4PY9bpYrrWX1Uu6lzGKAgEJTm4Diup8kyXHAc/DVL1
# 7e8vgg8CAwEAAaOB8jCB7zAfBgNVHSMEGDAWgBSgEQojPpbxB+zirynvgqV/0DCk
# tDAdBgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgGG
# MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEMGA1UdHwQ8MDow
# OKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNlcnRpZmljYXRlU2Vy
# dmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29j
# c3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUAA4IBAQAYh1HcdCE9nIrgJ7cz
# 0C7M7PDmy14R3iJvm3WOnnL+5Nb+qh+cli3vA0p+rvSNb3I8QzvAP+u431yqqcau
# 8vzY7qN7Q/aGNnwU4M309z/+3ri0ivCRlv79Q2R+/czSAaF9ffgZGclCKxO/WIu6
# pKJmBHaIkU4MiRTOok3JMrO66BQavHHxW/BBC5gACiIDEOUMsfnNkjcZ7Tvx5Dq2
# +UUTJnWvu6rvP3t3O9LEApE9GQDTF1w52z97GA1FzZOFli9d31kWTz9RvdVFGD/t
# So7oBmF0Ixa1DVBzJ0RHfxBdiSprhTEUxOipakyAvGp4z7h/jnZymQyd/teRCBah
# o1+VMIIF9TCCA92gAwIBAgIQHaJIMG+bJhjQguCWfTPTajANBgkqhkiG9w0BAQwF
# ADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcT
# C0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAs
# BgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN
# MTgxMTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjB8MQswCQYDVQQGEwJHQjEbMBkG
# A1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYD
# VQQKEw9TZWN0aWdvIExpbWl0ZWQxJDAiBgNVBAMTG1NlY3RpZ28gUlNBIENvZGUg
# U2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIYijTKF
# ehifSfCWL2MIHi3cfJ8Uz+MmtiVmKUCGVEZ0MWLFEO2yhyemmcuVMMBW9aR1xqkO
# UGKlUZEQauBLYq798PgYrKf/7i4zIPoMGYmobHutAMNhodxpZW0fbieW15dRhqb0
# J+V8aouVHltg1X7XFpKcAC9o95ftanK+ODtj3o+/bkxBXRIgCFnoOc2P0tbPBrRX
# BbZOoT5Xax+YvMRi1hsLjcdmG0qfnYHEckC14l/vC0X/o84Xpi1VsLewvFRqnbyN
# VlPG8Lp5UEks9wO5/i9lNfIi6iwHr0bZ+UYc3Ix8cSjz/qfGFN1VkW6KEQ3fBiSV
# fQ+noXw62oY1YdMCAwEAAaOCAWQwggFgMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh
# 2JvAnfKyA2bLMB0GA1UdDgQWBBQO4TqoUzox1Yq+wbutZxoDha00DjAOBgNVHQ8B
# Af8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUEFjAUBggrBgEFBQcD
# AwYIKwYBBQUHAwgwEQYDVR0gBAowCDAGBgRVHSAAMFAGA1UdHwRJMEcwRaBDoEGG
# P2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0
# aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0
# dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNy
# dDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG
# 9w0BAQwFAAOCAgEATWNQ7Uc0SmGk295qKoyb8QAAHh1iezrXMsL2s+Bjs/thAIia
# G20QBwRPvrjqiXgi6w9G7PNGXkBGiRL0C3danCpBOvzW9Ovn9xWVM8Ohgyi33i/k
# lPeFM4MtSkBIv5rCT0qxjyT0s4E307dksKYjalloUkJf/wTr4XRleQj1qZPea3FA
# mZa6ePG5yOLDCBaxq2NayBWAbXReSnV+pbjDbLXP30p5h1zHQE1jNfYw08+1Cg4L
# BH+gS667o6XQhACTPlNdNKUANWlsvp8gJRANGftQkGG+OY96jk32nw4e/gdREmaD
# JhlIlc5KycF/8zoFm/lv34h/wCOe0h5DekUxwZxNqfBZslkZ6GqNKQQCd3xLS81w
# vjqyVVp4Pry7bwMQJXcVNIr5NsxDkuS6T/FikyglVyn7URnHoSVAaoRXxrKdsbwc
# Ctp8Z359LukoTBh+xHsxQXGaSynsCz1XUNLK3f2eBVHlRHjdAd6xdZgNVCT98E7j
# 4viDvXK6yz067vBeF5Jobchh+abxKgoLpbn0nu6YMgWFnuv5gynTxix9vTp3Los3
# QqBqgu07SqqUEKThDfgXxbZaeTMYkuO1dfih6Y4KJR7kHvGfWocj/5+kUZ77OYAR
# zdu1xKeogG/lU9Tg46LC0lsa+jImLWpXcBw8pFguo/NbSwfcMlnzh6cabVgwggbs
# MIIE1KADAgECAhAwD2+s3WaYdHypRjaneC25MA0GCSqGSIb3DQEBDAUAMIGIMQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKTmV3IEplcnNleTEUMBIGA1UEBxMLSmVyc2V5
# IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEuMCwGA1UEAxMl
# VVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xOTA1MDIw
# MDAwMDBaFw0zODAxMTgyMzU5NTlaMH0xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJH
# cmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1Nl
# Y3RpZ28gTGltaXRlZDElMCMGA1UEAxMcU2VjdGlnbyBSU0EgVGltZSBTdGFtcGlu
# ZyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMgbAa/ZLH6ImX0B
# mD8gkL2cgCFUk7nPoD5T77NawHbWGgSlzkeDtevEzEk0y/NFZbn5p2QWJgn71TJS
# eS7JY8ITm7aGPwEFkmZvIavVcRB5h/RGKs3EWsnb111JTXJWD9zJ41OYOioe/M5Y
# SdO/8zm7uaQjQqzQFcN/nqJc1zjxFrJw06PE37PFcqwuCnf8DZRSt/wflXMkPQEo
# vA8NT7ORAY5unSd1VdEXOzQhe5cBlK9/gM/REQpXhMl/VuC9RpyCvpSdv7QgsGB+
# uE31DT/b0OqFjIpWcdEtlEzIjDzTFKKcvSb/01Mgx2Bpm1gKVPQF5/0xrPnIhRfH
# uCkZpCkvRuPd25Ffnz82Pg4wZytGtzWvlr7aTGDMqLufDRTUGMQwmHSCIc9iVrUh
# cxIe/arKCFiHd6QV6xlV/9A5VC0m7kUaOm/N14Tw1/AoxU9kgwLU++Le8bwCKPRt
# 2ieKBtKWh97oaw7wW33pdmmTIBxKlyx3GSuTlZicl57rjsF4VsZEJd8GEpoGLZ8D
# Xv2DolNnyrH6jaFkyYiSWcuoRsDJ8qb/fVfbEnb6ikEk1Bv8cqUUotStQxykSYtB
# ORQDHin6G6UirqXDTYLQjdprt9v3GEBXc/Bxo/tKfUU2wfeNgvq5yQ1TgH36tjlY
# Mu9vGFCJ10+dM70atZ2h3pVBeqeDAgMBAAGjggFaMIIBVjAfBgNVHSMEGDAWgBRT
# eb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUGqH4YRkgD8NBd0UojtE1XwYS
# BFUwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEwYDVR0lBAww
# CgYIKwYBBQUHAwgwEQYDVR0gBAowCDAGBgRVHSAAMFAGA1UdHwRJMEcwRaBDoEGG
# P2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0
# aW9uQXV0aG9yaXR5LmNybDB2BggrBgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0
# dHA6Ly9jcnQudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNy
# dDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG
# 9w0BAQwFAAOCAgEAbVSBpTNdFuG1U4GRdd8DejILLSWEEbKw2yp9KgX1vDsn9Fqg
# uUlZkClsYcu1UNviffmfAO9Aw63T4uRW+VhBz/FC5RB9/7B0H4/GXAn5M17qoBwm
# WFzztBEP1dXD4rzVWHi/SHbhRGdtj7BDEA+N5Pk4Yr8TAcWFo0zFzLJTMJWk1vSW
# Vgi4zVx/AZa+clJqO0I3fBZ4OZOTlJux3LJtQW1nzclvkD1/RXLBGyPWwlWEZuSz
# xWYG9vPWS16toytCiiGS/qhvWiVwYoFzY16gu9jc10rTPa+DBjgSHSSHLeT8AtY+
# dwS8BDa153fLnC6NIxi5o8JHHfBd1qFzVwVomqfJN2Udvuq82EKDQwWli6YJ/9Gh
# lKZOqj0J9QVst9JkWtgqIsJLnfE5XkzeSD2bNJaaCV+O/fexUpHOP4n2HKG1qXUf
# cb9bQ11lPVCBbqvw0NP8srMftpmWJvQ8eYtcZMzN7iea5aDADHKHwW5NWtMe6vBE
# 5jJvHOsXTpTDeGUgOw9Bqh/poUGd/rG4oGUqNODeqPk85sEwu8CgYyz8XBYAqNDE
# f+oRnR4GxqZtMl20OAkrSQeq/eww2vGnL8+3/frQo4TZJ577AWZ3uVYQ4SBuxq6x
# +ba6yDVdM3aO8XwgDCp3rrWiAoa6Ke60WgCxjKvj+QrJVF3UuWp0nr1Irpgwggb2
# MIIE3qADAgECAhEAkDl/mtJKOhPyvZFfCDipQzANBgkqhkiG9w0BAQwFADB9MQsw
# CQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQH
# EwdTYWxmb3JkMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxJTAjBgNVBAMTHFNl
# Y3RpZ28gUlNBIFRpbWUgU3RhbXBpbmcgQ0EwHhcNMjIwNTExMDAwMDAwWhcNMzMw
# ODEwMjM1OTU5WjBqMQswCQYDVQQGEwJHQjETMBEGA1UECBMKTWFuY2hlc3RlcjEY
# MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSwwKgYDVQQDDCNTZWN0aWdvIFJTQSBU
# aW1lIFN0YW1waW5nIFNpZ25lciAjMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
# AgoCggIBAJCycT954dS5ihfMw5fCkJRy7Vo6bwFDf3NaKJ8kfKA1QAb6lK8KoYO2
# E+RLFQZeaoogNHF7uyWtP1sKpB8vbH0uYVHQjFk3PqZd8R5dgLbYH2DjzRJqiB/G
# /hjLk0NWesfOA9YAZChWIrFLGdLwlslEHzldnLCW7VpJjX5y5ENrf8mgP2xKrdUA
# T70KuIPFvZgsB3YBcEXew/BCaer/JswDRB8WKOFqdLacRfq2Os6U0R+9jGWq/fzD
# POgNnDhm1fx9HptZjJFaQldVUBYNS3Ry7qAqMfwmAjT5ZBtZ/eM61Oi4QSl0AT8N
# 4BN3KxE8+z3N0Ofhl1tV9yoDbdXNYtrOnB786nB95n1LaM5aKWHToFwls6UnaKNY
# /fUta8pfZMdrKAzarHhB3pLvD8Xsq98tbxpUUWwzs41ZYOff6Bcio3lBYs/8e/OS
# 2q7gPE8PWsxu3x+8Iq+3OBCaNKcL//4dXqTz7hY4Kz+sdpRBnWQd+oD9AOH++DrU
# w167aU1ymeXxMi1R+mGtTeomjm38qUiYPvJGDWmxt270BdtBBcYYwFDk+K3+rGNh
# R5G8RrVGU2zF9OGGJ5OEOWx14B0MelmLLsv0ZCxCR/RUWIU35cdpp9Ili5a/xq3g
# vbE39x/fQnuq6xzp6z1a3fjSkNVJmjodgxpXfxwBws4cfcz7lhXFAgMBAAGjggGC
# MIIBfjAfBgNVHSMEGDAWgBQaofhhGSAPw0F3RSiO0TVfBhIEVTAdBgNVHQ4EFgQU
# JS5oPGuaKyQUqR+i3yY6zxSm8eAwDgYDVR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQC
# MAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwSgYDVR0gBEMwQTA1BgwrBgEEAbIx
# AQIBAwgwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYG
# Z4EMAQQCMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuc2VjdGlnby5jb20v
# U2VjdGlnb1JTQVRpbWVTdGFtcGluZ0NBLmNybDB0BggrBgEFBQcBAQRoMGYwPwYI
# KwYBBQUHMAKGM2h0dHA6Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb1JTQVRpbWVT
# dGFtcGluZ0NBLmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5j
# b20wDQYJKoZIhvcNAQEMBQADggIBAHPa7Whyy8K5QKExu7QDoy0UeyTntFsVfajp
# /a3Rkg18PTagadnzmjDarGnWdFckP34PPNn1w3klbCbojWiTzvF3iTl/qAQF2jTD
# FOqfCFSr/8R+lmwr05TrtGzgRU0ssvc7O1q1wfvXiXVtmHJy9vcHKPPTstDrGb4V
# LHjvzUWgAOT4BHa7V8WQvndUkHSeC09NxKoTj5evATUry5sReOny+YkEPE7jghJi
# 67REDHVBwg80uIidyCLxE2rbGC9ueK3EBbTohAiTB/l9g/5omDTkd+WxzoyUbNsD
# bSgFR36bLvBk+9ukAzEQfBr7PBmA0QtwuVVfR745ZM632iNUMuNGsjLY0imGyRVd
# gJWvAvu00S6dOHw14A8c7RtHSJwialWC2fK6CGUD5fEp80iKCQFMpnnyorYamZTr
# lyjhvn0boXztVoCm9CIzkOSEU/wq+sCnl6jqtY16zuTgS6Ezqwt2oNVpFreOZr9f
# +h/EqH+noUgUkQ2C/L1Nme3J5mw2/ndDmbhpLXxhL+2jsEn+W75pJJH/k/xXaZJL
# 2QU/bYZy06LQwGTSOkLBGgP70O2aIbg/r6ayUVTVTMXKHxKNV8Y57Vz/7J8mdq1k
# ZmfoqjDg0q23fbFqQSduA4qjdOCKCYJuv+P2t7yeCykYaIGhnD9uFllLFAkJmuau
# v2AV3Yb1MYIFlDCCBZACAQEwgZEwfDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
# ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2Vj
# dGlnbyBMaW1pdGVkMSQwIgYDVQQDExtTZWN0aWdvIFJTQSBDb2RlIFNpZ25pbmcg
# Q0ECEQCPKpf8Xi5s8FoozZAa2VspMA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQB
# gjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYK
# KwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIDpTMiRi
# bvFbsf7kVI6dOIYgCmmwIZCvDKOouFbqYg9rMA0GCSqGSIb3DQEBAQUABIIBAKlN
# tNXb/Gu5s6d36jzIFixlNrUmQFyX2Bov847J4bFyECCZikR2jqIgpb1QrbVAKhnx
# bVFu/GeXqF+xeNb0MiLhUuuFZTSfb4/nf8mAVd0U/lfGnk1UOE6YJh1cM+X0VT11
# Z0pQUGBupP26Z4SCV/dOahaxXHyOXzlO/McMX3hj71sk7gycBWCspZeWDHTSOCx8
# aoJSQg7Ld9xsDfK5x/FYy2snZ1e1KfabfNaLy6G3vogMRXPZucRa5VrjsqD940JJ
# dT2RfincJLQIVIMOIEws+HVEjOqHAj1LfD3h1x0foZpd03m5D2JT0drb0Mi6YBRq
# dbdlh71O4ElFaff7adGhggNMMIIDSAYJKoZIhvcNAQkGMYIDOTCCAzUCAQEwgZIw
# fTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
# A1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSUwIwYDVQQD
# ExxTZWN0aWdvIFJTQSBUaW1lIFN0YW1waW5nIENBAhEAkDl/mtJKOhPyvZFfCDip
# QzANBglghkgBZQMEAgIFAKB5MBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJ
# KoZIhvcNAQkFMQ8XDTIyMTIxOTE2NDgxNlowPwYJKoZIhvcNAQkEMTIEMAybQMkI
# PkbSOirSzR9SG02uFg10y7mzKJMQ+TL64A9txt7TCZ/cwM0o09kNSY0EhjANBgkq
# hkiG9w0BAQEFAASCAgBx/0AQL9MPe28AFSOb5RTR/mvSe7+EjvrtiXl+B93xi5Ae
# hRIMY9KqmzZgsAcbkTxgMtSEe3kzpYxaIOcyKFxXPb9J1lVwz5i6dgSUG6fkcQ3L
# bwZlqFAuJJ5MwB2mIcV+d+eSZSwAuxOQNwUkJ4kevc68U7veYRU3MupcrdzS3J2y
# 3OnK9+u8DuwsAmsGg/FaPFJQx/mvBLaZSPt6VRpBGcAe86xFT1/O6ofAQGtuGBMW
# AgAmLUqbgdBHwyGhmNNDh2Fhz+mdiOBKliAacekUwjkT35nfSV6P6nL0e7Ob+pBf
# kH/6nnEcoDjZhWSllTrYLvYnskl0wPwWlYwoRNVEfzH9i3zS/rnXA74PreqWNeMg
# tPmRuA9srAwVPQC2ctX6N1UkAyOUX4FFfruFJtNyADzQAWIvms7wrvpp2GoE26mC
# 9R6KFLPN/eOpPw6DJzi7OjGYHOxpOHPZtDvKtzIO7SxrJFuXwYKjX1SE+DUk9f7S
# phswynoKDfHaauDfabw1EZiAM21XuLnIKQI6TG2lfryRNDo/ol32jTg8n2k54oK7
# ABZfaSbmSBGkrz6W4NMG8p/uBvtBE6YDaEtqlQmnW4KsE2Rq9Oqp4OGTBnhlb+Rm
# PZsnVnnVod0wS8HLwIA+Nq6Fs9HjURh4XLd84CblO1vn9D8JthVUq06aFqkLjA==
# SIG # End signature block