AdSyncConfig.psm1

<#
  
.SYNOPSIS
    Prepares Active Directory configuration for various purposes.
 
.DESCRIPTION
 
    AdSyncConfig.psm1 is a Windows PowerShell script module that provides functions that are
    used to prepare your Active Directory forest and domains for Azure AD Connect Sync
    features.
#>


#----------------------------------------------------------
#STATIC VARIABLES
#----------------------------------------------------------
# Well known SIDS
$selfSid = "S-1-5-10"
$enterpriseDomainControllersSid = "S-1-5-9"

<#.SYNOPSIS
        Tighten permissions on an AD object that is not otherwise included in any AD protected security group.
        A typical example is the AD Connect account (MSOL) created by AAD Connect automatically. This account
        has replicate permissions on all domains, however can be easily compromised as it is not protected.
 
    .DESCRIPTION
        The Set-ADSyncRestrictedPermissions Function will tighten permissions oo the
        account provided. Tightening permissions involves the following steps:
        1. Disable inheritance on the specified object
        2. Remove all ACEs on the specific object, except ACEs specific to SELF. We want to keep
           the default permissions intact when it comes to SELF.
        3. Assign these specific permissions:
 
                Type Name Access Applies To
                =============================================================================================
                Allow SYSTEM Full Control This object
                Allow Enterprise Admins Full Control This object
                Allow Domain Admins Full Control This object
                Allow Administrators Full Control This object
 
                Allow Enterprise Domain Controllers List Contents
                                                                    Read All Properties
                                                                    Read Permissions This object
 
                Allow Authenticated Users List Contents
                                                                    Read All Properties
                                                                    Read Permissions This object
 
    .PARAMETER $ObjectDN
        The Active Directory account whose permissions need to be tightened.
 
    .PARAMETER $Credential
        Administrator credential that has the necessary privileges to restrict the permissions on $ObjectDN account.
        This is typically the Enterprise or Domain administrator.
        Use the fully qualified domain name of the administrator account to avoid account lookup failures. Example: contoso.com\admin.
 
    .EXAMPLE
       Set-ADSyncRestrictedPermissions -ObjectDN "CN=TestAccount1,CN=Users,DC=bvtadwbackdc,DC=com" -Credential $credential
#>

function Set-ADSyncRestrictedPermissions
{
    [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="high")]
    param(
        [Parameter(Mandatory=$True)] [string] $ObjectDN,
        [Parameter(Mandatory=$True)] [System.Management.Automation.PSCredential] $Credential,
        [Parameter(Mandatory=$False)] [switch] $DisableCredentialValidation
    )

    if ($PSCmdlet.ShouldProcess($ObjectDN, "Set restricted permissions")) {
        if (!$DisableCredentialValidation)
        {
            Test-Credential $Credential
        }

        try
        {    
            $networkCredential = $Credential.GetNetworkCredential()        
            $path = "LDAP://" + $networkCredential.Domain + "/" + $ObjectDN    

            $de = New-Object System.DirectoryServices.DirectoryEntry($path, $Credential.UserName, $networkCredential.Password)
            $selfName = Convert-SIDtoName $selfSid            
            
            [System.DirectoryServices.DirectoryEntryConfiguration]$deOptions = $de.get_Options()
            $deOptions.SecurityMasks = [System.DirectoryServices.SecurityMasks]::Dacl

            # disable inheritance on the object and remove inherited DACLs
            $de.ObjectSecurity.SetAccessRuleProtection($true, $false);

            # remove all DACLs on the object except SELF
            $acl = $de.ObjectSecurity.GetAccessRules($true, $false, [System.Security.Principal.NTAccount])
            ForEach ($ace in $acl) {
                if ($ace.IdentityReference -ne $selfName) {
                    $de.ObjectSecurity.RemoveAccessRule($ace) > $null
                }
            }

            # Add specific DACLs on the object
            # Add Full Control for SYSTEM
            $systemSid = New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::LocalSystemSid, $null)
            $systemDacl = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($systemSid, [System.DirectoryServices.ActiveDirectoryRights]::GenericAll, [System.Security.AccessControl.AccessControlType]::Allow)
            $de.ObjectSecurity.AddAccessRule($systemDacl)

            # Add Full Control for Enterprise Admins
            $eaSid = Get-EnterpriseAdminsSid $Credential
            $eaDacl = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($eaSid, [System.DirectoryServices.ActiveDirectoryRights]::GenericAll, [System.Security.AccessControl.AccessControlType]::Allow)
            $de.ObjectSecurity.AddAccessRule($eaDacl)

            # Add Full Control for Domain Admins
            $daSid = Get-DomainAdminsSid $Credential
            $daDacl = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($daSid, [System.DirectoryServices.ActiveDirectoryRights]::GenericAll, [System.Security.AccessControl.AccessControlType]::Allow)
            $de.ObjectSecurity.AddAccessRule($daDacl)

            # Add Full Control for Administrators
            $adminSid = New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid, $null)
            $adminDacl = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($adminSid, [System.DirectoryServices.ActiveDirectoryRights]::GenericAll, [System.Security.AccessControl.AccessControlType]::Allow)
            $de.ObjectSecurity.AddAccessRule($adminDacl)

            # Add Generic Read for ENTERPRISE DOMAIN CONTROLLERS
            $edcSid = New-Object System.Security.Principal.SecurityIdentifier($enterpriseDomainControllersSid)
            $edcDacl = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($edcSid, [System.DirectoryServices.ActiveDirectoryRights]::GenericRead, [System.Security.AccessControl.AccessControlType]::Allow)
            $de.ObjectSecurity.AddAccessRule($edcDacl)

            # Add Generic Read for Authenticated Users
            $authenticatedUsersSid = New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::AuthenticatedUserSid, $null)
            $authenticatedUsersDacl = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($authenticatedUsersSid, [System.DirectoryServices.ActiveDirectoryRights]::GenericRead, [System.Security.AccessControl.AccessControlType]::Allow)
            $de.ObjectSecurity.AddAccessRule($authenticatedUsersDacl)

            $de.CommitChanges()
            Write-Output "Setting Restricted permissions on $ObjectDN completed successfully."
        }
        catch [Exception]
        {
            Write-Error "Setting Restricted permissions on $ObjectDN failed. Exception Details: $_"
            throw
        }
        finally
        {
            if ($de -ne $null)
            {
                $de.Dispose()
            }            
        }
    }
}

function Test-Credential
{
    param(
        [Parameter(Mandatory=$True)] [System.Management.Automation.PSCredential] $Credential
    )

    if ($Credential.UserName.Contains("@"))
    {
        throw [System.ArgumentException] "Validating credential parameter failed. Credential.UserName should use the fully qualified domain name of the administrator account. Example: contoso.com\admin"
    }

    $networkCredential = $Credential.GetNetworkCredential()
    # $Credential.UserName == FQDN\Username, $networkCredential.UserName == just the Username portion. We need to use the FQDN form here
    $dc = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext([System.DirectoryServices.ActiveDirectory.DirectoryContextType]::Domain, $networkCredential.Domain, $Credential.UserName, $networkCredential.Password)
    try
    {
        $credentialValid = $false
        $domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($dc)

        $enterpriseAdminsSid = Get-EnterpriseAdminsSid $Credential
        $domainAdminsSid = Get-DomainAdminsSid $Credential

        $rootDomainDE = $domain.Forest.RootDomain.GetDirectoryEntry()
        $searchFilter = "(samAccountName=" + $networkCredential.UserName +")"
        $directorySearcher = New-Object System.DirectoryServices.DirectorySearcher($rootDomainDE, $searchFilter)

        $searchResult = $directorySearcher.FindOne()
        if ($searchResult -eq $null)
        {
            throw [System.ArgumentException] "Validating credential parameter failed. Admin account $Credential.UserName could not be found."
        }

        $adminDE = $searchResult.GetDirectoryEntry()

        [string[]] $propertyName = @("tokenGroups")
        $adminDE.RefreshCache($propertyName)
        ForEach ($resultBytes in $adminDE.Properties["tokenGroups"])
        {
            $sid = New-Object System.Security.Principal.SecurityIdentifier($resultBytes, 0)
            if ($sid.Equals($enterpriseAdminsSid) -or $sid.Equals($domainAdminsSid))
            {
                $credentialValid = $true
                break
            }
        }

        if (!$credentialValid)
        {
            throw [System.ArgumentException] "Validating credential parameter failed. Enterprise Admin or Domain Admin credential is required to restrict permissions on the account."
        }
    }
    catch [Exception]
    {
        Write-Error "Validating credential parameter failed. Exception Details: $_"
        throw
    }
    finally
    {
        if ($domain -ne $null)
        {
            $domain.Dispose()
        }

        if ($rootDomainDE -ne $null)
        {
            $rootDomainDE.Dispose()
        }

        if ($directorySearcher -ne $null)
        {
            $directorySearcher.Dispose()
        }

        if ($adminDE -ne $null)
        {
            $adminDE.Dispose()
        }
    }
}

function Get-EnterpriseAdminsSid
{
    param(
        [Parameter(Mandatory=$True)] [System.Management.Automation.PSCredential] $Credential
    )

    $networkCredential = $Credential.GetNetworkCredential()
    $dc = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext([System.DirectoryServices.ActiveDirectory.DirectoryContextType]::Domain, $networkCredential.Domain, $Credential.UserName, $networkCredential.Password)            

    try
    {
        $domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($dc)        
        try
        {
            $de = $domain.Forest.RootDomain.GetDirectoryEntry()
            $rootDomainSidInBytes = $de.Properties["ObjectSID"].Value
            $domainSid = New-Object System.Security.Principal.SecurityIdentifier($rootDomainSidInBytes, 0)
            $eaSid = New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::AccountEnterpriseAdminsSid, $domainSid)
            return $eaSid
        }
        finally
        {
            if ($de -ne $null)
            {
                $de.Dispose()
            }
        }
    }
    finally
    {
        if ($domain -ne $null)
        {
            $domain.Dispose()
        }
    }
}

function Get-DomainAdminsSid
{
    param(
        [Parameter(Mandatory=$True)] [System.Management.Automation.PSCredential] $Credential
    )

    $networkCredential = $Credential.GetNetworkCredential()
    $dc = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext([System.DirectoryServices.ActiveDirectory.DirectoryContextType]::Domain, $networkCredential.Domain, $Credential.UserName, $networkCredential.Password)
    

    try
    {
        $domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($dc)        
        try
        {
            $de = $domain.GetDirectoryEntry()
            $domainSidInBytes = $de.Properties["ObjectSID"].Value
            $domainSid = New-Object System.Security.Principal.SecurityIdentifier($domainSidInBytes, 0)
            $domainAdminsSid = New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::AccountDomainAdminsSid, $domainSid)
            return $domainAdminsSid
        }
        finally
        {
            if ($de -ne $null)
            {
                $de.Dispose()
            }
        }
    }
    finally
    {
        if ($domain -ne $null)
        {
            $domain.Dispose()
        }
    }
}

# Convert SIDs to readable names
function Convert-SIDtoName
{
    param(
        [Parameter(Mandatory=$True,Position=0)] [string] $sid
    )

    $ID = New-Object -TypeName System.Security.Principal.SecurityIdentifier -ArgumentList $sid
    $User = $ID.Translate([System.Security.Principal.NTAccount])
    $User.Value
}

Export-ModuleMember -Function Set-ADSyncRestrictedPermissions
# SIG # Begin signature block
# MIIkAAYJKoZIhvcNAQcCoIIj8TCCI+0CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAs07YgMVCbiJzI
# pVHVOFbAAOLH8lEVIlc10rwsvrPvDqCCDXEwggXvMIID16ADAgECAhMzAAAA05Ss
# NkWNAZ8GAAAAAADTMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMTcxMDA1MTgzMDAwWhcNMTgxMDA1MTgzMDAwWjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQCZzG+qz8gQWzXQhiTr40mGHs+HcHDWlDWtZZgDjABJnr6g6oIOFJ113bEvIRLI
# WjYqD5E0be7QMdCvdQgOtbF/PBAvv4bugBCadSKRf+bd0CGZBzBEifjilb5ZcX7i
# 3LqYLa+P0CY1x6bG2E350DyLh2gMdwI2gTpZ9GwgBl7RbqUUGK2uyVAfU8OQE4RA
# rFsi3T6ERo/5J6lMUEwTxyOOvMJtZh6QiDNCE1Mefpu6AZ6c4hfGakADkoH0MPGS
# fu1oY/6xIf3ky4wRHp/c0IeRa+Jv8tgq78jXHdCOm+vDMncH5j2jESsQXjcpKHK7
# WDayUVZY1jWCfGS2UO4WRBpfAgMBAAGjggFuMIIBajArBgNVHSUEJDAiBgorBgEE
# AYI3TBMBBgorBgEEAYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUXUytcDTeS0i3
# M6e3uym/aAzKBOMwNAYDVR0RBC0wK6QpMCcxDTALBgNVBAsTBE1PUFIxFjAUBgNV
# BAUTDTIzMzExMCsyNDI4NTIwHwYDVR0jBBgwFoAUSG5k5VAF04KqFzc3IrVtqMp1
# ApUwVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3Br
# aW9wcy9jcmwvTWljQ29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNybDBhBggrBgEF
# BQcBAQRVMFMwUQYIKwYBBQUHMAKGRWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
# a2lvcHMvY2VydHMvTWljQ29kU2lnUENBMjAxMV8yMDExLTA3LTA4LmNydDAMBgNV
# HRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQB2qRmrcckClX2oK/Jn5swfthwS
# HaykSXGRm53xPysKVO/170v5u1s273YiYRzAqIz7jbHZTK1pSfyQFh5alTc/J823
# O78rqShUeZUdOrDzq4UxAJ4aQxWbCnqC1ahfj5Em+Dpxd+vpQTp1LXN+NCLPi8WR
# jT746bRpzyFzpaZS17Vj1rGbpHsdaRmSgAo5FicbI3JdjPCKCUFvISCexGQuyimi
# AhyDuONhsaCDMWiw6OoyHad8W66oDmPkdwosOLep5+TbmC+X+W2F7UP6JjjnDrP8
# QfhhV/YCKJ7+/kQxw5RbhxBhEYW9NGmu8xTM7KpQag53VLQ2QM7Nj3Ena1WOgKWJ
# dDDiUNG3WO77D0z+rRelaCVtV09sNmGGvCHDJetAG38knW5Ihcb04T9MnYfKyxMH
# 6fqQ/B0DJeq6BRNGsM6OkLUyFvPuCzNvF+L4AnJj4lABRtLT/JSheDkNLWFOFtSa
# vzaETE7z7bg0mckzOvkLaIOPupXXYUhhnYiKlvgB0ChOOlLSiiWcU3Q0VQgWWTgO
# 5vkn6Z92I0zpGq9ppEFCtU/RU+QldNWNrDT+UFyekVkHOlPk/9K+biW5lkKcB2rS
# z+iKvjPxJ6zicexXGjV/jFxxHVTFLviBFZ9D63dVBg2ZwZel43OKa9/L07V5kEcC
# 9ISJcCrs2DqA3+qyIjCCB3owggVioAMCAQICCmEOkNIAAAAAAAMwDQYJKoZIhvcN
# AQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
# VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAw
# BgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEx
# MB4XDTExMDcwODIwNTkwOVoXDTI2MDcwODIxMDkwOVowfjELMAkGA1UEBhMCVVMx
# EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT
# FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9zb2Z0IENvZGUg
# U2lnbmluZyBQQ0EgMjAxMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
# AKvw+nIQHC6t2G6qghBNNLrytlghn0IbKmvpWlCquAY4GgRJun/DDB7dN2vGEtgL
# 8DjCmQawyDnVARQxQtOJDXlkh36UYCRsr55JnOloXtLfm1OyCizDr9mpK656Ca/X
# llnKYBoF6WZ26DJSJhIv56sIUM+zRLdd2MQuA3WraPPLbfM6XKEW9Ea64DhkrG5k
# NXimoGMPLdNAk/jj3gcN1Vx5pUkp5w2+oBN3vpQ97/vjK1oQH01WKKJ6cuASOrdJ
# Xtjt7UORg9l7snuGG9k+sYxd6IlPhBryoS9Z5JA7La4zWMW3Pv4y07MDPbGyr5I4
# ftKdgCz1TlaRITUlwzluZH9TupwPrRkjhMv0ugOGjfdf8NBSv4yUh7zAIXQlXxgo
# tswnKDglmDlKNs98sZKuHCOnqWbsYR9q4ShJnV+I4iVd0yFLPlLEtVc/JAPw0Xpb
# L9Uj43BdD1FGd7P4AOG8rAKCX9vAFbO9G9RVS+c5oQ/pI0m8GLhEfEXkwcNyeuBy
# 5yTfv0aZxe/CHFfbg43sTUkwp6uO3+xbn6/83bBm4sGXgXvt1u1L50kppxMopqd9
# Z4DmimJ4X7IvhNdXnFy/dygo8e1twyiPLI9AN0/B4YVEicQJTMXUpUMvdJX3bvh4
# IFgsE11glZo+TzOE2rCIF96eTvSWsLxGoGyY0uDWiIwLAgMBAAGjggHtMIIB6TAQ
# BgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUSG5k5VAF04KqFzc3IrVtqMp1ApUw
# GQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB
# /wQFMAMBAf8wHwYDVR0jBBgwFoAUci06AjGQQ7kUBU7h6qfHMdEjiTQwWgYDVR0f
# BFMwUTBPoE2gS4ZJaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJv
# ZHVjdHMvTWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNybDBeBggrBgEFBQcB
# AQRSMFAwTgYIKwYBBQUHMAKGQmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kv
# Y2VydHMvTWljUm9vQ2VyQXV0MjAxMV8yMDExXzAzXzIyLmNydDCBnwYDVR0gBIGX
# MIGUMIGRBgkrBgEEAYI3LgMwgYMwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvZG9jcy9wcmltYXJ5Y3BzLmh0bTBABggrBgEFBQcC
# AjA0HjIgHQBMAGUAZwBhAGwAXwBwAG8AbABpAGMAeQBfAHMAdABhAHQAZQBtAGUA
# bgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAZ/KGpZjgVHkaLtPYdGcimwuWEeFj
# kplCln3SeQyQwWVfLiw++MNy0W2D/r4/6ArKO79HqaPzadtjvyI1pZddZYSQfYtG
# UFXYDJJ80hpLHPM8QotS0LD9a+M+By4pm+Y9G6XUtR13lDni6WTJRD14eiPzE32m
# kHSDjfTLJgJGKsKKELukqQUMm+1o+mgulaAqPyprWEljHwlpblqYluSD9MCP80Yr
# 3vw70L01724lruWvJ+3Q3fMOr5kol5hNDj0L8giJ1h/DMhji8MUtzluetEk5CsYK
# wsatruWy2dsViFFFWDgycScaf7H0J/jeLDogaZiyWYlobm+nt3TDQAUGpgEqKD6C
# PxNNZgvAs0314Y9/HG8VfUWnduVAKmWjw11SYobDHWM2l4bf2vP48hahmifhzaWX
# 0O5dY0HjWwechz4GdwbRBrF1HxS+YWG18NzGGwS+30HHDiju3mUv7Jf2oVyW2ADW
# oUa9WfOXpQlLSBCZgB/QACnFsZulP0V3HjXG0qKin3p6IvpIlR+r+0cjgPWe+L9r
# t0uX4ut1eBrs6jeZeRhL/9azI2h15q/6/IvrC4DqaTuv/DDtBEyO3991bWORPdGd
# Vk5Pv4BXIqF4ETIheu9BCrE/+6jMpF3BoYibV3FWTkhFwELJm3ZbCoBIa/15n8G9
# bW1qyVJzEw16UM0xghXlMIIV4QIBATCBlTB+MQswCQYDVQQGEwJVUzETMBEGA1UE
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5n
# IFBDQSAyMDExAhMzAAAA05SsNkWNAZ8GAAAAAADTMA0GCWCGSAFlAwQCAQUAoIHU
# MBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgor
# BgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCDGrbTgOBToRYgd1W81SAJ9OW2TrhKl
# APdP8L/PLVgoDTBoBgorBgEEAYI3AgEMMVowWKAkgCIATQBpAGMAcgBvAHMAbwBm
# AHQAIABXAGkAbgBkAG8AdwBzoTCALmh0dHA6Ly9nby5taWNyb3NvZnQuY29tL2Z3
# bGluay8/TGlua0lkPTUyMTcwNCAwDQYJKoZIhvcNAQEBBQAEggEAMDdw6GKyIy1j
# kDURksbd6lkCxFp7tC3SzZSpSR5qLcCGFuD+dnPXOLwiaVtRBjoYz9E+mLZRZw4y
# zJQzsrZM5zLXjjAwiDEUQiKSvLWt1L9FoFq41J1O8tggNm/Ng5vKM0Sxkv5jqU5I
# ijTB/p+rcQGNiGVxKEliFNTi3VWvU2u5r52pBstv7HBGCqrHiEjMqvuafL7Y4Xws
# QtEUpWaa9yjmrDmDFBzJCa3yV2xl0iGzWK0SNr/Y2TBkrj7veY3l0M85MaNupccJ
# 1BHEosXMdwgM5HDgli8RQjZiloYEofSbH+Hih6VHoRX3ptZoPWg3vDlGhkn163fu
# HxbiKavDxaGCE0kwghNFBgorBgEEAYI3AwMBMYITNTCCEzEGCSqGSIb3DQEHAqCC
# EyIwghMeAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggE8BgsqhkiG9w0BCRABBKCCASsE
# ggEnMIIBIwIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQCAQUABCAZwlRHSV6I
# QRwtrQXxF4B36HCVLlrJj3Jy1SqTSpXYSQIGWk7SMzk/GBMyMDE4MDIwMjE3NDUw
# OC4wNDFaMAcCAQGAAgH0oIG4pIG1MIGyMQswCQYDVQQGEwJVUzETMBEGA1UECBMK
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMQwwCgYDVQQLEwNBT0MxJzAlBgNVBAsTHm5DaXBoZXIgRFNF
# IEVTTjoyMTM3LTM3QTAtNEFBQTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3Rh
# bXAgU2VydmljZaCCDs0wggZxMIIEWaADAgECAgphCYEqAAAAAAACMA0GCSqGSIb3
# DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIw
# MAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAx
# MDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVT
# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1l
# LVN0YW1wIFBDQSAyMDEwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
# qR0NvHcRijog7PwTl/X6f2mUa3RUENWlCgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AV
# UycEMR9BGxqVHc4JE458YTBZsTBED/FgiIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN
# 0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeRX4FUsc+TTJLBxKZd0WETbijGGvmGgLvf
# YfxGwScdJGcSchohiq9LZIlQYrFd/XcfPfBXday9ikJNQFHRD5wGPmd/9WbAA5ZE
# fu/QS/1u5ZrKsajyeioKMfDaTgaRtogINeh4HLDpmc085y9Euqf03GS9pAHBIAmT
# eM38vMDJRF1eFpwBBU8iTQIDAQABo4IB5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAw
# HQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvFM2hahW1VMBkGCSsGAQQBgjcUAgQMHgoA
# UwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQY
# MBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6
# Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1
# dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0
# dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIw
# MTAtMDYtMjMuY3J0MIGgBgNVHSABAf8EgZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9
# BggrBgEFBQcCARYxaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQ
# Uy9kZWZhdWx0Lmh0bTBABggrBgEFBQcCAjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8A
# bABpAGMAeQBfAFMAdABhAHQAZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0BAQsFAAOC
# AgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Prpsz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn
# 8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOMzPRgEop2zEBAQZvcXBf/XPleFzWYJFZL
# dO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCvOA8X9S95gWXZqbVr5MfO9sp6AG9LMEQk
# IjzP7QOllo9ZKby2/QThcJ8ySif9Va8v/rbljjO7Yl+a21dA6fHOmWaQjP9qYn/d
# xUoLkSbiOewZSnFjnXshbcOco6I8+n99lmqQeKZt0uGc+R38ONiU9MalCpaGpL2e
# Gq4EQoO4tYCbIjggtSXlZOz39L9+Y1klD3ouOVd2onGqBooPiRa6YacRy5rYDkea
# gMXQzafQ732D8OE7cQnfXXSYIghh2rBQHm+98eEA3+cxB6STOvdlR3jo+KhIq/fe
# cn5ha293qYHLpwmsObvsxsvYgrRyzR30uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjm
# mC3qjeAzLhIp9cAvVCch98isTtoouLGp25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3Qy
# S99je/WZii8bxyGvWbWu3EQ8l1Bx16HSxVXjad5XwdHeMMD9zOZN+w2/XU/pnR4Z
# OC+8z1gFLu8NoFA12u8JJxzVs341Hgi62jbb01+P3nSISRIwggTZMIIDwaADAgEC
# AhMzAAAArzWP/9MiRXZLAAAAAACvMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU
# aW1lLVN0YW1wIFBDQSAyMDEwMB4XDTE2MDkwNzE3NTY1NloXDTE4MDkwNzE3NTY1
# NlowgbIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDDAKBgNV
# BAsTA0FPQzEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNOOjIxMzctMzdBMC00QUFB
# MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIBIjANBgkq
# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk+hAhg4ay3HwAw2mj6TnYRLQYeqQapVW
# uregTUspZNhRmjtdZ5OtiO5D1N1d1O8ScZ9tP/XqlyrIOrdVEdSnM7V0RE2YTeF6
# pcfdqSzMiB8Ibz7xz4Tl4WwP58PuOYGLKTMnWfhPzqWbjQYDrt7USVNi41kn9egK
# TLzG4B9X3dGb/04H0GxgmJeBrmEOkHnkCyjL+b0QazzBcxEQXuLjUvY/YXrkRa91
# Qa1LDLXpNBoRN3CgP+isK7QHk76ug8nZ4nSRcGGwFXpE9ISRDfzbJDNmAMwgi+7B
# aD1xH599C+XSaCeGnmmyqrMcShdU+Qdp/ndvxz/GnNLxUlCrx5c4owIDAQABo4IB
# GzCCARcwHQYDVR0OBBYEFH0eVcYxitpgCwZmsBTZavx7EvbhMB8GA1UdIwQYMBaA
# FNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9j
# cmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0YVBDQV8y
# MDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6
# Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENBXzIwMTAt
# MDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJ
# KoZIhvcNAQELBQADggEBAGrIAIZ4+wxCnBDW9yisD4Rqi/zdW+ofWkBEqS4TX4sa
# SXZpEirmhOb45rrRjzwuKe1LNSDggbr61YMXFZt1U5o8f2OQy6AIZC/zYfNK8Irw
# RU6IjTxrkI0A4msjSax5ZyDnZTOu+uQiwUINdWUP1J3NHuMw3qxahhrChYdHJO58
# POJyODkYbjx1jeYB2cd3cKPa+lm5iUBZkbbF8ruFLZ3VGH/jkxtyf7EJrRADrsUl
# JufNo36itbj1StU0FHyP8oLDNgjSMIg2ddcIGWtiF5HTA0Kyc4zRFah1Kaz/gEUL
# RbHdcvZZNblSBs7miH//Lays0fzgo8/8HDkf29AQ09uhggN3MIICXwIBATCB4qGB
# uKSBtTCBsjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV
# BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEMMAoG
# A1UECxMDQU9DMScwJQYDVQQLEx5uQ2lwaGVyIERTRSBFU046MjEzNy0zN0EwLTRB
# QUExJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiJQoBATAJ
# BgUrDgMCGgUAAxUA2OqsFS1vLqUtpv0CA1DigBv+TiOggcEwgb6kgbswgbgxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDDAKBgNVBAsTA0FPQzEn
# MCUGA1UECxMebkNpcGhlciBOVFMgRVNOOjI2NjUtNEMzRi1DNURFMSswKQYDVQQD
# EyJNaWNyb3NvZnQgVGltZSBTb3VyY2UgTWFzdGVyIENsb2NrMA0GCSqGSIb3DQEB
# BQUAAgUA3h6rBDAiGA8yMDE4MDIwMjA5MTY1MloYDzIwMTgwMjAzMDkxNjUyWjB3
# MD0GCisGAQQBhFkKBAExLzAtMAoCBQDeHqsEAgEAMAoCAQACAjzQAgH/MAcCAQAC
# AhomMAoCBQDeH/yEAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwGg
# CjAIAgEAAgMW42ChCjAIAgEAAgMehIAwDQYJKoZIhvcNAQEFBQADggEBAAaom4T/
# jJNr8VET8IgggqT4eCwseTjk3G4b+2G9HuTMR6j863NKcUrZC9eRZhIAgBa9vaSM
# Ar8JFsNQF9YDU9Xbl6T/kGvxOsyZ7Bb+ApVYYigAOaPONq+m0LVV/zodczYH2M6m
# iYk2D7S0x9kkWkKAxAk+51nljqmu5L05FnjCUFCQziWWsrJ/TM9GaTcCdHk718sq
# PDBWxiEfXz2N25Q4fjJ5rJBIHaOorJPvZJSK/HWRPo9aJfjEN8rFyaY1qTEm5sYf
# ydaBsy6mpkaC5Qo13Rx6muAqC7BkIPjnvJaRBWUTNOGf8W43TIG4jvvoILMcjs4a
# FrpWDu2duSyKVF0xggL1MIIC8QIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UE
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQ
# Q0EgMjAxMAITMwAAAK81j//TIkV2SwAAAAAArzANBglghkgBZQMEAgEFAKCCATIw
# GgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCBtNAiz
# SlwJTSW4JlWWCbD/I0UZ/qiWWrVUXi8ajv13FzCB4gYLKoZIhvcNAQkQAgwxgdIw
# gc8wgcwwgbEEFNjqrBUtby6lLab9AgNQ4oAb/k4jMIGYMIGApH4wfDELMAkGA1UE
# BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
# BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0
# IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAACvNY//0yJFdksAAAAAAK8wFgQUcbci
# euPwpGiwZ2BU2Rx0DTvx/XowDQYJKoZIhvcNAQELBQAEggEAPoof/emyKKvPMpD3
# IS2PCukaYGgtzpGZ07w0JgPPPQYhYPfmqmmNwdX7+bc2iNSq8/6iDX0peYMihXkk
# HPUr1Hnd+sjXOsTg0Gw43fcEeoGmvgA5L0DtriRzFl7gf+p5mey1JnU4dEUYeJwx
# g1UTnLlR0aP0DcAIWzH0p8fooK4hoX/lxba9Cv54zSjfGuBU0D4jA8c2pcvt1v08
# QByAjHimYFft03X/xdDAomGYUMNxBVlKwmaO+deFfa19Io9AyFotpVDf3FVq7wGy
# OdqLst44LVjNMuk1OJC81OPXNVjhQrfN8KiRmN4iZKE1JUzrIiPhRz3ZZ9Pxvvk3
# 5SoLUA==
# SIG # End signature block