Functions/Invoke-AnalyzeHybridJoinStatus.ps1

function Invoke-AnalyzeHybridJoinStatus {
    <#
    .Synopsis
    Analyzes current status of the device regarding Azure AD Hybrid Join.
 
    .Description
    Analyzes current status of the device regarding Azure AD Hybrid Join. It checks also AD Service Connection Points and IE Site Assignments and GPO Settings.
 
    Returns array of Messages with four properties:
 
    - Testname: Name of the Tets
    - Type: Information, Warning or Error
    - Issue: Description of the issue
    - Possible Cause: Tips on how to solve the issue.
 
    .Parameter IncludeEventLog
    By specifying this command also the most relevant Windows Event Log entries from the last 10 Minutes related to Azure AD and Hybrid Join are included in the Output of this CmdLet.
 
    .Example
    # Displays a deep analyisis of the currently found issues in the system.
    Invoke-AnalyzeHybridJoinStatus
 
    #>

    param(
        [switch]$IncludeEventLog
    )
    $dsreg = Get-DsRegStatus
    $possibleErrors = @()
    if ($dsreg.AzureAdJoined -eq "NO") {
        $possibleErrors += New-AnalyzeResult -TestName "AzureAdJoined" -Type Error -Issue "The join to Azure AD has not completed yet." -PossibleCause "Authentication of the computer for a join failed.
        There is an HTTP proxy in the organization that cannot be discovered by the computer
        The computer cannot reach Azure AD to authenticate or Azure DRS for registration
        The computer may not be on the organization's internal network or on VPN with direct line of sight to an on-premises AD domain controller.
        If the computer has a TPM, it can be in a bad state.
        There might be a misconfiguration in the services noted in the document earlier that you will need to verify again. Common examples are:
        - Your federation server does not have WS-Trust endpoints enabled
        - Your federation server does not allow inbound authentication from computers in your network using Integrated Windows Authentication.
        - There is no Service Connection Point object that points to your verified domain name in Azure AD in the AD forest where the computer belongs to."

    }

    if ($dsreg.DomainJoined -eq "NO") {
        $possibleErrors += New-AnalyzeResult -TestName "DomainJoined" -Type Error -Issue "The device is not joined to an on-premises Active Directory. Therefore, the device cannot perform a hybrid Azure AD join." -PossibleCause "Join the device to a domain, otherwise no Hybrid Join will be possible."
    }
    else {
        # Check Service Connection Point
        $Forest = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
        $getdomaindn = $Forest.RootDomain.Name.Split('.') -join ",DC="
        $scp = New-Object System.DirectoryServices.DirectoryEntry
        $scp.Path = "LDAP://CN=62a0ff2e-97b9-4513-943f-0d221bd30080,CN=Device Registration Configuration,CN=Services,CN=Configuration,DC=$getdomaindn";
        if ([String]::IsNullOrWhiteSpace($scp.Keywords)) {
            $possibleErrors += New-AnalyzeResult -TestName "ADServiceConnectionPoint" -Type Error -Issue "No Service Connection Point defined in Active Directory." -PossibleCause "Join the device to a domain, otherwise no Hybrid Join will be possible."
        }
        else {
            $possibleErrors += New-AnalyzeResult -TestName "ADServiceConnectionPoint" -Type Warning -Issue "Current Value: $($scp.Keywords) `n Validate if the AzureAD GUID and tenant name is correct." -PossibleCause "Sometimes there are incorrect vslues left from a PoC or Testenvironment which can result in an incorrect entriy."
        }

        if ($dsreg.WorkplaceJoined -eq "YES") {
            if ($dsreg.DomainJoined -eq "YES") {
                $possibleErrors += New-AnalyzeResult -TestName "WorkplaceJoined" -Type Error -Issue "A work or school account was added before the completion of a hybrid Azure AD join." -PossibleCause "If the value is YES, a work or school account was added prior to the completion of the hybrid Azure AD join. In this case, the account is ignored when using the Anniversary Update version of Windows 10 (1607). This value should be NO for a domain-joined computer that is also hybrid Azure AD joined."
            }
        }

        $IESites = Get-SiteToZoneAssignment | Where-Object { ($_.Url -eq "https://autologon.microsoftazuread-sso.com" -or $_.Url -eq "autologon.microsoftazuread-sso.com") -and $_.Zone -eq "Local Intranet Zone" }
        if ($null -eq $IESites) {
            #Check if it is also not set manually:
            $IESitesManual = Get-ItemPropertyValue -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\microsoftazuread-sso.com\autologon" -Name https -ErrorAction SilentlyContinue
            if($IESitesManual -ne 1){
                $possibleErrors += New-AnalyzeResult -TestName "IE Site Assignment" -Type Warning -Issue "We could not detect https://autologon.microsoftazuread-sso.com in the Local Intranet Zone of Internet Explorer." -PossibleCause "One possibility is, that you have configured it manually on this test client in Internet Explorer. This check only validates, if it is assigned through a group policy.
                The second option is, that you configured a toplevel site in the intranet site and not especially the above mentioned URL including the protocol."

            }
        }

        $IESites = Get-SiteToZoneAssignment | Where-Object { ($_.Url -eq "https://device.login.microsoftonline.com" -or $_.Url -eq "device.login.microsoftonline.com") -and $_.Zone -eq "Local Intranet Zone" }
        if ($null -eq $IESites) {
            #Check if it is also not set manually:
            $IESitesManual = Get-ItemPropertyValue -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\microsoftonline.com\device.login" -Name https -ErrorAction SilentlyContinue
            if($IESitesManual -ne 1){
                $possibleErrors += New-AnalyzeResult -TestName "IE Site Assignment" -Type Warning -Issue "We could not detect https://device.login.microsoftonline.com in the Local Intranet Zone of Internet Explorer. To avoid certificate prompts when users in register devices authenticate to Azure AD you can push a policy to your domain-joined devices to add the following URL to the Local Intranet zone in Internet Explorer." -PossibleCause "One possibility is, that you have configured it manually on this test client in Internet Explorer. This check only validates, if it is assigned through a group policy.
                The second option is, that you configured a toplevel site in the intranet site and not especially the above mentioned URL including the protocol."

            }
        }
        # GPO Checks
        try {
            $IEStatusBarUpdates = Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1" -Name 2103 -ErrorAction SilentlyContinue
        }
        catch {
            $IEStatusBarUpdates = $null
        }
        if ($IEStatusBarUpdates -eq 3) {
            $possibleErrors += New-AnalyzeResult -TestName "IE Update Status Bar" -Type Error -Issue "The following setting should be enabled in the user's intranet zone, if you plan to use SSO: 'Allow status bar updates via script.'. This is also the default value, which means you have a policy which disables this explicity." -PossibleCause "Reconfigure the policy"
        }
        try {
            $AutoDeviceReg = Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WorkplaceJoin" -Name autoWorkplaceJoin -ErrorAction SilentlyContinue
        }
        catch {
            $AutoDeviceReg = $null
        }
        if ($AutoDeviceReg -ne 1) {
            $possibleErrors += New-AnalyzeResult -TestName "Auto Workplace Join GPO" -Type Error -Issue "The following setting should be enabled to trigger the automatic Azure AD Hybrid Join." -PossibleCause "Reconfigure the policy: Computer Configuration > Policies > Administrative Templates > Windows Components > Device Registration > Register domain-joined computers as devices"
        }
    }

    

    if ($dsreg.WamDefaultSet -eq "NO") {
        $possibleErrors += New-AnalyzeResult -TestName "WamDefaultSet" -Type Error -Issue "These fields indicate whether the user has successfully authenticated to Azure AD when signing in to the device." -PossibleCause "If the values are NO, it could be due:
        Bad storage key (STK) in TPM associated with the device upon registration (check the KeySignTest while running elevated).
        Alternate Login ID
        HTTP Proxy not found"

    }

    if ($dsreg.AzureAdPrt -eq "NO") {
        $possibleErrors += New-AnalyzeResult -TestName "AzureAdPrt" -Type Error -Issue "These fields indicate whether the user has successfully authenticated to Azure AD when signing in to the device." -PossibleCause "If the values are NO, it could be due:
        Bad storage key (STK) in TPM associated with the device upon registration (check the KeySignTest while running elevated).
        Alternate Login ID
        HTTP Proxy not found"

    }
    
    # Analyze Eventlogs
    if ($IncludeEventLog) {
        $AADEvents = Get-WinEvent -LogName "Microsoft-Windows-AAD/Operational" | Where-Object { ($_.LevelDisplayName -eq "Error" -or $_.LevelDisplayName -eq "Warning") -and $_.TimeCreated -gt [DateTime]::Now.AddMinutes(-10)  }
        foreach ($AADEvent in ($AADEvents | Group-Object -Property Id)) {
            $possibleErrors += New-AnalyzeResult -TestName "EventLog-AAD" -Type ($AADEvent.Group[0].LevelDisplayName) -Issue "EventId: $($AADEvent.Name)`n$($AADEvent.Group[0].Message)" -PossibleCause ""
        }
        $WPJoinEvents = Get-WinEvent -LogName "Microsoft-Windows-Workplace Join/Admin" | Where-Object { ($_.LevelDisplayName -eq "Error" -or $_.LevelDisplayName -eq "Warning") -and $_.TimeCreated -gt [DateTime]::Now.AddMinutes(-10)  }
        foreach ($WPJoinEvent in ($WPJoinEvents | Group-Object -Property Id)) {
            $possibleErrors += New-AnalyzeResult -TestName "EventLog-WorkplaceJoin" -Type ($WPJoinEvent.Group[0].LevelDisplayName) -Issue "EventId: $($WPJoinEvent.Name)`n$($WPJoinEvent.Group[0].Message)" -PossibleCause ""
        }
        $UsrDevRegEvents = Get-WinEvent -LogName "Microsoft-Windows-User Device Registration/Admin" | Where-Object { ($_.LevelDisplayName -eq "Error" -or $_.LevelDisplayName -eq "Warning") -and $_.TimeCreated -gt [DateTime]::Now.AddMinutes(-10)  }
        foreach ($UsrDevRegEvent in ($UsrDevRegEvents | Group-Object -Property Id)) {
            $possibleErrors += New-AnalyzeResult -TestName "EventLog-WorkplaceJoin" -Type ($UsrDevRegEvent.Group[0].LevelDisplayName) -Issue "EventId: $($UsrDevRegEvent.Name)`n$($UsrDevRegEvent.Group[0].Message)" -PossibleCause ""
        }
        
    }
    # Connectifity Tests
    $isVerbose = $VerbosePreference -eq 'Continue'

    $data = New-Object System.Collections.Generic.List[System.Collections.Hashtable]

    # https://docs.microsoft.com/en-us/azure/active-directory/devices/hybrid-azuread-join-manual-steps

    $data.Add(@{ TestUrl = 'https://enterpriseregistration.windows.net'; ExpectedStatusCode = 404; PerformBluecoatLookup = $PerformBluecoatLookup; Verbose = $isVerbose }) 
    $data.Add(@{ TestUrl = 'https://login.microsoftonline.com'; IgnoreCertificateValidationErrors = $false; PerformBluecoatLookup = $PerformBluecoatLookup; Verbose = $isVerbose })
    $data.Add(@{ TestUrl = 'https://device.login.microsoftonline.com'; IgnoreCertificateValidationErrors = $true; PerformBluecoatLookup = $PerformBluecoatLookup; Verbose = $isVerbose }) 
    $data.Add(@{ TestUrl = 'https://autologon.microsoftazuread-sso.com'; ExpectedStatusCode = 404; Description = 'URL required for Seamless SSO'; IgnoreCertificateValidationErrors = $true; PerformBluecoatLookup = $PerformBluecoatLookup; Verbose = $isVerbose })
    
    $results = New-Object System.Collections.Generic.List[pscustomobject]

    $data | ForEach-Object {
        $connectivity = Get-HttpConnectivity @_
        $results.Add($connectivity)
        if ($connectivity.Blocked -eq $true) {
            $possibleErrors += New-AnalyzeResult -TestName "Connectivity" -Type "Error" -Issue "Connection blocked `n $($connectivity)" -PossibleCause "Firewall is blocking connection to '$($connectivity.UnblockUrl)'."
        }
        if ($connectivity.Resolved -eq $false) {
            $possibleErrors += New-AnalyzeResult -TestName "Connectivity" -Type "Error" -Issue "DNS name not resolved `n $($connectivity)" -PossibleCause "DNS server not correctly configured."
        }
        if ($connectivity.ExpectedStatusCode -notcontains $connectivity.ActualStatusCode) {
            if($connectivity.ActualStatusCode -eq 407){
                $Cause = "Keep in mind that the proxy has to be set in WinHTTP.`nWindows 1709 and newer: Set the proxy by using netsh or WPAD. --> https://docs.microsoft.com/en-us/windows/desktop/WinHttp/winhttp-autoproxy-support `nWindows 1709 and older: Set the proxy by using 'netsh winhttp set proxy ?' --> https://blogs.technet.microsoft.com/netgeeks/2018/06/19/winhttp-proxy-settings-deployed-by-gpo/ "
             } else {
                $Cause = "Interfering Proxy server can change HTTP status codes."
             }
            $possibleErrors += New-AnalyzeResult -TestName "Connectivity" -Type "Error" -Issue "Returned HTTP Status code '$($connectivity.ActualStatusCode)' is not expected '$($connectivity.ExpectedStatusCode)'`n $($connectivity)" -PossibleCause $Cause
        }
        if ($null -ne $connectivity.ServerCertificate -and $connectivity.ServerCertificate.HasError) {
            $possibleErrors += New-AnalyzeResult -TestName "Connectivity" -Type "Error" -Issue "Certificate Error when connecting to $($connectivity.TestUrl)`n $(($connectivity.ServerCertificate))" -PossibleCause "Interfering Proxy server can change Certificate or not the Root Certificate is not trusted."
        }
    }

    # No errors detected, return success message
    if ($possibleErrors.Count -eq 0) {
        $possibleErrors += New-AnalyzeResult -TestName "All" -Type Information -Issue "All tests went through successfully. $(if(-not $IncludeEventLog){'You can try to run the command again with the -IncludeEventLog parameter.'})" -PossibleCause ""
    }

    return $possibleErrors
}
# SIG # Begin signature block
# MIIXxQYJKoZIhvcNAQcCoIIXtjCCF7ICAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUVsQ5vW+gcnw+bQ2yE8P12SMg
# ifKgghL4MIID7jCCA1egAwIBAgIQfpPr+3zGTlnqS5p31Ab8OzANBgkqhkiG9w0B
# AQUFADCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIG
# A1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhh
# d3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcg
# Q0EwHhcNMTIxMjIxMDAwMDAwWhcNMjAxMjMwMjM1OTU5WjBeMQswCQYDVQQGEwJV
# UzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xMDAuBgNVBAMTJ1N5bWFu
# dGVjIFRpbWUgU3RhbXBpbmcgU2VydmljZXMgQ0EgLSBHMjCCASIwDQYJKoZIhvcN
# AQEBBQADggEPADCCAQoCggEBALGss0lUS5ccEgrYJXmRIlcqb9y4JsRDc2vCvy5Q
# WvsUwnaOQwElQ7Sh4kX06Ld7w3TMIte0lAAC903tv7S3RCRrzV9FO9FEzkMScxeC
# i2m0K8uZHqxyGyZNcR+xMd37UWECU6aq9UksBXhFpS+JzueZ5/6M4lc/PcaS3Er4
# ezPkeQr78HWIQZz/xQNRmarXbJ+TaYdlKYOFwmAUxMjJOxTawIHwHw103pIiq8r3
# +3R8J+b3Sht/p8OeLa6K6qbmqicWfWH3mHERvOJQoUvlXfrlDqcsn6plINPYlujI
# fKVOSET/GeJEB5IL12iEgF1qeGRFzWBGflTBE3zFefHJwXECAwEAAaOB+jCB9zAd
# BgNVHQ4EFgQUX5r1blzMzHSa1N197z/b7EyALt0wMgYIKwYBBQUHAQEEJjAkMCIG
# CCsGAQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMBIGA1UdEwEB/wQIMAYB
# Af8CAQAwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NybC50aGF3dGUuY29tL1Ro
# YXd0ZVRpbWVzdGFtcGluZ0NBLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCDAOBgNV
# HQ8BAf8EBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAXBgNVBAMTEFRpbWVTdGFtcC0y
# MDQ4LTEwDQYJKoZIhvcNAQEFBQADgYEAAwmbj3nvf1kwqu9otfrjCR27T4IGXTdf
# plKfFo3qHJIJRG71betYfDDo+WmNI3MLEm9Hqa45EfgqsZuwGsOO61mWAK3ODE2y
# 0DGmCFwqevzieh1XTKhlGOl5QGIllm7HxzdqgyEIjkHq3dlXPx13SYcqFgZepjhq
# IhKjURmDfrYwggSjMIIDi6ADAgECAhAOz/Q4yP6/NW4E2GqYGxpQMA0GCSqGSIb3
# DQEBBQUAMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3Jh
# dGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2aWNlcyBD
# QSAtIEcyMB4XDTEyMTAxODAwMDAwMFoXDTIwMTIyOTIzNTk1OVowYjELMAkGA1UE
# BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMTQwMgYDVQQDEytT
# eW1hbnRlYyBUaW1lIFN0YW1waW5nIFNlcnZpY2VzIFNpZ25lciAtIEc0MIIBIjAN
# BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomMLOUS4uyOnREm7Dv+h8GEKU5Ow
# mNutLA9KxW7/hjxTVQ8VzgQ/K/2plpbZvmF5C1vJTIZ25eBDSyKV7sIrQ8Gf2Gi0
# jkBP7oU4uRHFI/JkWPAVMm9OV6GuiKQC1yoezUvh3WPVF4kyW7BemVqonShQDhfu
# ltthO0VRHc8SVguSR/yrrvZmPUescHLnkudfzRC5xINklBm9JYDh6NIipdC6Anqh
# d5NbZcPuF3S8QYYq3AhMjJKMkS2ed0QfaNaodHfbDlsyi1aLM73ZY8hJnTrFxeoz
# C9Lxoxv0i77Zs1eLO94Ep3oisiSuLsdwxb5OgyYI+wu9qU+ZCOEQKHKqzQIDAQAB
# o4IBVzCCAVMwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAO
# BgNVHQ8BAf8EBAMCB4AwcwYIKwYBBQUHAQEEZzBlMCoGCCsGAQUFBzABhh5odHRw
# Oi8vdHMtb2NzcC53cy5zeW1hbnRlYy5jb20wNwYIKwYBBQUHMAKGK2h0dHA6Ly90
# cy1haWEud3Muc3ltYW50ZWMuY29tL3Rzcy1jYS1nMi5jZXIwPAYDVR0fBDUwMzAx
# oC+gLYYraHR0cDovL3RzLWNybC53cy5zeW1hbnRlYy5jb20vdHNzLWNhLWcyLmNy
# bDAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQVGltZVN0YW1wLTIwNDgtMjAdBgNV
# HQ4EFgQURsZpow5KFB7VTNpSYxc/Xja8DeYwHwYDVR0jBBgwFoAUX5r1blzMzHSa
# 1N197z/b7EyALt0wDQYJKoZIhvcNAQEFBQADggEBAHg7tJEqAEzwj2IwN3ijhCcH
# bxiy3iXcoNSUA6qGTiWfmkADHN3O43nLIWgG2rYytG2/9CwmYzPkSWRtDebDZw73
# BaQ1bHyJFsbpst+y6d0gxnEPzZV03LZc3r03H0N45ni1zSgEIKOq8UvEiCmRDoDR
# EfzdXHZuT14ORUZBbg2w6jiasTraCXEQ/Bx5tIB7rGn0/Zy2DBYr8X9bCT2bW+IW
# yhOBbQAuOA2oKY8s4bL0WqkBrxWcLC9JG9siu8P+eJRRw4axgohd8D20UaF5Mysu
# e7ncIAkTcetqGVvP6KUwVyyJST+5z3/Jvz4iaGNTmr1pdKzFHTx/kuDDvBzYBHUw
# ggUnMIIED6ADAgECAhAB7uHu9sSCKgqVgJoW5mKYMA0GCSqGSIb3DQEBCwUAMHIx
# CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
# dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJ
# RCBDb2RlIFNpZ25pbmcgQ0EwHhcNMTkwMzE0MDAwMDAwWhcNMjIwNjExMTIwMDAw
# WjBkMQswCQYDVQQGEwJDSDESMBAGA1UECBMJU29sb3RodXJuMREwDwYDVQQHDAhE
# w6RuaWtlbjEWMBQGA1UEChMNYmFzZVZJU0lPTiBBRzEWMBQGA1UEAxMNYmFzZVZJ
# U0lPTiBBRzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMfM1Zl2D4mV
# Ej7w9rAboqVD3E6JHf3GUOw0cPPP94occ4dCeqITcVME6s2nhVcnff+68FPtJB2g
# BKWIB8zL4bD1SZBgLywRe3F/KvmbULw9gp5Qk8nLeVOLtXsyKEIfNMzMWeMxTMsx
# mtr910G0knpBnuHQgJVNpKF4BgSpIJZ8FQJlvYvLm0y73HXj/YSUJt7bstqnJ9Q6
# s+ngp/en1pykXhzgj76u6yPKc/kdZQwfzsLj2FQ3y7ScWt7Ps1fevkh8JBmJc+ti
# 6oKVDMArOEj7IdXn9rjPkeTSakFoqb1ceNRnMYyMOEaflMFwxylT2NTm4cYTF65m
# HtZEm//K7QECAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5
# LfZldQ5YMB0GA1UdDgQWBBTP/wNYXuPPmMSxVMf7zj/HD4TQbTAOBgNVHQ8BAf8E
# BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0
# cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAz
# oDGGL2h0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEu
# Y3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBz
# Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4
# MHYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEF
# BQcwAoZCaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFz
# c3VyZWRJRENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcN
# AQELBQADggEBAJV9TChoYXmc7/3Qc8p9EgcF4I+6cnLSBpQOfYGi3f3bBcATTPle
# cJiruue4AxIpNwtGwZnqneGxAWT4C98yjBQbCq7nt0k3HF1LjeTNdExNx6cVGF4S
# 9HvcSsoqFNnQuMpzjnFredIP0LPvLQouYtEKcvYJDmx0Bb/72anpAlUiY0WzBF6t
# cYU//dNDqiw/0uQqFMuKzUTKSgGlf+bLsebz8XNIcJPrrui3dduig20oOR2V60Yq
# PmZhLDS3CXNvKXZbo/ib02zendVAFYDIoKZOtmNOalBoWwlQRYWmwQWuSJRbQFl1
# ridyuVRrTlCgWJj4547jqr4/cxmFLV+hrZcwggUwMIIEGKADAgECAhAECRgbX9W7
# ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV
# BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBa
# Fw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lD
# ZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3
# DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/l
# qJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fT
# eyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqH
# CN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+
# bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLo
# LFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIB
# yTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK
# BggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9v
# Y3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHow
# eDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl
# ZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp
# Z2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwA
# AgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAK
# BghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0j
# BBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7s
# DVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGS
# dQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6
# r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo
# +MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qz
# sIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHq
# aGxEMrJmoecYpJpkUe8xggQ3MIIEMwIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMG
# A1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEw
# LwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENB
# AhAB7uHu9sSCKgqVgJoW5mKYMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQow
# CKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcC
# AQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBShZPpyrWZ70MiJnCyU
# apY9OPEkXDANBgkqhkiG9w0BAQEFAASCAQBO8U2z9lfMAlJE7aNX2ksWT/h/4DtS
# XeV/HCZXSkU7dLiPgcrVQUmUXQ8XT1r7oab1+ToM+Aw5QFXFyjZwMDszdJAkp4bz
# jE3mWX0fTYDcW0lDUlVS/wFh/iJAyQ+TphLHHzpuEbVpEct3B3dxpHulWgMprCJV
# /hRxrzBUQi5eFTyEINvl+TtbL+Pa8IrwiTAc10TTeq/1QIbVL3gj4czMEaaylCgT
# QBE8i7TuxjtWo1WzowpIlaYf4v2SFcMIqxT4zMz7ZnvaU8FtPil5RmA3wpwb4Ycc
# Z2UUSBEBP/QHN2TxmbyEUmPPn2NzsxFZfvPnXGgXCwvPUBXI6sL2cPjOoYICCzCC
# AgcGCSqGSIb3DQEJBjGCAfgwggH0AgEBMHIwXjELMAkGA1UEBhMCVVMxHTAbBgNV
# BAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMTAwLgYDVQQDEydTeW1hbnRlYyBUaW1l
# IFN0YW1waW5nIFNlcnZpY2VzIENBIC0gRzICEA7P9DjI/r81bgTYapgbGlAwCQYF
# Kw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkF
# MQ8XDTE5MTEyNDE0MjMxNFowIwYJKoZIhvcNAQkEMRYEFBcwPssO92W/bXzB2Irp
# kVu9swLeMA0GCSqGSIb3DQEBAQUABIIBAHuBP29RvRWur0gwEPmEKvpShBwgVthL
# 4cfjbH40V2C2nmKKC9HoYh5TlLZh3aHUPxy5QAU0Gnlb7J+XzC7kkk8pgDljnpUQ
# uXE+3NdF4uJCE/YGwAh/21LSzTZ79oeECOLtGFawu4qsziPjpjbsnqwk+TvxkIN+
# ItCxaGN2GQFj/Glj/jiFmPMZuiYAb9DlgS3sSEISzOeYuMci0Ndwy/6oYYCpt1du
# e7N2yvUCYlRYhIUJr6FEJ+5KwLEZlWVGeN8bGBqUD2jtHKjE+B2JioUyrjpEvRAD
# zm0oUCGK4rAChVXAGWOjIzhl7+V70WJSXB+/5+OxwGFMLdh5H7onz1Y=
# SIG # End signature block