Public/ServicePrincipals/Get-EntraOpsWorkloadIdentityInfo.ps1

<#
.SYNOPSIS
    Get information of service principals and application in Microsoft Entra ID for creating content for the WatchList "WorkloadIdentityInfo".
 
.DESCRIPTION
    Get information of service principals and application in Microsoft Entra ID for creating content for the WatchList "WorkloadIdentityInfo".
 
.PARAMETER CustomSecurityServicePrincipalAttribute
    Custom Security Attribute to be used for the service principal to get Attributes "adminTier", "adminTierLevelName", "service" and "associatedWorkload" for detailed enrichment to classify the service principal. Default attribute set name is "privilegedWorkloadIdentity".
 
.EXAMPLE
    Get information of service principals and application in Microsoft Entra ID for creating content for the WatchList "WorkloadIdentityInfo".
    Get-EntraOpsWorkloadIdentityInfo
#>


function Get-EntraOpsWorkloadIdentityInfo {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [System.String]$CustomSecurityServicePrincipalAttribute = $EntraOpsConfig.CustomSecurityAttributes.PrivilegedServicePrincipalAttribute
    )

    # Global Variables
    $ErrorActionPreference = "Stop"

    #region New watchlist items
    $NewWatchlistItems = [System.Collections.Concurrent.ConcurrentBag[psobject]]::new()
    Write-Verbose "Query tenant service principals - https://graph.microsoft.com/v1.0/serviceprincipals"
    $ServicePrincipals = Invoke-GkSeMgGraphRequest -Uri "https://graph.microsoft.com/v1.0/serviceprincipals"

    Write-Verbose "Query tenant applications - https://graph.microsoft.com/v1.0/applications"
    $Applications = Invoke-GkSeMgGraphRequest -Uri "https://graph.microsoft.com/v1.0/applications"

    Write-Verbose "Query directory role templates for mapping ID to name and further details"
    $DirectoryRoleDefinitions = Invoke-GkSeMgGraphRequest -Uri "https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions" | Select-Object displayName, templateId, isPrivileged, isBuiltin

    Write-Verbose "Query app roles for mapping ID to name"
    $SPObjectWithAppRoles = $ServicePrincipals | Where-Object { $_.AppRoles -ne $null }
    $AppRoles = foreach ($SPObjectWithAppRole in $SPObjectWithAppRoles) {

        $SPObjectWithAppRole.AppRoles | ForEach-Object {

            [PSCustomObject]@{
                "AppId"                    = $SPObjectWithAppRole.appId
                "ServicePrincipalObjectId" = $SPObjectWithAppRole.id
                "AppRoleId"                = $_.id
                "AppRoleDisplayName"       = $_.value
            }
        }
    }

    Write-Verbose "Query list of first party apps"
    try {
        $ProgressPreference = 'SilentlyContinue'
        $FirstPartyApps = Invoke-WebRequest -UseBasicParsing -Method GET -Uri "https://raw.githubusercontent.com/merill/microsoft-info/main/_info/MicrosoftApps.json" | ConvertFrom-Json
    } catch {
        Write-Warning "Issue to query list of first party apps from GitHub - $($_.Exception)"
    }

    Write-Verbose "Get details for enrichment of service principals"
    $ServicePrincipals | ForEach-Object -Parallel {
        $ServicePrincipal = $_

        #region Function to get tenant information
        function Get-AADTenantInformation {
            [CmdletBinding()]
            param (
                [Parameter(Mandatory = $true)]
                [System.String]$AppTenantId
            )

            $ConnectedTenants = Get-AzTenant | select-object TenantId, DefaultDomain
            if ($ConnectedTenants.TenantId -contains $AppTenantId) {
                $KnownTenant = $ConnectedTenants | where-object { $_.TenantId -eq $AppTenantId } | select-object DefaultDomain, TenantId
                $Tenant = [PSCustomObject]@{
                    TenantName = $KnownTenant.DefaultDomain
                    TenantId   = $KnownTenant.TenantId
                }
            } elseif ($AppTenantId -eq "f8cdef31-a31e-4b4a-93e4-5f571e91255a") {
                $Tenant = [PSCustomObject]@{
                    TenantName = "Microsoft"
                    TenantId   = $($AppTenantId)
                }
            } elseif ($AppTenantId -eq "72f988bf-86f1-41af-91ab-2d7cd011db47") {
                $Tenant = [PSCustomObject]@{
                    TenantName = "Microsoft"
                    TenantId   = $($AppTenantId)
                }
            } elseif ($null -eq $AppTenantId) {
                $Tenant = $null
            } else {
                $Tenant = [PSCustomObject]@{
                    TenantName = "Unknown"
                    TenantId   = ($AppTenantId)
                }
            }
            $Tenant
        }
        #endregion

        try {
            Write-Verbose "Collecting data for $($ServicePrincipal.displayName)"

            # Custom Security Attributes
            $ObjectCustomSec = (Invoke-MgGraphRequest -Method Get -Uri ("https://graph.microsoft.com/beta/servicePrincipals/$($ServicePrincipal.Id)" + '?$select=customSecurityAttributes') -OutputType PSObject).customSecurityAttributes.$($using:CustomSecurityServicePrincipalAttribute)
            if ($Null -eq $ObjectCustomSec) {
                $adminTier = "Unclassified"
                $adminTierLevelName = "Unclassified"
                $service = "Unclassified"
                $associatedWorkload = ""
            } else {
                $adminTier = $ObjectCustomSec.adminTier
                $adminTierLevelName = $ObjectCustomSec.adminTierLevelName
                $AssociatedService = @()
                $AssociatedService += $ObjectCustomSec.service
                $AssociatedWorkload = @()
                $AssociatedWorkload += $ObjectCustomSec.associatedWorkload
            }

            # App Owner Tenant
            if ($null -eq $ServicePrincipal.AppOwnerOrganizationId) {
                $AppOwnerTenant = [PSCustomObject]@{
                    TenantId   = $Null
                    TenantName = $Null
                }
            } else {
                $AppOwnerTenant = Get-AADTenantInformation -AppTenantId $ServicePrincipal.AppOwnerOrganizationId
            }           

            Write-Verbose "Query Application of ServicePrincipal `"$($ServicePrincipal.displayName)`""
            try {
                $Application = $using:Applications | Where-Object appId -eq $ServicePrincipal.AppId
            } catch {
                Write-Verbose "Can not find app registration for $($ServicePrincipal.DisplayName)"
            }

            Write-Verbose "Query Application Permissions of ServicePrincipal `"$($ServicePrincipal.displayName)`""
            try {
                $AssignedAppRoles = New-Object System.Collections.ArrayList
                $SPRoleAssignments = (Invoke-MgGraphRequest -Uri "https://graph.microsoft.com/v1.0/servicePrincipals/$($ServicePrincipal.id)/appRoleAssignments" -Verbose:$False)['value']
                $SPRoleAssignments = foreach ($SPRoleAssignment in $SPRoleAssignments) {
                    $AppRole = $using:AppRoles | Where-Object { $_.appRoleId -eq $SPRoleAssignment.appRoleId -and $_.ServicePrincipalObjectId -eq $SPRoleAssignment.resourceId }

                    [PSCustomObject]@{
                        "ResourceAppId"       = $AppRole.AppId
                        "ResourceDisplayName" = $SPRoleAssignment.resourceDisplayName
                        "AppRoleId"           = $SPRoleAssignment.appRoleId
                        "AppRoleDisplayName"  = $AppRole.AppRoleDisplayName
                    }
                }
                $AssignedAppRoles = $SPRoleAssignments | ConvertTo-Json -Compress -AsArray
            } catch {
                Write-Error -Message $_.Exception
                throw $_.Exception
            }

            Write-Verbose "Query Ownership of ServicePrincipal `"$($ServicePrincipal.displayName)`""
            try {
                $ServicePrincipalOwnerships = New-Object System.Collections.ArrayList
                $SpOwners = Invoke-GkSeMgGraphRequest -Uri "https://graph.microsoft.com/v1.0/serviceprincipals/$($ServicePrincipal.id)/owners" | Select-Object id
                foreach ($SpOwner in $SpOwners) {
                    $ServicePrincipalOwnerships.Add($SpOwner.id) | Out-Null
                }
                $ServicePrincipalOwnerships = $ServicePrincipalOwnerships | ConvertTo-Json -Compress -AsArray
            } catch {
                Write-Error -Message $_.Exception
                throw $_.Exception
            }

            if ($null -ne $Application.id) {
                Write-Verbose "Query Ownership of Application `"$($ServicePrincipal.displayName)`""
                try {
                    $AppOwnerships = New-Object System.Collections.ArrayList
                    $AppOwners = Invoke-GkSeMgGraphRequest -Uri "https://graph.microsoft.com/v1.0/applications/$($Application.Id)/owners" | Select-Object id
                    foreach ($AppOwner in $AppOwners) {
                        $AppOwnerships.Add($AppOwner.id) | Out-Null
                    }
                    $AppOwnerships = $AppOwnerships | ConvertTo-Json -Compress -AsArray
                } catch {
                    Write-Error -Message $_.Exception
                    throw $_.Exception
                }
            }

            Write-Verbose "Query Group Memberships of ServicePrincipal `"$($ServicePrincipal.displayName)`""
            try {
                $GroupMemberships = New-Object System.Collections.ArrayList
                $TransitiveMemberOf = Invoke-GkSeMgGraphRequest -Uri "https://graph.microsoft.com/v1.0/serviceprincipals/$($ServicePrincipal.id)/transitiveMemberOf" | Select-Object id, displayName, isAssignableToRole
                foreach ($GroupMembership in $TransitiveMemberOf) {
                    $GroupMemberships.Add($GroupMembership) | Out-Null
                }
                $GroupMemberships = $GroupMemberships | ConvertTo-Json -Compress -AsArray
            } catch {
                Write-Error -Message $_.Exception
                throw $_.Exception
            }

            Write-Verbose "Query Directory Roles of ServicePrincipal `"$($ServicePrincipal.displayName)`""
            try {
                $TransitiveRoleAssignments = New-Object System.Collections.ArrayList

                $HeaderParams = @{
                    'ConsistencyLevel' = "eventual"
                }
                $TransitiveRoleAssignments = (Invoke-MgGraphRequest -Method Get -Headers $HeaderParams -Uri "https://graph.microsoft.com/beta/roleManagement/directory/transitiveRoleAssignments?`$count=true&`$filter=principalId eq '$($ServicePrincipal.Id)'")['value']
                $TransitiveRoleAssignments = foreach ($TransitiveRoleAssignment in $TransitiveRoleAssignments) {
                    $RoleDefinition = $using:DirectoryRoleDefinitions | Where-Object { $_.templateid -eq $TransitiveRoleAssignment.roleDefinitionId }

                    [PSCustomObject]@{
                        "RoleDefinitionName" = $RoleDefinition.displayName
                        "RoleDefinitionId"   = $TransitiveRoleAssignment.roleDefinitionId
                        "ResourceScope"      = $TransitiveRoleAssignment.resourceScope
                        "RoleAssignmentId"   = $TransitiveRoleAssignment.id
                        "IsPrivileged"       = $RoleDefinition.isPrivileged
                    }
                }
                $AssignedRoles = $TransitiveRoleAssignments | ConvertTo-Json -Compress -AsArray
            } catch {
                Write-Error -Message $_.Exception
                throw $_.Exception
            }

            if ( $ServicePrincipal.AppId -in $($using:FirstPartyApps).AppId ) {
                $IsFirstPartyApp = $true
            } else {
                $IsFirstPartyApp = $false
            }

            if ( $null -ne $ServicePrincipal.appId) {
                $CurrentItem = [PSCustomObject]@{
                    "ServicePrincipalObjectId"   = $ServicePrincipal.Id
                    "AppObjectId"                = $Application.Id
                    "AppId"                      = $ServicePrincipal.AppId
                    "AppDisplayName"             = $ServicePrincipal.DisplayName
                    "CreatedDateTime"            = $ServicePrincipal.createdDateTime
                    "IsAccountEnabled"           = $ServicePrincipal.accountEnabled
                    "DisabledByMicrosoft"        = $ServicePrincipal.DisabledByMicrosoftStatus
                    "VerifiedPublisher"          = $ServicePrincipal.VerifiedPublisher.DisplayName
                    "PublisherName"              = $ServicePrincipal.PublisherName                    
                    "AppOwnerTenantName"         = $AppOwnerTenant.TenantName                    
                    "AppOwnerTenantId"           = $ServicePrincipal.AppOwnerOrganizationId
                    "IsFirstPartyApp"            = $IsFirstPartyApp
                    "ServicePrincipalType"       = $ServicePrincipal.servicePrincipalType
                    "SignInAudience"             = $ServicePrincipal.SignInAudience
                    "UserAssignmentRequired"     = $ServicePrincipal.appRoleAssignmentRequired
                    "ServiceManagementReference" = $ServicePrincipal.serviceManagementReference
                    "ServicePrincipalOwners"     = $ServicePrincipalOwnerships
                    "AppOwners"                  = $AppOwnerships
                    "AssignedAppRoles"           = $AssignedAppRoles
                    "GroupMembership"            = $GroupMemberships
                    "AssignedRoles"              = $AssignedRoles
                    "ObjectAdminTierLevel"       = $adminTier
                    "ObjectAdminTierLevelName"   = $adminTierLevelName            
                    "Tags"                       = @("Entra ID", "Automated Enrichment") | ConvertTo-Json -Compress -AsArray
                }
                ($using:NewWatchlistItems).Add( $CurrentItem ) | Out-Null
            }
        } catch {
            Write-Warning "Could not add $($ServicePrincipal.displayName) - Error $($_.Exception)"
            Continue
        }
    }

    #endregion
    return $NewWatchlistItems    
}
# SIG # Begin signature block
# MIIniAYJKoZIhvcNAQcCoIIneTCCJ3UCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDt4FtA17pihLj+
# Yh7n7lVnkgZ5I2lvVg8n8MkuzJymoqCCIDwwggXJMIIEsaADAgECAhAbtY8lKt8j
# AEkoya49fu0nMA0GCSqGSIb3DQEBDAUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK
# ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy
# dGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5l
# dHdvcmsgQ0EwHhcNMjEwNTMxMDY0MzA2WhcNMjkwOTE3MDY0MzA2WjCBgDELMAkG
# A1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAl
# BgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMb
# Q2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMIICIjANBgkqhkiG9w0BAQEFAAOC
# Ag8AMIICCgKCAgEAvfl4+ObVgAxknYYblmRnPyI6HnUBfe/7XGeMycxca6mR5rlC
# 5SBLm9qbe7mZXdmbgEvXhEArJ9PoujC7Pgkap0mV7ytAJMKXx6fumyXvqAoAl4Va
# qp3cKcniNQfrcE1K1sGzVrihQTib0fsxf4/gX+GxPw+OFklg1waNGPmqJhCrKtPQ
# 0WeNG0a+RzDVLnLRxWPa52N5RH5LYySJhi40PylMUosqp8DikSiJucBb+R3Z5yet
# /5oCl8HGUJKbAiy9qbk0WQq/hEr/3/6zn+vZnuCYI+yma3cWKtvMrTscpIfcRnNe
# GWJoRVfkkIJCu0LW8GHgwaM9ZqNd9BjuiMmNF0UpmTJ1AjHuKSbIawLmtWJFfzcV
# WiNoidQ+3k4nsPBADLxNF8tNorMe0AZa3faTz1d1mfX6hhpneLO/lv403L3nUlbl
# s+V1e9dBkQXcXWnjlQ1DufyDljmVe2yAWk8TcsbXfSl6RLpSpCrVQUYJIP4ioLZb
# MI28iQzV13D4h1L92u+sUS4Hs07+0AnacO+Y+lbmbdu1V0vc5SwlFcieLnhO+Nqc
# noYsylfzGuXIkosagpZ6w7xQEmnYDlpGizrrJvojybawgb5CAKT41v4wLsfSRvbl
# jnX98sy50IdbzAYQYLuDNbdeZ95H7JlI8aShFf6tjGKOOVVPORa5sWOd/7cCAwEA
# AaOCAT4wggE6MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLahVDkCw6A/joq8
# +tT4HKbROg79MB8GA1UdIwQYMBaAFAh2zcsH/yT2xc3tu5C84oQ3RnX3MA4GA1Ud
# DwEB/wQEAwIBBjAvBgNVHR8EKDAmMCSgIqAghh5odHRwOi8vY3JsLmNlcnR1bS5w
# bC9jdG5jYS5jcmwwawYIKwYBBQUHAQEEXzBdMCgGCCsGAQUFBzABhhxodHRwOi8v
# c3ViY2Eub2NzcC1jZXJ0dW0uY29tMDEGCCsGAQUFBzAChiVodHRwOi8vcmVwb3Np
# dG9yeS5jZXJ0dW0ucGwvY3RuY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQG
# CCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQEM
# BQADggEBAFHCoVgWIhCL/IYx1MIy01z4S6Ivaj5N+KsIHu3V6PrnCA3st8YeDrJ1
# BXqxC/rXdGoABh+kzqrya33YEcARCNQOTWHFOqj6seHjmOriY/1B9ZN9DbxdkjuR
# mmW60F9MvkyNaAMQFtXx0ASKhTP5N+dbLiZpQjy6zbzUeulNndrnQ/tjUoCFBMQl
# lVXwfqefAcVbKPjgzoZwpic7Ofs4LphTZSJ1Ldf23SIikZbr3WjtP6MZl9M7JYjs
# NhI9qX7OAo0FmpKnJ25FspxihjcNpDOO16hO0EoXQ0zF8ads0h5YbBRRfopUofbv
# n3l6XYGaFpAP4bvxSgD5+d2+7arszgowggZrMIIEU6ADAgECAhBX5gfP8LabvnxC
# XoItEBa/MA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhB
# c3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBDb2RlIFNp
# Z25pbmcgMjAyMSBDQTAeFw0yNjEwMDYwODI4MjNaFw0yNzEwMDYwODI4MjJaMIGQ
# MQswCQYDVQQGEwJERTEdMBsGA1UECAwUUmhpbmVsYW5kLVBhbGF0aW5hdGUxEjAQ
# BgNVBAcMCUxhaG5zdGVpbjEeMBwGA1UECgwVT3BlbiBTb3VyY2UgRGV2ZWxvcGVy
# MS4wLAYDVQQDDCVPcGVuIFNvdXJjZSBEZXZlbG9wZXIgVGhvbWFzIE5hdW5oZWlt
# MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAphp2ljSmVsRB6gvkEq7A
# DUMENpKZiDFoAfF1ktD1nCwaVyI+bJ0ROjHwAn4iJgS+vlBDPOUIw2GLHkiqUhOg
# HSwzg6gj45GNmt6zxsKP0zPlhMB/fb0zmz7/F7e3yfKCXLfhbHuk0Es9gJ+8Wmet
# 9StVwwSE/K0MpW06GKA9nPWyE4N/ADwigDIj9rsTKJR4cve9w8G1b3zohpUc/qMr
# onab+HVw5r9b3sOBnnaXC6zvrX4fovRz1ztwfWjRjILLoFG6mW/TuK5F2ICD3Rhl
# 9R2rJWWWhzTDMsQlzvX+/SaM74q3OFpIVNdhvtmWU9pKUBRAyYMijcDqKEFGSzrc
# 8JFmGMpP5TuroWF+N21d3px2eARvW1mV0DCfFAH+Og20SH/gVW6/ltQQEkH/z/Zt
# 49ARyJrgESLOQtlMCIYSoKISdkk4ml4VUS1E/PcbzXEYj3a7m6DOxcd3WuY03UT9
# cnk3p0LMN6LeLYAZgVY+HRloZlH+kW2SkOHNuWgtXvZhAgMBAAGjggF4MIIBdDAM
# BgNVHRMBAf8EAjAAMD0GA1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly9jY3NjYTIwMjEu
# Y3JsLmNlcnR1bS5wbC9jY3NjYTIwMjEuY3JsMHMGCCsGAQUFBwEBBGcwZTAsBggr
# BgEFBQcwAYYgaHR0cDovL2Njc2NhMjAyMS5vY3NwLWNlcnR1bS5jb20wNQYIKwYB
# BQUHMAKGKWh0dHA6Ly9yZXBvc2l0b3J5LmNlcnR1bS5wbC9jY3NjYTIwMjEuY2Vy
# MB8GA1UdIwQYMBaAFN10XUwA23ufoHTKsW73PMAywHDNMB0GA1UdDgQWBBTBvGyH
# MXj1dMbVnxuof9oP4PY7cDBLBgNVHSAERDBCMAgGBmeBDAEEATA2BgsqhGgBhvZ3
# AgUBBDAnMCUGCCsGAQUFBwIBFhlodHRwczovL3d3dy5jZXJ0dW0ucGwvQ1BTMBMG
# A1UdJQQMMAoGCCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsF
# AAOCAgEAkC165c7/r6y3VeEEpNXas9bQs6ZpKPdJffHkf9xoPi4kWvAIWGc4ocG1
# DJLb18RXiDYShDmT5sb/6I08FeipKi2DNJkuOq6yOTJ3S7+hNFIZCyd6i7WKO8ea
# P5I+FAbyJP4+5coZoMg45bUa9JoocaJCm+5n7WiCfN7/EQpClW5Trm4+ZMbp7EMN
# F1uLJgGCMnN0SsoUarp7PHlqupMxMC4Uhhe+lAP2ytcSIU81L97/qjrADbLWqICk
# 9il5iGM+aZndguq/cmfH9rJj4GRZHWnG6WwnzYD9+KgYlRI6em+/9dq+IRiXe2Bs
# thUuIaFW7U2gWw8tBTEYm1UBLHdJx+L1gjJCLs5KT/wy5wU32wZxNDqPUQejUC1x
# GvU3cKqmLgRq+yNf3gFVfzqIoggyM3U9wQvnk7nBtCkpjXS2hdx4yxzcmrlWsDHr
# z6+6/jeyQySzbYUlFmKnc4n9Mw2soHOajEua5poFARVRS5KgUBuiiQ21YFNYzWBo
# qGuECaaAI/C5rGxapMJ3dAOBnHw6NLqBet+ZXBJEccX5y89MLlOQu+jDmJP8HieR
# qDLlwfhVZnw4RY8Rus43NZBwhNlVuOUXqocHKmJhKNlekda3qsJj93eQBQOxKJcc
# w5O08q9jukpH2+yzFAj+7ll33DuNUgWptogc4Awtbx3glzcEvJQwggaCMIIEaqAD
# AgECAhAo8HfBHDa9/l90MkdwJy4DMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYT
# AlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMT
# G0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQTAeFw0yNjAzMTEwNzM0NTRaFw0z
# NjAyMjcwNzM0NTRaMFAxCzAJBgNVBAYTAlBMMSEwHwYDVQQKDBhBc3NlY28gRGF0
# YSBTeXN0ZW1zIFMuQS4xHjAcBgNVBAMMFUNlcnR1bSBUaW1lc3RhbXAgMjAyNjCC
# AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALi9zfBw+xI12hi2F9uNQBNO
# STkTIi13fuh3DiWybI5392bBfJw6tO7zDs7UqP/rejVf4xFTU3XNOPsuOFkP5SPF
# snWwn3VJL+NhNhsuujvYsQtaQnvNo1wk46reTgws1L8OFEdKaxgyqT4zOQx81mLw
# NZSqXNU9Rrb9oAJWJF4Mydz+C1ebu0D0+vgM3tqAQ8TU203fqgKCPqIdHloaFqH9
# eyR+8tnpmy2hnnN59ZOtmsuHeRwf5iTOhlhf0d/qqquLOSIGPgGVL1Hj5XBUox2O
# E7tQRr+l/xxNbL6OuwBO4Aa2EbuxYg37cpXv5i2/lTL4NASB/duf9W4fjA3Ro+GP
# +bC54n2OYiM3Cq8z92ejx8F5HWO2e4/75eC95B9tMw/eq7109GDyW2+2ut5Bn0o8
# MXJTERkyystWbqcnUkomA97qfiDCwvpWuOMdfTOksXe9S+xDxOJaCbiyTivgPulx
# cT+tfQTRXBr5UwtPvc+INnafOEilzVHA11tv+pHcylryxBc08cUihf/ttqkZS0bm
# x3VxQay8uohaTp0//ECA9vYGW51SKdJMJhXvKyIdBLy8WYNchTt8yRITv9Adxg9J
# qGujh+TnP1bW3aQjFtlEl7SzgNeI8OVA/CJAWWUuRT3Au9ToOpHy/flrrknhN4he
# Ew7/6ILMv4HSsj0YZ4otAgMBAAGjggFQMIIBTDB1BggrBgEFBQcBAQRpMGcwOwYI
# KwYBBQUHMAKGL2h0dHA6Ly9zdWJjYS5yZXBvc2l0b3J5LmNlcnR1bS5wbC9jdHNj
# YTIwMjEuY2VyMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0u
# Y29tMB8GA1UdIwQYMBaAFL5UAi+/QGxzQ86sCSVOnkNEGu7gMAwGA1UdEwEB/wQC
# MAAwOQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL3N1YmNhLmNybC5jZXJ0dW0ucGwv
# Y3RzY2EyMDIxLmNybDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8E
# BAMCB4AwIgYDVR0gBBswGTAIBgZngQwBBAIwDQYLKoRoAYb2dwIFAQswHQYDVR0O
# BBYEFCM5aiirmhKnpKfyH/lFmr+N/oIDMA0GCSqGSIb3DQEBDAUAA4ICAQBm/pOb
# rAveTqYFPCSthxNVwBHTW4TfuBQY2KGCdMlH6ALjVPYf2XARNGMTXScR0JQ2/c2L
# xLpoHHhRwxFf3d933DhFS165rYj6iPSQKm41rc9AMpTCjMdmai1aK9o870pOzTzL
# RhWFVIxm+5Qf+t4V5z14tPoUsAWdfRKD1Zzvzfe5AHlE9rxOZcGROiULxs3Edf7Z
# J8RZI0jzD9juj2oEX2XS7BVKuNCK1W0h1mjapv028yqo8UtZh5/1Ib48Yyp88BDY
# Shh5PSGUUuS5tYXVfcduIPBe3PdNTYRYdT5VNxkwLgjMzIcr/6SH2fejFJDjnCxj
# vXLuarErJg/IdI+hXdGIBDVOGv1zrkF4ktoQvFZIp5DIAYh0GwyUhc87qqn5UaYT
# j2+iyiBDSNh7aGCrkuAnqg7Qh7frhX+QhMGeJ9SpLpnG76qN85hLyjvYR6gRYiLT
# j8G4fxjqV400/buPw0rBo9yJZyq/8cGdCOLPOYf9qpefTcrZKeO9pg+UJHx8UABb
# aTqizRxm8sUSEycccCCFhIit3AI/3wGuSOADeiA676NcQ7+dsP04YvzvdN7pTZNy
# g672WpBDJdg0eItHl4yomvNeIOWh1qs4QqOW6TI8Ocsi4uSDTLorxLUDnBTwKQzz
# pxd1YUctEgRh32R0J9FkFkeEruJU94RljFr1uDCCBrkwggShoAMCAQICEQCZo4AK
# JlU7ZavcboSms+o5MA0GCSqGSIb3DQEBDAUAMIGAMQswCQYDVQQGEwJQTDEiMCAG
# A1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVt
# IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3Rl
# ZCBOZXR3b3JrIENBIDIwHhcNMjEwNTE5MDUzMjE4WhcNMzYwNTE4MDUzMjE4WjBW
# MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu
# MSQwIgYDVQQDExtDZXJ0dW0gQ29kZSBTaWduaW5nIDIwMjEgQ0EwggIiMA0GCSqG
# SIb3DQEBAQUAA4ICDwAwggIKAoICAQCdI88EMCM7wUYs5zNzPmNdenW6vlxNur3r
# Lfi+5OZ+U3iZIB+AspO+CC/bj+taJUbMbFP1gQBJUzDUCPx7BNLgid1TyztVLn52
# NKgxxu8gpyTr6EjWyGzKU/gnIu+bHAse1LCitX3CaOE13rbuHbtrxF2tPU8f253Q
# gX6eO8yTbGps1Mg+yda3DcTsOYOhSYNCJiL+5wnjZ9weoGRtvFgMHtJg6i671OPX
# IciiHO4Lwo2p9xh/tnj+JmCQEn5QU0NxzrOiRna4kjFaA9ZcwSaG7WAxeC/xoZSx
# F1oK1UPZtKVt+yrsGKqWONoK6f5EmBOAVEK2y4ATDSkb34UD7JA32f+Rm0wsr5aj
# zftDhA5mBipVZDjHpwzv8bTKzCDUSUuUmPo1govD0RwFcTtMXcfJtm1i+P2UNXad
# PyYVKRxKQATHN3imsfBiNRdN5kiVVeqP55piqgxOkyt+HkwIA4gbmSc3hD8ke66t
# 9MjlcNg73rZZlrLHsAIV/nJ0mmgSjBI/TthoGJDydekOQ2tQD2Dup/+sKQptalDl
# ui59SerVSJg8gAeV7N/ia4mrGoiez+SqV3olVfxyLFt3o/OQOnBmjhKUANoKLYlK
# mUpKEFI0PfoT8Q1W/y6s9LTI6ekbi0igEbFUIBE8KDUGfIwnisEkBw5KcBZ3XwnH
# mfznwlKo8QIDAQABo4IBVTCCAVEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
# 3XRdTADbe5+gdMqxbvc8wDLAcM0wHwYDVR0jBBgwFoAUtqFUOQLDoD+Oirz61Pgc
# ptE6Dv0wDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDAGA1Ud
# HwQpMCcwJaAjoCGGH2h0dHA6Ly9jcmwuY2VydHVtLnBsL2N0bmNhMi5jcmwwbAYI
# KwYBBQUHAQEEYDBeMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0
# dW0uY29tMDIGCCsGAQUFBzAChiZodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwv
# Y3RuY2EyLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0
# cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBDAUAA4ICAQB1iFgP5Y9Q
# KJpTnxDsQ/z0O23JmoZifZdEOEmQvo/79PQg9nLF/GJe6ZiUBEyDBHMtFRK0mXj3
# Qv3gL0sYXe+PPMfwmreJHvgFGWQ7XwnfMh2YIpBrkvJnjwh8gIlNlUl4KENTK5DL
# qsYPEtRQCw7R6p4s2EtWyDDr/M58iY2UBEqfUU/ujR9NuPyKk0bEcEi62JGxauFY
# zZ/yld13fHaZskIoq2XazjaD0pQkcQiIueL0HKiohS6XgZuUtCKA7S6CHttZEsOb
# QJ1j2s0urIDdqF7xaXFVaTHKtAuMfwi0jXtF3JJphrJfc+FFILgCbX/uYBPBlbBI
# P4Ht4xxk2GmfzMn7oxPITpigQFJFWuzTMUUgdRHTxaTSKRJ/6Uh7ki/pFjf9sUAS
# WgxT69QF9Ki4JF5nBIujxZ2sOU9e1HSCJwOfK07t5nnzbs1LbHuAIGJsRJiQ6HX/
# DW1XFOlXY1rc9HufFhWU+7Uk+hFkJsfzqBz3pRO+5aI6u5abI4Qws4YaeJH7H7M8
# X/YNoaArZbV4Ql+jarKsE0+8XvC4DJB+IVcvC9Ydqahi09mjQse4fxfef0L7E3hh
# o2O3bLDM6v60rIRUCi2fJT2/IRU5ohgyTch4GuYWefSBsp5NPJh4QRTP9DC3gc5Q
# EKtbrTY0Ka87Web7/zScvLmvQBm8JDFpDjCCBrkwggShoAMCAQICEQDn/2nHOzXO
# S5Em2HR8aKWHMA0GCSqGSIb3DQEBDAUAMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UE
# ChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl
# cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBO
# ZXR3b3JrIENBIDIwHhcNMjEwNTE5MDUzMjA3WhcNMzYwNTE4MDUzMjA3WjBWMQsw
# CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQw
# IgYDVQQDExtDZXJ0dW0gVGltZXN0YW1waW5nIDIwMjEgQ0EwggIiMA0GCSqGSIb3
# DQEBAQUAA4ICDwAwggIKAoICAQDpEh8ENe25XXrFppVBvoplf0530W0lddNmjtv4
# YSh/f7eDQKFaIqc7tHj7ox+u8vIsJZlroakUeMS3i3T8aJRC+eQs4FF0GqvkM6+W
# ZO8kmzZfxmZaBYmMLs8FktgFYCzywmXeQ1fEExflee2OpbHVk665eXRHjH7MYZIz
# Nnjl2m8Hy8ulB9mR8wL/W0v0pjKNT6G0sfrx1kk+3OGosFUb7yWNnVkWKU4qSxLv
# 16kJ6oVJ4BSbZ4xMak6JLeB8szrK9vwGDpvGDnKCUMYL3NuviwH1x4gZG0JAXU3x
# 2pOAz91JWKJSAmRy/l0s0l5bEYKolg+DMqVhlOANd8Yh5mkQWaMEvBRE/kAGzIqg
# WhwzN2OsKIVtO8mf5sPWSrvyplSABAYa13rMYnzwfg08nljZHghquCJYCa/xHK9a
# cev9UD7Y+usr15d7mrszzxhF1JOr1Mpup2chNSBlyOObhlSO16rwrffVrg/SzaKf
# SndS5swRhr8bnDqNJY9TNyEYvBYpgF95K7p0g4LguR4A++Z1nFIHWVY5v0fNVZmg
# zxD9uVo/gta3onGOQj3JCxgYx0KrCXu4yc9QiVwTFLWbNdHFSjBCt5/8Q9pLuRhV
# ocdCunhcHudMS1CGQ/Rn0+7P+fzMgWdRKfEOh/hjLrnQ8BdJiYrZNxvIOhM2aa3z
# EDHNwwIDAQABo4IBVTCCAVEwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUvlQC
# L79AbHNDzqwJJU6eQ0Qa7uAwHwYDVR0jBBgwFoAUtqFUOQLDoD+Oirz61PgcptE6
# Dv0wDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMDAGA1UdHwQp
# MCcwJaAjoCGGH2h0dHA6Ly9jcmwuY2VydHVtLnBsL2N0bmNhMi5jcmwwbAYIKwYB
# BQUHAQEEYDBeMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1jZXJ0dW0u
# Y29tMDIGCCsGAQUFBzAChiZodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvY3Ru
# Y2EyLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0cDov
# L3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBDAUAA4ICAQC4k1l3yUwV/ZQH
# CKCneqAs8EGTnwEUJLdDpokN/dMhKjK0rR5qX8nIIHzxpQR3TAw2IRw1Uxsr2Pli
# G3bCFqSdQTUbfaTq6V3vBzEebDru9QFjqlKnxCF2h1jhLNFFplbPJiW+JSnJTh1f
# KEqEdKdxgl9rVTvlxfEJ7exOn25MGbd/wGPwuSmMxRJVO0wnqgS7kmoJjNF9zqee
# hFSDDP8ZVkWg4EZ2tIS0M3uZmByRr+1Lkwjjt8AtW83mVnZTyTsOb+FNfwJY7DS4
# FmWhkRbgcHRetreoTirPOr/ozyDKhT8MTSTf6Lttg6s6T/u08mDWw6HK04ZRDfQ9
# sb77QV8mKgO44WGP31vXnVKoWVJpFBjPvjL8/Zck/5wXX2iqjOaLStFOR/IQki+E
# hn4zlcgVm22ZVCBPF+l8nAwUUShCtKuSU7GmZLKCmmxQMkSiWILTm8EtVD6AxnJh
# oq8EnhjEEyUoflkeRF2WhFiVQOmWTwZRr44IxWGkNJC6tTorW5rl2Zl+2e9JLPYf
# 3pStAPMDoPKIjVXd6NW2+fZrNUBeDo2eOa5Fn7Brs/HLQff5Xgris5MeUbdVgDrF
# 8uxO6cLPvZPo63j62SsNg55pTWk9fUIF9iPoRbb4QurjoY/woI1RAOKtYtTic6aA
# Jq3u83RIPpGXBSJKwx4KJAOZnCDCtTGCBqIwggaeAgEBMGowVjELMAkGA1UEBhMC
# UEwxITAfBgNVBAoTGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjEkMCIGA1UEAxMb
# Q2VydHVtIENvZGUgU2lnbmluZyAyMDIxIENBAhBX5gfP8LabvnxCXoItEBa/MA0G
# CWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZI
# hvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcC
# ARUwLwYJKoZIhvcNAQkEMSIEIMLZJ39JxiO+RnpSm9jOxN1DtpBCf1gBAV6IMPeg
# YYbuMA0GCSqGSIb3DQEBAQUABIIBgH9LGX8rqQoQ8RgGIyupzFsMenUzMhK+nmoV
# mDvwaIMZBW1JTaEJBQbviWD3oOT8k+M2yvCOf0mUBOguCn1sMKNy3WLYyprrQ98/
# lp+fwRvCfRMyeP8Xnn69Dwv3DH4EQjTZ6Nyg17gUTxNkKakjTvCiCn/zsI0UVwbu
# 0lPJ0OgylOf/VFTyqUrryhlPPTwyWN4WwWLfpUUuZ7YP6tQHbU4kLFqW7LoqKEi+
# G1aOP34PWVruv3Fb+TYzCUcBsSFvZCbPhwHBYwwYQLYaakLq4hsRNF2OeEQH3i3l
# S8/ZUQGoi0zaHO4ycmxlAuhx7MCPme8jQonLNMv9wan5jhAEi22lyQEh2gMJ0+6H
# 5DssCAIbtjk3BO5YOLhdB5HXbIl6ohTJWX2fXbTKHJmYr4aXvUiH/SBhth9kpMBO
# XjrtWro/whUWHQPqYESVYTLGCNOe+W+IjM02oyFZuCjyFF9CCrLXHEZLRXKkBZX1
# 81/GVfYVk4cSCyaOg+MffViZqBW3FKGCBAIwggP+BgkqhkiG9w0BCQYxggPvMIID
# 6wIBATBqMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0
# ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQQIQ
# KPB3wRw2vf5fdDJHcCcuAzANBglghkgBZQMEAgIFAKCCAVYwGgYJKoZIhvcNAQkD
# MQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNjEwMTMwOTQyMDNaMDcG
# CyqGSIb3DQEJEAIvMSgwJjAkMCIEIIW+kOEK0kONfMkotq9IsJqyCBd87PiwEmxY
# 05EFJcQ8MD8GCSqGSIb3DQEJBDEyBDDpptUoZIrgm6fkvKAhCdXERe9QqrP+0SDt
# 4Y3vJL1Hor1s7XPyi8L9u0XBPvjbjK8wgZ8GCyqGSIb3DQEJEAIMMYGPMIGMMIGJ
# MIGGBBRXFGhBDKha80JO+RZKUTYQ9NONmDBuMFqkWDBWMQswCQYDVQQGEwJQTDEh
# MB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQwIgYDVQQDExtDZXJ0
# dW0gVGltZXN0YW1waW5nIDIwMjEgQ0ECECjwd8EcNr3+X3QyR3AnLgMwDQYJKoZI
# hvcNAQEBBQAEggIAinEtI1D4DNGRz/VzhyiN2nF25X5wrnvUMFkikC30ZbdRWQ2n
# Kaaaj5VibYeRb6We1JTXzIc/MWWE+lZg4+GswckmbV+z46fojDHERWMT5etc3osi
# uMiFe3oaY3+0lDOSWyw4eBT4jb7nZI5INFQFPrxLAeAM+kj8CMEioYvOkSeVnxij
# 7VRE4ogQOMIX4C0zjME77ng7fQwBzyukAbDFpfv+Vl6XCTBEVr2m/A31/5IYtsC7
# mqz0ja0TWFOmrZhpyG4cK7eG2qbjdX9FnyGbJVyKC0PJopqlvUyaYxpG/emOF1gs
# EUFupCKF6Xed0KnLWiGVKn6z+USGijGO5x1AZ0PArtrp//eM+S+rwg9Ix9fyRq+4
# llfFZx422L6WeDdIRkFPeNUrHHqFnYozJq5YQ7MuFUeY3gzJ2pjWr0qyQzlKNFK1
# vqwRrcpsiR06iijDMYZPYMutC0l3Dw3OFglREeCnQTkOQBhWO6bVO5TIdFPYaf2m
# XNCHvotgNa7QpxdhLJAchbPWxaGxNKKigC5E0H6N121CoAlnwU0EMT/TWey3IGh7
# nVXU6kZQwFw4n1f+ZXFG5S3zyt5YLFm++zgfKhaSUUC/OF9YeY4WqTjZ+m2iBPyY
# cORll9VQ2sJ+ewGzBT4UeRTyW8cLUDA5ZbyBVsqcon4G5/F5gQFjWSE2RAY=
# SIG # End signature block