New-AaddsReplicaSet.ps1
<#PSScriptInfo
.VERSION 1.2.0 .GUID 81AC38BE-645B-4A55-A882-F20A3BC04838 .AUTHOR aaddsfb@microsoft.com .COMPANYNAME Microsoft Corporation .COPYRIGHT (c) Microsoft Corporation .TAGS Azure-AD-Domain-Services ReplicaSet .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES 07/19/2020 - Initial release 01/09/2024 - Rebrand to Microsoft Entra Domain Services #> <# .SYNOPSIS Adds an Microsoft Entra Domain Services replica set. .DESCRIPTION Adds an Microsoft Entra Domain Services replica set to the designated Resource Group, Virtual Network, and Subnet. The cmdlet creates the Resource Group, Virtual Network, Subnet, the network security group needed for the replica set, and peers the virtual network with the Microsoft Entra Domain Services virtual network before creating the replica set. .PARAMETER ManagedDomainFqdn The fqdn of the managed domain (aadds.ufcontoso.com). This parameter is MANDATORY .PARAMETER RsLocation The name of Azure region to create the Microsoft Entra Domain Services replica set. Use "Get-AzLocation | Sort-Object -Property Location | fl -Property Location" for a list of locations. This parameter is MANDATORY .PARAMETER RsResourceGroupName The name of the replica set resource group. If not found, the script creates it in the specified location. This parameter is MANDATORY .PARAMETER RsVnetName The name of the Azure virtual network that hosts the Microsoft Entra Domain Services replica set. If not found, the script creates it in the specified resource group and location. This parameter is MANDATORY .PARAMETER RsVnetCIDRAddressSpace The virtual network's address range in CIDR notation. This parameter is MANDATORY if the scripts creates the virtual network. OMIT/SKIP this parameter if you are using an existing virutal network .PARAMETER RsSubnetName The name of the subnet hosting Microsoft Entra Domain Services. This CANNOT be an existing subnet on the virtual network. The script MUST create a subnet specifically for the Microsoft Entra Domain Service replica set. This parameter is MANDATORY .PARAMETER RsSubnetCIRDAddressRange The subnet's address range in CIDR notation for the Microsoft Entra Domain Services instance (e.g. 192.168.1.0/24). It must be contained by the address range of the virtual network and different from other subnets. This parameter is MANDATORY .PARAMETER Credential The credentials used to authenticate to Azure. This parameter is OPTIONAL #> [CmdletBinding()] Param ( [Parameter( Mandatory=$true)] [string] $ManagedDomainFqdn, [Parameter( Mandatory=$true)] [string] $RsLocation, [Parameter( Mandatory=$true)] [string] $RsResourceGroupName, [Parameter( Mandatory=$true)] [string] $RsVnetName, [Parameter( Mandatory=$false)] [string] $RsVnetCIDRAddressSpace, [Parameter( Mandatory=$true)] [string] $RsSubnetName, [Parameter( Mandatory=$true)] [string] $RsSubnetCIDRAddressRange, [Parameter( Mandatory=$false)] [pscredential] $Credentials ) Process { function New-HeuristicSubnetId([string] $subscriptionId, [string] $targetResourceGroup, [string] $targetVnetName, [string] $targetSubnetName) { $rv = [String]::Empty if( ([string]::Empty -eq $subscriptionId) -or ([string]::Empty -eq $targetResourceGroup) -or ([string]::Empty -eq $targetVnetName) -or ([string]::Empty -eq $targetSubnetName) ) { return $rv } $rvTemplate = "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/virtualNetworks/{2}/subnets/{3}" $rv = ($rvTemplate -f $subscriptionId, $targetResourceGroup, $targetVnetName, $targetSubnetName) return $rv } function Convert-VnetResourceIdToVnetName( [string] $vnetResourceId) { [int] $VNET_NAME_INDEX = 7 $rv = [string]::Empty $parts = $vnetResourceId.Split("/",[System.StringSplitOptions]::RemoveEmptyEntries) if( ($VNET_NAME_INDEX+1) -ne $parts.Count) {return $rv} $rv = $parts[$VNET_NAME_INDEX] return $rv } function Convert-SubnetResourceIdToResourceGroupName( [string] $subnetResourceId) { [int] $RESOURCEGROUP_NAME_INDEX = 3 [int] $SUBNET_NAME_INDEX = 9 $rv = [string]::Empty $parts = $subnetResourceId.Split("/",[System.StringSplitOptions]::RemoveEmptyEntries) if( ($SUBNET_NAME_INDEX+1) -ne $parts.Count) {return $rv} $rv = $parts[$RESOURCEGROUP_NAME_INDEX] return $rv } function Convert-SubnetResourceIdToVnetName( [string] $subnetResourceId) { [int] $SUBNET_NAME_INDEX = 9 [int] $VNET_NAME_INDEX = 7 $rv = [string]::Empty $parts = $subnetResourceId.Split("/",[System.StringSplitOptions]::RemoveEmptyEntries) if( ($SUBNET_NAME_INDEX+1) -ne $parts.Count) {return $rv} $rv = $parts[$VNET_NAME_INDEX] return $rv } function New-HeuristicVnetIdFromSubnetId([string] $subnetId) { [int] $SUBSCRIPTION_INDEX = 2 [int] $RESOURCEGROUP_NAME_INDEX = 3 [int] $VNET_NAME_INDEX = 7 $rv = [String]::Empty $sourceSubnetParts = $sourceSubnetId.Split("/", [System.StringSplitOptions]::RemoveEmptyEntries) if(10 -ne $sourceSubnetParts.Count) {return $rv} $rvTemplate = "/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/virtualNetworks/{2}" $rv = ($rvTemplate -f $sourceSubnetParts[$SUBSCRIPTION_INDEX], $sourceSubnetParts[$RESOURCEGROUP_NAME_INDEX], $sourceSubnetParts[$VNET_NAME_INDEX] ) return $rv } function Get-AaddsSubscription([string] $managedDomainFqdn) { # # Locate Microsoft Entra Domain Services in a subscription # Use the first instance found as there should only be one instance per tenant $rv = [String]::Empty ($AzSubs = Get-AzSubscription) | Out-Null foreach($azsub in $AzSubs) { (Select-AzSubscription $azsub.Id) | Out-Null $aadds = Get-AzResource -Name $managedDomainFqdn -ApiVersion 2020-01-01 -ExpandProperties -ErrorAction SilentlyContinue if($null -ne $aadds) { # Found Microsoft Entra DS in this subscription # Add to the subscription List $rv = $azsub.Id break } } return $rv } function New-AaddsNetworkSecurityGroup( [string] $resourceGroupName, [string] $location, [string] $subnetName, [Microsoft.Azure.Commands.Network.Models.PSVirtualNetwork] $vnet, [string] $cidrRange ) { # Create the default AAD DS NSG with rules and link it to AAD DS Subnet Write-Host ("Creating network security group network security group in the {0} resource group..." -f $resourceGroupName) -NoNewline # # Build the rules $nsg101 = New-AzNetworkSecurityRuleConfig -Name AllowSyncWithAzureAD ` -Access Allow -Protocol Tcp -Direction Inbound -Priority 101 ` -SourceAddressPrefix AzureActiveDirectoryDomainServices ` -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 443 $nsg201 = New-AzNetworkSecurityRuleConfig -Name AllowRD ` -Access Allow -Protocol Tcp -Direction Inbound -Priority 201 ` -SourceAddressPrefix CorpNetSaw ` -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 3389 $nsg301 = New-AzNetworkSecurityRuleConfig -Name AllowPSRemoting ` -Access Allow -Protocol Tcp -Direction Inbound -Priority 301 ` -SourceAddressPrefix AzureActiveDirectoryDomainServices ` -SourcePortRange * -DestinationAddressPrefix * -DestinationPortRange 5986 # # Find an available name for the NSG $nsgNamePrefix = "aadds-nsg-" $nsgName = [String]::Empty $rv = $true for($inc = 1; $rv -eq $true; $inc++) { $nsgName = [String]::Concat($nsgNamePrefix,$inc) $tempNsg = Get-AzNetworkSecurityGroup -Name $nsgNAme -ResourceGroupName $resourceGroupName -ErrorAction SilentlyContinue if($null -eq $tempNsg) { break } if($inc -gt 50) { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red "There are more than 50 network security groups that begin with aadds-nsg-." Write-Host -ForegroundColor Red "Remove the unused network security groups and run the script again." Return $null } } # # Create the NSG with the rules $nsg = New-AzNetworkSecurityGroup -Name $nsgName -ResourceGroupName $resourceGroupName ` -Location $location -SecurityRules $nsg101,$nsg201,$nsg301 -ErrorAction SilentlyContinue if($null -eq $nsg) { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red ("ERROR: Could not create a network security group in the {0} resource group." -f $resourceGroupName) Return $null } else { Write-Host -ForegroundColor Green "[Success!]" } # # Link the NSG to the subnet Write-Host ("Linking the {0} network security group to the {1} subnet in {2}..." -f $nsgName, $vnet.Name, $subnetName )-NoNewline Set-AzVirtualNetworkSubnetConfig -Name $subnetName ` -VirtualNetwork $vnet ` -AddressPrefix $cidrRange ` -NetworkSecurityGroup $nsg ` -ErrorAction SilentlyContinue | Out-Null # # Commit the changes to the virtual network $vnet = Set-AzVirtualNetwork -VirtualNetwork $vnet -ErrorAction SilentlyContinue # # Get the aadds subnet with the latest settings $subnet = Get-AzVirtualNetworkSubnetConfig ` -Name $subnetName ` -VirtualNetwork $vnet -ErrorAction SilentlyContinue if($null -eq $subnet) { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red ("ERROR: Could not link the {0} network security group to the {1} subnet." -f $nsgName, $subnetName) } else { Write-Host -ForegroundColor Green "[Success!]" } Return $subnet } function Test-VirtualNetworkPeerings( [Microsoft.Azure.Commands.Network.Models.PSVirtualNetwork[]] $networks) { $rv = $true foreach($n in $networks) { #Check all the peerings Write-Host ("Checking remote peering for {0} virtual network..." -f $n.Name) foreach($p in $n.VirtualNetworkPeerings) { if("Disconnected" -eq $p.PeeringState) { Remove-AzVirtualNetworkPeering -Name $p.Name ` -VirtualNetworkName $n.Name ` -ResourceGroupName $n.ResourceGroupName -Force -ErrorAction SilentlyContinue if($false -eq $?) { Write-Host ("ERROR: Failed to remove disconnected peering {0} " -f $p.Name) $rv = $false } else { Write-Host -ForegroundColor Green ("Successfully removed disconnected peering removed from {0}" -f $p.Name) } } } } return $rv } function New-AaddsVirtualNetworkPeering([string] $aaddsDomainName, [string] $replicaSetVirtualNetworkName, [string] $replicaSetResourceGroupName) { $ERR_PEER_EXISTS = "Peering with the specified name already exists" $VNET_PEERNAME_TEMPLATE = "{0}-to-{1}" $vnetList = [System.Collections.ArrayList]::new() #Get the domain instance $aadds = Get-AzResource -Name $managedDomainFqdn -ApiVersion 2020-01-01 -ExpandProperties -ErrorAction SilentlyContinue # Get the new replica set vnet instance Write-Host ("Getting information for the {0} virtual network..." -f $replicaSetVirtualNetworkName ) -NoNewline $vnet = Get-AzVirtualNetwork -Name $replicaSetVirtualNetworkName -ResourceGroupName $replicaSetResourceGroupName -ErrorAction SilentlyContinue if($null -eq $vnet) { Write-Host -ForegroundColor Red "[Failed!]" $pass = $false } else { Write-Host -ForegroundColor Green "[Success!]" $vnetList.Add($vnet) | Out-Null } # Fail early if the new virtual network could not be contacted. if($false -eq $pass) {return $pass} #Get the collection of existing replica sets $rs = $aadds.Properties.replicaSets $pass = $true foreach($r in $rs) { $rg = Convert-SubnetResourceIdToResourceGroupName $r.subnetId $name = Convert-SubnetResourceIdToVnetName $r.subnetId Write-Host ("Getting information for the {0} virtual network..." -f $name ) -NoNewline $vnet = Get-AzVirtualNetwork -Name $name -ResourceGroupName $rg -ErrorAction SilentlyContinue if($null -eq $vnet) { Write-Host -ForegroundColor Red "[Failed!]" $pass = $false } else { Write-Host -ForegroundColor Green "[Success!]" $vnetList.Add($vnet) | Out-Null } } # Fail early if existing virtual networks could not be contacted. if($false -eq $pass) {return $pass} # Reset pass state for the next phase of work (disconnected peers) $pass = $true # Checking for disconnected virtual network peerings $pass = Test-VirtualNetworkPeerings($vnetList) # Fail early if existing virtual networks could not be contacted. if($false -eq $pass) {return $pass} # Reset pass state for the next phase of work (peering) $pass = $true # $vnetList has a list of vnet objects Write-Host "Peering virtual networks..." foreach($source in $vnetList) { # Get peered networks for the source foreach($target in $vnetList) { # Only process if the source and target networks are different if($source.Id -ne $target.Id) { Write-Host ("Peering {0} to {1}..." -f $source.Name, $target.Name) -NoNewline # Peer the source to the target $result = Add-AzVirtualNetworkPeering -Name ($VNET_PEERNAME_TEMPLATE -f $source.Name, $target.Name) ` -VirtualNetwork $source ` -RemoteVirtualNetworkId $target.Id -ErrorAction SilentlyContinue if($null -eq $result) # Error { if($ERR_PEER_EXISTS -ne $Error[0].Exception.Message) # Some other error { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red ("ERROR:{0}" -f $Error[0].Exception.Message) $pass = $false # At least one error occured and cannot continue } else # Exists Error { Write-Host -ForegroundColor Green "[Connected!]" } } else { Write-Host -ForegroundColor Green "[Success!]" } # Peer the the target to the source Write-Host ("Peering {0} to {1}..." -f $target.Name, $source.Name) -NoNewline $result = Add-AzVirtualNetworkPeering -Name ($VNET_PEERNAME_TEMPLATE -f $target.Name, $source.Name) ` -VirtualNetwork $target ` -RemoteVirtualNetworkId $source.Id -ErrorAction SilentlyContinue if($null -eq $result) # Error { if($ERR_PEER_EXISTS -ne $Error[0].Exception.Message) # Some other error { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red ("ERROR:{0}" -f $Error[0].Exception.Message) $pass = $false # At least one error occured and cannot continue } else # Exists error { Write-Host -ForegroundColor Green "[Connected!]" } } else # Success { Write-Host -ForegroundColor Green "[Success!]" } } # end if($source.Id -ne $target.Id) } # end foreach($target in $vnetList) } return $pass } Set-Item Env:\SuppressAzurePowerShellBreakingChangeWarnings "true" Write-Host ([String]::Empty) Write-Host ([String]::Empty) Write-Host -ForegroundColor Cyan "Add-AaddsReplicaSet" Write-Host ([String]::Empty) Write-Host -ForegroundColor White "This cmdlet creates an Microsoft Entra Domain Services replica set and the cloud " Write-Host -ForegroundColor White "infrastructure needed to support it (resource group, virtual network, " Write-Host -ForegroundColor White "virutal subnet, and virtual network peering)." Write-Host ([String]::Empty) Write-Host -ForegroundColor White "Creating a new replica set may take up to 90 minutes." Write-Host ([String]::Empty) Write-Host -ForegroundColor Green "Type 'Yes' to continue or 'No' to quit" $answer = Read-Host if("Yes" -ne $answer) { Write-Host "User canceled." Return } # # Create an empty replica set settings $replicaSetSettingsValue = [System.Collections.ArrayList]@() Write-Host ([string]::Empty) Write-Host ([string]::Empty) Write-Host -ForegroundColor White "Authenticating to Azure Resource Manager..." -NoNewline $armSession = $null # # Collect credentials from the user for authentication if($null -ne $Credentials) { $armSession = Connect-AzAccount -Credential $Credentials -ErrorAction SilentlyContinue } else { $armSession = Connect-AzAccount -ErrorAction SilentlyContinue } if($null -eq $armSession) { # Authentication failed Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red "ERROR: Could not authenticate to Azure Resource Manager. Check your credentials and try again." Write-Host -ForegroundColor Red ("Message: {0}" -f $Error.Exception.Message) Return } Write-Host -ForegroundColor Green "[Successs!]" Write-Host ("INFO: Authenticated to Azure as {0}" -f $armSession.Context.Account.Id) Write-Host "Searching for the Microsoft Entra Domain Service subscription..." -NoNewline $azureSubscriptionId = Get-AaddsSubscription $ManagedDomainFqdn if([string]::Empty -eq $azureSubscriptionId) { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red "ERROR: Could not find a subscription that has Microsoft Entra Domain Services." Write-Host -ForegroundColor Red ("Message: {0}" -f $Error.Exception.Message) return } else { Write-Host -ForegroundColor Green "[Found!]" Select-AzSubscription $azureSubscriptionId -ErrorAction SilentlyContinue| Out-Null } Write-Host "Getting Microsoft Entra Domain Services instance..." -NoNewline $aadds = Get-AzResource -Name $ManagedDomainFqdn -ApiVersion 2020-01-01 -ExpandProperties -ErrorAction SilentlyContinue if($null -eq $aadds) { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red ("ERROR: Could not find an Microsoft Entra Domain Services resource with the name {0}." -f $ManagedDomainFqdn) Write-Host -ForegroundColor Red ("Message: {0}" -f $Error.Exception.Message) Return } Write-Host ([string]::Empty) Write-Host "Checking prerequisites..." Write-Host "Validating resource type..." -NoNewline if($aadds.ResourceType -ne "Microsoft.AAD/domainServices") { $pass = $false Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red ("ERROR: The resource is not an Microsoft Entra Domain Services resource (Staus:{0})." -f $aadds.ResourceType) } else {Write-Host -ForegroundColor Green "[Pass!]"} $tempReplicaSetValue = $aadds.Properties.replicaSets Write-Host "Validating SKU..." -NoNewline if($aadds.properties.sku -eq "Standard") { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red ("ERROR: The managed domain {0} is does not support replica sets." -f $aadds.Name) Write-Host ([string]::Empty) Write-Host -ForegroundColor White "Replica Sets are only available on Enterprise and Premium SKUs." Write-Host -ForegroundColor White "SKU changes affect Azure billing. See https://go.microsoft.com/fwlink/?linkid=2117164 for details." Write-Host ([string]::Empty) Write-Host -ForegroundColor White "Do you want to upgrade Microsoft Entra Domain Services to the Enterprise SKU? Type 'Yes' to continue or 'No' to quit" Write-Host -ForegroundColor Green "Type 'Yes' to continue or 'No' to quit" $answer = Read-Host if("Yes" -ne $answer) { Write-Host "User canceled." Return } else { ## Upgrade the SKU Write-Host "Sending request to Azure. This action may take up to 10 minutes to complete. Please wait..." Write-Host ("Upgrading Microsoft Entra Domain instance {0} to Enterprise SKU..." -f $aadds.Name) -NoNewline $rv = Set-AzResource -ResourceId $aadds.ResourceId -Properties @{'Sku'='Enterprise'} -ApiVersion 2020-01-01 -Force | Out-Null $rvError = $Error[0].Exception.Message $aadds = Get-AzResource -Name $aadds.Name -ApiVersion 2020-01-01 -ExpandProperties -ErrorAction SilentlyContinue if($aadds.Properties.sku -ne "Enterprise") { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red "ERROR: Failed to upgrade the sku." Write-Host -ForegroundColor Red ("Message:{0}" -f $rvError) Return } else { Write-Host -ForegroundColor Green "[Success!]" } } } else { Write-Host -ForegroundColor Green "[Pass!]"} # Check for duplicate replica sets Write-Host "Checking existing replica sets for duplicates ..." -NoNewline $targetSubnetId = New-HeuristicSubnetId $azureSubscriptionId $RsResourceGroupName $RsVnetName $RsSubnetName if([string]::Empty -eq $targetSubnetId) { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red ("ERROR: Failed to generate a subnet Id for {0}." -f $RsSubnetName) Return } foreach($tempReplicaSetItem in $tempReplicaSetValue) { #check for matching subnetId if($targetSubnetId -eq $tempReplicaSetItem.subnetId) { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red ("ERROR: A replica set exists in the {0} virtual network and {1} subnet" -f $RsVnetName, $RsSubnetName ) Write-Host -ForegroundColor Red ("Message: {0}" -f $Error.Exception.Message) Return } } Write-Host -ForegroundColor Green "[Pass!]" # Create the resource group if it does not exists Write-Host ("Checking for the {0} resource group..." -f $RsResourceGroupName) -NoNewline $rg = Get-AzResourceGroup -Name $RsResourceGroupName -ErrorAction SilentlyContinue if($null -eq $rg) { # does not exist, create Write-Host -ForegroundColor Yellow "[Not Found!]" Write-Host ("Creating resource group {0}..." -f $RsResourceGroupName) -NoNewline $rg = New-AzResourceGroup -Name $RsResourceGroupName -Location $RsLocation -ErrorAction SilentlyContinue if($null -eq $rg) { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red ("ERROR: Could not create the resource group {0}" -f $RsResourceGroupName) Write-Host -ForegroundColor Red ("Message: {0}" -f $Error.Exception.Message) Return } else { Write-Host -ForegroundColor Green "[Success!]" } } else { Write-Host -ForegroundColor Green "[Found!]" } # Create the virtual network if it does not exist Write-Host ("Checking for the {0} virtual network..." -f $RsVnetName) -NoNewline $rsVnet = Get-AzVirtualNetwork -Name $RsVnetName -ResourceGroupName $RsResourceGroupName -ErrorAction SilentlyContinue if($null -eq $rsVnet) { Write-Host -ForegroundColor Yellow "[Not Found!]" # Check if the virtual Network CIDR address space was provided if( ($null -eq $RsVnetCIDRAddressSpace) -or ("" -eq $RsVnetCIDRAddressSpace)) { Write-Host -ForegroundColor Red "ERROR: Missing the virtual address space information." Write-Host -ForegroundColor Red "ERROR: Run the cmdlet again with the -RsVnetCIDRAddressSpace parameter and the appropriate value." Return } Write-Host ("Creating {0} virtual network..." -f $RsVnetName) -NoNewline # # Create a virtual network to host AAD DS $rsVnet = New-AzVirtualNetwork ` -ResourceGroupName $RsResourceGroupName ` -Location $RsLocation ` -Name $RsVnetName ` -AddressPrefix $RsVnetCIDRAddressSpace -ErrorAction SilentlyContinue if($null -eq $rsVnet) { Write-Host -ForegroundColor Red "[Failed!]" Write-host -ForegroundColor Red ("ERROR: Failed creating the {0} virtual network." -f $RsVnetName) Write-Host -ForegroundColor Red ("Message: {0}" -f $Error.Exception.Message) Return } else { Write-Host -ForegroundColor Green "[Success!]" } } else { write-Host -ForegroundColor Green "[Found!]" Write-Host ("INFO: Reusing existing virtual network [{0}]" -f $rsVnet.Name) } # Create the subnet, mandatory # Search the subnet, the script MUST create the AAD DS subnet # Create a dedicated subnet to host AAD DS Write-Host ("Checking for the {0} subnet in the {1} virtual network..." -f $rsSubnetName, $rsVnet.Name) -NoNewline $rsSubnet = Get-AzVirtualNetworkSubnetConfig ` -Name $RsSubnetName ` -VirtualNetwork $rsVnet -ErrorAction SilentlyContinue if($null -ne $rsSubnet) { # Subnet Exists # Do not allow the reuse of a subnet Write-Host -ForegroundColor Red "[Found!]" Write-Host -ForegroundColor Red ( "ERROR: A subnet with the name {0} exists in the {1} virtual network." -f $rsSubnet.Name, $rsVnet.Name) Write-Host -ForegroundColor Red "ERROR: Choose a different name or delete the subnet." Return } else { Write-Host -ForegroundColor Green "[Not Found!]" Write-Host ("Creating the {0} subnet and adding it to the {1} virtual network..." -f $RsSubnetName, $rsVnet.Name) -NoNewline $rv = $null $rv = Add-AzVirtualNetworkSubnetConfig ` -Name $RsSubnetName ` -VirtualNetwork $rsVnet ` -AddressPrefix $RsSubnetCIDRAddressRange -ErrorAction SilentlyContinue $rsVnet = Set-AzVirtualNetwork -VirtualNetwork $rsVnet -ErrorAction SilentlyContinue $rsSubnet = Get-AzVirtualNetworkSubnetConfig ` -Name $RsSubnetName ` -VirtualNetwork $rsVnet -ErrorAction SilentlyContinue if( ($null -eq $rv) -or ($null -eq $rsVnet) -or ($null -eq $rsSubnet) ) { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red ("ERROR: Could not create the {0} subnet." -f $RsSubnetName) Return } else { Write-Host -ForegroundColor Green "[Successs!]" } } # UI is in the function because the function returns the subnet # Create NSG and attach to subnet $rsSubnet = New-AaddsNetworkSecurityGroup $RsResourceGroupName ` $RsLocation ` $RsSubnetName ` $rsVnet ` $RsSubnetCIDRAddressRange if($null -eq $rsSubnet) { Return } # Peer the vNet with other vents Write-Host "Preparing to peer virtual networks..." $rv = New-AaddsVirtualNetworkPeering $aadds.Name ` $RsVnetName ` $RsResourceGroupName if($false -eq $rv) { Write-Host -ForegroundColor Red "ERROR: One or more errors occured while peering virtual networks." Write-Host -ForegroundColor Red "ERROR: All virtual networks for all replica sets must be peered before creating" Write-Host -ForegroundColor Red "a new replica set." Return } else { Write-Host -ForegroundColor Green "Virtual network peering complete!" } # Preprare the replicaSetsValue ## Add any existing replica sets to prevent Azure from deleting them foreach($tempReplicaSetItem in $tempReplicaSetValue) { $replicaSetSettingsValue.Add( $tempReplicaSetItem) | Out-Null } ## Add the new replica set for Azure to create $replicaSetSettingsValue.Add( @{ "subnetId" = $targetSubnetId; "location" = $RsLocation;} ) | Out-Null Write-host ([string]::Empty) $answer = Read-host -Prompt ("Type 'Yes' to confirm you want to add an Microsoft Entra Domain Services replica set to the {0} virtual network in the {1} region." -f $RsVnetName, $RsLocation) if("Yes" -ne $answer) { Write-Host "User canceled." Return } $replicaSetSettings = @{"replicaSets"=$replicaSetSettingsValue} $actionStart = Get-Date Write-Host ([string]::Empty) Write-Host "Sending the request to Azure." Write-Host ("{0}: This action may take up to 90 minutes to complete. Please wait..." -f [DateTime]::Now.ToLongTimeString()) Set-AzResource -ResourceId $aadds.ResourceId -Properties $replicaSetSettings -ApiVersion 2020-01-01 -Force -ErrorAction SilentlyContinue | Out-Null if($false -eq $?) { Write-Host -ForegroundColor Red "[Failed!]" Write-Host -ForegroundColor Red ("Message: {0}" -f $Error.Exception.Message) Return } else {Write-Host -ForegroundColor Green "Replica set added."} Set-Item Env:\SuppressAzurePowerShellBreakingChangeWarnings "false" $actionStop = Get-Date Write-Host "Elapsed Time: " ($actionStop - $actionStart) } # End Process # SIG # Begin signature block # MIIr7gYJKoZIhvcNAQcCoIIr3zCCK9sCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCckwiZCS6qGQeL # e3DUMV+T6ZcoThj9hnP22XoPr6fq5KCCEXgwggiIMIIHcKADAgECAhM2AAABzxvV # hIv3HFTwAAIAAAHPMA0GCSqGSIb3DQEBCwUAMEExEzARBgoJkiaJk/IsZAEZFgNH # QkwxEzARBgoJkiaJk/IsZAEZFgNBTUUxFTATBgNVBAMTDEFNRSBDUyBDQSAwMTAe # Fw0yMzAzMjAyMDAwMzJaFw0yNDAzMTkyMDAwMzJaMC8xLTArBgNVBAMTJE1pY3Jv # c29mdCBBenVyZSBEZXBlbmRlbmN5IENvZGUgU2lnbjCCASIwDQYJKoZIhvcNAQEB # BQADggEPADCCAQoCggEBAOREEBJi/WoqvCPTpdI+NM1fM/zljtamVZMTJaEFhALS # 3v0oF6vWx7zJy9McdDOyA9wY8x75/uBmwl1n8d5l/cLSD+PExSnU1o/zDyr80He+ # K1yZlVCdYSYsoWDsOeYCI0+sf6O6U2Y2kp+pIVLSf1j7amZd+vkbjHCbxRA28njz # MCxv66EZS2Sh5yTH+uFi+RzUWMaJltkPurDraCRNKKubmOpAmqbtaPu+FEIs+nyn # +xzFwefTOGNanTyOs2wmxBJ8VkQGU9tlRlbNrURi/5TtdktoTnM0Vn4M/2MbPlYC # QBcJtVadNVheejpKNhinXiZw8i9TsGHDOJvuz05Hl7UCAwEAAaOCBYkwggWFMCkG # CSsGAQQBgjcVCgQcMBowDAYKKwYBBAGCN1sDATAKBggrBgEFBQcDAzA8BgkrBgEE # AYI3FQcELzAtBiUrBgEEAYI3FQiGkOMNhNW0eITxiz6Fm90Wzp0SgWDigi2HkK4D # AgFkAgEOMIICdgYIKwYBBQUHAQEEggJoMIICZDBiBggrBgEFBQcwAoZWaHR0cDov # L2NybC5taWNyb3NvZnQuY29tL3BraWluZnJhL0NlcnRzL0JZMlBLSUNTQ0EwMS5B # TUUuR0JMX0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcnQwUgYIKwYBBQUHMAKGRmh0 # dHA6Ly9jcmwxLmFtZS5nYmwvYWlhL0JZMlBLSUNTQ0EwMS5BTUUuR0JMX0FNRSUy # MENTJTIwQ0ElMjAwMSgyKS5jcnQwUgYIKwYBBQUHMAKGRmh0dHA6Ly9jcmwyLmFt # ZS5nYmwvYWlhL0JZMlBLSUNTQ0EwMS5BTUUuR0JMX0FNRSUyMENTJTIwQ0ElMjAw # MSgyKS5jcnQwUgYIKwYBBQUHMAKGRmh0dHA6Ly9jcmwzLmFtZS5nYmwvYWlhL0JZ # MlBLSUNTQ0EwMS5BTUUuR0JMX0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcnQwUgYI # KwYBBQUHMAKGRmh0dHA6Ly9jcmw0LmFtZS5nYmwvYWlhL0JZMlBLSUNTQ0EwMS5B # TUUuR0JMX0FNRSUyMENTJTIwQ0ElMjAwMSgyKS5jcnQwga0GCCsGAQUFBzAChoGg # bGRhcDovLy9DTj1BTUUlMjBDUyUyMENBJTIwMDEsQ049QUlBLENOPVB1YmxpYyUy # MEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9 # QU1FLERDPUdCTD9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2VydGlm # aWNhdGlvbkF1dGhvcml0eTAdBgNVHQ4EFgQUF8EGJdg3VCco3OMElEnYjfOsKQAw # DgYDVR0PAQH/BAQDAgeAMEUGA1UdEQQ+MDykOjA4MR4wHAYDVQQLExVNaWNyb3Nv # ZnQgQ29ycG9yYXRpb24xFjAUBgNVBAUTDTIzNjE2OSs1MDAzNjQwggHmBgNVHR8E # ggHdMIIB2TCCAdWgggHRoIIBzYY/aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3Br # aWluZnJhL0NSTC9BTUUlMjBDUyUyMENBJTIwMDEoMikuY3JshjFodHRwOi8vY3Js # MS5hbWUuZ2JsL2NybC9BTUUlMjBDUyUyMENBJTIwMDEoMikuY3JshjFodHRwOi8v # Y3JsMi5hbWUuZ2JsL2NybC9BTUUlMjBDUyUyMENBJTIwMDEoMikuY3JshjFodHRw # Oi8vY3JsMy5hbWUuZ2JsL2NybC9BTUUlMjBDUyUyMENBJTIwMDEoMikuY3JshjFo # dHRwOi8vY3JsNC5hbWUuZ2JsL2NybC9BTUUlMjBDUyUyMENBJTIwMDEoMikuY3Js # hoG9bGRhcDovLy9DTj1BTUUlMjBDUyUyMENBJTIwMDEoMiksQ049QlkyUEtJQ1ND # QTAxLENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNl # cyxDTj1Db25maWd1cmF0aW9uLERDPUFNRSxEQz1HQkw/Y2VydGlmaWNhdGVSZXZv # Y2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50 # MB8GA1UdIwQYMBaAFJZRhOBrb3v+2Aarw/KF5imuavnUMB8GA1UdJQQYMBYGCisG # AQQBgjdbAwEGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBAQAy72n19XEpbA0F # OW2VYlwvvLf8AVlRHgV5AnFegvbNSGIlfvbTizxYyHrzzldeW/xZxpLMOfnU8Ymo # Oe3cpJYN6qX99cL50D2F0QibG6eJ4XpVNKDbt1YbaR+ekLgHoATohGFqAeI0LHO8 # jIQBJaICrYeLNXRcP8kXV0BrLtKXPsUojlvSxHzaECg7F2fhKt7WQkVZexhZB6QO # VGj/VQY9TjWsHi6D5evjT3o819ZINUG1mCKbBFL1pFHMDjFICKlPDFIt9oL2QbZZ # 27gH2HHcOqCIWeFlrz3qcH+dwcVGEOHz6j5SDMSIWBpS3pebi5kb0jnOu7m6uAz0 # Q8ksXFl/MIII6DCCBtCgAwIBAgITHwAAAFHqj/accwyoOwAAAAAAUTANBgkqhkiG # 9w0BAQsFADA8MRMwEQYKCZImiZPyLGQBGRYDR0JMMRMwEQYKCZImiZPyLGQBGRYD # QU1FMRAwDgYDVQQDEwdhbWVyb290MB4XDTIxMDUyMTE4NDQxNFoXDTI2MDUyMTE4 # NTQxNFowQTETMBEGCgmSJomT8ixkARkWA0dCTDETMBEGCgmSJomT8ixkARkWA0FN # RTEVMBMGA1UEAxMMQU1FIENTIENBIDAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A # MIIBCgKCAQEAyZpSCX0Bno1W1yqXMhT6BUlJZWpa4p3xFeiTHO4vm2Q6C/azR5xw # xnyYHrkSGDtS2P9X+KDE64V20mmEQkubxnPNeOVnE2RvdPGxgwlq+BhS3ONdVsQP # j79q7XgHM9HhzB9+qk0PC9KN1zm9p/seyiRS6JF1dbOqRf1pUl7FAVxmgiCFgV8h # HIb/rDPXig7FDi3S0yEx2CUDVpIq8jEhG8anUFE1WYxM+ni0S5KHwwKPKV4qyGDo # DO+9AmDoma3Chyu5WDlW5cdtqXTWsGPE3umtnX6AmlldUFLms4OVR4guKf+n5LIB # CC6bTiocfXPomqYjYTKx7AGMfaVLaaXmhQIDAQABo4IE3DCCBNgwEgYJKwYBBAGC # NxUBBAUCAwIAAjAjBgkrBgEEAYI3FQIEFgQUEmgkQiFHy9RrvjHPIKTACyN/P0cw # HQYDVR0OBBYEFJZRhOBrb3v+2Aarw/KF5imuavnUMIIBBAYDVR0lBIH8MIH5Bgcr # BgEFAgMFBggrBgEFBQcDAQYIKwYBBQUHAwIGCisGAQQBgjcUAgEGCSsGAQQBgjcV # BgYKKwYBBAGCNwoDDAYJKwYBBAGCNxUGBggrBgEFBQcDCQYIKwYBBQUIAgIGCisG # AQQBgjdAAQEGCysGAQQBgjcKAwQBBgorBgEEAYI3CgMEBgkrBgEEAYI3FQUGCisG # AQQBgjcUAgIGCisGAQQBgjcUAgMGCCsGAQUFBwMDBgorBgEEAYI3WwEBBgorBgEE # AYI3WwIBBgorBgEEAYI3WwMBBgorBgEEAYI3WwUBBgorBgEEAYI3WwQBBgorBgEE # AYI3WwQCMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAS # BgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFCleUV5krjS566ycDaeMdQHR # CQsoMIIBaAYDVR0fBIIBXzCCAVswggFXoIIBU6CCAU+GMWh0dHA6Ly9jcmwubWlj # cm9zb2Z0LmNvbS9wa2lpbmZyYS9jcmwvYW1lcm9vdC5jcmyGI2h0dHA6Ly9jcmwy # LmFtZS5nYmwvY3JsL2FtZXJvb3QuY3JshiNodHRwOi8vY3JsMy5hbWUuZ2JsL2Ny # bC9hbWVyb290LmNybIYjaHR0cDovL2NybDEuYW1lLmdibC9jcmwvYW1lcm9vdC5j # cmyGgapsZGFwOi8vL0NOPWFtZXJvb3QsQ049QU1FUm9vdCxDTj1DRFAsQ049UHVi # bGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlv # bixEQz1BTUUsREM9R0JMP2NlcnRpZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFzZT9v # YmplY3RDbGFzcz1jUkxEaXN0cmlidXRpb25Qb2ludDCCAasGCCsGAQUFBwEBBIIB # nTCCAZkwRwYIKwYBBQUHMAKGO2h0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2lp # bmZyYS9jZXJ0cy9BTUVSb290X2FtZXJvb3QuY3J0MDcGCCsGAQUFBzAChitodHRw # Oi8vY3JsMi5hbWUuZ2JsL2FpYS9BTUVSb290X2FtZXJvb3QuY3J0MDcGCCsGAQUF # BzAChitodHRwOi8vY3JsMy5hbWUuZ2JsL2FpYS9BTUVSb290X2FtZXJvb3QuY3J0 # MDcGCCsGAQUFBzAChitodHRwOi8vY3JsMS5hbWUuZ2JsL2FpYS9BTUVSb290X2Ft # ZXJvb3QuY3J0MIGiBggrBgEFBQcwAoaBlWxkYXA6Ly8vQ049YW1lcm9vdCxDTj1B # SUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29u # ZmlndXJhdGlvbixEQz1BTUUsREM9R0JMP2NBQ2VydGlmaWNhdGU/YmFzZT9vYmpl # Y3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MA0GCSqGSIb3DQEBCwUAA4IC # AQBQECO3Tw/o317Rrd7yadqcswPx1LvIYymkaTN6KcmuRt6HKa0Xe73Ux2/AQ30T # fgA9GBJngweRykKBusRzyOU17iIubJvy3gA21dwtqtB0DsoEv1U/ptVu2v++doTC # J/i+GbssVXkgaX8H+6EOGEmT4evp4GbwR4HwWlc+Dvf8HH8PdUA2Z04CvcwIfckS # ipbNm84jxJ8XjmTFTWscldL9edj2NsY6iGnyJFIyur2PS7VRYyV3p1VAJp91gj1j # RQtWEyCB8P5g9nE3z8u0ANaU/hjwEQCrdGyravWgnf2JtG+bT26YAokbc8m+32zU # tXRO+NK3tAjhOu2FdsG3qNrF4sc7y37R/C+7Pcb/cFfhttqsirepZii4xStcjMOD # YuXzGm3IJs0b0owHG6oKd7ZOGvHpmmh9K8/DLriD/sq8bURD10qi/wuW8zM7IpLg # 1vcR9dIK2mc0pj44pc6UX0XbttP/VEJgu3lT2eI9VjWtaKjx38xE9woSMyekPRtz # TwgfuysF9DkJisr+yA4po/FPxpbBw9c/hBf32DH/GFxteS2pmjgKIbMP8sDukmEq # 3lVvuWNJsybrZwQvQpvaM49fv+JKpLK5YWYEfwksYRR9wU8Hh/ID9hRCEkbUoQ2W # 7mMpsp2Nbp/kcn4ivfolUy3Q9Yf0scsQ6WTLYpm+AoCUJTGCGcwwghnIAgEBMFgw # QTETMBEGCgmSJomT8ixkARkWA0dCTDETMBEGCgmSJomT8ixkARkWA0FNRTEVMBMG # A1UEAxMMQU1FIENTIENBIDAxAhM2AAABzxvVhIv3HFTwAAIAAAHPMA0GCWCGSAFl # AwQCAQUAoIGuMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcC # AQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCB35tb4MWP7hST2XPbq # eTcJT2yM03Kpukv1ErmFZC/ugzBCBgorBgEEAYI3AgEMMTQwMqAUgBIATQBpAGMA # cgBvAHMAbwBmAHShGoAYaHR0cDovL3d3dy5taWNyb3NvZnQuY29tMA0GCSqGSIb3 # DQEBAQUABIIBAIQ3uTHHg4TNthWM6oy3o2kkJTki2kcAVwahL0S8wKcGlfV8UR9V # TZ+bgAoPv7JK8aqqrANQ2UFfuNu/21cJcsNBEfw6Ybig+ux5T97rhMuNQzewDRQn # aKFE8+GaXbhipI108WXfG4MTQA6uDpZjmN5UMGDhAJroKNXivVfHYlAsvxsGrBAq # UF7/b5FAc0xRJNihWIFSpj4mVmEg91Q/wn44K9g/GbkcXy0abOOWNidMyCT7ePKY # QUo3bGoQl8TrWl/o8P8A60+Bzn9NXLnP5voslWQo4rDaRfuQIgRPOpeGXesJ8+yv # ivrJS8jyfHFvYHl2paCF8F96Nf79N2CNVUKhgheUMIIXkAYKKwYBBAGCNwMDATGC # F4Awghd8BgkqhkiG9w0BBwKgghdtMIIXaQIBAzEPMA0GCWCGSAFlAwQCAQUAMIIB # UgYLKoZIhvcNAQkQAQSgggFBBIIBPTCCATkCAQEGCisGAQQBhFkKAwEwMTANBglg # hkgBZQMEAgEFAAQgIHhvAtCuP4W2D006jbzUC9HpxGluu+K3s2ycOJh/mAUCBmWf # 1wDJ8hgTMjAyNDAxMTUwNzIyMjMuMjM0WjAEgAIB9KCB0aSBzjCByzELMAkGA1UE # BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc # BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0 # IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOkE5 # MzUtMDNFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2 # aWNloIIR6jCCByAwggUIoAMCAQICEzMAAAHRsltAKGwu0kUAAQAAAdEwDQYJKoZI # hvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO # BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEm # MCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcNMjMwNTI1 # MTkxMjE4WhcNMjQwMjAxMTkxMjE4WjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgT # Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m # dCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0 # aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOkE5MzUtMDNFMC1EOTQ3MSUw # IwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG # 9w0BAQEFAAOCAg8AMIICCgKCAgEAmUzaNDnhs9lxXdoC4OZ05QZvFzqbsCSIl7DF # Ota8KtWSg6WuON0a0hv6R/Bs+lzZxUChpwqjQrZr6ClCwKcK0/7O/3tV9JTRSpo+ # 1O1+KdNEtLkG1ui8Ep/81h2htnOeGV7BmPgWH4Vg4GxaQk8Uc050Qhutm5Fj6emR # 22T4OB7dQkQgDIYThk0fMCOBu8MFmcHTHOlL1FJatKpfQMQH85GEaYtrUbwxzHZm # d78l6aoRcL0RvHIAh/00wo1uaumjW3aii9wRQz81LbgjbD1y9/xNHUdmwzKmtGjR # /oiH4RguP73MLrXjjAj1CA1UqgwjXyGjwxMGHItX3fYLtc1cPhxIQ2TOxGt58SFK # 87fkX6eU6DDI+EAJielGnZvkz2w26PJBSCu9EoZlvMJ/HyZPUXkEBKU7SDeN3kb/ # UJl8t1HnfNKLDgRPlpHTL0ghYfqoArCnc0MUCRutnE3qFNnqjYR96KaV5sn1VMG7 # Hn0MzD7W4pwmXdBVJZpTP3R/uDp4qkMmh767WMt8KiGn2N83hSE5VQKD/avbxeFu # yh0f7hdJr06QC+TWkwzdaZUEtDHYzJIM2SuYLcKjnv9605agc8cGu2GKd7qz+clp # E8yEhp4TViGTsTskCDsWX24iGwB25tzPIY+9ykFnAkeSWr4JMFJp3BRxEmkH+A66 # rPv9S9UCAwEAAaOCAUkwggFFMB0GA1UdDgQWBBQLjvFMxew3B9JprBeF0McR0L0t # ozAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSg # UqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3Nv # ZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEE # YDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz # L2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNy # dDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB # /wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAm7va0wB1duJmNKqBuXhJyJs+WpBl # 074gcCqdmOdbNusPKA61qK/ptNEeP9wXA5mJVCvDa8f2rmBWInWXXXFI8ONkMUkr # Zr/6lpwkIv9jpx99ilR0PpDDmTwAUExtV5HJ2D1DjhBKK+n/9ybNbo+MIx8xOFeG # rpmFwQLK+C+SkfLynrObRcYTJFjQ/zu1v0Wh2MCTIzJMVaLAaJO1dtbCQJcUnBF8 # XyWvv6pKlK+wmYMN0eIwh0ZD6kITFom1zzGGq/4hdGbiwfTvPQzCTYYyvQUn+oqo # GaDLsyFbfhAaE86b//aeMEOsaAQrNvZpI/xCFhXXPuWt9JLgkDkhDo9O/liNvQOJ # OkCEQecPnjJmdCXnNLEsnkAeSo8ROdYmDIbZTK1CnK9OpwagrEij2LEgCEwM4LLC # Q/mf3E0uwrt+Xya1oTPTWF9uLgMWCwFtIqTbVqbSHlempLmRHhFegTbTN1U5PpgJ # Vef3gv9GNe2lUoyuf4Mg6CzZq4FcL+UwGgZqv8IEURR5lvVCd87/C5pOpiKAMk6a # gW7lIzC8q7Wo7krAP5tg5yjDtEIs9b/hUlW6jN/Cfz05YQk1GxTsdJC0+2P+/mcq # 4pVQs8gGHxSIpwyI1pTPObQ3lPGXyQoxSsKtw7EcVeCWNfMcMPE05qHd5ZK/Tahk # OeC5sj1XPuYmza4wggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZAAAAAAAVMA0G # CSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 # aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3Jp # dHkgMjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMyMjVaMHwxCzAJBgNV # BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w # HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29m # dCBUaW1lLVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1V/YBf2xK4OK9 # uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9alKDRLemjkZr # BxTzxXb1hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmvHaus9ja+NSZk # 2pg7uhp7M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN7928jaTjkY+yOSxR # nOlwaQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3tpK56KTesy+uD # RedGbsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74kpEeHT39IM9zfUGa # RnXNxF803RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2K26oElHovwUDo9Fz # pk03dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG # 4tG9ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZki1ugpoMhXV8wdJGU # lNi5UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9QBXpsxREdcu+N+VLE # hReTwDwV2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0CAwEAAaOCAd0w # ggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+ # gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtTNRnpcjBcBgNV # HSAEVTBTMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0l # BAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0P # BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9 # lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQu # Y29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3Js # MFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3Nv # ZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJ # KoZIhvcNAQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEG # k5c9MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2 # LpypglYAA7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0jVOR4U3UkV7nd # n/OOPcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3+SmJw7wXsFSF # QrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmRsqlb30mjdAy8 # 7JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSwethQ/gpY3UA8 # x1RtnWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPXfx5bRAGOWhmRaw2f # pCjcZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz # /gq77EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGConsXHRWJjXD+57XQ # KBqJC4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAx # M328y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEGahC0HVUzWLOhcGby # oYIDTTCCAjUCAQEwgfmhgdGkgc4wgcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX # YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg # Q29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlv # bnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjpBOTM1LTAzRTAtRDk0NzElMCMG # A1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIa # AxUARyWNhb/hoS0LUQ0dryMwWkr/+yyggYMwgYCkfjB8MQswCQYDVQQGEwJVUzET # MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV # TWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1T # dGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsFAAIFAOlO8k8wIhgPMjAyNDAxMTQy # MzUyNDdaGA8yMDI0MDExNTIzNTI0N1owdDA6BgorBgEEAYRZCgQBMSwwKjAKAgUA # 6U7yTwIBADAHAgEAAgIcUDAHAgEAAgIUmTAKAgUA6VBDzwIBADA2BgorBgEEAYRZ # CgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0G # CSqGSIb3DQEBCwUAA4IBAQBT3nXSp/cfRRjqywDDWdeCnPrd3ct4kdkS4JOnBOQY # tjOG1k/YyuIV3Do4amuyo8ScQdgoz51HNkt7NkQgjlOWWiLJJ/f6twmM++lWNEIj # EQnH3fV+VnxAWI5rJQs7VH5DCNfeUn7LrAfSaO28VfpPDBdLNIaF0fQYREPrX6pV # ssQGqhFONtxUlpfmRT+YW3C4WAvON+i5A7Ed3EQ21UxlgHfI/zTNLgqi8xUgRuqA # peTbII/Mua3rMy6nLzzLv+F3shn0lsq1Kvn8I9OZ7qGyJqOOyxIu4aIYUI4PHSck # dZcCGSVv2eX2PnlHeinU3Rg+1ODOueJRGBZyIhopDMKgMYIEDTCCBAkCAQEwgZMw # fDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl # ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMd # TWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAHRsltAKGwu0kUAAQAA # AdEwDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRAB # BDAvBgkqhkiG9w0BCQQxIgQgGeT8zpc/UdPEC7q5mzpxD5izbZBMpmtZccI9dY2q # Im8wgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCDMvGF5AgC7+e3ObEYaz07m # 9auE8CeqFQN+pPCIiPwHDDCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQI # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv # ZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD # QSAyMDEwAhMzAAAB0bJbQChsLtJFAAEAAAHRMCIEIDyMtpSUFkrWwpkZBBSmrZ6l # 8us0fO0Ay4rLD0cTOZq2MA0GCSqGSIb3DQEBCwUABIICAEc3T0oxE/MIFjtEdTnS # 97ePqoWk7L/eyeuDeTcchE3L6+Q3UMCAfR8grgRSCFqdc0mjn9CRn84b6zNjiXs2 # TjFwbkat1GbR7PbvZ+wGnC3JrSrsALcjihp0E05JnPYkIxdLjNH+W6G20Z2ezINU # LgjEdFf6hdImNH0Me1BlajEKrPC5S3rjl/U/pXOp5+6fx0TIC7eR5+Z5JlJLPxEu # YjIYGOkUPYeygDJAXXBjQisYzIbbNIWJpHvbXN0vQhs2FF+k9zKuxDQK9TBbg0+w # +rojwp9idSBIwWUXwWtYoHfYiar4voFUyrHA8BaY4mLta7zVuo6jgLtgAMuXV/e+ # T9dp9ieYTRVCAXbwZ7xQ0rC1sSbEMp31oumeCeAlQ46orWEfvKt4EVVPDM/17FZW # +qO6hP4fD9zQDRBTZ0MQ1e8PH9XadQ2jtakU9aBNfnEoSw2U2rX8AwnXyMtxS7kQ # jtpeJRPK38u1yq1oDQoAImIQHmHPqJH/3HqtkQikk6uivz9upn41PyWZ+jgeAufP # h2EfMVR7134hQ9eqp3nw6QZWh6ENS8bX4smwsNDErRoiGSumbaPrtZfMQIFAXLZc # qMGAepmNBl2leqKW5xvpJgN+HKT/cnbkhNUxQKWKC2J6MNBq0TAZfPm0ILVIHvXw # H49OVznWH46z89YbY2KPC1/B # SIG # End signature block |