Functions/Add-ADPrincipalCertificate.ps1

<#
 
.SYNOPSIS
    Add certificates to an Active Directory principal's userCertificate attribute.
 
.DESCRIPTION
    This function adds certificates to the userCertificate attribute of AD principals (users, computers, service accounts, or other AD objects). Certificates can be provided as file paths via the -Certificate parameter, piped via the pipeline, or by piping a text file containing certificate file names using Get-Content. The function supports DER-encoded (.cer, .crt, .der) and PEM/Base64-encoded (.pem, .crt) certificate files. The script also accepts pipeline input from Get-ADUser, Get-ADComputer, Get-ADServiceAccount, or Get-ADObject cmdlets.
 
.PARAMETER Identity
    One or more AD principal identities. This can be a Distinguished Name, SamAccountName, ObjectGUID, or SID. This parameter accepts pipeline input and multiple values when using the ByIdentity parameter set.
 
.PARAMETER Certificate
    One or more paths to certificate files to add. Supported formats include DER-encoded (.cer, .crt, .der) and PEM/Base64-encoded (.pem, .crt) certificate files. This parameter accepts pipeline input when using the ByCertificatePipeline parameter set.
 
.INPUTS
    Microsoft.ActiveDirectory.Management.ADUser, Microsoft.ActiveDirectory.Management.ADComputer, Microsoft.ActiveDirectory.Management.ADServiceAccount, Microsoft.ActiveDirectory.Management.ADObject, or String values.
 
.OUTPUTS
    None.
 
.EXAMPLE
    Add-ADPrincipalCertificate -Identity 'juser' -Certificate 'C:\Certs\user.cer'
 
    Adds a certificate from the specified file to user juser.
 
.EXAMPLE
    Add-ADPrincipalCertificate -Identity 'juser' -Certificate 'cert1.cer', 'cert2.cer'
 
    Adds multiple certificates to user juser by specifying multiple file paths.
 
.EXAMPLE
    Get-ADUser juser | Add-ADPrincipalCertificate -Certificate 'C:\Certs\user.cer'
 
    Pipes a user object and adds the specified certificate.
 
.EXAMPLE
    Get-ADComputer 'app1' | Add-ADPrincipalCertificate -Certificate 'C:\Certs\computer.cer'
 
    Pipes a computer object and adds the specified certificate.
 
.EXAMPLE
    Get-ADServiceAccount 'svc_app' | Add-ADPrincipalCertificate -Certificate 'C:\Certs\svc.cer'
 
    Pipes a service account object and adds the specified certificate.
 
.EXAMPLE
    Get-ADUser -Filter {Department -eq 'Human Resources'} | Add-ADPrincipalCertificate -Certificate 'C:\Certs\hr.cer'
 
    Adds the same certificate to all users in the Human Resources department.
 
.EXAMPLE
    'cert1.cer', 'cert2.cer' | Add-ADPrincipalCertificate -Identity 'juser'
 
    Pipes certificate file paths to add multiple certificates to user juser.
 
.EXAMPLE
    Get-Content -Path .\certs.txt | Add-ADPrincipalCertificate -Identity 'juser'
 
    Reads certificate file paths from a text file (one per line) and adds each certificate to user juser.
 
.EXAMPLE
    Add-ADPrincipalCertificate -Identity 'app1' -Certificate 'C:\Certs\computer.cer' -WhatIf
 
    Shows what would happen if the certificate were added to computer app1 without actually adding it.
 
.EXAMPLE
    Add-ADPrincipalCertificate -Identity 'juser', 'jdoe' -Certificate 'C:\Certs\shared.cer'
 
    Adds the same certificate to multiple principals juser and jdoe.
 
.LINK
    https://github.com/richardhicks/adprincipalcertificate/blob/main/Functions/Add-ADPrincipalCertificate.ps1
 
.LINK
    https://www.richardhicks.com/
 
.NOTES
    Version: 1.0
    Creation Date: February 9, 2026
    Last Updated: February 9, 2026
    Author: Richard Hicks
    Organization: Richard M. Hicks Consulting, Inc.
    Contact: rich@richardhicks.com
    Website: https://www.richardhicks.com/
 
#>


Function Add-ADPrincipalCertificate {

    # Prerequisites
    #Requires -Module ActiveDirectory

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', DefaultParameterSetName = 'ByIdentity')]
    [OutputType([System.Void])]

    Param (

        [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0, Mandatory, ParameterSetName = 'ByIdentity', HelpMessage = 'Specify one or more AD principal identities')]
        [Parameter(Mandatory, Position = 0, ParameterSetName = 'ByCertificatePipeline', HelpMessage = 'Specify one or more AD principal identities')]
        [Alias('DistinguishedName', 'SamAccountName', 'ObjectGUID', 'SID', 'Name')]
        [ValidateNotNullOrEmpty()]
        $Identity,

        [Parameter(Mandatory, ParameterSetName = 'ByIdentity', HelpMessage = 'Specify one or more certificate file paths')]
        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'ByCertificatePipeline', HelpMessage = 'Specify one or more certificate file paths')]
        [ValidateNotNullOrEmpty()]
        [string[]]$Certificate

    )

    Begin {

        Write-Verbose 'Begin certificate addition process...'

        # Define required properties once in Begin block for efficiency
        $RequiredProperties = @('userCertificate', 'SamAccountName', 'ObjectClass', 'DistinguishedName')

        # Initialize collection for certificate paths when piping certificates
        If ($PSCmdlet.ParameterSetName -eq 'ByCertificatePipeline') {

            $Script:CollectedCertificatePaths = [System.Collections.Generic.List[string]]::new()

        }

        # Helper function to load certificate bytes from a file
        Function Get-CertificateByte {

            [CmdletBinding()]
            [OutputType([byte[]])]

            Param (

                [Parameter(Mandatory)]
                [string]$FilePath

            )

            # Resolve to full path
            $ResolvedPath = $null

            Try {

                $ResolvedPath = (Resolve-Path -Path $FilePath -ErrorAction Stop).Path

            }

            Catch {

                Write-Warning "Certificate file not found: $FilePath"
                Return $null

            }

            Try {

                # Load certificate using X509Certificate2 which handles DER, PEM, and Base64 formats
                $Certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($ResolvedPath)
                $RawData = $Certificate.RawData
                $Certificate.Dispose()
                Return $RawData

            }

            Catch {

                Write-Warning "Error loading certificate file '$FilePath': $_"
                Return $null

            }

        }

        # Helper function to resolve an AD principal
        Function Resolve-ADPrincipal {

            [CmdletBinding()]

            Param (

                [Parameter(Mandatory)]
                $Id,
                [Parameter(Mandatory)]
                [string[]]$Properties

            )

            $Principal = $null

            # Check if this is already an AD object
            If ($Id.PSObject.TypeNames -match 'Microsoft\.ActiveDirectory\.Management\.AD(User|Computer|ServiceAccount|Object)') {

                # Re-query to ensure we have the required properties
                Write-Verbose "Re-querying AD object for required properties: $($Id.DistinguishedName)"
                $IdentityValue = $Id.DistinguishedName
                $ObjectClass = $Id.ObjectClass

            }

            Else {

                Write-Verbose "Retrieving AD principal `"$Id`"..."
                $IdentityValue = $Id
                $ObjectClass = $null

            }

            Switch ($ObjectClass) {

                'User' {

                    $Principal = Get-ADUser -Identity $IdentityValue -Properties $Properties -ErrorAction Stop

                }

                'Computer' {

                    $Principal = Get-ADComputer -Identity $IdentityValue -Properties $Properties -ErrorAction Stop

                }

                { $_ -in 'msDS-ManagedServiceAccount', 'msDS-GroupManagedServiceAccount' } {

                    $Principal = Get-ADServiceAccount -Identity $IdentityValue -Properties $Properties -ErrorAction Stop

                }

                Default {

                    # Try to find the object using cascading approach
                    Try {

                        $Principal = Get-ADUser -Identity $IdentityValue -Properties $Properties -ErrorAction Stop
                        Write-Verbose "Found user account `"$IdentityValue`"."

                    }

                    Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {

                        Try {

                            $Principal = Get-ADComputer -Identity $IdentityValue -Properties $Properties -ErrorAction Stop
                            Write-Verbose "Found computer account `"$IdentityValue`"."

                        }

                        Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {

                            Try {

                                $Principal = Get-ADServiceAccount -Identity $IdentityValue -Properties $Properties -ErrorAction Stop
                                Write-Verbose "Found service account `"$IdentityValue`"."

                            }

                            Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {

                                $Principal = Get-ADObject -Identity $IdentityValue -Properties $Properties -ErrorAction Stop
                                Write-Verbose "Found AD object `"$IdentityValue`"."

                            }

                        }

                    }

                }

            }

            Return $Principal

        }

        # Helper function to add certificates to a principal
        Function Add-CertificatesToPrincipal {

            [CmdletBinding(SupportsShouldProcess)]

            Param (

                [Parameter(Mandatory)]
                $Principal,
                [Parameter(Mandatory)]
                [byte[][]]$CertificateBytes

            )

            $AddCount = $CertificateBytes.Count
            $ConfirmMessage = "Add $AddCount certificate(s) to '$($Principal.SamAccountName)' ($($Principal.ObjectClass))?"
            $WhatIfMessage = "Adding $AddCount certificate(s) to '$($Principal.SamAccountName)' ($($Principal.ObjectClass))"

            If ($PSCmdlet.ShouldProcess($WhatIfMessage, $ConfirmMessage, 'Add AD Principal Certificate(s)')) {

                Try {

                    Set-ADObject -Identity $Principal.DistinguishedName -Add @{ userCertificate = $CertificateBytes } -ErrorAction Stop
                    Write-Verbose "Successfully added $AddCount certificate(s) to '$($Principal.SamAccountName)'."
                    Write-Output "Added $AddCount certificate(s) to principal '$($Principal.SamAccountName)'."

                }

                Catch {

                    Write-Error "Failed to add certificates to '$($Principal.SamAccountName)': $_"

                }

            }

        }

    }

    Process {

        If ($PSCmdlet.ParameterSetName -eq 'ByCertificatePipeline') {

            # Collect certificate paths from pipeline for processing in End block
            ForEach ($CertPath in $Certificate) {

                If (-not [string]::IsNullOrWhiteSpace($CertPath)) {

                    $Script:CollectedCertificatePaths.Add($CertPath.Trim())

                }

            }

        }

        Else {

            # ByIdentity parameter set - process each identity from pipeline or parameter
            $IdsToProcess = If ($Identity -is [array]) { $Identity } Else { , $Identity }

            ForEach ($Id in $IdsToProcess) {

                Try {

                    # Resolve the AD principal
                    $Principal = Resolve-ADPrincipal -Id $Id -Properties $RequiredProperties

                    If (-not $Principal) {

                        Write-Warning "Unable to resolve AD principal: $Id"
                        Continue

                    }

                    # Load certificates from file paths
                    $CertBytesCollection = [System.Collections.Generic.List[byte[]]]::new()

                    ForEach ($CertPath in $Certificate) {

                        $CertBytes = Get-CertificateByte -FilePath $CertPath

                        If ($null -ne $CertBytes) {

                            $CertBytesCollection.Add($CertBytes)

                        }

                    }

                    If ($CertBytesCollection.Count -eq 0) {

                        Write-Warning "No valid certificates to add for principal '$($Principal.SamAccountName)'. Verify the specified certificate file path(s)."
                        Continue

                    }

                    # Add certificates to principal
                    Add-CertificatesToPrincipal -Principal $Principal -CertificateBytes $CertBytesCollection.ToArray()

                }

                Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {

                    Write-Warning "AD principal not found: $Id"

                }

                Catch {

                    Write-Warning "Error processing principal '$Id': $_"

                }

            }

        }

    }

    End {

        If ($PSCmdlet.ParameterSetName -eq 'ByCertificatePipeline') {

            If ($Script:CollectedCertificatePaths.Count -eq 0) {

                Write-Warning 'No certificate file paths were provided via the pipeline.'
                Return

            }

            Write-Verbose "Processing $($Script:CollectedCertificatePaths.Count) certificate file path(s) from pipeline..."

            # Resolve the AD principal(s)
            $IdsToProcess = If ($Identity -is [array]) { $Identity } Else { , $Identity }

            # Load all certificates from collected paths
            $CertBytesCollection = [System.Collections.Generic.List[byte[]]]::new()

            ForEach ($CertPath in $Script:CollectedCertificatePaths) {

                $CertBytes = Get-CertificateByte -FilePath $CertPath

                If ($null -ne $CertBytes) {

                    $CertBytesCollection.Add($CertBytes)

                }

            }

            If ($CertBytesCollection.Count -eq 0) {

                Write-Warning 'No valid certificates found from the provided file paths. Verify the specified certificate file path(s).'
                Return

            }

            $CertBytesArray = $CertBytesCollection.ToArray()

            ForEach ($Id in $IdsToProcess) {

                Try {

                    $Principal = Resolve-ADPrincipal -Id $Id -Properties $RequiredProperties

                    If (-not $Principal) {

                        Write-Warning "Unable to resolve AD principal: $Id"
                        Continue

                    }

                    # Add certificates to principal
                    Add-CertificatesToPrincipal -Principal $Principal -CertificateBytes $CertBytesArray

                }

                Catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {

                    Write-Warning "AD principal not found: $Id"

                }

                Catch {

                    Write-Warning "Error processing principal '$Id': $_"

                }

            }

        }

        Write-Verbose 'Certificate addition process completed.'

    }

}

# SIG # Begin signature block
# MIIf2wYJKoZIhvcNAQcCoIIfzDCCH8gCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCRKL9+vemuXNKG
# orOLKs6fDBdu3hwZwCSVWAcTWquBJaCCGpkwggNZMIIC36ADAgECAhAPuKdAuRWN
# A1FDvFnZ8EApMAoGCCqGSM49BAMDMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxE
# aWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xIDAeBgNVBAMT
# F0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMB4XDTIxMDQyOTAwMDAwMFoXDTM2MDQy
# ODIzNTk1OVowZDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu
# MTwwOgYDVQQDEzNEaWdpQ2VydCBHbG9iYWwgRzMgQ29kZSBTaWduaW5nIEVDQyBT
# SEEzODQgMjAyMSBDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAS7tKwnpUgNolNf
# jy6BPi9TdrgIlKKaqoqLmLWx8PwqFbu5s6UiL/1qwL3iVWhga5c0wWZTcSP8GtXK
# IA8CQKKjSlpGo5FTK5XyA+mrptOHdi/nZJ+eNVH8w2M1eHbk+HejggFXMIIBUzAS
# BgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSbX7A2up0GrhknvcCgIsCLizh3
# 7TAfBgNVHSMEGDAWgBSz20ik+aHF2K42QcwRY2liKbxLxjAOBgNVHQ8BAf8EBAMC
# AYYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwdgYIKwYBBQUHAQEEajBoMCQGCCsGAQUF
# BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQAYIKwYBBQUHMAKGNGh0dHA6
# Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RHMy5jcnQw
# QgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lD
# ZXJ0R2xvYmFsUm9vdEczLmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEE
# ATAKBggqhkjOPQQDAwNoADBlAjB4vUmVZXEB0EZXaGUOaKncNgjB7v3UjttAZT8N
# /5Ovwq5jhqN+y7SRWnjsBwNnB3wCMQDnnx/xB1usNMY4vLWlUM7m6jh+PnmQ5KRb
# qwIN6Af8VqZait2zULLd8vpmdJ7QFmMwggP+MIIDhKADAgECAhANSjTahpCPwBMs
# vIE3k68kMAoGCCqGSM49BAMDMGQxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp
# Q2VydCwgSW5jLjE8MDoGA1UEAxMzRGlnaUNlcnQgR2xvYmFsIEczIENvZGUgU2ln
# bmluZyBFQ0MgU0hBMzg0IDIwMjEgQ0ExMB4XDTI0MTIwNjAwMDAwMFoXDTI3MTIy
# NDIzNTk1OVowgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYw
# FAYDVQQHEw1NaXNzaW9uIFZpZWpvMSQwIgYDVQQKExtSaWNoYXJkIE0uIEhpY2tz
# IENvbnN1bHRpbmcxJDAiBgNVBAMTG1JpY2hhcmQgTS4gSGlja3MgQ29uc3VsdGlu
# ZzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFCbtcqpc7vGGM4hVM79U+7f0tKz
# o8BAGMJ/0E7JUwKJfyMJj9jsCNpp61+mBNdTwirEm/K0Vz02vak0Ftcb/3yjggHz
# MIIB7zAfBgNVHSMEGDAWgBSbX7A2up0GrhknvcCgIsCLizh37TAdBgNVHQ4EFgQU
# KIMkVkfISNUyQJ7bwvLm9sCIkxgwPgYDVR0gBDcwNTAzBgZngQwBBAEwKTAnBggr
# BgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB/wQE
# AwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzCBqwYDVR0fBIGjMIGgME6gTKBKhkho
# dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxHM0NvZGVTaWdu
# aW5nRUNDU0hBMzg0MjAyMUNBMS5jcmwwTqBMoEqGSGh0dHA6Ly9jcmw0LmRpZ2lj
# ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEczQ29kZVNpZ25pbmdFQ0NTSEEzODQyMDIx
# Q0ExLmNybDCBjgYIKwYBBQUHAQEEgYEwfzAkBggrBgEFBQcwAYYYaHR0cDovL29j
# c3AuZGlnaWNlcnQuY29tMFcGCCsGAQUFBzAChktodHRwOi8vY2FjZXJ0cy5kaWdp
# Y2VydC5jb20vRGlnaUNlcnRHbG9iYWxHM0NvZGVTaWduaW5nRUNDU0hBMzg0MjAy
# MUNBMS5jcnQwCQYDVR0TBAIwADAKBggqhkjOPQQDAwNoADBlAjBMOsBb80qx6E6S
# 2lnnHafuyY2paoDtPjcfddKaB1HKnAy7WLaEVc78xAC84iW3l6ECMQDhOPD5JHtw
# YxEH6DxVDle5pLKfuyQHiY1i0I9PrSn1plPUeZDTnYKmms1P66nBvCkwggWNMIIE
# daADAgECAhAOmxiO+dAt5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNV
# BAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdp
# Y2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAe
# Fw0yMjA4MDEwMDAwMDBaFw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUw
# EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
# ITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcN
# AQEBBQADggIPADCCAgoCggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC
# 4SmnPVirdprNrnsbhA3EMB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWl
# fr6fqVcWWVVyr2iTcMKyunWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1j
# KS3O7F5OyJP4IWGbNOsFxl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dP
# pzDZVu7Ke13jrclPXuU15zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3
# pC4FfYj1gj4QkXCrVYJBMtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJ
# pMLmqaBn3aQnvKFPObURWBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aa
# dMreSx7nDmOu5tTvkpI6nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXD
# j/chsrIRt7t/8tWMcCxBYKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB
# 4Q+UDCEdslQpJYls5Q5SUUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ
# 33xMdT9j7CFfxCBRa2+xq4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amy
# HeUbAgMBAAGjggE6MIIBNjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC
# 0nFdZEzfLmc/57qYrhwPTzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823I
# DzAOBgNVHQ8BAf8EBAMCAYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhho
# dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNl
# cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYD
# VR0fBD4wPDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
# QXNzdXJlZElEUm9vdENBLmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcN
# AQEMBQADggEBAHCgv0NcVec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxpp
# VCLtpIh3bb0aFPQTSnovLbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6
# mouyXtTP0UNEm0Mh65ZyoUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPH
# h6jSTEAZNUZqaVSwuKFWjuyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCN
# NWAcAgPLILCsWKAOQGPFmCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg6
# 2fC2h5b9W9FcrBjDTZ9ztwGpn1eqXijiuZQwgga0MIIEnKADAgECAhANx6xXBf8h
# mS5AQyIMOkmGMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yNTA1MDcwMDAwMDBaFw0z
# ODAxMTQyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
# SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcg
# UlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
# ggIKAoICAQC0eDHTCphBcr48RsAcrHXbo0ZodLRRF51NrY0NlLWZloMsVO1DahGP
# NRcybEKq+RuwOnPhof6pvF4uGjwjqNjfEvUi6wuim5bap+0lgloM2zX4kftn5B1I
# pYzTqpyFQ/4Bt0mAxAHeHYNnQxqXmRinvuNgxVBdJkf77S2uPoCj7GH8BLuxBG5A
# vftBdsOECS1UkxBvMgEdgkFiDNYiOTx4OtiFcMSkqTtF2hfQz3zQSku2Ws3IfDRe
# b6e3mmdglTcaarps0wjUjsZvkgFkriK9tUKJm/s80FiocSk1VYLZlDwFt+cVFBUR
# Jg6zMUjZa/zbCclF83bRVFLeGkuAhHiGPMvSGmhgaTzVyhYn4p0+8y9oHRaQT/ao
# fEnS5xLrfxnGpTXiUOeSLsJygoLPp66bkDX1ZlAeSpQl92QOMeRxykvq6gbylsXQ
# skBBBnGy3tW/AMOMCZIVNSaz7BX8VtYGqLt9MmeOreGPRdtBx3yGOP+rx3rKWDEJ
# lIqLXvJWnY0v5ydPpOjL6s36czwzsucuoKs7Yk/ehb//Wx+5kMqIMRvUBDx6z1ev
# +7psNOdgJMoiwOrUG2ZdSoQbU2rMkpLiQ6bGRinZbI4OLu9BMIFm1UUl9VnePs6B
# aaeEWvjJSjNm2qA+sdFUeEY0qVjPKOWug/G6X5uAiynM7Bu2ayBjUwIDAQABo4IB
# XTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU729TSunkBnx6yuKQ
# VvYv1Ensy04wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P
# AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAk
# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC
# hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v
# dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j
# b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEE
# AjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBABfO+xaAHP4HPRF2cTC9
# vgvItTSmf83Qh8WIGjB/T8ObXAZz8OjuhUxjaaFdleMM0lBryPTQM2qEJPe36zwb
# SI/mS83afsl3YTj+IQhQE7jU/kXjjytJgnn0hvrV6hqWGd3rLAUt6vJy9lMDPjTL
# xLgXf9r5nWMQwr8Myb9rEVKChHyfpzee5kH0F8HABBgr0UdqirZ7bowe9Vj2AIMD
# 8liyrukZ2iA/wdG2th9y1IsA0QF8dTXqvcnTmpfeQh35k5zOCPmSNq1UH410ANVk
# o43+Cdmu4y81hjajV/gxdEkMx1NKU4uHQcKfZxAvBAKqMVuqte69M9J6A47OvgRa
# Ps+2ykgcGV00TYr2Lr3ty9qIijanrUR3anzEwlvzZiiyfTPjLbnFRsjsYg39OlV8
# cipDoq7+qNNjqFzeGxcytL5TTLL4ZaoBdqbhOhZ3ZRDUphPvSRmMThi0vw9vODRz
# W6AxnJll38F0cuJG7uEBYTptMSbhdhGQDpOXgpIUsWTjd6xpR6oaQf/DJbg3s6KC
# LPAlZ66RzIg9sC+NJpud/v4+7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx9yHbxtl5TPau
# 1j/1MIDpMPx0LckTetiSuEtQvLsNz3Qbp7wGWqbIiOWCnb5WqxL3/BAPvIXKUjPS
# xyZsq8WhbaM2tszWkPZPubdcMIIG7TCCBNWgAwIBAgIQCoDvGEuN8QWC0cR2p5V0
# aDANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl
# cnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1w
# aW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUgQ0ExMB4XDTI1MDYwNDAwMDAwMFoXDTM2
# MDkwMzIzNTk1OVowYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ
# bmMuMTswOQYDVQQDEzJEaWdpQ2VydCBTSEEyNTYgUlNBNDA5NiBUaW1lc3RhbXAg
# UmVzcG9uZGVyIDIwMjUgMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
# ANBGrC0Sxp7Q6q5gVrMrV7pvUf+GcAoB38o3zBlCMGMyqJnfFNZx+wvA69HFTBdw
# bHwBSOeLpvPnZ8ZN+vo8dE2/pPvOx/Vj8TchTySA2R4QKpVD7dvNZh6wW2R6kSu9
# RJt/4QhguSssp3qome7MrxVyfQO9sMx6ZAWjFDYOzDi8SOhPUWlLnh00Cll8pjrU
# cCV3K3E0zz09ldQ//nBZZREr4h/GI6Dxb2UoyrN0ijtUDVHRXdmncOOMA3CoB/iU
# SROUINDT98oksouTMYFOnHoRh6+86Ltc5zjPKHW5KqCvpSduSwhwUmotuQhcg9tw
# 2YD3w6ySSSu+3qU8DD+nigNJFmt6LAHvH3KSuNLoZLc1Hf2JNMVL4Q1OpbybpMe4
# 6YceNA0LfNsnqcnpJeItK/DhKbPxTTuGoX7wJNdoRORVbPR1VVnDuSeHVZlc4seA
# O+6d2sC26/PQPdP51ho1zBp+xUIZkpSFA8vWdoUoHLWnqWU3dCCyFG1roSrgHjSH
# lq8xymLnjCbSLZ49kPmk8iyyizNDIXj//cOgrY7rlRyTlaCCfw7aSUROwnu7zER6
# EaJ+AliL7ojTdS5PWPsWeupWs7NpChUk555K096V1hE0yZIXe+giAwW00aHzrDch
# Ic2bQhpp0IoKRR7YufAkprxMiXAJQ1XCmnCfgPf8+3mnAgMBAAGjggGVMIIBkTAM
# BgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTkO/zyMe39/dfzkXFjGVBDz2GM6DAfBgNV
# HSMEGDAWgBTvb1NK6eQGfHrK4pBW9i/USezLTjAOBgNVHQ8BAf8EBAMCB4AwFgYD
# VR0lAQH/BAwwCgYIKwYBBQUHAwgwgZUGCCsGAQUFBwEBBIGIMIGFMCQGCCsGAQUF
# BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXQYIKwYBBQUHMAKGUWh0dHA6
# Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRpbWVTdGFt
# cGluZ1JTQTQwOTZTSEEyNTYyMDI1Q0ExLmNydDBfBgNVHR8EWDBWMFSgUqBQhk5o
# dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3Rh
# bXBpbmdSU0E0MDk2U0hBMjU2MjAyNUNBMS5jcmwwIAYDVR0gBBkwFzAIBgZngQwB
# BAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQBlKq3xHCcEua5gQezR
# CESeY0ByIfjk9iJP2zWLpQq1b4URGnwWBdEZD9gBq9fNaNmFj6Eh8/YmRDfxT7C0
# k8FUFqNh+tshgb4O6Lgjg8K8elC4+oWCqnU/ML9lFfim8/9yJmZSe2F8AQ/UdKFO
# tj7YMTmqPO9mzskgiC3QYIUP2S3HQvHG1FDu+WUqW4daIqToXFE/JQ/EABgfZXLW
# U0ziTN6R3ygQBHMUBaB5bdrPbF6MRYs03h4obEMnxYOX8VBRKe1uNnzQVTeLni2n
# HkX/QqvXnNb+YkDFkxUGtMTaiLR9wjxUxu2hECZpqyU1d0IbX6Wq8/gVutDojBIF
# eRlqAcuEVT0cKsb+zJNEsuEB7O7/cuvTQasnM9AWcIQfVjnzrvwiCZ85EE8LUkqR
# hoS3Y50OHgaY7T/lwd6UArb+BOVAkg2oOvol/DJgddJ35XTxfUlQ+8Hggt8l2Yv7
# roancJIFcbojBcxlRcGG0LIhp6GvReQGgMgYxQbV1S3CrWqZzBt1R9xJgKf47Cdx
# VRd/ndUlQ05oxYy2zRWVFjF7mcr4C34Mj3ocCVccAvlKV9jEnstrniLvUxxVZE/r
# ptb7IRE2lskKPIJgbaP5t2nGj/ULLi49xTcBZU8atufk+EMF/cWuiC7POGT75qaL
# 6vdCvHlshtjdNXOCIUjsarfNZzGCBJgwggSUAgEBMHgwZDELMAkGA1UEBhMCVVMx
# FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTwwOgYDVQQDEzNEaWdpQ2VydCBHbG9i
# YWwgRzMgQ29kZSBTaWduaW5nIEVDQyBTSEEzODQgMjAyMSBDQTECEA1KNNqGkI/A
# Eyy8gTeTryQwDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAA
# oQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4w
# DAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQg91WrGE67K0N9YsgaqW+c88UJ
# H3Yg5zZDJNNy41RS8mQwCwYHKoZIzj0CAQUABEgwRgIhAOIw5wMIhXxnznwpO5n4
# lhtTg2n9YlG/hfTz25z2oXavAiEAzU+cMzkmXpch9OZCyP1K+wC/7nF9ipqf4pev
# FUrCaUWhggMmMIIDIgYJKoZIhvcNAQkGMYIDEzCCAw8CAQEwfTBpMQswCQYDVQQG
# EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0
# IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUgQ0Ex
# AhAKgO8YS43xBYLRxHanlXRoMA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcNAQkD
# MQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjYwMjA5MjM0NDAxWjAvBgkq
# hkiG9w0BCQQxIgQgpV949y0Ej0TlZpOa9qij0hc89MAfzH9DvxAGOl2TuDwwDQYJ
# KoZIhvcNAQEBBQAEggIARvJs80X0kZZ2daqGK0QKKE355xXtnMChR5k9I8F3iu+P
# /a4xmvtuTwG9QDdhI4dMA8Wtc8rGk0lbmKy+NxwlKUv1+0Gm55ZUarxocC/ORaov
# WsShw5aynZFWnafWpXrJ24ukwIB3T/QTJ+W4xK0Tzq48MO77hkwXefEDJj0xeuVI
# ZZMShea1iMHNsOzShpqTRz0OIkke80uJ02e11Fn669A/6Wltey1DdRnDlg+z8IZ/
# c1UISFEai5HA5B1SBPKkjarflnBjCiPVKfQwS7UAhQ4+J4S0PuGiKoU7EZirdO79
# Z9IpoZ7h+lCkPY6HHCzdCGI/Kr9MGUg6231S4c2Bs2H9hP2czvVuG1yWE2uWiXVU
# 7sHMrsA1OtGzug2b2twFjEttXtV+bj8x7UGzhPupSAlRP2gN9NBlQ+Y8+VxO5oTn
# dvKanf3OoXsrGNdPd1V5ARKk4nb6HnodIfVQmdG8QNWjtQW73wjt61zm2bHGVKEC
# yT/Xe3aP91qCxN//9Dkd4UUVzU1mvqX82fQDgWfwgHH8nIa23vPlvew0UzLJXmyn
# D/eOl81U7OIWhvQjKzkS73YDVPQqkfQDt4SgiaSgTH+0QPXtIc+GkQA5hnaLMkZt
# GkNJxOlueXj5gD9zRQi25CuOnnjuiPnEpETBZflVsEZpujeO1wX5VRQV+FzJa2M=
# SIG # End signature block