Public/PrivilegedAccess/Get-EntraOpsPrivilegedDefenderRoles.ps1
|
<# .SYNOPSIS Get a list of directory role member assignments in Microsoft Defender. .DESCRIPTION Get a list of RBAC member assignments in Microsoft Defender. .PARAMETER TenantId Tenant ID of the Microsoft Microsoft Defender tenant. Default is the current tenant ID. .PARAMETER PrincipalTypeFilter Filter for principal type. Default is User, Group, ServicePrincipal. Possible values are User, Group, ServicePrincipal. .PARAMETER ExpandGroupMembers Expand group members for transitive role assignments. Default is $true. .PARAMETER SampleMode Use sample data for testing or offline mode. Default is $False. .EXAMPLE Get a list of assignment of Microsoft Defender roles. Get-EntraOpsPrivilegedDefenderRoles #> function Get-EntraOpsPrivilegedDefenderRoles { param ( [Parameter(Mandatory = $False)] [System.String]$TenantId = (Get-EntraOpsAzContextValue -Property TenantId) , [Parameter(Mandatory = $False)] [ValidateSet("User", "Group", "ServicePrincipal")] [Array]$PrincipalTypeFilter = ("User", "Group", "ServicePrincipal") , [Parameter(Mandatory = $False)] [System.Boolean]$ExpandGroupMembers = $true , [Parameter(Mandatory = $false)] [System.Boolean]$SampleMode = $False , [Parameter(Mandatory = $false)] [System.Boolean]$EnableParallelProcessing = $true , [Parameter(Mandatory = $false)] [System.Int32]$ParallelThrottleLimit = 10 , [Parameter(Mandatory = $false)] [System.Collections.Generic.List[psobject]]$WarningMessages ) # Set Error Action $ErrorActionPreference = "Stop" #region Get Role Definitions and Role Assignments Write-Host "Get Defender Role Management Assignments and Role Definition..." if ($SampleMode -eq $True) { Write-Warning "Not supported yet!" } else { $DefenderRoleDefinitions = Invoke-EntraOpsMsGraphQuery -Uri "/beta/roleManagement/defender/roleDefinitions?`$select=id,displayName,description,rolePermissions" -OutputType PSObject $DefenderRoleAssignments = Invoke-EntraOpsMsGraphQuery -Uri "/beta/roleManagement/defender/roleAssignments?`$select=id,principalIds,roleDefinitionId,appScopeIds,directoryScopeIds" -OutputType PSObject } # Optimization: Build Role Definition Lookup Hashtable for O(1) access Write-Verbose "Building Role Definition Lookup Table..." $RoleDefLookup = @{} foreach ($RoleDef in $DefenderRoleDefinitions) { $RoleDefLookup[$RoleDef.id] = $RoleDef } #endregion #region Get role assignments for all permanent role member Write-Host "Get details of Defender Role Assignments foreach individual principal..." if (![string]::IsNullOrWhiteSpace($DefenderRoleAssignments.id)) { # Fetch Defender custom app scopes for resolving appScopeIds to display names. Defender Unified RBAC # supports direct scoping on cloud scope sets (Defender for Cloud, type "CloudSet") and identity scopes # (MDI, type "UserGroupId"). The customAppScope.id is the value used as appScopeId in Defender Unified # RBAC role assignments. # NOTE: MDE device groups are NOT part of URBAC assignment scoping. Device group restrictions are # configured separately on the Device Groups page (per-group "User access" with Entra groups) and # govern per-device visibility alongside Unified RBAC. They are not exposed as appScopeIds. $DefenderAppScopes = @() try { $DefenderAppScopes = Invoke-EntraOpsMsGraphQuery -Method GET -Uri "/beta/roleManagement/defender/customAppScopes" -OutputType PSObject -DisableCache } catch { Write-Warning "Failed to fetch Defender custom app scopes for scope name resolution. $($_.Exception.Message)" } function Get-DefenderAppScopeLookupKey { param([string]$ScopeId, [string]$ScopeType) if ([string]::IsNullOrWhiteSpace($ScopeId)) { return $null } $ScopeId = $ScopeId.Trim().Trim('/') $ScopeParts = @($ScopeId -split '/') $ScopeLeafId = $ScopeParts[-1] $EffectiveScopeType = if (-not [string]::IsNullOrWhiteSpace($ScopeType)) { $ScopeType } elseif ($ScopeParts.Count -gt 1) { $ScopeParts[-2] } else { '' } return "$EffectiveScopeType/$ScopeLeafId".ToLowerInvariant() } $AppScopeLookup = @{} foreach ($AppScope in $DefenderAppScopes) { $LookupKey = Get-DefenderAppScopeLookupKey -ScopeId "$($AppScope.id)" -ScopeType "$($AppScope.type)" if (-not [string]::IsNullOrEmpty($LookupKey)) { $AppScopeLookup[$LookupKey] = $AppScope } } # CloudSet custom app scopes for Defender for Cloud RBAC are backed 1:1 by a Microsoft Security # Exposure Management "zone" (the CloudSet id's GUID is the zone id). Some zones (e.g. created # directly via Security Exposure Management rather than the classic Defender for Cloud RBAC UI) # are not returned by /beta/roleManagement/defender/customAppScopes at all, which is why their # appScopeId previously fell through to "Unresolved app scope" with 0 subscriptions. Resolving # directly against the zones API (using the guid embedded in the appScopeId/CloudSet id) works # even when the customAppScopes lookup misses the CloudSet entirely. function Get-CloudSetZoneInfo { param([string]$CloudSetAppScopeId) $Result = [pscustomobject]@{ DisplayName = $null; SubscriptionScopes = @() } $ZoneId = "$CloudSetAppScopeId".Trim().Trim('/') -replace '(?i)^cloudset/', '' if ([string]::IsNullOrWhiteSpace($ZoneId)) { return $Result } try { # -ThrowOnFailure so a real failure (e.g. missing Zone.Read.All) lands in the catch # below - without it, Invoke-EntraOpsMsGraphQuery just warns and returns $null, and # this function's own more specific warning message below never fires. # -SuppressForbiddenWarning avoids reporting the same 403 twice, since the catch # already emits a message naming the CloudSet and the missing permission. $Zone = Invoke-EntraOpsMsGraphQuery -Method GET -Uri "/beta/security/zones/$($ZoneId)?`$expand=environments" -OutputType PSObject -ThrowOnFailure -SuppressForbiddenWarning $Result.DisplayName = $Zone.displayName $ZoneSubscriptionScopes = [System.Collections.Generic.List[string]]::new() foreach ($Environment in @($Zone.environments)) { if ("$($Environment.kind)" -eq 'azureSubscription' -and "$($Environment.id)" -match '(?i)^/subscriptions/([0-9a-f-]{36})/?$') { $ZoneSubscriptionScopes.Add("/subscriptions/$($Matches[1].ToLowerInvariant())") | Out-Null } } $Result.SubscriptionScopes = @($ZoneSubscriptionScopes | Sort-Object -Unique) } catch { $ZoneWarningMessage = "Failed to resolve Security Exposure Management zone '$ZoneId' for CloudSet '$CloudSetAppScopeId': $($_.Exception.Message)" if ($_.Exception.Data['StatusCode'] -eq 403 -or $_.Exception.Message -match '(?i)forbidden') { $ZoneWarningMessage += " This usually means the 'Zone.Read.All' Microsoft Graph permission is missing - re-run New-EntraOpsWorkloadIdentity and grant admin consent, then repeat the collection." } if ($null -ne $WarningMessages) { $WarningMessages.Add([PSCustomObject]@{ Timestamp = (Get-Date) Type = 'CloudSetZoneResolutionError' ObjectId = "$CloudSetAppScopeId" Message = $ZoneWarningMessage }) } Write-Verbose $ZoneWarningMessage } return $Result } function Get-CloudSetSubscriptionScopes { param([psobject]$CloudSet) $ZoneInfo = Get-CloudSetZoneInfo -CloudSetAppScopeId "$($CloudSet.id)" if ($ZoneInfo.SubscriptionScopes.Count -gt 0) { return $ZoneInfo.SubscriptionScopes } # Fallback for CloudSets that are not zone-backed (or where the zone lookup failed/returned no # subscriptions): recover subscription ids embedded in customAttributes if present. $subscriptionScopes = [System.Collections.Generic.List[string]]::new() if ($null -ne $CloudSet.customAttributes) { function Add-CloudSetSubscriptionScope { param([object]$Value, [string]$PropertyName) if ($null -eq $Value) { return } if ($Value -is [string]) { if ($Value.TrimStart().StartsWith('{') -or $Value.TrimStart().StartsWith('[')) { try { Add-CloudSetSubscriptionScope -Value ($Value | ConvertFrom-Json) -PropertyName $PropertyName return } catch { Write-Verbose "CloudSet custom attribute '$PropertyName' is not valid JSON." } } if ($Value -match '(?i)^/subscriptions/([0-9a-f-]{36})/?$') { $subscriptionScopes.Add("/subscriptions/$($Matches[1].ToLowerInvariant())") | Out-Null } elseif ($PropertyName -match '(?i)subscription' -and $Value -match '(?i)^[0-9a-f-]{36}$') { $subscriptionScopes.Add("/subscriptions/$($Value.ToLowerInvariant())") | Out-Null } return } if ($Value -is [System.Collections.IEnumerable]) { foreach ($Item in $Value) { Add-CloudSetSubscriptionScope -Value $Item -PropertyName $PropertyName } return } foreach ($Property in $Value.PSObject.Properties) { Add-CloudSetSubscriptionScope -Value $Property.Value -PropertyName $Property.Name } } Add-CloudSetSubscriptionScope -Value $CloudSet.customAttributes -PropertyName 'customAttributes' } return @($subscriptionScopes | Sort-Object -Unique) } $DefenderRoleAssignmentPrincipals = ($DefenderRoleAssignments | select-object -ExpandProperty principalIds -Unique) Write-Host "Processing $($DefenderRoleAssignmentPrincipals.Count) Defender role principals..." $PrincipalCounter = 0 $DefenderPermanentRbacAssignments = foreach ($Principal in $DefenderRoleAssignmentPrincipals) { $PrincipalCounter++ if (($PrincipalCounter % 10) -eq 0 -or $PrincipalCounter -eq $DefenderRoleAssignmentPrincipals.Count) { $PercentComplete = [math]::Round(($PrincipalCounter / $DefenderRoleAssignmentPrincipals.Count) * 100, 0) Write-Progress -Activity "Processing Defender Role Principals" -Status "Processing principal $PrincipalCounter of $($DefenderRoleAssignmentPrincipals.Count)" -PercentComplete $PercentComplete } $RawPrincipalId = "$Principal" $PrincipalGuid = [guid]::Empty if (-not [guid]::TryParse($RawPrincipalId, [ref]$PrincipalGuid)) { $WarningMessage = "Skipping Defender role assignment principal with invalid GUID: $RawPrincipalId" if ($null -ne $WarningMessages) { $WarningMessages.Add([PSCustomObject]@{ Timestamp = (Get-Date) Type = "InvalidPrincipalId" ObjectId = $RawPrincipalId Message = $WarningMessage }) } Write-Warning $WarningMessage continue } $Principal = $PrincipalGuid.ToString() Write-Verbose "Get identity information from permanent member $Principal" # Reset to avoid carrying over the ObjectType from a previous iteration when resolution fails $ObjectType = $null try { $PrincipalProfile = Invoke-EntraOpsMsGraphQuery -Method Get -Uri "https://graph.microsoft.com/beta/directoryObjects/$($Principal)" -OutputType PSObject $ObjectType = $PrincipalProfile.'@odata.type'.Replace('#microsoft.graph.', '') } catch { $WarningMessage = "Issue to resolve directory object $Principal! $($_.Exception.Message)" if ($null -ne $WarningMessages) { $WarningMessages.Add([PSCustomObject]@{ Timestamp = (Get-Date) Type = "ObjectResolutionError" ObjectId = $Principal Message = $WarningMessage }) } Write-Warning $WarningMessage } $AllPrinicpalDefenderRoleAssignments = Invoke-EntraOpsMsGraphQuery -Uri "/beta/roleManagement/defender/RoleAssignments?`$count=true&`$filter=principalIds/any(a:a+eq+'$Principal')" -ConsistencyLevel "eventual" -OutputType PSObject foreach ($DefenderPrincipalRoleAssignment in $AllPrinicpalDefenderRoleAssignments) { # Optimization: Use hashtable lookup instead of Where-Object for O(1) access $Role = $RoleDefLookup[$DefenderPrincipalRoleAssignment.roleDefinitionId] if ($null -eq $Role) { $WarningMessage = "Role definition is empty or does not exist for Role Assignment $($DefenderPrincipalRoleAssignment.id)" if ($null -ne $WarningMessages) { $WarningMessages.Add([PSCustomObject]@{ Timestamp = (Get-Date) Type = "RoleDefinitionError" ObjectId = $DefenderPrincipalRoleAssignment.id Message = $WarningMessage }) } Write-Warning $WarningMessage } # Check for scope restriction in appScopeIds: # Defender Unified RBAC uses appScopeIds for two different things (verified against live tenant data): # - Workload/data source tokens (e.g. "Mde", "Mdo", "Mdi", "Mdc", "SecureScoreExternal") when the # assignment applies to ALL scopes of the selected data sources. These do NOT resolve in # customAppScopes and are effectively tenant-wide for the workload. MDE device group # restrictions are managed on the Device Groups page (per-group user access), NOT here. # - Ids of directly scoped assignments: customAppScope objects (type "CloudSet" for Defender for # Cloud, "UserGroupId" for Defender for Identity). Only these are real scope restrictions and # must be used as role scope. An unresolved CloudSet remains a bounded scope; it must never be # folded into the tenant-wide workload token list. $ResolvedAppScopes = @() $WorkloadWideTokens = @() $UnresolvedAppScopes = @() $WorkloadScopeTokens = @('Mde', 'Mdo', 'Mdi', 'Mdc', 'SecureScoreExternal') foreach ($AppScopeId in @($DefenderPrincipalRoleAssignment.appScopeIds | Where-Object { -not [string]::IsNullOrEmpty($_) -and $_ -ne "/" })) { $AppScopeLookupKey = Get-DefenderAppScopeLookupKey -ScopeId "$AppScopeId" $AppScope = $AppScopeLookup[$AppScopeLookupKey] if ($null -ne $AppScope) { $ResolvedAppScopes += [pscustomobject]@{ AppScopeId = "$AppScopeId"; Scope = $AppScope } } elseif ($WorkloadScopeTokens -contains $AppScopeId) { $WorkloadWideTokens += $AppScopeId } elseif ($AppScopeLookupKey -match '(?i)^cloudset/') { # Not returned by /beta/roleManagement/defender/customAppScopes (e.g. a zone created # directly via Security Exposure Management) -- still resolvable via the zones API # using the guid embedded in the appScopeId itself. $ZoneInfo = Get-CloudSetZoneInfo -CloudSetAppScopeId "$AppScopeId" if ($ZoneInfo.SubscriptionScopes.Count -gt 0 -or -not [string]::IsNullOrWhiteSpace($ZoneInfo.DisplayName)) { $SyntheticCloudSet = [pscustomobject]@{ id = "$AppScopeId"; type = 'CloudSet'; displayName = $ZoneInfo.DisplayName; customAttributes = $null } $ResolvedAppScopes += [pscustomobject]@{ AppScopeId = "$AppScopeId"; Scope = $SyntheticCloudSet } } else { $UnresolvedAppScopes += $AppScopeId $WarningMessage = "Defender app scope '$AppScopeId' could not be resolved (not in customAppScopes, and its Security Exposure Management zone lookup returned no data). It will be retained as a bounded scope rather than treated as tenant-wide." if ($null -ne $WarningMessages) { $WarningMessages.Add([PSCustomObject]@{ Timestamp = (Get-Date) Type = 'UnresolvedDefenderAppScope' ObjectId = $DefenderPrincipalRoleAssignment.id Message = $WarningMessage }) } Write-Warning $WarningMessage } } else { $UnresolvedAppScopes += $AppScopeId $WarningMessage = "Defender app scope '$AppScopeId' could not be resolved. It will be retained as a bounded scope rather than treated as tenant-wide." if ($null -ne $WarningMessages) { $WarningMessages.Add([PSCustomObject]@{ Timestamp = (Get-Date) Type = 'UnresolvedDefenderAppScope' ObjectId = $DefenderPrincipalRoleAssignment.id Message = $WarningMessage }) } Write-Warning $WarningMessage } } $RoleAssignmentScopes = @( # Assignment restricted to specific scopes (cloud scope sets, identity/user group scopes) foreach ($ResolvedAppScope in $ResolvedAppScopes) { $AppScope = $ResolvedAppScope.Scope $ScopeName = if (-not [string]::IsNullOrEmpty($AppScope.displayName)) { $AppScope.displayName } else { "$($AppScope.type)-$($ResolvedAppScope.AppScopeId)" } $CloudSetSubscriptionScopes = if ($AppScope.type -eq 'CloudSet') { @(Get-CloudSetSubscriptionScopes -CloudSet $AppScope) } else { @() } [pscustomobject]@{ ScopeId = $ResolvedAppScope.AppScopeId; ScopeName = $ScopeName; AppScopeName = @($WorkloadWideTokens); CloudSetSubscriptionScopes = $CloudSetSubscriptionScopes; ScopeResolutionStatus = 'Resolved' } } foreach ($UnresolvedAppScope in $UnresolvedAppScopes) { [pscustomobject]@{ ScopeId = "$UnresolvedAppScope"; ScopeName = "Unresolved app scope ($UnresolvedAppScope)"; AppScopeName = @($WorkloadWideTokens); CloudSetSubscriptionScopes = @(); ScopeResolutionStatus = 'Unresolved' } } if ($ResolvedAppScopes.Count -eq 0 -and $UnresolvedAppScopes.Count -eq 0 -and $WorkloadWideTokens.Count -gt 0) { # Workload-wide data source selection: tenant-wide scope, data sources kept visible in the # name. Kept as a single combined row (not one row per workload token) since this is one # physical role assignment - splitting it into multiple rows would duplicate it across # reports/exports that count or graph by RoleAssignmentId. AppScopeName instead exposes the # individual workload tokens (e.g. "Mde", "Mdo", "Mdi") for per-workload filtering/reporting # without touching the row count or RoleAssignmentScopeName's classification-relevant value. [pscustomobject]@{ ScopeId = "/"; ScopeName = "Tenant-wide ($($WorkloadWideTokens -join ', '))"; AppScopeName = @($WorkloadWideTokens); CloudSetSubscriptionScopes = @(); ScopeResolutionStatus = 'WorkloadWide' } } elseif ($ResolvedAppScopes.Count -eq 0 -and $UnresolvedAppScopes.Count -eq 0) { # No app scopes: directory scope applies (empty value means tenant-wide, # the role is assigned to all devices or all users without specific directoryScopeId) $DirectoryScopeIds = @($DefenderPrincipalRoleAssignment.directoryScopeIds | Where-Object { -not [string]::IsNullOrEmpty($_) }) if ($DirectoryScopeIds.Count -eq 0) { $DirectoryScopeIds = @("/") } foreach ($DirectoryScopeId in $DirectoryScopeIds) { $ScopeName = if ($DirectoryScopeId -eq "/") { "Tenant-wide" } else { $DirectoryScopeId } [pscustomobject]@{ ScopeId = "$DirectoryScopeId"; ScopeName = $ScopeName; AppScopeName = $null; CloudSetSubscriptionScopes = @(); ScopeResolutionStatus = 'DirectoryScope' } } } ) foreach ($RoleAssignmentScope in $RoleAssignmentScopes) { [pscustomobject]@{ RoleAssignmentId = $DefenderPrincipalRoleAssignment.Id RoleAssignmentScopeId = $RoleAssignmentScope.ScopeId RoleAssignmentScopeName = $RoleAssignmentScope.ScopeName AppScopeName = $RoleAssignmentScope.AppScopeName CloudSetSubscriptionScopes = $RoleAssignmentScope.CloudSetSubscriptionScopes ScopeResolutionStatus = $RoleAssignmentScope.ScopeResolutionStatus RoleAssignmentType = "Direct" RoleAssignmentSubType = "" PIMManagedRole = $False PIMAssignmentType = "Permanent" RoleDefinitionName = $Role.displayName RoleDefinitionId = $Role.id RoleType = if ($Role.isBuiltIn -eq $True) { "Built-In" } else { "Custom" } RoleIsPrivileged = $Role.isPrivileged ObjectId = $Principal ObjectTenantId = $TenantId ObjectType = $ObjectType TransitiveByObjectId = "" TransitiveByObjectDisplayName = "" TransitiveByNestingObjectIds = $null TransitiveByNestingObjectDisplayNames = $null } } } } Write-Progress -Activity "Processing Defender Role Principals" -Completed } else { Write-Warning "No Defender Role Assignments found!" $DefenderPermanentRbacAssignments = $null } #endregion # Summarize results with direct permanent (excl. activated roles) and eligible role assignments $AllDefenderRbacAssignments = @() $AllDefenderRbacAssignments += $DefenderPermanentRbacAssignments #region Collect transitive assignments by group members of Role-Assignable Groups or Security Groups if ($ExpandGroupMembers -eq $True) { Write-Verbose "Expanding groups for direct or transitive Entra Microsoft Defender XDR role assignments" $GroupsWithRbacAssignment = $AllDefenderRbacAssignments | where-object { $_.ObjectType -eq "group" } | Select-Object -Unique ObjectId, ObjectDisplayName $AllTransitiveMembers = @() foreach ($GroupWithRbacAssignment in $GroupsWithRbacAssignment) { $TransitiveMembers = Get-EntraOpsPrivilegedTransitiveGroupMember -GroupObjectId $($GroupWithRbacAssignment.ObjectId) -WarningMessages $WarningMessages $GroupObjectDisplayName = (Invoke-EntraOpsMsGraphQuery -Method Get -Uri "https://graph.microsoft.com/beta/groups/$($GroupWithRbacAssignment.ObjectId)" -OutputType PSObject).displayName 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 += $Member } } $DefenderTransitiveRbacAssignments = [System.Collections.Generic.List[object]]::new() foreach ($RbacAssignmentByGroup in ($AllDefenderRbacAssignments | where-object { $_.ObjectType -eq "group" }) ) { $RbacAssignmentByNestedGroupMembers = $AllTransitiveMembers | Where-Object { $_.GroupObjectId -eq $RbacAssignmentByGroup.ObjectId } if ($RbacAssignmentByNestedGroupMembers.Count -gt 0) { $RbacAssignmentByNestedGroupMembers | foreach-object { $TransitiveAssignment = [pscustomobject]@{ RoleAssignmentId = $RbacAssignmentByGroup.RoleAssignmentId RoleAssignmentScopeId = $RbacAssignmentByGroup.RoleAssignmentScopeId RoleAssignmentScopeName = $RbacAssignmentByGroup.RoleAssignmentScopeName AppScopeName = $RbacAssignmentByGroup.AppScopeName RoleAssignmentType = "Transitive" RoleAssignmentSubType = $_.RoleAssignmentSubType PIMManagedRole = $RbacAssignmentByGroup.PIMManagedRole PIMAssignmentType = $RbacAssignmentByGroup.PIMAssignmentType RoleDefinitionName = $RbacAssignmentByGroup.RoleDefinitionName RoleDefinitionId = $RbacAssignmentByGroup.RoleDefinitionId RoleType = $RbacAssignmentByGroup.RoleType RoleIsPrivileged = $RbacAssignmentByGroup.RoleIsPrivileged ObjectId = $_.Id ObjectType = $_.'@odata.type'.Replace("#microsoft.graph.", "").ToLower() TransitiveByObjectId = $RbacAssignmentByGroup.ObjectId TransitiveByObjectDisplayName = $_.GroupObjectDisplayName TransitiveByNestingObjectIds = $_.NestingObjectIds TransitiveByNestingObjectDisplayNames = $_.NestingObjectDisplayNames } $DefenderTransitiveRbacAssignments.Add($TransitiveAssignment) | Out-Null } } else { if ($null -ne $WarningMessages) { $WarningMessages.Add([PSCustomObject]@{ Type = "Empty Group" Message = "Empty group $($RbacAssignmentByGroup.ObjectId)" Target = $RbacAssignmentByGroup.ObjectId }) } } } } #endregion #region Filtering export if needed $AllDefenderRbacAssignments += $DefenderTransitiveRbacAssignments $AllDefenderRbacAssignments = $AllDefenderRbacAssignments | where-object { $_.ObjectType -in $PrincipalTypeFilter } $AllDefenderRbacAssignments = $AllDefenderRbacAssignments | select-object -Unique * $AllDefenderRbacAssignments | Sort-Object RoleAssignmentId, RoleAssignmentScopeName, RoleAssignmentScopeId, RoleAssignmentType, ObjectId #endregion } # SIG # Begin signature block # MIIniAYJKoZIhvcNAQcCoIIneTCCJ3UCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBlmWq6mf+6UlqQ # cbnbZVJJ1a9ODt2DeSiMW2ZaI2+IPaCCIDwwggXJMIIEsaADAgECAhAbtY8lKt8j # 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 # ARUwLwYJKoZIhvcNAQkEMSIEIIJlV/5h2gfMKfFiWXpE4kKugcrQ0qOFfL/6EnzW # yWIhMA0GCSqGSIb3DQEBAQUABIIBgD1qWylwrZHLIFCxFQvaenmmvNHqet3axi3O # XL7/JkF8C8d+FLdmXLXMNbAfnnXI4gTT3oFJ01Ez9eo8Uky1c4kKP4iMrT6vMyy0 # rR2J3F6m1mlTf4MC1WwadQgGSVYQW/LeaLJpn/c48Q/eDvljtpU9R5fbml07ISvJ # UtLtqBZ6TXpGeFyBH/SUh6STkZd7GM52nR7ZZMDxKJAZOKUfS0o9uSdnEdkpy0av # hv5L7xeXQoEz41RDfILkfi/GW55y7dwreSVM/dF3Nf7etNxQJwFcLnImQ7E1IJ4W # uCF97UmPESOKDj27tbzSuSvkv2jEhISMUhoSrausfx+3+zl+sodN+j6gXULySzTy # CK4snU+sYRMtHgIp3KIRcgjutlv/RxsTeKBdYAbgazBAQBcTMDy2AzBBFdNakimo # erDs/QYwXcdX7hGFZ8iFDzNeXHltlk8J71Bw/PJL6UkhIisl/5lkXr15NW5aAJwt # JqzrSOuJLvwxgiQL0sPbtSVABPLZgaGCBAIwggP+BgkqhkiG9w0BCQYxggPvMIID # 6wIBATBqMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0 # ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQQIQ # KPB3wRw2vf5fdDJHcCcuAzANBglghkgBZQMEAgIFAKCCAVYwGgYJKoZIhvcNAQkD # MQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNjEwMTMwOTQxMTJaMDcG # CyqGSIb3DQEJEAIvMSgwJjAkMCIEIIW+kOEK0kONfMkotq9IsJqyCBd87PiwEmxY # 05EFJcQ8MD8GCSqGSIb3DQEJBDEyBDCudTXBoG/bN5KOouMvNRZ8UVQYmG3jQsnM # QPZTxgv301uIMWoDKaffba2kX6gnZJowgZ8GCyqGSIb3DQEJEAIMMYGPMIGMMIGJ # MIGGBBRXFGhBDKha80JO+RZKUTYQ9NONmDBuMFqkWDBWMQswCQYDVQQGEwJQTDEh # MB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQwIgYDVQQDExtDZXJ0 # dW0gVGltZXN0YW1waW5nIDIwMjEgQ0ECECjwd8EcNr3+X3QyR3AnLgMwDQYJKoZI # hvcNAQEBBQAEggIATLemQsT8iWt6mNEAUQNabLUe0WF2vUBGb9xZkHXn9ZZgi0Em # R6jzLGehdL4yNeuKxULdjWtswLy3mwq7RUU3l2+PnlwA7rn2MQJMwHUXHI6b9HXk # LmGAiPyiyJF/qlzPxmHUXFlf+ZxctajY23wx5HEn6UNvfC9Z3tMFKuZ7Hnbmzzgl # WkIyg3Em/7H8xfhcADJ0GuatKKY5QzKGlFqweNlZjLjHPq0c2Cg/+K+W8mNpNEZT # V4WQP8dMg1i7OJligNjO9+xFiuC6/TNA4JalBhj83Umqs/mZfUTtMxywOSCC/kpB # i1TQ5xk+Ip1L8/yxr9QM44YhMa5hu8IduNYg14c5M9j9bQLdv3sh5fnhKZUpINZF # pcmbdmWSQOSVLj936VjDfEvyayLwGK6Nh87Xs9ITrXuidY7DB2zg4fkCwNOGgnMa # W7Ll2FiePtaqf6M0i9tBP9vqW2lHeralzwKW9THblZ8rwX1zomAi8dHGQg6hQYpz # Sc89mB7ReNMG0GtXMfRFCkhwPfI7oFJe6/iLgB9PQ2n3E76Q0nRQTa4yAVviL6aw # 8P4uobee596ZCqFyzBjMG/EHGLX1Qc+u7NNm94ascAASs9Y/PYXchlUD/+9BKyG/ # XGbfLiEW8ehH328wcH8XVuh4UL847ItB23aWq5u3ECCAOkmIK55aCzaIkq8= # SIG # End signature block |