Public/PrivilegedAccess/Save-EntraOpsPrivilegedEAMJson.ps1
|
<# .SYNOPSIS Export and save EntraOps Privileged EAM data to JSON files. .DESCRIPTION Get information from EntraOps about classification based on Enterprise Access Model and save them as JSON to folder. .PARAMETER ExportFolder Folder where the JSON files should be stored. Default is ./PrivilegedEAM. .PARAMETER RbacSystems Array of RBAC systems to be processed. Default is Azure, AzureBilling, EntraID, IdentityGovernance, DeviceManagement, ResourceApps. .PARAMETER UseCache Use existing cache instead of clearing it before analysis. Default is $false (cache is cleared for fresh data). Set to $true to leverage cached data from previous calls for better performance. .PARAMETER DefaultCacheTTL Cache TTL (in seconds) for regular API responses during this execution. Default is 7200 (2 hours). If not specified, uses 2 hours for this execution and restores session value afterwards. .PARAMETER StaticDataCacheTTL Cache TTL (in seconds) for static data like role definitions during this execution. Default is 7200 (2 hours). If not specified, uses 2 hours for this execution and restores session value afterwards. .PARAMETER ExportFailedRequests Export details of failed requests (Uri, StatusCode, ErrorMessage, Category) to a local FailedRequests_*.json file in the export folder. Category is either "ExhaustedRetries" (a request retried the maximum number of times for a transient/throttling condition and still failed) or "NonRetryable" (an expected data condition, e.g. a deleted access package catalog or a group not enabled for PIM for Groups). Default is $false, so no file is written locally by default. .PARAMETER IncludeJustification Include the Justification property (documenting a manual classification overwrite) on all Classification entries of the exported objects. Default is $false, so the property is not present in the export at all. .PARAMETER IncludeObjectDetails Include descriptive object details in console output. Defaults to ConsoleOutput.IncludeObjectDetails from EntraOpsConfig.json. Object IDs are always shown. .EXAMPLE Export and save JSON files of EntraOps to default folder Save-EntraOpsPrivilegedEAMJson .EXAMPLE Export using cached data for better performance Save-EntraOpsPrivilegedEAMJson -UseCache $true .EXAMPLE Run with custom cache TTL of 6 hours Save-EntraOpsPrivilegedEAMJson -DefaultCacheTTL 21600 -StaticDataCacheTTL 21600 .EXAMPLE Export failed request details to a local FailedRequests_*.json file Save-EntraOpsPrivilegedEAMJson -ExportFailedRequests $true #> function Save-EntraOpsPrivilegedEAMJson { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] [System.String]$ExportFolder = $DefaultFolderClassifiedEam , [Parameter(Mandatory = $False)] [ValidateSet("Azure", "EntraID", "IdentityGovernance", "DeviceManagement", "ResourceApps", "Defender")] [Array]$RbacSystems = ("Azure", "EntraID", "IdentityGovernance", "DeviceManagement", "ResourceApps", "Defender") , [Parameter(Mandatory = $false)] [System.Boolean]$UseCache = $false , [Parameter(Mandatory = $False)] [System.Int32]$DefaultCacheTTL = 7200 # Default is 2 hours for this cmdlet , [Parameter(Mandatory = $False)] [System.Int32]$StaticDataCacheTTL = 7200 # Default is 2 hours for this cmdlet , [Parameter(Mandatory = $False)] [System.Boolean]$ExportFailedRequests = $false , [Parameter(Mandatory = $False)] [System.Boolean]$IncludeObjectDetails = [bool]$Global:EntraOpsIncludeObjectDetails , [Parameter(Mandatory = $False)] [switch]$IncludeJustification ) # Store original TTL values to restore after execution $OriginalDefaultTTL = $__EntraOpsSession.DefaultCacheTTL $OriginalStaticTTL = $__EntraOpsSession.StaticDataCacheTTL # Use provided values (default 2 hours for this cmdlet) $EffectiveDefaultTTL = $DefaultCacheTTL $EffectiveStaticTTL = $StaticDataCacheTTL # Set TTL values for this execution $__EntraOpsSession.DefaultCacheTTL = $EffectiveDefaultTTL $__EntraOpsSession.StaticDataCacheTTL = $EffectiveStaticTTL # Notify user about TTL changes if ($EffectiveDefaultTTL -ne $OriginalDefaultTTL -or $EffectiveStaticTTL -ne $OriginalStaticTTL) { Write-Host "" Write-Host "════════════════════════════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host " ⏱️ Cache TTL Modified for This Execution" -ForegroundColor Cyan Write-Host "════════════════════════════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host " Default Cache TTL : $([Math]::Round($EffectiveDefaultTTL / 3600, 1)) hours (was $([Math]::Round($OriginalDefaultTTL / 3600, 1)) hours)" -ForegroundColor Yellow Write-Host " Static Data Cache TTL: $([Math]::Round($EffectiveStaticTTL / 3600, 1)) hours (was $([Math]::Round($OriginalStaticTTL / 3600, 1)) hours)" -ForegroundColor Yellow Write-Host " ℹ️ Cache will be restored to original values after completion" -ForegroundColor Gray Write-Host "════════════════════════════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host "" } try { if (-not $UseCache) { Write-Output "Clearing cache before analyzing RBAC and classification data" Clear-EntraOpsCache } else { Write-Output "Using existing cache for analysis (UseCache = $true)" Write-Verbose "Current cache contains $($__EntraOpsSession.GraphCache.Count) entries" } #region Entra ID if ($RbacSystems -contains "EntraID") { $EamAzureAD = Get-EntraOpsPrivilegedEAMEntraId -IncludeJustification:$IncludeJustification -IncludeObjectDetails $IncludeObjectDetails Save-EntraOpsEAMRbacSystemJson -ExportFolder "$($ExportFolder)/EntraID" -RbacSystemName "EntraID" -EamData $EamAzureAD -AggregateFileName "EntraID.json" } #endregion #region Entra Resource Apps if ($RbacSystems -contains "ResourceApps") { $EamAzureAdResourceApps = Get-EntraOpsPrivilegedEAMResourceApps -IncludeJustification:$IncludeJustification -IncludeObjectDetails $IncludeObjectDetails Save-EntraOpsEAMRbacSystemJson -ExportFolder "$($ExportFolder)/ResourceApps" -RbacSystemName "ResourceApps" -EamData $EamAzureAdResourceApps -AggregateFileName "ResourceApps.json" } #endregion #region Device Management if ($RbacSystems -contains "DeviceManagement") { $EamDeviceMgmt = Get-EntraOpsPrivilegedEAMIntune -IncludeJustification:$IncludeJustification -IncludeObjectDetails $IncludeObjectDetails Save-EntraOpsEAMRbacSystemJson -ExportFolder "$($ExportFolder)/DeviceManagement" -RbacSystemName "DeviceManagement" -EamData $EamDeviceMgmt -AggregateFileName "DeviceManagement.json" } #endregion #region Identity Governance if ($RbacSystems -contains "IdentityGovernance") { $EamIdGov = Get-EntraOpsPrivilegedEAMIdGov -IncludeJustification:$IncludeJustification -IncludeObjectDetails $IncludeObjectDetails Save-EntraOpsEAMRbacSystemJson -ExportFolder "$($ExportFolder)/IdentityGovernance" -RbacSystemName "IdentityGovernance" -EamData $EamIdGov -AggregateFileName "IdentityGovernance.json" } #endregion #region Defender if ($RbacSystems -contains "Defender") { $EamDefender = Get-EntraOpsPrivilegedEAMDefender -IncludeJustification:$IncludeJustification -IncludeObjectDetails $IncludeObjectDetails Save-EntraOpsEAMRbacSystemJson -ExportFolder "$($ExportFolder)/Defender" -RbacSystemName "Defender" -EamData $EamDefender -AggregateFileName "Defender.json" } #endregion #region Azure # Azure RBAC is collected last so classification of managed identities (resolved from the other RBAC # systems) is available beforehand. Get-EntraOpsPrivilegedEAMAzure uses the Azure (Get-AzContext) tenant. if ($RbacSystems -contains "Azure") { $EamAzure = Get-EntraOpsPrivilegedEAMAzure -IncludeJustification:$IncludeJustification -IncludeObjectDetails $IncludeObjectDetails Save-EntraOpsEAMRbacSystemJson -ExportFolder "$($ExportFolder)/Azure" -RbacSystemName "Azure" -EamData $EamAzure -AggregateFileName "Azure.json" } #endregion # Display Throttle Statistics Summary if ($__EntraOpsSession.ContainsKey('RetryStatistics') -and ($__EntraOpsSession.RetryStatistics.TotalRetries -gt 0 -or $__EntraOpsSession.RetryStatistics.FailedRequests -gt 0 -or $__EntraOpsSession.RetryStatistics.NonRetryableRequests -gt 0)) { Write-Host "" Write-Host "═══════════════════════════════════════════════════════════════════════════════" -ForegroundColor Yellow Write-Host " ⚠ API Throttling Summary" -ForegroundColor Yellow Write-Host "═══════════════════════════════════════════════════════════════════════════════" -ForegroundColor Yellow $Stats = $__EntraOpsSession.RetryStatistics Write-Host " Total Retries : $($Stats.TotalRetries)" -ForegroundColor Yellow Write-Host " Throttled Requests : $($Stats.ThrottledRequests)" -ForegroundColor Yellow # Requests that failed immediately on a non-retryable status (404 for a deleted access # package catalog/directory object, 400 for a group not enabled for PIM for Groups, etc.). # These are expected data conditions the caller already accounts for (falls back or logs a # dedicated warning), so they are reported for visibility only and never fail the run. if ($Stats.NonRetryableRequests -gt 0) { Write-Host " ℹ Non-Retryable Requests (expected, e.g. deleted/unsupported resources): $($Stats.NonRetryableRequests)" -ForegroundColor Yellow } $FailedRequestDetails = @($Stats.FailedRequestDetails) $NonRetryableRequestDetails = @($Stats.NonRetryableRequestDetails) $AllRequestDetails = @($FailedRequestDetails | ForEach-Object { $_ | Add-Member -NotePropertyName Category -NotePropertyValue "ExhaustedRetries" -Force -PassThru }) + @($NonRetryableRequestDetails | ForEach-Object { $_ | Add-Member -NotePropertyName Category -NotePropertyValue "NonRetryable" -Force -PassThru }) $ExportedLogPath = $null if ($AllRequestDetails.Count -gt 0 -and $ExportFailedRequests) { $ExportedLogPath = Join-Path -Path $ExportFolder -ChildPath "FailedRequests_$(Get-Date -Format 'yyyyMMdd_HHmmss').json" $AllRequestDetails | Sort-Object Timestamp | ConvertTo-Json -Depth 5 | Out-File -FilePath $ExportedLogPath -Force Write-Host " Details exported to : $ExportedLogPath" -ForegroundColor Yellow Write-Host "" } if ($NonRetryableRequestDetails.Count -gt 0) { Write-Host " Non-retryable request(s):" -ForegroundColor Yellow # Grouped by (StatusCode, GUID-normalized Uri) so e.g. 30 deleted Access Package Catalogs # collapse into a single summarized line instead of one line per catalog ID. foreach ($Group in (Group-EntraOpsRequestDetailsByUriTemplate -RequestDetails $NonRetryableRequestDetails | Sort-Object StatusCode, NormalizedUri)) { Write-EntraOpsGroupedRequestDetail -Group $Group -Color "Yellow" -DetailColor "DarkYellow" -IncludeObjectDetails $IncludeObjectDetails } } if ($Stats.FailedRequests -gt 0) { Write-Host " ❌ Failed Requests : $($Stats.FailedRequests)" -ForegroundColor Red if ($FailedRequestDetails.Count -gt 0) { Write-Host " Failed request(s):" -ForegroundColor Red foreach ($Group in (Group-EntraOpsRequestDetailsByUriTemplate -RequestDetails $FailedRequestDetails | Sort-Object StatusCode, NormalizedUri)) { Write-EntraOpsGroupedRequestDetail -Group $Group -Color "Red" -DetailColor "DarkRed" -IncludeObjectDetails $IncludeObjectDetails } } # Intended non-terminating post-export summary (exports above already completed); # -ErrorAction Continue keeps these Write-Error calls non-terminating despite the # module-wide $ErrorActionPreference = "Stop" if ($ExportedLogPath) { Write-Error "Some requests failed completely after exhausting retries. See '$ExportedLogPath' for details." -ErrorAction Continue } else { Write-Error "Some requests failed completely after exhausting retries. Re-run with -ExportFailedRequests `$true to export details to a local JSON file." -ErrorAction Continue } } elseif ($Stats.NonRetryableRequests -eq 0) { Write-Host " ✓ All requests succeeded after retries" -ForegroundColor Green } Write-Host "═══════════════════════════════════════════════════════════════════════════════" -ForegroundColor Yellow Write-Host "" } } finally { # Restore original TTL values $__EntraOpsSession.DefaultCacheTTL = $OriginalDefaultTTL $__EntraOpsSession.StaticDataCacheTTL = $OriginalStaticTTL Write-Verbose "Cache TTL restored to original values: Default=$([Math]::Round($OriginalDefaultTTL / 3600, 1))h, Static=$([Math]::Round($OriginalStaticTTL / 3600, 1))h" } } # SIG # Begin signature block # MIIniAYJKoZIhvcNAQcCoIIneTCCJ3UCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD9pazr0ALD1pHN # 8FEHniufs63+c7oD5R29KTKpzFv6QqCCIDwwggXJMIIEsaADAgECAhAbtY8lKt8j # 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 # ARUwLwYJKoZIhvcNAQkEMSIEIBzuwQfkwZ9skgN9uWfiZJZQieUCNNrhxZGsyX2C # tCQ8MA0GCSqGSIb3DQEBAQUABIIBgFOuZqOaHp2KZ53Hrt6rgOkIhh06PQ5QnrR+ # ooxnM2TcayvtMQYKDr13JaulOo1KddWo2N3qs1lvJfi6z3sv8wMSsicvvhe4iVas # 4Pln6oSlVi8Jimg3ubcE/Y4dOl9bp9soYhJm4W6v7iia65W4VyDFZVJ82uOUEyPT # BcJWn9XtKm55sJ7i/e6B6EodpmBMKo2y/OAgoaNKTjKXAZ3qVGgTLxutq/F/bIp+ # ZSWjWEq8TlrOJuj1IxSynEXWpPgCt88xvQoqB/4HmlGIEdvNAZcv4F8tJ/lfqraj # JMaWTwZNIW7nT5Ev7q/R5PCNvo5MCXjQlqJEvvRNFKv5kwzAUdbysh3xWLzockuv # tfZKKUpPJ0ev1rF0eD8rEeUfeRZDqe5fFSb9Y5LKYokfIv/24bbWoDNtN3m3BgLe # S27aD8s1mtnVDKAOA3JllkxIK6tJPxmaUMEDQs97k5nwMbXIx3zzJsTMr+NL7pt3 # IpmSCptFwViuTnTkVDIvxvdas3gcUqGCBAIwggP+BgkqhkiG9w0BCQYxggPvMIID # 6wIBATBqMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0 # ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQQIQ # KPB3wRw2vf5fdDJHcCcuAzANBglghkgBZQMEAgIFAKCCAVYwGgYJKoZIhvcNAQkD # MQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNjEwMTMwOTQxMzdaMDcG # CyqGSIb3DQEJEAIvMSgwJjAkMCIEIIW+kOEK0kONfMkotq9IsJqyCBd87PiwEmxY # 05EFJcQ8MD8GCSqGSIb3DQEJBDEyBDCqLNY7duf0mwANsdMuRQsdBay91G5Z33X9 # wq9JKjeL5stZetr/XrfauXFruIvaq+UwgZ8GCyqGSIb3DQEJEAIMMYGPMIGMMIGJ # MIGGBBRXFGhBDKha80JO+RZKUTYQ9NONmDBuMFqkWDBWMQswCQYDVQQGEwJQTDEh # MB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQwIgYDVQQDExtDZXJ0 # dW0gVGltZXN0YW1waW5nIDIwMjEgQ0ECECjwd8EcNr3+X3QyR3AnLgMwDQYJKoZI # hvcNAQEBBQAEggIAW6IOEchGvg3s1GHYM5mNOGrO/oWdB29j0AwpiHwnG7oxqMtj # j4TtaSNMFhycOR4A2hVJ16iudLkPNGXLP46uP3X5eAnF7WoJf0wtnxnxevxLJL8R # 5HhSTrwz5Oh2X2fPKbZfCXyPOjsEcG5GxhIUXrbSmlFL+n8aUaXVHyjqDYfriPuz # K+visRKzWIqWGrd60G9XF/xW7IrK/kQpq1pfUPmwqSCeqs8oXEjfHINPuBwxES5u # LX7AKJCMJ9ifBRFAGlJtFwElaToobNcEMlIx6fQTOSv0b0l2RNbd2LHke7GA0t99 # BqIXwcht5DBO3Umjz7vDXUS+D7QIIFPc5HNQjhsAi766jPL7nqn++RWISU8vo0/A # XGD9jo8OdPVV42X9avZchh46nlJAQQCceqLDD2OA/2tMmZf6yUFsqxh+qDVbFzK1 # DMhjZsKjGDfaMJpFeSGGI03RM19fs7G8QimsKI4IiE2SDPovaRojckqbQDf+R5j9 # KF+8nAdtLMktszmQ3bKckGqQMqEfMkKpBDahEgGaeRpHiaolwkFSlZmOjMbwA6jQ # HdNVIHcaDNjFoSx7veDyqtmHfcfuJMXdCanHdOYsvlEf0tCERNGXcVvw5wB/HR9V # bmWYV3uwx3F0pjU0v3cfVOtPXZIZBaY1XeFrXUd9pCjnXnqv61HY/uTXy4M= # SIG # End signature block |