ozo-ad-manage-delegations.ps1
|
#Requires -Modules ActiveDirectory,DFSN,DFSR,DSACL,GroupPolicy,ImportExcel,OZO,OZOAD,OZOFiles,OZOLogger <#PSScriptInfo .VERSION 0.0.1 .GUID 069ad55f-163a-4900-b35b-2a1100d64e81 .AUTHOR Andy Lievertz <alievertz@onezeroone.dev> .COMPANYNAME One Zero One .COPYRIGHT This script is released under the terms of the GNU General Public License ("GPL") version 2.0. .TAGS .LICENSEURI https://github.com/onezeroone-dev/OZO-AD-Manage-Delegations/blob/main/LICENSE .PROJECTURI https://github.com/onezeroone-dev/OZO-AD-Manage-Delegations .ICONURI .EXTERNALMODULEDEPENDENCIES ActiveDirectory,DFSN,DFSR,DSACL,GroupPolicy,ImportExcel .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES https://github.com/onezeroone-dev/OZO-AD-Manage-Delegations/blob/main/CHANGELOG.md #> <# .SYNOPSIS See description. .DESCRIPTION Creates AD delegations based on a configuration file. This script can create OU Delegations, apply permissions to GPOs, grant access to DFSN roots, grant access to DFSN folders, and create delegations to DFSR replication groups. .PARAMETER Configuration Path to the JSON configuration file. Defaults to "ad-create-delegations.json" in the same directory as the script. .PARAMETER OutDir Path for the Excel results report. Defaults to the current directory. .LINK https://github.com/onezeroone-dev/OZO-AD-Manage-Delegations/blob/main/README.md .LINK https://github.com/SimonWahlin/DSACL/blob/master/docs .LINK https://learn.microsoft.com/en-us/powershell/module/grouppolicy/set-gppermission?view=windowsserver2022-ps .LINK https://learn.microsoft.com/en-us/powershell/module/dfsn/grant-dfsnaccess?view=windowsserver2022-ps .LINK https://learn.microsoft.com/en-us/powershell/module/dfsr/grant-dfsrdelegation?view=windowsserver2022-ps .NOTES Run this script as a user with rights to create AD delegations (e.g., a Domain Admin) from within a writable directory. #> # PARAMETERS [CmdletBinding(SupportsShouldProcess = $true)] Param ( [Parameter(Mandatory=$false,HelpMessage="Path to the JSON configuration file")][String]$Configuration = (Join-Path -Path $PSScriptRoot -ChildPath "ad-create-delegations.json"), [Parameter(Mandatory=$false,HelpMessage="Path for the Excel results report")][String]$OutDir = (Get-Location) ) # CLASSES Class Main { # PROPERTIES: Strings [String] $excelPath = $null # PROPERTIES: PSCustomObjects [PSCustomObject] $Json = $null [PSCustomObject] $ozoLogger = $null # PROPERTIES: PSCUstomObject lists [System.Collections.Generic.List[PSCustomObject]] $ouDelegations = @() [System.Collections.Generic.List[PSCustomObject]] $gpoPermissions = @() [System.Collections.Generic.List[PSCustomObject]] $dfsnRootPermissions = @() [System.Collections.Generic.List[PSCustomObject]] $dfsnFolderPermissions = @() [System.Collections.Generic.List[PSCustomObject]] $dfsrPermissions = @() # METHODS: Constructor method Main($Configuration,$OutDir) { # Create a logger object $this.ozoLogger = (New-OZOLogger) # Declare ourselves to the world $this.ozoLogger.Write("Starting process.","Information") # And the results of ValidateConfiguration and ValidateEnvironment to set validates If (($this.ValidateConfiguration($Configuration) -And $this.ValidateEnvironment($OutDir)) -eq $true) { # Configuration and environment validate; call the permissions methods $this.CreateOUDelegations() $this.SetGPOPermissions() $this.GrantDFSNRootPermissions() $this.GrantDFSNFolderPermissions() $this.GrantDFSRPermissions() } # Report $this.Report() $this.ozoLogger.Write("Process complete.","Information") } # METHODS: Configuration validation method Hidden [Boolean] ValidateConfiguration($Configuration) { # control variable [Boolean]$Return = $true # Determine if the JSON path is valid If ([Boolean](Test-Path -Path $Configuration -ErrorAction SilentlyContinue) -eq $true) { # JSON path is valid; try to read the JSON Try { $this.Json = Get-Content $Configuration -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop # Success } Catch { # Failure $this.ozoLogger.Write(("Invalid JSON in " + $Configuration + "."),"Error") $Return = $false } } Else { # JSON path is not valid $this.ozoLogger.Write(("Could not read configuration file " + $Configuration + "."),"Error") $Return = $false } # Return return $Return } # METHODS: Environment validation method Hidden [Boolean] ValidateEnvironment($OutDir) { # Control variable [Boolean] $Return = $true # Determine if outDir is writable If ((Test-OZOPath -Path $OutDir -Writable) -eq $true) { # OutDir is writable $this.excelPath = (Join-Path -Path $OutDir -ChildPath ((Get-OZO8601Date -Time) + "-ozo-ad-manage-delegations.xlsx")) $this.ozoLogger.Write(("Using " + $this.excelPath + " for the Excel report."),"Information") } Else { # OutDir is not writable $this.ozoLogger.Write("Provided output directory is not writable.","Warning") # Determine if current location is writable If ((Test-OZOPath -Path (Get-Location) -Writable) -eq $true) { # Current location is writable $this.excelPath = (Join-Path -Path (Get-Location) -ChildPath ((Get-OZO8601Date -Time) + "-ozo-ad-manage-delegations.xlsx")) $this.ozoLogger.Write(("Using " + $this.excelPath + " for the Excel results report."),"Information") } Else { # Current location is not writable $this.ozoLogger.Write("Current directory is not writable; cannot proceed.","Error") $Return = $false } } # Return return $Return } # METHODS: CreateDelegations method Hidden [Void] CreateOUDelegations() { # Determine if there are OU Delegations to process If (($this.Json.ADOUDelegations).Count -gt 0) { # There are OU Delegations to process; report $this.ozoLogger.Write("Processing Delegations.","Information") # Iterate over the OU Delegations ForEach ($delegation in $this.Json.ADOUDelegations) { # Iterate over the OUs ForEach ($ouDN in $delegation.OUs) { # Iterate over the Identities ForEach ($identity in $delegation.Identities) { # Iterate over the Permissions ForEach ($permission in $delegation.Permissions) { # Create an OUDelegation object for this Delegation's OU + Identity + Permission $this.ouDelegations.Add(([OUDelegation]::new($ouDN,$identity,$permission))) } } } } } Else { # There are no OU Delegations to process $this.ozoLogger.Write("No delegations to process.","Warning") } } # METHODS: SetGPOPermissions method Hidden [Void] SetGPOPermissions() { # Determine if there are GPO Permissions to process If (($this.Json.ADGPOPermissions).Count -gt 0) { # There are GPO Permissiont to process; report $this.ozoLogger.Write("Processing GPO Permissions.","Information") # Iterate over the Permissions ForEach ($gpoPermission in $this.Json.ADGPOPermissions) { # Iterate over the GPO Names ForEach ($gpoName in $gpoPermission.GPONames) { # Iterate over the Group Names ForEach ($group in $gpoPermission.GroupNames) { # Iterate over the Permissions ForEach ($permission in $gpoPermission.Permissions) { # Create a GPOPermissions object for this GPO Name + Group Name + Permission $this.gpoPermissions.Add(([GPOPermissions]::new($gpoName,$group,$permission))) } } } } } Else { # There are no GPO Permissiosn to process $this.ozoLogger.Write("No GPO permissions to process.","Warning") } } # METHODS: GrantDFSNRootPermissions method Hidden [Void] GrantDFSNRootPermissions() { # Determine if there are DFSN Root Permissions to process If (($this.Json.ADDFSNRootPermissions).Count -gt 0) { # There are DFSN Root Permissions to process; report $this.ozoLogger.Write("Processing DFSN root permissions.","Information") # Iterate over the DFSN Root Permissions ForEach ($dfsnRootPermission in $this.Json.ADDFSNRootPermissions) { # Iterate over the Roots ForEach ($dfsnRoot in $dfsnRootPermission.DFSNRoots) { # Iterate over the Identities ForEach ($identity in $dfsnRootPermission.Identities) { # Create a DFSNRootPermissions object for this Root + Identity $this.dfsnRootPermissions.Add(([DFSNRootPermissions]::new($dfsnRoot,$identity))) } } } } Else { # There are no DFSN Root Permissions to process $this.ozoLogger.Write("No DFSN root permissions to set.","Warning") } } # METHODS: GrantDFSNFolderPermissions method Hidden [Void] GrantDFSNFolderPermissions() { # Determine if there are DFSN Folder Permissions to process If (($this.Json.ADDFSNFolderPermissions).Count -gt 0) { # There are DFSN Folder Permissions to process $this.ozoLogger.Write("Processing DFSN folder permissions.","Information") # Iterate over the DFSN Folder Permissions ForEach ($dfsnFolderPermission in $this.Json.ADDFSNFolderPermissions) { # Iterate over the Folders ForEach ($dfsnFolder in $dfsnFolderPermission.DFSNFolders) { # Iterate over the Identities ForEach ($identity in $dfsnFolderPermission.Identities) { # Create a DFSNFolderPermissions object for this Folder + Identity $this.dfsnFolderPermissions.Add(([DFSNFolderPermissions]::new($dfsnFolder,$identity))) } } } } Else { # There are no DFSN Folder Permissions to process $this.ozoLogger.Write("No DFSN folder permissions to set.","Warning") } } # METHODS: GrantDFSRPermissions method Hidden [Void] GrantDFSRPermissions() { # Determine if there are DFSR Permissions to process If (($this.Json.ADDFSRPermissions).Count -gt 0) { # There are DFSR Permissions to process; report $this.ozoLogger.Write("Processing DFSR Permissions.","Information") # Iterate over the DFSR Permissions ForEach ($dfsrPermission in $this.Json.ADDFSRPermissions) { # Iterate over the Groups ForEach ($dfsrGroup in $dfsrPermission.DFSRGroups) { # Iterate over the Identities ForEach ($identity in $dfsrPermission.Identities) { # Create a DFSRPermissions object for this Group + Identity $this.dfsrPermissions.Add(([DFSRPermissions]::new($dfsrGroup,$identity))) } } } } Else { # There are no DFSR Permissiosn to process $this.ozoLogger.Write("No DFSR permissions to set.","Warning") } } # Report method Hidden [Void] Report() { # Determine that at least one object was processed If (($this.ouDelegations + $this.gpoPermissions + $this.dfsnRootPermissions + $this.dfsnFolderPermissions + $this.dfsrPermissions).Count -gt 0) { # At least one object was processed; Produce Excel output $this.ouDelegations | Select-Object -Property @{Name="Delegation";Expression={$_.Description}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Export-Excel -WorksheetName "Delegations" -Path $this.excelPath $this.gpoPermissions | Select-Object -Property @{Name="GPO Permission";Expression={$_.Description}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Export-Excel -WorksheetName "GPO Permissions" -Path $this.excelPath $this.dfsnRootPermissions | Select-Object -Property @{Name="DFSN Root Permission";Expression={$_.Description}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Export-Excel -WorksheetName "DFSN Root Permissions" -Path $this.excelPath $this.dfsnFolderPermissions | Select-Object -Property @{Name="DFSN Folder Permission";Expression={$_.Description}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Export-Excel -WorksheetName "DFSN Folder Permissions" -Path $this.excelPath $this.dfsrPermissions | Select-Object -Property @{Name="DFSR Permission";Expression={$_.Description}},@{Name="Success";Expression={$_.Success}},@{Name="Messages";Expression={$_.messages -Join "; "}} | Export-Excel -WorksheetName "DFSR Permissions" -Path $this.excelPath # Determine if session is interactive If ([Environment]::UserInteractive -eq $true) { # Session is interactive; produce output for the operator $this.ouDelegations | Select-Object -Property @{Name="Delegation";Expression={$_.Description}},@{Name="Success";Expression={$_.Success}} | Format-Table | Out-Host $this.gpoPermissions | Select-Object -Property @{Name="GPO Permission";Expression={$_.Description}},@{Name="Success";Expression={$_.Success}} | Format-Table | Out-Host $this.dfsnRootPermissions | Select-Object -Property @{Name="DFSN Root Permission";Expression={$_.Description}},@{Name="Success";Expression={$_.Success}} | Format-Table | Out-Host $this.dfsnFolderPermissions | Select-Object -Property @{Name="DFSN Folder Permission";Expression={$_.Description}},@{Name="Success";Expression={$_.Success}} | Format-Table | Out-Host $this.dfsrPermissions | Select-Object -Property @{Name="DFSR Permission";Expression={$_.Description}},@{Name="Success";Expression={$_.Success}} | Format-Table | Out-Host # Determine if Excel was created If ([Boolean](Test-Path -Path $this.excelPath -ErrorAction SilentlyContinue) -eq $true) { # Excel was created $this.ozoLogger.Write(("For additional information, please see " + $this.excelPath + "."),"Information") } Else { $this.ozoLogger.Write("No Excel results report generated.","Warning") } } } Else { # No objects were processed $this.ozoLogger.Write("No objects were processed.","Warning") } } } Class OUDelegation { # PROPERTIES: Booleans, Hashtables, Strings [Boolean] $Success = $false [Boolean] $Validates = $false # PROPERTIES: Hashtables [Hashtable] $erMap = @{} [Hashtable] $guidMap = @{} # PROPERTIES: Strings [String] $dcOuDN = $null [String] $duOuDN = $null [String] $ouDN = $null [String] $Description = $null [String] $Identity = $null [String] $identityDN = $null [String] $Permission = $null # PROPERTIES: PSCustomObjects [PSCustomObject] $Acl = $null [PSCustomObject] $Permissions = @{ CreateChildComputers = "Delegates create child computer objects" CreateChildContacts = "Delegates create child contacts objects" CreateChildGroups = "Delegates create child groups objects" CreateChildUsers = "Delegates create child user objects" CreateOUs = "Delegates create OU" DeleteChildComputers = "Delegates delete child computer objects" DeleteChildContacts = "Delegates delete child contacts objects" DeleteChildGroups = "Delegates delete child groups objects" DeleteChildUsers = "Delegates delete child user objects" DeleteOUs = "Delegates delete OU" DomainJoinComputer = "Delegates create computer objects, Write Name, and Write name" DomainLeaveComputer = "Delegates delete computer objects, Write Name, and Write name" EnableDisableComputers = "Delegates enable and disable computer objects" EnableDisableUsers = "Delegates enable and disable user objects" FullControlComputers = "Delegates full control to computer objects" FullControlContacts = "Delegates full control to contacts objects" FullControlGroups = "Delegates full control to group objects" FullControlUsers = "Delegates full control to user objects" FullControlOUs = "Delegates full control for organizational unit objects" LinkGPO = "Delegates link GPO" ModifyGroupMembership = "Delegates modify group membership" ResetUserPasswords = "Delegates reset password" ReadBitLockerRecovery = "Delegates read to the BitLocker Recovery information" } # PROPERTIES: String lists [System.Collections.Generic.List[String]] $Messages = @() # METHODS: Constructor method OUDelegation($ouDN,$Identity,$Permission) { # Set properties $this.ouDN = $ouDN $this.Identity = $Identity $this.Permission = $Permission $this.Description = ($this.Permission + " for " + $this.Identity + " on " + $this.ouDN) # Create a guid map and extended rights map $this.guidMap = (New-OZOADGuidMap) $this.erMap = (New-OZOADExtendedRightsMap) # Determine if delegation validates If ($this.ValidateDelegation() -eq $true) { # Delegation validated $this.Validates = $true # Switch on permission Switch ($this.Permission) { "CreateChildComputers" { $this.Success = $this.CreateChildComputers() } "CreateChildContacts" { $this.Success = $this.CreateChildContacts() } "CreateChildGroups" { $this.Success = $this.CreateChildGroups() } "CreateChildUsers" { $this.Success = $this.CreateChildUsers() } "CreateOUs" { $this.Success = $this.CreateOUs() } "DeleteChildComputers" { $this.Success = $this.DeleteChildComputers() } "DeleteChildContacts" { $this.Success = $this.DeleteChildContacts() } "DeleteChildGroups" { $this.Success = $this.DeleteChildGroups() } "DeleteChildUsers" { $this.Success = $this.DeleteChildUsers() } "DeleteOUs" { $this.Success = $this.DeleteOUs() } "DomainJoinComputer" { $this.Success = $this.DomainJoinComputer() } "EnableDisableComputers" { $this.Success = $this.EnableDisableComputers() } "EnableDisableUsers" { $this.Success = $this.EnableDisableUsers() } "FullControlComputers" { $this.Success = $this.FullControlComputers() } "FullControlContacts" { $this.Success = $this.FullControlContacts() } "FullControlGroups" { $this.Success = $this.FullControlGroups() } "FullControlUsers" { $this.Success = $this.FullControlUsers() } "FullControlOUs" { $this.Success = $this.FullControlOUs() } "LinkGPO" { $this.Success = $this.LinkGPO() } "ModifyGroupMembership" { $this.Success = $this.ModifyGroupMembership() } "ReadBitLockerRecovery" { $this.Success = $this.ReadBitLockerRecovery() } "ResetUserPasswords" { $this.Success = $this.ResetUserPasswords() } default { $this.Messages.Add(("No method found that matches " + $this.permission)) $this.Success = $false } } } Else { # Delegation did not validate $this.Messages.Add("Delegation does not validate") $this.Validates = $false } } # METHODS: ValidateDelegation method Hidden [Boolean] ValidateDelegation() { # Control variable [Boolean] $Return = $true # Determine if ouDN is empty or null If ([String]::IsNullOrEmpty($this.ouDN)) { # ouDN is empty or null $this.Messages.Add("OU cannot be empty or null") $Return = $false } # Determine if Identity is empty or null If ([String]::IsNullOrEmpty($this.Identity)) { # Identity is empty or null $this.Messages.Add("Identity cannot be empty or null") $Return = $false } Else { # Try to get the distinguished name of the Identity Try { $this.identityDN = (Get-ADObject -Filter {SamAccountName -eq $this.Identity} -ErrorAction Stop).DistinguishedName # Success; determine if IdentityDN is empty or null If ([String]::IsNullOrEmpty($this.identityDN)) { # IdentityDN is empty or null $this.Messages.Add("Failed to retrieve distinguished name for Identity") $Return = $false } } Catch { # Failure $this.Messages.Add("Identity does not exist in AD") $Return = $false } } # Determine if Permission is null or empty If ([String]::IsNullOrEmpty($this.Permission)) { # Permission is null or empty $this.Messages.Add("Permission cannot be empty or null") $Return = $false } Else { # Permission is not null or empty; determine if it does not match the permissions hashtable If (($this.Permissions.PSObject.Properties -Match $this.Permission) -eq $false) { # Permission does not appear in the hash table $this.Messages.Add("Permission does not exist") $Return = $false } } # Try to get the ACL for the OU Try { $this.Acl = Get-ACL ("AD:" + $this.ouDN) -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Unable to obtain ACL for " + $this.ouDN)) $Return = $false } # Return return $Return } # METHODS: CreateChildUsers method Hidden [Boolean] CreateChildComputers() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLCreateChild -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName Computer -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding create child computers delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: CreateChildContacts method Hidden [Boolean] CreateChildContacts() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLCreateChild -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName Contact -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding create child contacts delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: CreateChildGroups method Hidden [Boolean] CreateChildGroups() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLCreateChild -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName Group -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding create child groups delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: CreateChildUsers method Hidden [Boolean] CreateChildUsers() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLCreateChild -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName User -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding create child users delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: CreateDeleteOUs method Hidden [Boolean] CreateOUs() { # Control variable [Boolean] $Return = $true # Try to delegate create OU Try { Add-DSACLCreateChild -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeGuid ($this.guidMap['OrganizationalUnit']) -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding create OU delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: DeleteChildUsers method Hidden [Boolean] DeleteChildComputers() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLDeleteChild -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName Computer -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding delete child computers delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: DeleteChildContacts method Hidden [Boolean] DeleteChildContacts() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLDeleteChild -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName Contact -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding delete child contacts delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: DeleteChildGroups method Hidden [Boolean] DeleteChildGroups() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLDeleteChild -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName Group -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding delete child groups delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: DeleteChildUsers method Hidden [Boolean] DeleteChildUsers() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLDeleteChild -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName User -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding delete child users delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: CreateDeleteOUs method Hidden [Boolean] DeleteOUs() { # Control variable [Boolean] $Return = $true # Try to delegate delete OU Try { Add-DSACLDeleteChild -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeGuid ($this.guidMap['OrganizationalUnit']) -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding delete OU delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: DomainJoinComputer method Hidden [Boolean] DomainJoinComputer() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLJoinDomain -TargetDN $this.ouDN -DelegateDN $this.identityDN -AllowCreate -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding join domain delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: EnableDisableComputers method Hidden [Boolean] EnableDisableComputers() { # Control variable [Boolean] $Return = $true # Try to delegate Try { # Add-DSACLWriteAccountRestrictions -TargetDN <String> -DelegateDN <String> -ObjectTypeName <String> -AccessType <AccessControlType> [-NoInheritance] [<CommonParameters>] Add-DSACLWriteAccountRestrictions -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName Computer -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding enable disable users delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: EnableDisableUsers method Hidden [Boolean] EnableDisableUsers() { # Control variable [Boolean] $Return = $true # Try to delegate Try { # Add-DSACLWriteAccountRestrictions -TargetDN <String> -DelegateDN <String> -ObjectTypeName <String> -AccessType <AccessControlType> [-NoInheritance] [<CommonParameters>] Add-DSACLWriteAccountRestrictions -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName User -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding enable disable users delegation. Error message is " + $_)) $Return = $false } # Return return $Return } # METHODS: FullControlComputers method Hidden [Boolean] FullControlComputers() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLFullControl -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName Computer -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding full control computers delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: FullControlContacts method Hidden [Boolean] FullControlContacts() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLFullControl -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName Contact -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding full control contacts delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: FullControlGroup method Hidden [Boolean] FullControlGroups() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLFullControl -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName Group -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding full control groups delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: FullControlUsers method Hidden [Boolean] FullControlUsers() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLFullControl -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName User -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding full control users delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: FullControlUsers method Hidden [Boolean] FullControlOUs() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLFullControl -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeGuid ($this.guidMap['OrganizationalUnit']) -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding full control organizational units delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: LinkGPO method Hidden [Boolean] LinkGPO() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLLinkGPO -TargetDN $this.ouDN -DelegateDN $this.identityDN -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding link GPO delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: ModifyGroupMembership method Hidden [Boolean] ModifyGroupMembership() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLManageGroupMember -TargetDN $this.ouDN -DelegateDN $this.identityDN -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding modify group membership delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: ReadBitLockerRecovery method Hidden [Boolean] ReadBitLockerRecovery() { # Control variable [Boolean] $Return = $true # Set parameters [Hashtable] $Parameters = @{ TargetDN = $this.ouDN DelegatDN = $this.identityDN ActiveDirectoryRights = [System.DirectoryServices.ActiveDirectoryRights]"ReadProperty,ExtendedRight" AccessControlType = [System.Security.AccessControl.AccessControlType]"Allow" ObjectType = [Guid]"00000000-0000-0000-0000-000000000000" InheritanceType = [System.DirectoryServices.ActiveDirectorySecurityInheritance]"All" InheritedObjectType = [Guid]$this.guidMap["msFVE-RecoveryInformation"] } # Try to delegate Try { Add-DSACLCustom @Parameters -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding read bitlocker recovery information delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } # METHODS: Reset password method Hidden [Boolean] ResetUserPasswords() { # Control variable [Boolean] $Return = $true # Try to delegate Try { Add-DSACLResetPassword -TargetDN $this.ouDN -DelegateDN $this.identityDN -ObjectTypeName User -AccessType Allow -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error adding reset password delegation. Error message is: " + $_)) $Return = $false } # Return return $Return } } Class GPOPermissions { # PROPERTIES: Booleans [Boolean] $Success = $false [Boolean] $Validates = $false # PROPERTIES: Strings [String] $Description = $null [String] $gpoName = $null [String] $Group = $null [String] $Permission = $null # PROPERTIES: PSCustomObjects [PSCustomObject] $Permissions = [PSCustomObject]@{ GpoRead = "Allows reading a named GPO" GpoApply = "placeholder" GpoEdit = "Allows editing a named GPO" GpoEditDeleteModifySecurity = "placeholder" } # PROPERTIES: String lists [System.Collections.Generic.List[String]] $Messages = @() # METHODS: Constructor method GPOPermissions($gpoName,$group,$permission) { # Set properties $this.gpoName = $gpoName $this.Group = $group $this.Permission = $permission $this.Description = ($this.Permission + " for " + $Group + " on " + $gpoName) # Determine if the GPO permissions validate If ($this.ValidateGPOPermission() -eq $true) { # GPO permissions validate $this.Validates = $true $this.Success = $this.SetGPOPermission() } Else { # GPO permissions do not validate $this.Messages.Add("GPO permission does not validate") $this.Validates = $false } } # METHODS: ValidateGPOPermission method Hidden [Boolean] ValidateGPOPermission() { # Control variable [Boolean] $Return = $true # Determine if gpoName is null or empty If ([String]::IsNullOrEmpty($this.gpoName)) { # gpoName is null or empty $this.Messages.Add("GpoName cannot be empty or null") $Return = $false } Else { # gpoName is not null or empty; try to get the GPO Try { Get-GPO -Name $this.gpoName -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add("GPO does not exist in AD") $Return = $false } } # Determine if Group is null or empty If ([String]::IsNullOrEmpty($this.Group)) { # Group is null or empty $this.Messages.Add("Group cannot be empty or null") $Return = $false } Else { # Group is not null or empty; try to get the group Try { Get-ADObject -Filter {SamAccountName -eq $this.Group} -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add("Group does not exist in AD") $Return = $false } } # Determine if Permission is null or empty If ([String]::IsNullOrEmpty($this.Permission)) { # Permission is null or empty $this.Messages.Add("Permission cannot be empty or null") $Return = $false } Else { # Permission is not null or empty; detemine if Permissions exists in the Permissions object If (($this.Permissions.PSObject.Properties -Match $this.Permission) -eq $false) { # Permission does not exist in Permisssions object $this.Messages.Add("Permission is not handled") $Return = $false } } # Return return $Return } # METHODS: GpoEdit method Hidden [Boolean] SetGPOPermission() { # Control variable [Boolean] $Return = $true # Try to set GPO permission Try { Set-GPPermission -Name $this.gpoName -TargetName $this.Group -TargetType Group -PermissionLevel $this.Permission -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add("Error setting GPO permission") $Return = $false } # Return return $Return } } Class DFSNRootPermissions { # PROPERTIES: Booleans [Boolean] $Success = $false [Boolean] $Validates = $false # PROPERTIES: Strings [String] $Description = $null [String] $dfsnRoot = $null [String] $Identity = $null # PROPERTIES: String lists [System.Collections.Generic.List[String]] $Messages = @() # METHODS: Constructor method DFSNRootPermissions($dfsnRoot,$identity) { # Set properties $this.dfsnRoot = $dfsnRoot $this.Identity = $identity $this.Description = ("Permission for " + $this.Identity + " on " + $this.dfsnRoot) # Determine if the DFSN root permission validates If ($this.ValidateDFSNRootPermission() -eq $true) { # DFSN root permission validates $this.Validates = $true # Call SetDFSNRootPermission to set Success $this.Success = $this.SetDFSNRootPermission() } Else { # DFSN root permission does not validate $this.Messages.Add("DFSN root permission does not validate.") $this.Validates = $false } } # METHODS: ValidateDFSNPermission method Hidden [Boolean] ValidateDFSNRootPermission() { # Control variable [Boolean] $Return = $true # Determine if dfsnRoot is null or empty If ([String]::IsNullOrEmpty($this.dfsnRoot)) { # dfsnRoot is null or empty $this.Messages.Add("DFSNRoot cannot be empty or null") $Return = $false } Else { # dfsnRoot is not null or empty; try to get the DFSN root Try { Get-DfsnRoot -Path $this.dfsnRoot -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("DFSN root does not exist in DFS. Error message is: " + $_)) $Return = $false } } # Determine if Identity is null or empty If ([String]::IsNullOrEmpty($this.Identity)) { # Identity is null or empty $this.Messages.Add("Identity cannot be empty or null") $Return = $false } Else { # Identity is not null or empty; try to get the object Try { Get-ADObject -Filter {SamAccountName -eq $this.Identity} -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add("Identity does not exist in AD") $Return = $false } } # Return return $Return } # METHODS: SetDFSNPermission Hidden [Boolean] SetDFSNRootPermission() { # Control variable [Boolean] $Return = $true # Try to set the DFSN root permission Try { Set-DfsnRoot -GrantAdminAccounts $this.Identity -Path $this.dfsnRoot -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("Error setting DFSN root permission. Error message is: " + $_)) $Return = $false } # Return return $Return } } Class DFSNFolderPermissions { # PROPERTIES: Booleans [Boolean] $Success = $false [Boolean] $Validates = $false # PROPERTIES: Strings [String] $Description = $null [String] $dfsnFolder = $null [String] $Identity = $null # PROPERTIES: String lists [System.Collections.Generic.List[String]] $Messages = @() # METHODS: Constructor method DFSNFolderPermissions($dfsnFolder,$identity) { # Set properties $this.dfsnFolder = $dfsnFolder $this.Identity = $identity $this.Description = ("Permission for " + $this.Identity + " on " + $this.dfsnFolder) # Determine if the DFSN folder permission validates If ($this.ValidateDFSNFolderPermission() -eq $true) { # DFSN folder permission validates $this.Validates = $true # Call SetDFSNFolderPermissions to set Success $this.Success = $this.SetDFSNFolderPermission() } Else { # DFSN folder permission does not validate $this.Messages.Add(("DFSN folder permission " + $this.Description + " does not validate")) $this.Validates = $false } } # METHODS: ValidateDFSNPermission method Hidden [Boolean] ValidateDFSNFolderPermission() { # Control variable [Boolean] $Return = $true # Determine if dfsnFolder is null or empty If ([String]::IsNullOrEmpty($this.dfsnFolder)) { # dfsnFolder is null or ermpty $this.Messages.Add("DFSNFolder cannot be empty or null") $Return = $false } Else { # dfsnFolder is not null or empty; attempt to get the folder Try { Get-DfsnFolder -Path $this.dfsnFolder -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add(("DFSN folder does not exist in DFS. Error message is: " + $_)) $Return = $false } } # Determine if Identity is null or empty If ([String]::IsNullOrEmpty($this.Identity)) { # Identity is null or empty $this.Messages.Add("Identity cannot be empty or null") $Return = $false } Else { # Identity is not null or empty Try { Get-ADObject -Filter {SamAccountName -eq $this.identity} -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add("Identity does not exist in AD") $Return = $false } } # Return return $Return } # METHODS: SetDFSNPermission Hidden [Boolean] SetDFSNFolderPermission() { # Control variable $Return = $true # Try to grant the DFSN folder permission Try { Grant-DfsnAccess -Path $this.dfsnFolder -AccountName $this.Identity -ErrorAction Stop # Success } Catch { $this.Messages.Add(("Error setting DFSN folder permission. Error message is: " + $_)) $Return = $false } # Return return $Return } } Class DFSRPermissions { # PROPERTIES: Booleans [Boolean] $Success = $false [Boolean] $Validates = $false # PROPERTIES: Strings [String] $Description = $null [String] $dfsrGroup = $null [String] $Identity = $null # PROPERTIES: String lists [System.Collections.Generic.List[String]] $Messages = @() # METHODS: Constructor method DFSRPermissions($dfsrGroup,$identity) { $this.dfsrGroup = $dfsrGroup $this.identity = $identity $this.Description = ("Permission for " + $this.Identity + " to " + $this.dfsrGroup) # Determine if the DFSR permission validates If ($this.ValidateDFSRPermission() -eq $true) { # DFSR permission validates $this.Validates = $true # Call SetDFSRPermission to set Success $this.Success = $this.SetDFSRPermission() } Else { # DFSR permission does not validate $this.Messages.Add("Permission does not validate") $this.Validates = $false } } # METHODS: ValidateDFSRPermission method Hidden [Boolean] ValidateDFSRPermission() { # Control variable [Boolean] $Return = $true # Determine if dfsrGroup is null or empty If ([String]::IsNullOrEmpty($this.dfsrGroup)) { # dfsrGroup is null or empty $this.Messages.Add("DFSRGroup cannot be empty or null") $Return = $false } Else { # dfsrGroup is not null or empty; try to get replication grpu Try { Get-DfsReplicationGroup -GroupName $this.dfsrGroup -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add("DFSR group does not exist in DFS") $Return = $false } } # Determine if Identity is null or empty If ([String]::IsNullOrEmpty($this.Identity)) { # Identity is null or empty $this.Messages.Add("Identity cannot be empty or null") $Return = $false } Else { # Identity is not null or empty; attempt to get the object Try { Get-ADObject -Filter {SamAccountName -eq $this.Identity} -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add("Identity does not exist in AD") $Return = $false } } return $Return } # METHODS: SetDFSRPermission method Hidden [Boolean] SetDFSRPermission() { # Control variable [Boolean] $Return = $true # Try to grant permission Try { Grant-DfsrDelegation -GroupName $this.dfsrGroup -AccountName $this.identity -ErrorAction Stop # Success } Catch { # Failure $this.Messages.Add("Error setting DFSR permission") $Return = $false } # Return return $Return } } # MAIN [Main]::new($Configuration,$OutDir) | Out-Null # SIG # Begin signature block # MIIvsAYJKoZIhvcNAQcCoIIvoTCCL50CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA7ZODJnk+7WSDZ # 3vNSlBXbUJ9xM/jT4oUd5exAcZCgfqCCEgUwggVvMIIEV6ADAgECAhBI/JO0YFWU # jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI # DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM # EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy # dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG # EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv # IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s # hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD # J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7 # P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme # me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz # T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q # RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz # mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc # QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T # OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/ # AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID # AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD # VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV # HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE # VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v # ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE # KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI # hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF # OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC # J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ # pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl # d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH # +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggYaMIIEAqADAgECAhBiHW0M # UgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYD # VQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENv # ZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5 # NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzAp # BgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0G # CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjI # ztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NV # DgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/3 # 6F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05Zw # mRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm # +qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUe # dyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz4 # 4MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBM # dlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQY # MBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritU # pimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNV # HSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsG # A1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1 # YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsG # AQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2Rl # U2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0 # aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURh # w1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0Zd # OaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajj # cw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNc # WbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalO # hOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJs # zkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z7 # 6mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5J # KdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHH # j95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2 # Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/ # L9Uo2bC5a4CH2RwwggZwMIIE2KADAgECAhAbV4ef7ZvUwZ6AKRT0hWSAMA0GCSqG # SIb3DQEBDAUAMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0 # ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYw # HhcNMjYwOTE0MDAwMDAwWhcNMjcwOTE0MjM1OTU5WjBiMQswCQYDVQQGEwJVUzER # MA8GA1UECAwIQ29sb3JhZG8xHzAdBgNVBAoMFkxpZXZlcnR6IEFuZHJldyBIdWJl # cnQxHzAdBgNVBAMMFkxpZXZlcnR6IEFuZHJldyBIdWJlcnQwggIiMA0GCSqGSIb3 # DQEBAQUAA4ICDwAwggIKAoICAQCZl/Kqmb1yMMbn0868VlBqxo7LGu/SDy7bO3wz # D6jMoxzh2UT4iFxNnIEpHJq9SzxkhNgy60Lhzr0kGxBXypLJVGKP3JpS9inmF3zn # e/DWJcOFkQPkwYAsqEoJ6xt/klQlJqnwaN7AJUwUIgZ/72j37//UcWxltCMxnwT2 # wVUQ357c3GOafCKfBMUN9dEgUhwxt4x5GZ6Re/WSGKlh+eFtP1wNBsBXoT6Hme5E # u2L5vTYl0fmKVAsTGJ9k7eHvLE7IUWXOD6NI548uxFQ2FeISOdCRt0WmYmpWgi6S # j1Aoh1zLhsMaLgUPP+BXcOy0cO3zDJ+SZky+S4AB37Y0UBqy9hNvX0WbfQh3BF+2 # uWYGxHYc3FtefKKAbhQGNo9EO4pB0SBh/19a/EbbUpv67CRlO8PmGf8hEk6ic8O6 # 28OjkFi5ByIB7y/XKPKCZmeS/TWDrkyMpu8h9NGqHyWONE5oxpqCYMm3a0L92kfd # zY5e6vSLDuZZjlANRUm3VLnbxZcD8znUvaDbR+ALdJeSZryev8NVMnfOzwZM6vKz # fTPbYpFRBo0owFluKK85CKeZ8z+NyKQfvWh5gYXZw0JFZwdE4SE46fnNLJ3z9loF # Qly+7Dn2zUd/+CxwlRgkuEO1ng6EJ1OAAeA7PixyZob0gjg7ob7YzSK2v4AV/QdQ # oXa04QIDAQABo4IBrjCCAaowHwYDVR0jBBgwFoAUDyrLIIcouOxvSK4rVKYpqhek # zQwwHQYDVR0OBBYEFMiE5GpeP6V7hsDSdHBbSjojZscBMA4GA1UdDwEB/wQEAwIH # gDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMEoGA1UdIARDMEEw # NQYMKwYBBAGyMQECAQMCMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5j # b20vQ1BTMAgGBmeBDAEEATBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLnNl # Y3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ0NBUjM2LmNybDB5Bggr # BgEFBQcBAQRtMGswRAYIKwYBBQUHMAKGOGh0dHA6Ly9jcnQuc2VjdGlnby5jb20v # U2VjdGlnb1B1YmxpY0NvZGVTaWduaW5nQ0FSMzYuY3J0MCMGCCsGAQUFBzABhhdo # dHRwOi8vb2NzcC5zZWN0aWdvLmNvbTAjBgNVHREEHDAagRhhbGlldmVydHpAb25l # emVyb29uZS5kZXYwDQYJKoZIhvcNAQEMBQADggGBACvVVz+HNOH8p+CBcwmrYBVx # mlWNkTz84gmJZ/57FF5XK4kHeo6+QFalQkBSkiDheZa13+FdwUYf1zcJu5hfymkZ # 9zmBhLlIkdluT1llv9GKr/tQaJFd2NXoLiJ7ysqRDbu47U1RR7XGU42HZHLUHa00 # Ha8KDHKYeRcCBMhltjpBK4Hw5daTzT+5fLhMHaOy3ZuWn4Fgx8zEcH1/cdEqnWNn # NxxCWbKcp4sRI0v9uStoUYGpvX8LkYtMUUuWPr7tZAAZiPws6ctOrdROmdEwfyah # IMt2drMfTXZVPpL/5okl37qOYhzV+u6vEvbc3xeAicAgsgOYkvvx5L2iUyFfGdLb # JN4ioPTCKcvN7oXFPwHfyGqwBxARyJy3so2OAFvY4AGY/9DwQVE8KZuplrkktC7Y # MzjB9SjEtvqnyW+h0fHd3H85B8GJiL8slRmIb5f+jJDvmu5RgoaoaMAYeX/V4HXY # gpSD92Hq5AwUjjUvj1WPk+AagPBupA+J4OM2S6eO0DGCHQEwghz9AgEBMGgwVDEL # MAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDErMCkGA1UEAxMi # U2VjdGlnbyBQdWJsaWMgQ29kZSBTaWduaW5nIENBIFIzNgIQG1eHn+2b1MGegCkU # 9IVkgDANBglghkgBZQMEAgEFAKB8MBAGCisGAQQBgjcCAQwxAjAAMBkGCSqGSIb3 # DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEV # MC8GCSqGSIb3DQEJBDEiBCCw468cKCOLy6mEp6Oy8Qg7kGhbhj/L2LsLq31z2YEe # YDANBgkqhkiG9w0BAQEFAASCAgBzV7aeiOhQw4RRc2rCfUTt552xUMJxruyMVTdD # U5h0ik+0zq57G3KUTRZfdxiKr7qPoZfqkVVilGWQoo1CtzzzPSykxBB1Vhk7QaiG # pYa4VjJgXiYTwg5b8b0hYbVNItNaY8emU7gc0laGUN14urnJdJs4H8vK2ptJnzjX # cxXtvmAP2dTesQoFAzmWuJg8GkuzFL/F7WA8P5shIrrMteBqUyqLuIf04P9AnbtI # iEqEVJgWoMOM9ZCxc+t/LZ1IO7yHqrkQNtvDU5VHwjBdG9Ygsm60TmGyq3ZTl3jJ # syL39AJfr6c7IZzrh00Vsk8TKpffib9FEoGsPIvIumvS3Pbtp1OlTLoMgOH6COYs # fu03irTUtNB1Id67qutgWfSKYPjQ7/BYjIY+JGlUIVHquJaRNnsQqGHBcUjnMLh5 # yUJEOtj0FWnVmWmgGw6oR6fOYjBsWe+S82F3Pbda5xYkXkMsexdrTmicJRU8h9/W # U1YfkjmQqOCIY24LSHg0P8o1X9b1bEZHM4EPra8sJDsl2r0Cuy6rnn+OvELydX9c # 7ORG/qYuwIznYsLCj1/Y6G6R182buGa7/KWy70BxJPMee9kj/C+w8X17xerkIrXt # aPzNxLP4fEQX4IFqIYw/I0qbYg6uOOzQPsMgDb3EaRlY7bW8coL6q7ehB5jP7jRG # 8bTvmKGCGewwghnoBgorBgEEAYI3AwMBMYIZ2DCCGdQGCSqGSIb3DQEHAqCCGcUw # ghnBAgEDMQ8wDQYJYIZIAWUDBAICBQAwgfgGCyqGSIb3DQEJEAEEoIHoBIHlMIHi # AgEBBgorBgEEAbIxAgEBMDEwDQYJYIZIAWUDBAIBBQAEIDKA8DJs3BpUwOpV4Gun # LoArmrQWqx/88zOMHph8xxkPAhUAsL56E6t9pJwwayQT1dzXF85Dlo0YDzIwMjYw # OTI4MDc0NzM2WqB2pHQwcjELMAkGA1UEBhMCR0IxFzAVBgNVBAgTDkdyZWF0ZXIg # TG9uZG9uMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxMDAuBgNVBAMTJ1NlY3Rp # Z28gUHVibGljIFRpbWUgU3RhbXBpbmcgU2lnbmVyIFIzN6CCFBcwggbiMIIEyqAD # AgECAhEA507yVbBQT/rbpt/3/IujFTANBgkqhkiG9w0BAQwFADBVMQswCQYDVQQG # EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSwwKgYDVQQDEyNTZWN0aWdv # IFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFI0MTAeFw0yNjAzMjUwMDAwMDBaFw0z # NzA2MjQyMzU5NTlaMHIxCzAJBgNVBAYTAkdCMRcwFQYDVQQIEw5HcmVhdGVyIExv # bmRvbjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTAwLgYDVQQDEydTZWN0aWdv # IFB1YmxpYyBUaW1lIFN0YW1waW5nIFNpZ25lciBSMzcwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQCy/8NtS9xQ2UUtBRF32bj7VK3n4m50Uqjk/zTciSzi # YV40H1LKah0/oEklYG42E4VCP3DvsBUB6DmpCkDZ0jCnZBPIEevaH15ZJOQwFWP2 # ZXr5YjlJpb68Nlbs+ElNvKx32/1YHde3qqUSLybjulxPLz6T85+HOIqK7M1Bep8L # spyhEP/q6nw5kGxTSrGvufmeH+JF8CnVBcVMFA40FlIYh0cDJVFhhfTfdWgLy/vW # uLMQoKkf3s/FvByf16r0rtbyHm/iemwxSioJL9zyZDDKUNAbHXl0dhXo2VxUV2Nc # PXWXuoKsjL+6cfk6Vm2DHnxAlFdFsaBDIF1JOkSnC6PeLlBznZn2buF3vIIYJcq6 # N/zeFRCk4/HXDz7zgRsRRMdUB+rhyk5FoZaBjw0nLq3GZ3fClLUx5es5pUAxzNOD # MBn7JkFYip2BAGBPER5eV0ROhk6tGTG+fUiMiV+vgjg1YnP5FvnYWyEtWeQD/B2h # p3vz0RvtdkM0p3igyadzrfpOBq5ppVk/YsuhTQkP99ivneHAGfi5e7lmxJ+meoBP # rRLuzMmb81rzzbESjJHMsn5RVtc6Ucs7rcMqQC13PUIO7BbGBETV2ufCmV6lPTp3 # P7XJOvmnUCRTPbVvMTpxP/z+SOHg4/OCBhiqs4FA9+4oQvlkk9w32NGASli9GWrm # 5wIDAQABo4IBjjCCAYowHwYDVR0jBBgwFoAUOnSlDGfGQlDC/bX8x7spNIL0erkw # HQYDVR0OBBYEFGEQ6XoSr1HEhdTyz6R0D1DNIK/4MA4GA1UdDwEB/wQEAwIGwDAM # BgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMEoGA1UdIARDMEEw # CAYGZ4EMAQQCMDUGDCsGAQQBsjEBAgEDCDAlMCMGCCsGAQUFBwIBFhdodHRwczov # L3NlY3RpZ28uY29tL0NQUzBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vY3JsLnNl # Y3RpZ28uY29tL1NlY3RpZ29QdWJsaWNUaW1lU3RhbXBpbmdDQVI0MS5jcmwwegYI # KwYBBQUHAQEEbjBsMEUGCCsGAQUFBzAChjlodHRwOi8vY3J0LnNlY3RpZ28uY29t # L1NlY3RpZ29QdWJsaWNUaW1lU3RhbXBpbmdDQVI0MS5jcnQwIwYIKwYBBQUHMAGG # F2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAD6j2N # 0azN+hl6k6bKB5/U6VuSOs93ZBb3Pczy9VtBIKu4947Z5GwL0aFngIxl+GSuLFrJ # gPruBCRvKJEJsm7kv+LQ1COVCEG9tZ+IRtr4ocUoa53lgdFaENlS0N4wgkZkbQEP # v+x+1lSjYh+T4JeL9mUznT7Erc6Sp5dWLka5sMP/m3GZi6oJPdPcsCKWagH7m2H2 # xDGIyHJC5PdH9phvi/KmhkktiSVTNNqVeV5bWdX2zhRE6UTfz0IcMoCL996lFIyd # XxOCE4MNDHDM0as4lnTiT/KHMccO6l8c9TnUVgmpci9ar1IABZ2U1XUkYjGGSn9M # C3EHDP9V39VuBVvZ33/BEV/EWSRrf07T7jFplKX+gQr/UOqPGMlE7ZJ72UaUkNJy # 7bVl3bcLKzdpjIHzLkf/4MVa1V7w8wqCv5W4gOnRGTlud5UMARbRM8BPxR/CXYXo # MmIOD8pmTk2axgRL4LG8XtuchISdCHRmtacAmLGq5XSYSVTHTXADlO48iDKh3HM2 # r98LSF6f0sG12d8V9Jn7C3wDUieOxuKj4MdWrW+hiJU2kF87v6eH00HgCFFc2V0+ # CvfOCMn7juzS41jLaINcBlKWQ/fKb/uDLfWOW73z1I2lFY7Xj8tQ1XYtK5eREjWI # tM8jpl1cbQOc88btR+0XS2TmboE/141+va2PWzCCBqcwggSPoAMCAQICEQCQrAhy # IP3Fp8RrXMcN9z0GMA0GCSqGSIb3DQEBDAUAMFcxCzAJBgNVBAYTAkdCMRgwFgYD # VQQKEw9TZWN0aWdvIExpbWl0ZWQxLjAsBgNVBAMTJVNlY3RpZ28gUHVibGljIFRp # bWUgU3RhbXBpbmcgUm9vdCBSNDYwHhcNMjYwMzI1MDAwMDAwWhcNNDEwMzI0MjM1 # OTU5WjBVMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSww # KgYDVQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFI0MTCCAiIw # DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK7kSqIBrYIcYvlmLVuaA8zw1RfB # hkn4G1CoemzjcYtML6yNUvKmwGH7y6/5MuSC1UYP/+9KYDSqvMQt/1hEKHYxMAD9 # oZpBkoaDQFEKbOJHelsKe+BaO0ZcENTKfePcraVkA7wrGAW2XHA5gQCQv4IKori/ # 3PNOXxnDMOk8yIMgVrlMeTxqfWJ4XkjT1xc2s9DD7URHWWJOFobTPoWs6mrDFlaY # 9FlAHDYTfbzvxQHVsvRmn3W+5ZmCwyk02I8KgGPT/UX4sTz41GiR+ppwUjQXa1+2 # tEHZbsdAKUtH3OPEVtZvlt7atx4h83IdRR8oYi8wjY3OjFKXFecWpQbzzsPxbUKP # wMWiTrzwkrFa8dH/1pDKRJt371W62PfqKPayCr/XbnBOlRn8CALSmHnRtGzuAWtT # JpcT3BKw6oy8IIL6wSbu938F6ZIbRNIc1dKbIJtr4ULN6R5ZfTdNEhwXctqp3RHD # bg4fuOl6LjNoaFwjud92EEDhzxFJzE1jqN4csceZIwxOT1aqfsfh0uFQE/lgTBuB # s3i6/WL2W1OceWLy3XEdXRK1f0EWCuea6dNfX2RRdjUfk5EltFnJkN2+bWhnK14O # PRKcyjOv5hKZ0iV4NRNd1+hjtva1rPyzb5Bs7EvFxqEQhgZbOq7qH3nm0rBwA0dx # niBOYCFPdu246JCxAgMBAAGjggFuMIIBajAfBgNVHSMEGDAWgBT2d2rdP/0BE/8W # oWyCAi/QCj0UJTAdBgNVHQ4EFgQUOnSlDGfGQlDC/bX8x7spNIL0erkwDgYDVR0P # AQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUH # AwgwIwYDVR0gBBwwGjAIBgZngQwBBAIwDgYMKwYBBAGyMQECAQMIMEwGA1UdHwRF # MEMwQaA/oD2GO2h0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY1Rp # bWVTdGFtcGluZ1Jvb3RSNDYuY3JsMHwGCCsGAQUFBwEBBHAwbjBHBggrBgEFBQcw # AoY7aHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljVGltZVN0YW1w # aW5nUm9vdFI0Ni5wN2MwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28u # Y29tMA0GCSqGSIb3DQEBDAUAA4ICAQAy3lJHZvGeA2b43yhzoarvobHVzbfl+Rfu # PDwej0wCQkYAN6scTt2GwFe22qbOCv/tllqFlLKQZE+E9jVyuPTbyQHwrM7R0oLa # pAEDC1+CowsqSRf/ptira5Pfd4PoHICnb9coPQtyZmHSQp5y9IGvqWf1qNfq7V2f # HZ8DvEQrLUzeoGF9BJRYu2OzacW3QQtUum3NOVf0gPRwv6I4991uhncJ6VP4lcpU # pHZKB7R3hiIUC09mR9KjzPVnXHvL9n2bAwiUECfK5Zezhiw27F2tgi39DETfU8M4 # n0N6xLgFzsf05M5GURX8C9+IX9V6kpmmKtrUzMti4LD66gtmf+mSm934K81NL6YQ # eMEk1rpYrWPypcW76Mir6wb1AgseLIHqn/GkeuQm7zOTDf3f5WoX14qVNjZWNHF3 # JxkutV6ZnhinfCLfdv5bnwKWUfceqOajCVntI6uCbHxjBg6SCsexc5AfIGno7gVF # vwifT4XONPsSUaJ71XsJ+EvciVUVnjOO4qxm0fWJTd8a7jP8mc4ZPqwJvQFtOp7+ # 6G+kUJAF0fnE8YgD8uttBReNTa1YmAeFMiqc38e8fI4eLm0zjM/eeGCHasnoqqrb # GwcF41iz9HXzFDwN4iD5z3QShp6HRiU3UpTwDJiiXcr0z6pjl7PyzJ3/tmWtGehV # 7CAfc/WlyzCCBoIwggRqoAMCAQICEDbCsL18Gzrno7PdNsvJdWgwDQYJKoZIhvcN # AQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYD # VQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3Jr # MS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 # MB4XDTIxMDMyMjAwMDAwMFoXDTM4MDExODIzNTk1OVowVzELMAkGA1UEBhMCR0Ix # GDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEuMCwGA1UEAxMlU2VjdGlnbyBQdWJs # aWMgVGltZSBTdGFtcGluZyBSb290IFI0NjCCAiIwDQYJKoZIhvcNAQEBBQADggIP # ADCCAgoCggIBAIid2LlFZ50d3ei5JoGaVFTAfEkFm8xaFQ/ZlBBEtEFAgXcUmanU # 5HYsyAhTXiDQkiUvpVdYqZ1uYoZEMgtHES1l1Cc6HaqZzEbOOp6YiTx63ywTon43 # 4aXVydmhx7Dx4IBrAou7hNGsKioIBPy5GMN7KmgYmuu4f92sKKjbxqohUSfjk1mJ # lAjthgF7Hjx4vvyVDQGsd5KarLW5d73E3ThobSkob2SL48LpUR/O627pDchxll+b # TSv1gASn/hp6IuHJorEu6EopoB1CNFp/+HpTXeNARXUmdRMKbnXWflq+/g36NJXB # 35ZvxQw6zid61qmrlD/IbKJA6COw/8lFSPQwBP1ityZdwuCysCKZ9ZjczMqbUcLF # yq6KdOpuzVDR3ZUwxDKL1wCAxgL2Mpz7eZbrb/JWXiOcNzDpQsmwGQ6Stw8tTCqP # umhLRPb7YkzM8/6NnWH3T9ClmcGSF22LEyJYNWCHrQqYubNeKolzqUbCqhSqmr/U # dUeb49zYHr7ALL8bAJyPDmubNqMtuaobKASBqP84uhqcRY/pjnYd+V5/dcu9ieER # jiRKKsxCG1t6tG9oj7liwPddXEcYGOUiWLm742st50jGwTzxbMpepmOP1mLnJskv # ZaN5e45NuzAHteORlsSuDt5t4BBRCJL+5EZnnw0ezntk9R8QJyAkL6/bAgMBAAGj # ggEWMIIBEjAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4E # FgQU9ndq3T/9ARP/FqFsggIv0Ao9FCUwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB # /wQFMAMBAf8wEwYDVR0lBAwwCgYIKwYBBQUHAwgwEQYDVR0gBAowCDAGBgRVHSAA # MFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VS # VHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDA1BggrBgEFBQcBAQQp # MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZI # hvcNAQEMBQADggIBAA6+ZUHtaES45aHF1BGH5Lc7JYzrftrIF5Ht2PFDxKKFOct/ # awAEWgHQMVHol9ZLSyd/pYMbaC0IZ+XBW9xhdkkmUV/KbUOiL7g98M/yzRyqUOZ1 # /IY7Ay0YbMniIibJrPcgFp73WDnRDKtVutShPSZQZAdtFwXnuiWl8eFARK3PmLqE # m9UsVX+55DbVIz33Mbhba0HUTEYv3yJ1fwKGxPBsP/MgTECimh7eXomvMm0/GPxX # 2uhwCcs/YLxDnBdVVlxvDjHjO1cuwbOpkiJGHmLXXVNbsdXUC2xBrq9fLrfe8IBs # A4hopwsCj8hTuwKXJlSTrZcPRVSccP5i9U28gZ7OMzoJGlxZ5384OKm0r568Mo9T # YrqzKeKZgFo0fj2/0iHbj55hc20jfxvK3mQi+H7xpbzxZOFGm/yVQkpo+ffv5gdh # p+hv1GDsvJOtJinJmgGbBFZIThbqI+MHvAmMmkfb3fTxmSkop2mSJL1Y2x/955S2 # 9Gu0gSJIkc3z30vU/iXrMpWx2tS7UVfVP+5tKuzGtgkP7d/doqDrLF1u6Ci3TpjA # ZdeLLlRQZm867eVeXED58LXd1Dk6UvaAhvmWYXoiLz4JA5gPBcz7J311uahxCweN # xE+xxxR3kT0WKzASo5G/PyDez6NHdIUKBeE3jDPs2ACc6CkJ1Sji4PKWVT0/MYIE # kzCCBI8CAQEwajBVMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1p # dGVkMSwwKgYDVQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFI0 # MQIRAOdO8lWwUE/626bf9/yLoxUwDQYJYIZIAWUDBAICBQCgggH6MBoGCSqGSIb3 # DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwOTI4MDc0NzM2 # WjA/BgkqhkiG9w0BCQQxMgQwvaGd++A4wwQdlwfICZCa87vMXrYaFtiO0yxWvbn8 # nudYJTXzKtF6D2elEwjkkBB6MIIBewYLKoZIhvcNAQkQAgwxggFqMIIBZjCCAWIw # FgQU6XgYqSjaFQqf4b+czHqruaAO7qwwgYgEFGXDKGlvfU5QLP0Dx8IGlxjK+/dP # MHAwW6RZMFcxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQx # LjAsBgNVBAMTJVNlY3RpZ28gUHVibGljIFRpbWUgU3RhbXBpbmcgUm9vdCBSNDYC # EQCQrAhyIP3Fp8RrXMcN9z0GMIG8BBSFPWMtk4KCYXzQkDXEkd6SwULaxzCBozCB # jqSBizCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNV # BAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsx # LjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkC # EDbCsL18Gzrno7PdNsvJdWgwDQYJKoZIhvcNAQEBBQAEggIAQErwtb7lqEDE2RV3 # FVyXA/yRr79Myi0JJsXUC9T52xX7Tjp3J/aJKOUYFQjePZQusgxURLJ1ITY9SfW1 # 4CATstLozEzGQT+vdB1qOL2TQWLWcRlAUoiBgSV8hIH1xnYv2mn5cFeTiiIK21P0 # zJXVU0kZbTm5qzM2heCTtAGXx1Q39SvI2HMMvwGbHOt4R4LicAplp8wd26pkNXif # 66xwzlrW2a6ReOd1i4AeC1e9sVErG6pByCiLdP6ilPpHGHcI2x1e9n84QzkIsb60 # gKgdtZni2/wwfiV0WMDv/t3q2Cc35/QO5TnNK3YcNALHlxEden8tqseppBO7sl/z # IN7WEyQcTBQzHXP1MsYpAFyh0pK3eN1IjoI+Ydm4+QkKXOlqLFbRDTjctqBsLQWC # oGKn4Szg7ppQQn4O3+rg+wxX0v9VHg9aQ7CJIapwCuGW8D5qClWemFWqi6KonWeF # 9k4xA6Oqr2tlNVT1JO4IGHKd+hWasJAXHNXVC1VSLKFAdzhbcNO4sVnZUz5LXeQx # cq3TjJfv4YPUAYj0FU9D9B2X0AkaJ9vvPr9ik8PDedYSqRlIA+f9/e4U3r8xcXZj # 43sVGRqTOIDYxJcLzF3Buy3YVDLt8KD+rBGmdX87xeeLCr19bBBuFUEJVNgntG8R # TaxFg3j8tUcGkpTR2Mcjw2lZYbI= # SIG # End signature block |