Public/PrivilegedAccess/Get-EntraOpsPrivilegedAzureRoles.ps1
|
<# .SYNOPSIS Get a list of Azure RBAC role assignments (Azure Resource Manager) including Azure PIM. .DESCRIPTION Get a list of Azure RBAC role assignments across the Azure Resource Manager (ARM) hierarchy. By default the collection starts at the ARM tenant root scope ("/") so that role assignments made directly at the tenant level are included, then expands to all descendant management groups and subscriptions to cover the entire tenant. The cmdlet uses the optimized ARM query wrapper (Invoke-EntraOpsAzQuery) to batch requests across all scopes and supports the same privileged-access concepts as the other EntraOps Roles cmdlets: - Azure PIM (eligible, activated and time-bounded active assignments) - Custom roles (RoleType BuiltInRole / CustomRole) - Constrained delegations (role assignment ABAC conditions returned in RoleAssignmentCondition / RoleAssignmentConditionVersion, or delegated managed identity) - Nested groups and PIM for Groups (transitive expansion of group assignments) .PARAMETER TenantId Tenant ID of the Microsoft Entra ID tenant. Default is the current tenant ID. .PARAMETER Scope ARM scope to collect role assignments from (e.g. a management group, subscription, resource group or resource). Default is "/" (ARM tenant root scope), which captures tenant-level role assignments and, when ExpandDescendantScopes is $true, all management groups and subscriptions beneath the Tenant Root Group. .PARAMETER ExpandDescendantScopes When the scope is a management group, expand to all descendant management groups and subscriptions to cover the entire sub-tree (tenant-wide by default). Default is $true. .PARAMETER ControlPlaneScopeFilter Optional array of ARM scope patterns (e.g. Control Plane RoleAssignmentScopeName hierarchies from Classification_Azure.json) used to restrict the collected scopes. After the scope sub-tree is resolved, only scopes that equal, are an ancestor of, or are a descendant of any of the provided patterns are queried. Wildcard patterns ("/" and "/*") are ignored because they would not constrain the scan. Default is an empty array (no filtering; full sub-tree is scanned). .PARAMETER PrincipalTypeFilter Filter for principal type. Default is User, Group, ServicePrincipal, ForeignGroup, AgentUser and AgentServicePrincipal. ForeignGroup and agent types are normalized by the downstream object resolver. .PARAMETER ExpandGroupMembers Expand group members for transitive role assignments (covers nested groups and PIM for Groups). Default is $true. .PARAMETER SampleMode Use sample data for testing or offline mode. Default is $False. .EXAMPLE Get all Azure RBAC role assignments across the entire tenant (Tenant Root Group and below). Get-EntraOpsPrivilegedAzureRoles .EXAMPLE Get Azure RBAC role assignments of a single subscription only. Get-EntraOpsPrivilegedAzureRoles -Scope "/subscriptions/00000000-0000-0000-0000-000000000000" -ExpandDescendantScopes $false .EXAMPLE Get Azure RBAC role assignments of a management group and all its descendant scopes. Get-EntraOpsPrivilegedAzureRoles -Scope "/providers/Microsoft.Management/managementGroups/Contoso-Platform" #> function Get-EntraOpsPrivilegedAzureRoles { param ( [Parameter(Mandatory = $False)] [System.String]$TenantId = (Get-EntraOpsAzContextValue -Property TenantId) , [Parameter(Mandatory = $False)] [System.String]$Scope , [Parameter(Mandatory = $False)] [System.Boolean]$ExpandDescendantScopes = $true , [Parameter(Mandatory = $False)] [Array]$ControlPlaneScopeFilter = @() , [Parameter(Mandatory = $False)] [ValidateSet("User", "Group", "ServicePrincipal", "ForeignGroup", "AgentUser", "AgentServicePrincipal")] [Array]$PrincipalTypeFilter = ("User", "Group", "ServicePrincipal", "ForeignGroup", "AgentUser", "AgentServicePrincipal") , [Parameter(Mandatory = $False)] [System.Boolean]$ExpandGroupMembers = $true , [Parameter(Mandatory = $false)] [System.Boolean]$SampleMode = $False , [Parameter(Mandatory = $False)] [System.Collections.Generic.List[psobject]]$WarningMessages ) # Set Error Action $ErrorActionPreference = "Stop" # Default to the ARM tenant root scope so tenant-level role assignments are included if ([string]::IsNullOrEmpty($Scope)) { $Scope = "/" } # ARM API versions $PimApiVersion = "2020-10-01" $RbacApiVersion = "2022-04-01" $MgmtApiVersion = "2020-05-01" $AzureRbacAssignments = @() if ($SampleMode -eq $True) { Write-Warning "Not supported yet!" return } #region Resolve the list of scopes to query (entire sub-tree for management groups) Write-Host "Get Azure RBAC role assignments starting at scope '$Scope'..." $Scopes = [System.Collections.Generic.List[string]]::new() $Scopes.Add($Scope) # When the scope is "/", expand descendants from the Tenant Root Group MG so all management # groups and subscriptions are covered in addition to the tenant-level "/" scope itself. if ($ExpandDescendantScopes -eq $True -and $Scope -eq "/") { $ManagementGroupName = $TenantId } elseif ($ExpandDescendantScopes -eq $True -and $Scope -like "*/providers/Microsoft.Management/managementGroups/*") { $ManagementGroupName = ($Scope -split '/managementGroups/')[-1] } else { $ManagementGroupName = $null } if ($ExpandDescendantScopes -eq $True -and $null -ne $ManagementGroupName) { try { $Descendants = Invoke-EntraOpsAzQuery -Uri "/providers/Microsoft.Management/managementGroups/$($ManagementGroupName)/descendants" -ApiVersion $MgmtApiVersion foreach ($Descendant in $Descendants) { if ($Descendant.type -eq "Microsoft.Management/managementGroups") { $Scopes.Add("/providers/Microsoft.Management/managementGroups/$($Descendant.name)") } elseif ($Descendant.type -like "*subscriptions") { $Scopes.Add("/subscriptions/$($Descendant.name)") } } } catch { $WarningMessage = "Could not expand descendant scopes of management group $($ManagementGroupName): $($_.Exception.Message)" if ($null -ne $WarningMessages) { $WarningMessages.Add([pscustomobject]@{ Timestamp = (Get-Date); Type = "ScopeExpansion"; ObjectId = $ManagementGroupName; Message = $WarningMessage }) } Write-Warning $WarningMessage } # Ensure the Tenant Root MG itself is also in the list when starting from "/" if ($Scope -eq "/") { $Scopes.Add("/providers/Microsoft.Management/managementGroups/$ManagementGroupName") } } # Case-insensitive dedup: ARM returns management group and subscription ids with inconsistent # casing, and Select-Object -Unique compares case-sensitively - the same scope could otherwise be # queried twice, duplicating every role definition and assignment request made against it. $Scopes = @( $Scopes | Group-Object -Property { "$_".ToLowerInvariant() } | ForEach-Object { $_.Group[0] } ) # Restrict scan to Control Plane hierarchies when a scope filter is provided. # A scope is kept when it equals, is an ancestor of, or is a descendant of any # Control Plane RoleAssignmentScopeName pattern (matching the ARM hierarchy). $ScopeFilterPatterns = @($ControlPlaneScopeFilter | Where-Object { -not [string]::IsNullOrWhiteSpace($_) -and $_ -ne "/" -and $_ -ne "/*" } | Select-Object -Unique) if ($ScopeFilterPatterns.Count -gt 0) { $UnfilteredScopeCount = @($Scopes).Count $Scopes = @($Scopes | Where-Object { # Management groups are always retained. Ancestor matching below is string-prefix based, and a # management group scope (/providers/Microsoft.Management/managementGroups/<name>) is never a # string prefix of /subscriptions/<id>. Filtering them out means the ancestor MG is never # queried, so an assignment that is "Direct" only at that MG survives solely as an "Inherited" # instance at the subscription - which is skipped below - and disappears entirely. Management # groups number in the tens, so retaining all of them is cheap. if ($_ -like "/providers/Microsoft.Management/managementGroups/*") { return $true } $ScopeItem = $_.TrimEnd('/') $Keep = $false foreach ($Pattern in $ScopeFilterPatterns) { $PatternTrimmed = $Pattern.TrimEnd('/') if ($ScopeItem -ieq $PatternTrimmed -or $ScopeItem -like $Pattern -or $PatternTrimmed -like "$ScopeItem/*" -or $ScopeItem -like "$PatternTrimmed/*") { $Keep = $true break } } $Keep }) Write-Host "Control Plane scope filter applied: $(@($Scopes).Count) of $UnfilteredScopeCount scope(s) retained." if (@($Scopes).Count -eq 0) { $WarningMessage = "Control Plane scope filter matched no scopes; no Azure RBAC assignments will be collected." if ($null -ne $WarningMessages) { $WarningMessages.Add([pscustomobject]@{ Timestamp = (Get-Date); Type = "ScopeFilter"; ObjectId = ""; Message = $WarningMessage }) } Write-Warning $WarningMessage } } Write-Host "Collecting Azure RBAC assignments across $($Scopes.Count) scope(s)..." #endregion #region Get role definitions to determine custom roles and privileged classification # Fetch built-ins once at the starting scope, then only custom roles at every collected scope. # Custom-role visibility depends on assignable scopes, so those queries cannot be collapsed safely. $RoleDefinitionRequests = [System.Collections.Generic.List[string]]::new() if ($Scopes.Count -gt 0) { $RoleDefinitionRequests.Add("$($Scopes[0].TrimEnd('/'))/providers/Microsoft.Authorization/roleDefinitions?api-version=$($RbacApiVersion)") } foreach ($ScopeItem in $Scopes) { $RoleDefinitionRequests.Add("$($ScopeItem.TrimEnd('/'))/providers/Microsoft.Authorization/roleDefinitions?api-version=$($RbacApiVersion)&`$filter=type%20eq%20%27CustomRole%27") } $RoleDefinitions = Invoke-EntraOpsAzQuery -BatchRequest $RoleDefinitionRequests # Build a lookup keyed by role definition GUID (stable across scope prefixes) with name, type and privileged flag $PrivilegedActions = @('*', 'Microsoft.Authorization/*', 'Microsoft.Authorization/roleAssignments/write', 'Microsoft.Authorization/roleDefinitions/write', 'Microsoft.Authorization/elevateAccess/action') $RoleDefinitionLookup = @{} foreach ($RoleDefinition in $RoleDefinitions) { $RoleDefinitionGuid = ($RoleDefinition.name) if ([string]::IsNullOrEmpty($RoleDefinitionGuid) -or $RoleDefinitionLookup.ContainsKey($RoleDefinitionGuid)) { continue } $IsPrivileged = $false foreach ($Permission in @($RoleDefinition.properties.permissions)) { foreach ($Action in (@($Permission.actions) + @($Permission.dataActions))) { if ($Action -in $PrivilegedActions -or $Action -like 'Microsoft.Authorization/role*/write') { $IsPrivileged = $true break } } if ($IsPrivileged) { break } } $RoleDefinitionLookup[$RoleDefinitionGuid] = [pscustomobject]@{ RoleDefinitionName = $RoleDefinition.properties.roleName RoleType = if ($RoleDefinition.properties.type -eq "CustomRole") { "CustomRole" } else { "BuiltInRole" } IsPrivileged = $IsPrivileged } } #endregion #region Get active/permanent (roleAssignmentScheduleInstances) and eligible (roleEligibilityScheduleInstances) assignments # Both endpoints return expandedProperties (principal, roleDefinition, scope) which avoids extra lookups. # The ARM tenant root ("/") does not support PIM schedule instance endpoints; exclude it here and # handle it separately below via the plain roleAssignments endpoint. $PimScopes = @($Scopes | Where-Object { $_ -ne "/" }) $AssignmentRequests = foreach ($ScopeItem in $PimScopes) { "$($ScopeItem.TrimEnd('/'))/providers/Microsoft.Authorization/roleAssignmentScheduleInstances?api-version=$($PimApiVersion)" "$($ScopeItem.TrimEnd('/'))/providers/Microsoft.Authorization/roleEligibilityScheduleInstances?api-version=$($PimApiVersion)" } $AllInstances = Invoke-EntraOpsAzQuery -BatchRequest $AssignmentRequests # Collect plain (always-permanent) role assignments at the tenant root "/" scope. $RootScopeRoleAssignments = @() if ($Scopes -contains "/") { try { $RootScopeRoleAssignments = @(Invoke-EntraOpsAzQuery -Uri "/providers/Microsoft.Authorization/roleAssignments?api-version=$($RbacApiVersion)&`$filter=atScope()") } catch { $WarningMessage = "Could not retrieve role assignments at tenant root scope '/': $($_.Exception.Message)" if ($null -ne $WarningMessages) { $WarningMessages.Add([pscustomobject]@{ Timestamp = (Get-Date); Type = "ScopeQuery"; ObjectId = "/"; Message = $WarningMessage }) } Write-Warning $WarningMessage } } # Keep only directly assigned instances (memberType "Direct"); PIM-expanded group members (memberType # "Group") are resolved by our own transitive expansion below. Dedupe by instance id (the same # inherited assignment can be returned from multiple child scope queries). $SeenAssignmentIds = @{} $AzureRbacAssignments = foreach ($Instance in $AllInstances) { if ($null -eq $Instance.properties) { continue } if ($Instance.properties.memberType -eq "Group" -or $Instance.properties.memberType -eq "Inherited") { continue } if ($SeenAssignmentIds.ContainsKey($Instance.id)) { continue } $SeenAssignmentIds[$Instance.id] = $true $InstanceProperties = $Instance.properties $IsEligible = $Instance.type -like "*RoleEligibilityScheduleInstances" # Determine PIM assignment type and whether the role is PIM managed if ($IsEligible) { $PIMAssignmentType = "Eligible" $PIMManagedRole = $True } elseif ($InstanceProperties.assignmentType -eq "Activated") { $PIMAssignmentType = "Activated" $PIMManagedRole = $True } elseif ($null -ne $InstanceProperties.endDateTime -or $null -ne $InstanceProperties.linkedRoleEligibilityScheduleInstanceId) { $PIMAssignmentType = "TimeBounded" $PIMManagedRole = $True } else { $PIMAssignmentType = "Permanent" $PIMManagedRole = $False } # Resolve role definition details (lookup by GUID, fallback to expandedProperties) $RoleDefinitionGuid = ($InstanceProperties.roleDefinitionId -split '/')[-1] $RoleDefinitionInfo = $RoleDefinitionLookup[$RoleDefinitionGuid] if ($null -ne $RoleDefinitionInfo) { $RoleDefinitionName = $RoleDefinitionInfo.RoleDefinitionName $RoleType = $RoleDefinitionInfo.RoleType $RoleIsPrivileged = $RoleDefinitionInfo.IsPrivileged } else { $RoleDefinitionName = $InstanceProperties.expandedProperties.roleDefinition.displayName $RoleType = if ($InstanceProperties.expandedProperties.roleDefinition.type -eq "CustomRole") { "CustomRole" } else { "BuiltInRole" } $RoleIsPrivileged = $false } # Constrained delegation: role assignment conditions (ABAC) or delegated managed identity $RoleAssignmentSubType = "" $RoleAssignmentCondition = $InstanceProperties.condition $RoleAssignmentConditionVersion = $InstanceProperties.conditionVersion if (-not [string]::IsNullOrEmpty($RoleAssignmentCondition)) { $RoleAssignmentSubType = "Constrained delegation" } elseif (-not [string]::IsNullOrEmpty($InstanceProperties.delegatedManagedIdentityResourceId)) { $RoleAssignmentSubType = "Delegated Managed Identity" } $ScopeId = $InstanceProperties.scope $ScopeName = if (-not [string]::IsNullOrEmpty($InstanceProperties.expandedProperties.scope.displayName)) { $InstanceProperties.expandedProperties.scope.displayName } else { $ScopeId } [pscustomobject]@{ RoleAssignmentId = $Instance.name RoleAssignmentScopeId = $ScopeId RoleAssignmentScopeName = $ScopeName RoleAssignmentType = "Direct" RoleAssignmentSubType = $RoleAssignmentSubType RoleAssignmentCondition = $RoleAssignmentCondition RoleAssignmentConditionVersion = $RoleAssignmentConditionVersion PIMManagedRole = $PIMManagedRole PIMAssignmentType = $PIMAssignmentType RoleDefinitionName = $RoleDefinitionName RoleDefinitionId = $RoleDefinitionGuid RoleType = $RoleType RoleIsPrivileged = $RoleIsPrivileged ObjectId = $InstanceProperties.principalId ObjectTenantId = $TenantId ObjectType = ($InstanceProperties.principalType ?? "unknown").toLower() TransitiveByObjectId = "" TransitiveByObjectDisplayName = "" TransitiveByNestingObjectIds = $null TransitiveByNestingObjectDisplayNames = $null } } # Append permanent role assignments from the ARM tenant root "/" scope. # The plain roleAssignments API returns a different shape (no expandedProperties / schedule fields). foreach ($RootAssignment in $RootScopeRoleAssignments) { if ($null -eq $RootAssignment.properties) { continue } if ($SeenAssignmentIds.ContainsKey($RootAssignment.id)) { continue } $SeenAssignmentIds[$RootAssignment.id] = $true $RootProps = $RootAssignment.properties $RoleDefinitionGuid = ($RootProps.roleDefinitionId -split '/')[-1] $RoleDefinitionInfo = $RoleDefinitionLookup[$RoleDefinitionGuid] if ($null -ne $RoleDefinitionInfo) { $RoleDefinitionName = $RoleDefinitionInfo.RoleDefinitionName $RoleType = $RoleDefinitionInfo.RoleType $RoleIsPrivileged = $RoleDefinitionInfo.IsPrivileged } else { $RoleDefinitionName = $RoleDefinitionGuid $RoleType = "BuiltInRole" $RoleIsPrivileged = $false } $RoleAssignmentSubType = "" $RoleAssignmentCondition = $RootProps.condition $RoleAssignmentConditionVersion = $RootProps.conditionVersion if (-not [string]::IsNullOrEmpty($RoleAssignmentCondition)) { $RoleAssignmentSubType = "Constrained delegation" } elseif (-not [string]::IsNullOrEmpty($RootProps.delegatedManagedIdentityResourceId)) { $RoleAssignmentSubType = "Delegated Managed Identity" } $AzureRbacAssignments += [pscustomobject]@{ RoleAssignmentId = $RootAssignment.name RoleAssignmentScopeId = "/" RoleAssignmentScopeName = "/" RoleAssignmentType = "Direct" RoleAssignmentSubType = $RoleAssignmentSubType RoleAssignmentCondition = $RoleAssignmentCondition RoleAssignmentConditionVersion = $RoleAssignmentConditionVersion PIMManagedRole = $False PIMAssignmentType = "Permanent" RoleDefinitionName = $RoleDefinitionName RoleDefinitionId = $RoleDefinitionGuid RoleType = $RoleType RoleIsPrivileged = $RoleIsPrivileged ObjectId = $RootProps.principalId ObjectTenantId = $TenantId ObjectType = ($RootProps.principalType ?? "unknown").toLower() TransitiveByObjectId = "" TransitiveByObjectDisplayName = "" TransitiveByNestingObjectIds = $null TransitiveByNestingObjectDisplayNames = $null } } #endregion #region Collect transitive assignments by group members (nested groups and PIM for Groups) $AzureRbacTransitiveAssignments = [System.Collections.Generic.List[object]]::new() if ($ExpandGroupMembers -eq $True) { Write-Verbose "Expanding groups for direct or transitive Azure RBAC role assignments" $GroupsWithRbacAssignment = $AzureRbacAssignments | Where-Object { $_.ObjectType -eq "group" } $AllTransitiveMembers = [System.Collections.Generic.List[object]]::new() foreach ($GroupWithRbacAssignment in ($GroupsWithRbacAssignment | Sort-Object ObjectId -Unique)) { try { $GroupObjectDisplayName = (Invoke-EntraOpsMsGraphQuery -Method Get -Uri "https://graph.microsoft.com/beta/groups/$($GroupWithRbacAssignment.ObjectId)" -OutputType PSObject).displayName $TransitiveMembers = Get-EntraOpsPrivilegedTransitiveGroupMember -GroupObjectId $($GroupWithRbacAssignment.ObjectId) -TenantId $TenantId -WarningMessages $WarningMessages } catch { $WarningMessage = "Could not expand group $($GroupWithRbacAssignment.ObjectId): $($_.Exception.Message)" if ($null -ne $WarningMessages) { $WarningMessages.Add([pscustomobject]@{ Timestamp = (Get-Date); Type = "GroupExpansion"; ObjectId = $GroupWithRbacAssignment.ObjectId; Message = $WarningMessage }) } Write-Warning $WarningMessage continue } foreach ($TransitiveMember in $TransitiveMembers) { $Member = [pscustomobject]@{ displayName = $TransitiveMember.displayName id = $TransitiveMember.id '@odata.type' = $TransitiveMember.'@odata.type' RoleAssignmentSubType = $TransitiveMember.RoleAssignmentSubType GroupObjectDisplayName = $GroupObjectDisplayName GroupObjectId = $GroupWithRbacAssignment.ObjectId NestingObjectIds = $TransitiveMember.NestingObjectIds NestingObjectDisplayNames = $TransitiveMember.NestingObjectDisplayNames } $AllTransitiveMembers.Add($Member) } } # Index transitive members by their assigning group for O(1) lookups instead of # re-scanning the full member list for every group assignment. $TransitiveMembersByGroup = @{} foreach ($TransitiveMemberEntry in $AllTransitiveMembers) { if (-not $TransitiveMembersByGroup.ContainsKey($TransitiveMemberEntry.GroupObjectId)) { $TransitiveMembersByGroup[$TransitiveMemberEntry.GroupObjectId] = [System.Collections.Generic.List[object]]::new() } $TransitiveMembersByGroup[$TransitiveMemberEntry.GroupObjectId].Add($TransitiveMemberEntry) } foreach ($RbacAssignmentByGroup in $GroupsWithRbacAssignment) { $RbacAssignmentByNestedGroupMembers = $TransitiveMembersByGroup[$RbacAssignmentByGroup.ObjectId] if ($null -ne $RbacAssignmentByNestedGroupMembers -and $RbacAssignmentByNestedGroupMembers.Count -gt 0) { $RbacAssignmentByNestedGroupMembers | ForEach-Object { $TransitiveAssignment = [pscustomobject]@{ RoleAssignmentId = $RbacAssignmentByGroup.RoleAssignmentId RoleAssignmentScopeId = $RbacAssignmentByGroup.RoleAssignmentScopeId RoleAssignmentScopeName = $RbacAssignmentByGroup.RoleAssignmentScopeName RoleAssignmentType = "Transitive" RoleAssignmentSubType = $_.RoleAssignmentSubType RoleAssignmentCondition = $RbacAssignmentByGroup.RoleAssignmentCondition RoleAssignmentConditionVersion = $RbacAssignmentByGroup.RoleAssignmentConditionVersion PIMManagedRole = $RbacAssignmentByGroup.PIMManagedRole PIMAssignmentType = $RbacAssignmentByGroup.PIMAssignmentType RoleDefinitionName = $RbacAssignmentByGroup.RoleDefinitionName RoleDefinitionId = $RbacAssignmentByGroup.RoleDefinitionId RoleType = $RbacAssignmentByGroup.RoleType RoleIsPrivileged = $RbacAssignmentByGroup.RoleIsPrivileged ObjectId = $_.id ObjectTenantId = $TenantId ObjectType = $_.'@odata.type'.Replace('#microsoft.graph.', '').toLower() TransitiveByObjectId = $RbacAssignmentByGroup.ObjectId TransitiveByObjectDisplayName = $_.GroupObjectDisplayName TransitiveByNestingObjectIds = $_.NestingObjectIds TransitiveByNestingObjectDisplayNames = $_.NestingObjectDisplayNames } $AzureRbacTransitiveAssignments.Add($TransitiveAssignment) | Out-Null } } else { if ($null -ne $WarningMessages) { $WarningMessages.Add([pscustomobject]@{ Timestamp = (Get-Date); Type = "EmptyGroup"; ObjectId = $RbacAssignmentByGroup.ObjectId; Message = "Group has no members or members could not be resolved." }) } } } } #endregion $AllAzureRbacAssignments = @() $AllAzureRbacAssignments += $AzureRbacAssignments $AllAzureRbacAssignments += $AzureRbacTransitiveAssignments $AllAzureRbacAssignments = $AllAzureRbacAssignments | Where-Object { $_.ObjectType -in $PrincipalTypeFilter } # Efficient deduplication using composite key (assignment, principal, assignment type) $DeduplicationHash = @{} $UniqueAssignments = foreach ($Assignment in $AllAzureRbacAssignments) { $Key = "$($Assignment.RoleAssignmentId)|$($Assignment.ObjectId)|$($Assignment.RoleAssignmentType)" if (-not $DeduplicationHash.ContainsKey($Key)) { $DeduplicationHash[$Key] = $true $Assignment } } $UniqueAssignments | Sort-Object RoleAssignmentId, RoleAssignmentType, ObjectId } # SIG # Begin signature block # MIIniAYJKoZIhvcNAQcCoIIneTCCJ3UCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBRqcXMgaFxvPvB # mR2JF1eNlztlYnimNgCLxZAXaCqhD6CCIDwwggXJMIIEsaADAgECAhAbtY8lKt8j # 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 # ARUwLwYJKoZIhvcNAQkEMSIEIG0LfSmImqxaCs0oneedW21eLr1/TiA3v5nPXDDg # +RPzMA0GCSqGSIb3DQEBAQUABIIBgIoMN7igrxItJBV6Rm2ZW9FhNfe0J/GHd+8N # ifgle6Gn9maWTETcRWxJwgKwJqJOS3/ayXfL70ZUfGKT+KkRR3nGd4eu50M4o36z # hDa8SbaVZTl3OsUHUPzZ/tAe8AQNHQCf05ym7gH3BbvpFBW0td/6xuhkFw/gLIXC # WB1/0ku6fO4OYpGGJn8fUtYu86VmbmfhR+4ZDSH9hmRCRE5GqfX7t17oZPp8agfl # HuLnupsOxMKO65mu9gDrVp+pKMJwaQrcNZH0RSDe7PoAVzBHUN2L07z6pj+683DL # 0iHK1typkAA3CIFRLyVsDy1GFNrw3FdU1iV0q/ZsBt8B3nINmZAG33EqqNZ7ad4c # BeDP/wPBHaeKUCS92AR+fwSmFWZTB6ggeZS+d5GGE3HFG9OfzcSAdxPAUIh8cU/y # g6uTmJ5IM6jxvQySM9F3k7AR8jCgc9wpLCZYUtrvCJ4gghconeF+NTuRQH3Buq7T # 5QpUaP5j9TytSqv1/hslJANKkcWx+qGCBAIwggP+BgkqhkiG9w0BCQYxggPvMIID # 6wIBATBqMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0 # ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQQIQ # KPB3wRw2vf5fdDJHcCcuAzANBglghkgBZQMEAgIFAKCCAVYwGgYJKoZIhvcNAQkD # MQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNjEwMTMwOTQxMTFaMDcG # CyqGSIb3DQEJEAIvMSgwJjAkMCIEIIW+kOEK0kONfMkotq9IsJqyCBd87PiwEmxY # 05EFJcQ8MD8GCSqGSIb3DQEJBDEyBDB5sQTBTgB13Tqx1BNlDvjWMzmGFKoZeaIH # 3ZDPiUj6DSOwe8wnVBB3JJHiUZUs/icwgZ8GCyqGSIb3DQEJEAIMMYGPMIGMMIGJ # MIGGBBRXFGhBDKha80JO+RZKUTYQ9NONmDBuMFqkWDBWMQswCQYDVQQGEwJQTDEh # MB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQwIgYDVQQDExtDZXJ0 # dW0gVGltZXN0YW1waW5nIDIwMjEgQ0ECECjwd8EcNr3+X3QyR3AnLgMwDQYJKoZI # hvcNAQEBBQAEggIAA1DagfqOTxOsYZGUuzuxnoLuhYQA4sTCAo5YK8/mgZ2M+MuN # vATTSjZWaZu0L1nZ7X4NaVFmEU0LQ134rs9wut4Hli7b2yQl4dWMyro7xnowBgsV # vr4ILl9LXGRykiAtp7eOebzr0ShvGVm2Z7QU4Z2uEh9FU/+OszwZE2pCXCwIAfHV # bcfj7hCS8ZjYQyvzATmgcUr667z3aooEFzzAdy+DalC8G8IdRh55nhxid37gOM5s # VczZJ+L42AfxwSna758eDvrAjRLg6+UPEQAyHEv+VImr3i1D2yM1bhiw8iGXlBLb # ks5Nj1YYzJtvhUGlY7g2nO+mtUFcO1tZvsl7UCfj3SlZBu9ZoTTa42H+fAaRYjxi # LuFKOPOc2oHKideFPFdvQz2rOOFQ56AfbzgSqCAs0fZHAaCzOZuLZdNVeIoScDO1 # 80MvGU6Q5tkDIFOC3DNJtZxk8fmd42jElxhbhJfradBT+4BOn0dVtJm5gvRrl8k/ # Yv9ZT5omoCs2Y0jp0enW1xMKldu87NvzFWZrokukrq1rm+X58X47kt/DOnEfz2xH # 9GFu6bKEFkzOtc/ByOHB/lbHas9/kQz1R7BUlf7gIGjXQZITv3wsfaiAdjWObmEQ # p+0CwNV4inKf/D9ymBHUc/jzB9JVXWypcyveOTBzje6SG0lKuBsK7q/oLaM= # SIG # End signature block |