Migrate.Autorest/custom/Initialize-AzMigrateHCIReplicationInfrastructure.ps1
# ---------------------------------------------------------------------------------- # # Copyright Microsoft Corporation # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ---------------------------------------------------------------------------------- <# .Synopsis Initializes the infrastructure for the migrate project. .Description The Initialize-AzMigrateHCIReplicationInfrastructure cmdlet initializes the infrastructure for the migrate project in AzStackHCI scenario. .Link https://learn.microsoft.com/powershell/module/az.migrate/initialize-azmigratehcireplicationinfrastructure #> function Initialize-AzMigrateHCIReplicationInfrastructure { [OutputType([System.Boolean], ParameterSetName = 'AzStackHCI')] [CmdletBinding(DefaultParameterSetName = 'AzStackHCI', PositionalBinding = $false, SupportsShouldProcess, ConfirmImpact = 'Medium')] param( [Parameter(Mandatory)] [ValidateNotNull()] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Path')] [System.String] # Specifies the Resource Group of the Azure Migrate Project in the current subscription. ${ResourceGroupName}, [Parameter(Mandatory)] [ValidateNotNull()] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Path')] [System.String] # Specifies the name of the Azure Migrate project to be used for server migration. ${ProjectName}, [Parameter()] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Path')] [System.String] # Specifies the Storage Account ARM Id to be used for private endpoint scenario. ${CacheStorageAccountId}, [Parameter()] [System.String] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Runtime.DefaultInfo(Script = '(Get-AzContext).Subscription.Id')] # Azure Subscription ID. ${SubscriptionId}, [Parameter(Mandatory)] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Path')] [System.String] # Specifies the source appliance name for the AzStackHCI scenario. ${SourceApplianceName}, [Parameter(Mandatory)] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Path')] [System.String] # Specifies the target appliance name for the AzStackHCI scenario. ${TargetApplianceName}, [Parameter()] [Alias('AzureRMContext', 'AzureCredential')] [ValidateNotNull()] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Azure')] [System.Management.Automation.PSObject] # The credentials, account, tenant, and subscription used for communication with Azure. ${DefaultProfile}, [Parameter(DontShow)] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Runtime')] [System.Management.Automation.SwitchParameter] # Wait for .NET debugger to attach ${Break}, [Parameter(DontShow)] [ValidateNotNull()] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Runtime')] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Runtime.SendAsyncStep[]] # SendAsync Pipeline Steps to be appended to the front of the pipeline ${HttpPipelineAppend}, [Parameter()] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Runtime')] [System.Management.Automation.SwitchParameter] # Returns true when the command succeeds ${PassThru}, [Parameter(DontShow)] [ValidateNotNull()] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Runtime')] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Runtime.SendAsyncStep[]] # SendAsync Pipeline Steps to be prepended to the front of the pipeline ${HttpPipelinePrepend}, [Parameter(DontShow)] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Runtime')] [System.Uri] # The URI for the proxy server to use ${Proxy}, [Parameter(DontShow)] [ValidateNotNull()] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Runtime')] [System.Management.Automation.PSCredential] # Credentials for a proxy server to use for the remote call ${ProxyCredential}, [Parameter(DontShow)] [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Category('Runtime')] [System.Management.Automation.SwitchParameter] # Use the default credentials for the proxy ${ProxyUseDefaultCredentials} ) process { Import-Module $PSScriptRoot\Helper\AzStackHCICommonSettings.ps1 Import-Module $PSScriptRoot\Helper\CommonHelper.ps1 CheckResourcesModuleDependency CheckStorageModuleDependency Import-Module Az.Resources Import-Module Az.Storage $context = Get-AzContext # Get SubscriptionId if ([string]::IsNullOrEmpty($SubscriptionId)) { Write-Host "No -SubscriptionId provided. Using the one from Get-AzContext." $SubscriptionId = $context.Subscription.Id if ([string]::IsNullOrEmpty($SubscriptionId)) { throw "Please login to Azure to select a subscription." } } Write-Host "*Selected Subscription Id: '$($SubscriptionId)'." # Get resource group $resourceGroup = Get-AzResourceGroup -Name $ResourceGroupName -ErrorVariable notPresent -ErrorAction SilentlyContinue if ($null -eq $resourceGroup) { throw "Resource group '$($ResourceGroupName)' does not exist in the subscription. Please create the resource group and try again." } Write-Host "*Selected Resource Group: '$($ResourceGroupName)'." # Verify user validity $userObject = Get-AzADUser -UserPrincipalName $context.Subscription.ExtendedProperties.Account if (-not $userObject) { $userObject = Get-AzADUser -Mail $context.Subscription.ExtendedProperties.Account } if (-not $userObject) { $mailNickname = "{0}#EXT#" -f $($context.Account.Id -replace '@', '_') $userObject = Get-AzADUser | Where-Object { $_.MailNickname -eq $mailNickname } } if (-not $userObject) { $userObject = Get-AzADServicePrincipal -ApplicationID $context.Account.Id } if (-not $userObject) { throw 'User Object Id Not Found!' } # Get Migrate Project $migrateProject = Az.Migrate\Get-AzMigrateProject ` -Name $ProjectName ` -ResourceGroupName $ResourceGroupName ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $migrateProject) { throw "Migrate project '$($ProjectName)' not found." } # Access Discovery Service $discoverySolutionName = "Servers-Discovery-ServerDiscovery" $discoverySolution = Az.Migrate\Get-AzMigrateSolution ` -SubscriptionId $SubscriptionId ` -ResourceGroupName $ResourceGroupName ` -MigrateProjectName $ProjectName ` -Name $discoverySolutionName ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($discoverySolution.Name -ne $discoverySolutionName) { throw "Server Discovery Solution not found." } # Get Appliances Mapping $appMap = @{} if ($null -ne $discoverySolution.DetailExtendedDetail["applianceNameToSiteIdMapV2"]) { $appMapV2 = $discoverySolution.DetailExtendedDetail["applianceNameToSiteIdMapV2"] | ConvertFrom-Json # Fetch all appliance from V2 map first. Then these can be updated if found again in V3 map. foreach ($item in $appMapV2) { $appMap[$item.ApplianceName.ToLower()] = $item.SiteId } } if ($null -ne $discoverySolution.DetailExtendedDetail["applianceNameToSiteIdMapV3"]) { $appMapV3 = $discoverySolution.DetailExtendedDetail["applianceNameToSiteIdMapV3"] | ConvertFrom-Json foreach ($item in $appMapV3) { $t = $item.psobject.properties $appMap[$t.Name.ToLower()] = $t.Value.SiteId } } if ($null -eq $discoverySolution.DetailExtendedDetail["applianceNameToSiteIdMapV2"] -And $null -eq $discoverySolution.DetailExtendedDetail["applianceNameToSiteIdMapV3"] ) { throw "Server Discovery Solution missing Appliance Details. Invalid Solution." } $hyperVSiteTypeRegex = "(?<=/Microsoft.OffAzure/HyperVSites/).*$" $vmwareSiteTypeRegex = "(?<=/Microsoft.OffAzure/VMwareSites/).*$" # Validate SourceApplianceName & TargetApplianceName $sourceSiteId = $appMap[$SourceApplianceName.ToLower()] $targetSiteId = $appMap[$TargetApplianceName.ToLower()] if ($sourceSiteId -match $hyperVSiteTypeRegex -and $targetSiteId -match $hyperVSiteTypeRegex) { $instanceType = $AzStackHCIInstanceTypes.HyperVToAzStackHCI } elseif ($sourceSiteId -match $vmwareSiteTypeRegex -and $targetSiteId -match $hyperVSiteTypeRegex) { $instanceType = $AzStackHCIInstanceTypes.VMwareToAzStackHCI } else { throw "Error encountered in matching the given source appliance name '$SourceApplianceName' and target appliance name '$TargetApplianceName'. Please verify the VM site type to be either for HyperV or VMware for both source and target appliances, and the appliance names are correct." } # Get Data Replication Service, or the AMH solution $amhSolution = Az.Migrate\Get-AzMigrateSolution ` -ResourceGroupName $ResourceGroupName ` -MigrateProjectName $ProjectName ` -Name "Servers-Migration-ServerMigration_DataReplication" ` -SubscriptionId $SubscriptionId ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $amhSolution) { throw "No Data Replication Service Solution found. Please verify your appliance setup." } # Get Source and Target Fabrics $allFabrics = Az.Migrate\Get-AzMigrateHCIReplicationFabric -ResourceGroupName $ResourceGroupName foreach ($fabric in $allFabrics) { if ($fabric.Property.CustomProperty.MigrationSolutionId -ne $amhSolution.Id) { continue } if (($instanceType -eq $AzStackHCIInstanceTypes.HyperVToAzStackHCI) -and ($fabric.Property.CustomProperty.InstanceType -ceq $FabricInstanceTypes.HyperVInstance)) { $sourceFabric = $fabric } elseif (($instanceType -eq $AzStackHCIInstanceTypes.VMwareToAzStackHCI) -and ($fabric.Property.CustomProperty.InstanceType -ceq $FabricInstanceTypes.VMwareInstance)) { $sourceFabric = $fabric } elseif ($fabric.Property.CustomProperty.InstanceType -ceq $FabricInstanceTypes.AzStackHCIInstance) { $targetFabric = $fabric } if (($null -ne $sourceFabric) -and ($null -ne $targetFabric)) { break } } if ($null -eq $sourceFabric) { throw "Source Fabric not found. Please verify your appliance setup." } Write-Host "*Selected Source Fabric: '$($sourceFabric.Name)'." if ($null -eq $targetFabric) { throw "Target Fabric not found. Please verify your appliance setup." } Write-Host "*Selected Target Fabric: '$($targetFabric.Name)'." # Get Source and Target Dras from Fabrics $sourceDras = Az.Migrate.Internal\Get-AzMigrateDra ` -FabricName $sourceFabric.Name ` -ResourceGroupName $ResourceGroupName ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $sourceDras) { throw "Source Dra found. Please verify your appliance setup." } $sourceDra = $sourceDras[0] Write-Host "*Selected Source Dra: '$($sourceDra.Name)'." $targetDras = Az.Migrate.Internal\Get-AzMigrateDra ` -FabricName $targetFabric.Name ` -ResourceGroupName $ResourceGroupName ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $targetDras) { throw "Source Dra found. Please verify your appliance setup." } $targetDra = $targetDras[0] Write-Host "*Selected Target Dra: '$($targetDra.Name)'." # Get Replication Vault $replicationVaultName = $amhSolution.DetailExtendedDetail["vaultId"].Split("/")[8] $replicationVault = Az.Migrate.Internal\Get-AzMigrateVault ` -ResourceGroupName $ResourceGroupName ` -Name $replicationVaultName if ($null -eq $replicationVault) { throw "No Replication Vault found in Resource Group '$($ResourceGroupName)'." } # Put Policy $policyName = $replicationVault.Name + $instanceType + "policy" $policy = Az.Migrate.Internal\Get-AzMigratePolicy ` -ResourceGroupName $ResourceGroupName ` -Name $policyName ` -VaultName $replicationVault.Name ` -SubscriptionId $SubscriptionId ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue # Default policy is found if ($null -ne $policy) { # Give time for create/update to reach a terminal state. Timeout after 10min if ($policy.Property.ProvisioningState -eq [ProvisioningState]::Creating -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Updating) { Write-Host "Policy '$($policyName)' found in Provisioning State '$($policy.Property.ProvisioningState)'." for ($i = 0; $i -lt 20; $i++) { Start-Sleep -Seconds 30 $policy = Az.Migrate.Internal\Get-AzMigratePolicy -InputObject $policy if (-not ( $policy.Property.ProvisioningState -eq [ProvisioningState]::Creating -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Updating)) { break } } # Make sure Policy is no longer in Creating or Updating state if ($policy.Property.ProvisioningState -eq [ProvisioningState]::Creating -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Updating) { throw "Policy '$($policyName)' times out with Provisioning State: '$($policy.Property.ProvisioningState)'. Please re-run this command or contact support if help needed." } } # Check and remove if policy is in a bad terminal state if ($policy.Property.ProvisioningState -eq [ProvisioningState]::Canceled -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Failed) { Write-Host "Policy '$($policyName)' found but in an unusable terminal Provisioning State '$($policy.Property.ProvisioningState)'.`nRemoving policy..." # Remove policy try { Az.Migrate.Internal\Remove-AzMigratePolicy -InputObject $policy | Out-Null } catch { if ($_.Exception.Message -notmatch "Status: OK") { throw $_.Exception.Message } } Start-Sleep -Seconds 30 $policy = Az.Migrate.Internal\Get-AzMigratePolicy ` -InputObject $policy ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue # Make sure Policy is no longer in Canceled or Failed state if ($null -ne $policy -and ($policy.Property.ProvisioningState -eq [ProvisioningState]::Canceled -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Failed)) { throw "Failed to change the Provisioning State of policy '$($policyName)'by removing. Please re-run this command or contact support if help needed." } } # Give time to remove policy. Timeout after 10min if ($null -eq $policy -and $policy.Property.ProvisioningState -eq [ProvisioningState]::Deleting) { Write-Host "Policy '$($policyName)' found in Provisioning State '$($policy.Property.ProvisioningState)'." for ($i = 0; $i -lt 20; $i++) { Start-Sleep -Seconds 30 $policy = Az.Migrate.Internal\Get-AzMigratePolicy ` -InputObject $policy ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $policy -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Deleted) { break } elseif ($policy.Property.ProvisioningState -eq [ProvisioningState]::Deleting) { continue } throw "Policy '$($policyName)' has an unexpected Provisioning State of '$($policy.Property.ProvisioningState)' during removal process. Please re-run this command or contact support if help needed." } # Make sure Policy is no longer in Deleting state if ($null -ne $policy -and $policy.Property.ProvisioningState -eq [ProvisioningState]::Deleting) { throw "Policy '$($policyName)' times out with Provisioning State: '$($policy.Property.ProvisioningState)'. Please re-run this command or contact support if help needed." } } # Indicate policy was removed if ($null -eq $policy -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Deleted) { Write-Host "Policy '$($policyName)' was removed." } } # Refresh local policy object if exists if ($null -ne $policy) { $policy = Az.Migrate.Internal\Get-AzMigratePolicy -InputObject $policy } # Create policy if not found or previously deleted if ($null -eq $policy -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Deleted) { Write-Host "Creating Policy..." $params = @{ InstanceType = $instanceType; RecoveryPointHistoryInMinute = $ReplicationDetails.PolicyDetails.DefaultRecoveryPointHistoryInMinutes; CrashConsistentFrequencyInMinute = $ReplicationDetails.PolicyDetails.DefaultCrashConsistentFrequencyInMinutes; AppConsistentFrequencyInMinute = $ReplicationDetails.PolicyDetails.DefaultAppConsistentFrequencyInMinutes; } # Setup Policy deployment parameters $policyProperties = [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Models.Api20210216Preview.PolicyModelProperties]::new() if ($instanceType -eq $AzStackHCIInstanceTypes.HyperVToAzStackHCI) { $policyCustomProperties = [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Models.Api20210216Preview.HyperVToAzStackHcipolicyModelCustomProperties]::new() } elseif ($instanceType -eq $AzStackHCIInstanceTypes.VMwareToAzStackHCI) { $policyCustomProperties = [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Models.Api20210216Preview.VMwareToAzStackHcipolicyModelCustomProperties]::new() } else { throw "Instance type '$($instanceType)' is not supported. Currently, for AzStackHCI scenario, only HyperV and VMware as the source is supported." } $policyCustomProperties.InstanceType = $params.InstanceType $policyCustomProperties.RecoveryPointHistoryInMinute = $params.RecoveryPointHistoryInMinute $policyCustomProperties.CrashConsistentFrequencyInMinute = $params.CrashConsistentFrequencyInMinute $policyCustomProperties.AppConsistentFrequencyInMinute = $params.AppConsistentFrequencyInMinute $policyProperties.CustomProperty = $policyCustomProperties try { Az.Migrate.Internal\New-AzMigratePolicy ` -Name $policyName ` -ResourceGroupName $ResourceGroupName ` -VaultName $replicationVaultName ` -Property $policyProperties ` -SubscriptionId $SubscriptionId ` -NoWait | Out-Null } catch { if ($_.Exception.Message -notmatch "Status: OK") { throw $_.Exception.Message } } # Check Policy creation status every 30s. Timeout after 10min for ($i = 0; $i -lt 20; $i++) { Start-Sleep -Seconds 30 $policy = Az.Migrate.Internal\Get-AzMigratePolicy ` -ResourceGroupName $ResourceGroupName ` -Name $policyName ` -VaultName $replicationVault.Name ` -SubscriptionId $SubscriptionId ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $policy) { throw "Unexpected error occurred during policy creation. Please re-run this command or contact support if help needed." } # Stop if policy reaches a terminal state if ($policy.Property.ProvisioningState -eq [ProvisioningState]::Succeeded -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Deleted -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Canceled -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Failed) { break } } # Make sure Policy is in a terminal state if (-not ( $policy.Property.ProvisioningState -eq [ProvisioningState]::Succeeded -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Deleted -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Canceled -or $policy.Property.ProvisioningState -eq [ProvisioningState]::Failed)) { throw "Policy '$($policyName)' times out with Provisioning State: '$($policy.Property.ProvisioningState)' during creation process. Please re-run this command or contact support if help needed." } } if ($policy.Property.ProvisioningState -ne [ProvisioningState]::Succeeded) { throw "Policy '$($policyName)' has an unexpected Provisioning State of '$($policy.Property.ProvisioningState)'. Please re-run this command or contact support if help needed." } $policy = Az.Migrate.Internal\Get-AzMigratePolicy ` -ResourceGroupName $ResourceGroupName ` -Name $policyName ` -VaultName $replicationVault.Name ` -SubscriptionId $SubscriptionId ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $policy) { throw "Unexpected error occurred during policy creation. Please re-run this command or contact support if help needed." } elseif ($policy.Property.ProvisioningState -ne [ProvisioningState]::Succeeded) { throw "Policy '$($policyName)' has an unexpected Provisioning State of '$($policy.Property.ProvisioningState)'. Please re-run this command or contact support if help needed." } else { Write-Host "*Selected Policy: '$($policyName)'." } # Put Cache Storage Account $amhSolution = Az.Migrate\Get-AzMigrateSolution ` -ResourceGroupName $ResourceGroupName ` -MigrateProjectName $ProjectName ` -Name "Servers-Migration-ServerMigration_DataReplication" ` -SubscriptionId $SubscriptionId ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $amhSolution) { throw "No Data Replication Service Solution found. Please verify your appliance setup." } $amhStoredStorageAccountId = $amhSolution.DetailExtendedDetail["replicationStorageAccountId"] # Record of rsa found in AMH solution if (![string]::IsNullOrEmpty($amhStoredStorageAccountId)) { $amhStoredStorageAccountName = $amhStoredStorageAccountId.Split("/")[8] $amhStoredStorageAccount = Get-AzStorageAccount ` -ResourceGroupName $ResourceGroupName ` -Name $amhStoredStorageAccountName ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue # Wait for amhStoredStorageAccount to reach a terminal state if ($null -ne $amhStoredStorageAccount -and $null -ne $amhStoredStorageAccount.ProvisioningState -and $amhStoredStorageAccount.ProvisioningState -ne [StorageAccountProvisioningState]::Succeeded) { # Check rsa state every 30s if not Succeeded already. Timeout after 10min for ($i = 0; $i -lt 20; $i++) { Start-Sleep -Seconds 30 $amhStoredStorageAccount = Get-AzStorageAccount ` -ResourceGroupName $ResourceGroupName ` -Name $amhStoredStorageAccountName ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue # Stop if amhStoredStorageAccount is not found or in a terminal state if ($null -eq $amhStoredStorageAccount -or $null -eq $amhStoredStorageAccount.ProvisioningState -or $amhStoredStorageAccount.ProvisioningState -eq [StorageAccountProvisioningState]::Succeeded) { break } } } # amhStoredStorageAccount exists and in Succeeded state if ($null -ne $amhStoredStorageAccount -and $amhStoredStorageAccount.ProvisioningState -eq [StorageAccountProvisioningState]::Succeeded) { # Use amhStoredStorageAccount and ignore user provided Cache Storage Account Id if (![string]::IsNullOrEmpty($CacheStorageAccountId) -and $amhStoredStorageAccount.Id -ne $CacheStorageAccountId) { Write-Host "A Cache Storage Account '$($amhStoredStorageAccountName)' has been linked already. The given -CacheStorageAccountId '$($CacheStorageAccountId)' will be ignored." } $cacheStorageAccount = $amhStoredStorageAccount } elseif ($null -eq $amhStoredStorageAccount -or $null -eq $amhStoredStorageAccount.ProvisioningState) { # amhStoredStorageAccount is found but in a bad state, so log to ask user to remove if ($null -ne $amhStoredStorageAccount -and $null -eq $amhStoredStorageAccount.ProvisioningState) { Write-Host "A previously linked Cache Storage Account with Id '$($amhStoredStorageAccountId)' is found but in a unusable state. Please remove it manually and re-run this command." } # amhStoredStorageAccount is not found or in a bad state but AMH has a record of it, so remove the record if ($amhSolution.DetailExtendedDetail.ContainsKey("replicationStorageAccountId")) { $amhSolution.DetailExtendedDetail.Remove("replicationStorageAccountId") | Out-Null $amhSolution.DetailExtendedDetail.Add("replicationStorageAccountId", $null) | Out-Null Az.Migrate.Internal\Set-AzMigrateSolution ` -MigrateProjectName $ProjectName ` -Name $amhSolution.Name ` -ResourceGroupName $ResourceGroupName ` -DetailExtendedDetail $amhSolution.DetailExtendedDetail.AdditionalProperties | Out-Null } } else { throw "A linked Cache Storage Account with Id '$($amhStoredStorageAccountId)' times out with Provisioning State: '$($amhStoredStorageAccount.ProvisioningState)'. Please re-run this command or contact support if help needed." } $amhSolution = Az.Migrate\Get-AzMigrateSolution ` -ResourceGroupName $ResourceGroupName ` -MigrateProjectName $ProjectName ` -Name "Servers-Migration-ServerMigration_DataReplication" ` -SubscriptionId $SubscriptionId ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue # Check if AMH record is removed if (($null -eq $amhStoredStorageAccount -or $null -eq $amhStoredStorageAccount.ProvisioningState) -and ![string]::IsNullOrEmpty($amhSolution.DetailExtendedDetail["replicationStorageAccountId"])) { throw "Unexpected error occurred in unlinking Cache Storage Account with Id '$($amhSolution.DetailExtendedDetail["replicationStorageAccountId"])'. Please re-run this command or contact support if help needed." } } # No linked Cache Storage Account found in AMH solution but user provides a Cache Storage Account Id if ($null -eq $cacheStorageAccount -and ![string]::IsNullOrEmpty($CacheStorageAccountId)) { $userProvidedStorageAccountIdSegs = $CacheStorageAccountId.Split("/") if ($userProvidedStorageAccountIdSegs.Count -ne 9) { throw "Invalid Cache Storage Account Id '$($CacheStorageAccountId)' provided. Please provide a valid one." } $userProvidedStorageAccountName = ($userProvidedStorageAccountIdSegs[8]).ToLower() # Check if user provided Cache Storage Account exists $userProvidedStorageAccount = Get-AzStorageAccount ` -ResourceGroupName $ResourceGroupName ` -Name $userProvidedStorageAccountName ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue # Wait for userProvidedStorageAccount to reach a terminal state if ($null -ne $userProvidedStorageAccount -and $null -ne $userProvidedStorageAccount.ProvisioningState -and $userProvidedStorageAccount.ProvisioningState -ne [StorageAccountProvisioningState]::Succeeded) { # Check rsa state every 30s if not Succeeded already. Timeout after 10min for ($i = 0; $i -lt 20; $i++) { Start-Sleep -Seconds 30 $userProvidedStorageAccount = Get-AzStorageAccount ` -ResourceGroupName $ResourceGroupName ` -Name $userProvidedStorageAccountName ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue # Stop if userProvidedStorageAccount is not found or in a terminal state if ($null -eq $userProvidedStorageAccount -or $null -eq $userProvidedStorageAccount.ProvisioningState -or $userProvidedStorageAccount.ProvisioningState -eq [StorageAccountProvisioningState]::Succeeded) { break } } } if ($null -ne $userProvidedStorageAccount -and $userProvidedStorageAccount.ProvisioningState -eq [StorageAccountProvisioningState]::Succeeded) { $cacheStorageAccount = $userProvidedStorageAccount } elseif ($null -eq $userProvidedStorageAccount) { throw "Cache Storage Account with Id '$($CacheStorageAccountId)' is not found. Please re-run this command without -CacheStorageAccountId to create one automatically or re-create the Cache Storage Account yourself and try again." } elseif ($null -eq $userProvidedStorageAccount.ProvisioningState) { throw "Cache Storage Account with Id '$($CacheStorageAccountId)' is found but in an unusable state. Please re-run this command without -CacheStorageAccountId to create one automatically or re-create the Cache Storage Account yourself and try again." } else { throw "Cache Storage Account with Id '$($CacheStorageAccountId)' is found but times out with Provisioning State: '$($userProvidedStorageAccount.ProvisioningState)'. Please re-run this command or contact support if help needed." } } # No Cache Storage Account found or provided, so create one if ($null -eq $cacheStorageAccount) { $suffix = (GenerateHashForArtifact -Artifact "$($sourceSiteId)/$($SourceApplianceName)").ToString() if ($suffixHash.Length -gt 14) { $suffix = $suffixHash.Substring(0, 14) } $cacheStorageAccountName = "migratersa" + $suffix $cacheStorageAccountId = "/subscriptions/$($SubscriptionId)/resourceGroups/$($ResourceGroupName)/providers/Microsoft.Storage/storageAccounts/$($cacheStorageAccountName)" # Check if default Cache Storage Account already exists, which it shoudln't $cacheStorageAccount = Get-AzStorageAccount ` -ResourceGroupName $ResourceGroupName ` -Name $cacheStorageAccountName ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -ne $cacheStorageAccount) { throw "Unexpected error encountered: Cache Storage Account '$($cacheStorageAccountName)' already exists. Please re-run this command to create a different one or contact support if help needed." } Write-Host "Creating Cache Storage Account with default name '$($cacheStorageAccountName)'..." $params = @{ name = $cacheStorageAccountName; location = $migrateProject.Location; migrateProjectName = $migrateProject.Name; skuName = "Standard_LRS"; tags = @{ "Migrate Project" = $migrateProject.Name }; kind = "StorageV2"; encryption = @{ services = @{blob = @{ enabled = $true }; file = @{ enabled = $true } } }; } # Create Cache Storage Account $cacheStorageAccount = New-AzStorageAccount ` -ResourceGroupName $ResourceGroupName ` -Name $params.name ` -SkuName $params.skuName ` -Location $params.location ` -Kind $params.kind ` -Tags $params.tags ` -AllowBlobPublicAccess $true if ($null -ne $cacheStorageAccount -and $null -ne $cacheStorageAccount.ProvisioningState -and $cacheStorageAccount.ProvisioningState -ne [StorageAccountProvisioningState]::Succeeded) { # Check rsa state every 30s if not Succeeded already. Timeout after 10min for ($i = 0; $i -lt 20; $i++) { Start-Sleep -Seconds 30 $cacheStorageAccount = Get-AzStorageAccount ` -ResourceGroupName $ResourceGroupName ` -Name $params.name ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue # Stop if cacheStorageAccount is not found or in a terminal state if ($null -eq $cacheStorageAccount -or $null -eq $cacheStorageAccount.ProvisioningState -or $cacheStorageAccount.ProvisioningState -eq [StorageAccountProvisioningState]::Succeeded) { break } } } if ($null -eq $cacheStorageAccount -or $null -eq $cacheStorageAccount.ProvisioningState) { throw "Unexpected error occurs during Cache Storgae Account creation process. Please re-run this command or provide -CacheStorageAccountId of the one created own your own." } elseif ($cacheStorageAccount.ProvisioningState -ne [StorageAccountProvisioningState]::Succeeded) { throw "Cache Storage Account with Id '$($cacheStorageAccount.Id)' times out with Provisioning State: '$($cacheStorageAccount.ProvisioningState)' during creation process. Please remove it manually and re-run this command or contact support if help needed." } } # Sanity check if ($null -eq $cacheStorageAccount -or $null -eq $cacheStorageAccount.ProvisioningState -or $cacheStorageAccount.ProvisioningState -ne [StorageAccountProvisioningState]::Succeeded) { throw "Unexpected error occurs during Cache Storgae Account selection process. Please re-run this command or contact support if help needed." } $params = @{ contributorRoleDefId = [System.Guid]::parse($RoleDefinitionIds.ContributorId); storageBlobDataContributorRoleDefId = [System.Guid]::parse($RoleDefinitionIds.StorageBlobDataContributorId); sourceAppAadId = $sourceDra.ResourceAccessIdentityObjectId; targetAppAadId = $targetDra.ResourceAccessIdentityObjectId; } # Grant Source Dra AAD App access to Cache Storage Account as "Contributor" $hasAadAppAccess = Get-AzRoleAssignment ` -ObjectId $params.sourceAppAadId ` -RoleDefinitionId $params.contributorRoleDefId ` -Scope $cacheStorageAccount.Id ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $hasAadAppAccess) { New-AzRoleAssignment ` -ObjectId $params.sourceAppAadId ` -RoleDefinitionId $params.contributorRoleDefId ` -Scope $cacheStorageAccount.Id | Out-Null } # Grant Source Dra AAD App access to Cache Storage Account as "StorageBlobDataContributor" $hasAadAppAccess = Get-AzRoleAssignment ` -ObjectId $params.sourceAppAadId ` -RoleDefinitionId $params.storageBlobDataContributorRoleDefId ` -Scope $cacheStorageAccount.Id ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $hasAadAppAccess) { New-AzRoleAssignment ` -ObjectId $params.sourceAppAadId ` -RoleDefinitionId $params.storageBlobDataContributorRoleDefId ` -Scope $cacheStorageAccount.Id | Out-Null } # Grant Target Dra AAD App access to Cache Storage Account as "Contributor" $hasAadAppAccess = Get-AzRoleAssignment ` -ObjectId $params.targetAppAadId ` -RoleDefinitionId $params.contributorRoleDefId ` -Scope $cacheStorageAccount.Id ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $hasAadAppAccess) { New-AzRoleAssignment ` -ObjectId $params.targetAppAadId ` -RoleDefinitionId $params.contributorRoleDefId ` -Scope $cacheStorageAccount.Id | Out-Null } # Grant Target Dra AAD App access to Cache Storage Account as "StorageBlobDataContributor" $hasAadAppAccess = Get-AzRoleAssignment ` -ObjectId $params.targetAppAadId ` -RoleDefinitionId $params.storageBlobDataContributorRoleDefId ` -Scope $cacheStorageAccount.Id ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $hasAadAppAccess) { New-AzRoleAssignment ` -ObjectId $params.targetAppAadId ` -RoleDefinitionId $params.storageBlobDataContributorRoleDefId ` -Scope $cacheStorageAccount.Id | Out-Null } # Give time for role assignments to be created. Times out after 2min $rsaPermissionGranted = $false for ($i = 0; $i -lt 4; $i++) { # Check Source Dra AAD App access to Cache Storage Account as "Contributor" $hasAadAppAccess = Get-AzRoleAssignment ` -ObjectId $params.sourceAppAadId ` -RoleDefinitionId $params.contributorRoleDefId ` -Scope $cacheStorageAccount.Id ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue $rsaPermissionGranted = $null -ne $hasAadAppAccess # Check Source Dra AAD App access to Cache Storage Account as "StorageBlobDataContributor" $hasAadAppAccess = Get-AzRoleAssignment ` -ObjectId $params.sourceAppAadId ` -RoleDefinitionId $params.storageBlobDataContributorRoleDefId ` -Scope $cacheStorageAccount.Id ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue $rsaPermissionGranted = $rsaPermissionGranted -and ($null -ne $hasAadAppAccess) # Check Target Dra AAD App access to Cache Storage Account as "Contributor" $hasAadAppAccess = Get-AzRoleAssignment ` -ObjectId $params.targetAppAadId ` -RoleDefinitionId $params.contributorRoleDefId ` -Scope $cacheStorageAccount.Id ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue $rsaPermissionGranted = $rsaPermissionGranted -and ($null -ne $hasAadAppAccess) # Check Target Dra AAD App access to Cache Storage Account as "StorageBlobDataContributor" $hasAadAppAccess = Get-AzRoleAssignment ` -ObjectId $params.targetAppAadId ` -RoleDefinitionId $params.storageBlobDataContributorRoleDefId ` -Scope $cacheStorageAccount.Id ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue $rsaPermissionGranted = $rsaPermissionGranted -and ($null -ne $hasAadAppAccess) if ($rsaPermissionGranted) { break } Start-Sleep -Seconds 30 } if (!$rsaPermissionGranted) { throw "Failed to grant Cache Storage Account permissions. Please re-run this command or contact support if help needed." } $amhSolution = Az.Migrate\Get-AzMigrateSolution ` -ResourceGroupName $ResourceGroupName ` -MigrateProjectName $ProjectName ` -Name "Servers-Migration-ServerMigration_DataReplication" ` -SubscriptionId $SubscriptionId if ($amhSolution.DetailExtendedDetail.ContainsKey("replicationStorageAccountId")) { $amhStoredStorageAccountId = $amhSolution.DetailExtendedDetail["replicationStorageAccountId"] if ([string]::IsNullOrEmpty($amhStoredStorageAccountId)) { # Remove "replicationStorageAccountId" key $amhSolution.DetailExtendedDetail.Remove("replicationStorageAccountId") | Out-Null } elseif ($amhStoredStorageAccountId -ne $cacheStorageAccount.Id) { # Record of rsa mismatch throw "Unexpected error occurred in linking Cache Storage Account with Id '$($cacheStorageAccount.Id)'. Please re-run this command or contact support if help needed." } } # Update AMH record with chosen Cache Storage Account if (!$amhSolution.DetailExtendedDetail.ContainsKey("replicationStorageAccountId")) { $amhSolution.DetailExtendedDetail.Add("replicationStorageAccountId", $cacheStorageAccount.Id) Az.Migrate.Internal\Set-AzMigrateSolution ` -MigrateProjectName $ProjectName ` -Name $amhSolution.Name ` -ResourceGroupName $ResourceGroupName ` -DetailExtendedDetail $amhSolution.DetailExtendedDetail.AdditionalProperties | Out-Null } Write-Host "*Selected Cache Storage Account: '$($cacheStorageAccount.StorageAccountName)' in Resource Group '$($ResourceGroupName)' at Location '$($cacheStorageAccount.Location)' for Migrate Project '$($migrateProject.Name)'." # Put replication extension $replicationExtensionName = ($sourceFabric.Id -split '/')[-1] + "-" + ($targetFabric.Id -split '/')[-1] + "-MigReplicationExtn" $replicationExtension = Az.Migrate.Internal\Get-AzMigrateReplicationExtension ` -ResourceGroupName $ResourceGroupName ` -Name $replicationExtensionName ` -VaultName $replicationVaultName ` -SubscriptionId $SubscriptionId ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue # Remove replication extension if does not match the selected Cache Storage Account if ($null -ne $replicationExtension -and $replicationExtension.Property.CustomProperty.StorageAccountId -ne $cacheStorageAccount.Id) { Write-Host "Replication Extension '$($replicationExtensionName)' found but linked to a different Cache Storage Account '$($replicationExtension.Property.CustomProperty.StorageAccountId)'." try { Az.Migrate.Internal\Remove-AzMigrateReplicationExtension -InputObject $replicationExtension | Out-Null } catch { if ($_.Exception.Message -notmatch "Status: OK") { throw $_.Exception.Message } } Write-Host "Removing Replication Extension and waiting for 2 minutes..." Start-Sleep -Seconds 120 $replicationExtension = Az.Migrate.Internal\Get-AzMigrateReplicationExtension ` -InputObject $replicationExtension ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $replicationExtension) { Write-Host "Replication Extension '$($replicationExtensionName)' was removed." } } # Replication extension exists if ($null -ne $replicationExtension) { # Give time for create/update to reach a terminal state. Timeout after 10min if ($replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Creating -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Updating) { Write-Host "Replication Extension '$($replicationExtensionName)' found in Provisioning State '$($replicationExtension.Property.ProvisioningState)'." for ($i = 0; $i -lt 20; $i++) { Start-Sleep -Seconds 30 $replicationExtension = Az.Migrate.Internal\Get-AzMigrateReplicationExtension ` -InputObject $replicationExtension ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if (-not ( $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Creating -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Updating)) { break } } # Make sure replication extension is no longer in Creating or Updating state if ($replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Creating -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Updating) { throw "Replication Extension '$($replicationExtensionName)' times out with Provisioning State: '$($replicationExtension.Property.ProvisioningState)'. Please re-run this command or contact support if help needed." } } # Check and remove if replication extension is in a bad terminal state if ($replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Canceled -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Failed) { Write-Host "Replication Extension '$($replicationExtensionName)' found but in an unusable terminal Provisioning State '$($replicationExtension.Property.ProvisioningState)'.`nRemoving Replication Extension..." # Remove replication extension try { Az.Migrate.Internal\Remove-AzMigrateReplicationExtension -InputObject $replicationExtension | Out-Null } catch { if ($_.Exception.Message -notmatch "Status: OK") { throw $_.Exception.Message } } Start-Sleep -Seconds 30 $replicationExtension = Az.Migrate.Internal\Get-AzMigrateReplicationExtension ` -InputObject $replicationExtension ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue # Make sure replication extension is no longer in Canceled or Failed state if ($null -ne $replicationExtension -and ($replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Canceled -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Failed)) { throw "Failed to change the Provisioning State of Replication Extension '$($replicationExtensionName)'by removing. Please re-run this command or contact support if help needed." } } # Give time to remove replication extension. Timeout after 10min if ($null -ne $replicationExtension -and $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Deleting) { Write-Host "Replication Extension '$($replicationExtensionName)' found in Provisioning State '$($replicationExtension.Property.ProvisioningState)'." for ($i = 0; $i -lt 20; $i++) { Start-Sleep -Seconds 30 $replicationExtension = Az.Migrate.Internal\Get-AzMigrateReplicationExtension ` -InputObject $replicationExtension ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $replicationExtension -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Deleted) { break } elseif ($replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Deleting) { continue } throw "Replication Extension '$($replicationExtensionName)' has an unexpected Provisioning State of '$($replicationExtension.Property.ProvisioningState)' during removal process. Please re-run this command or contact support if help needed." } # Make sure replication extension is no longer in Deleting state if ($null -ne $replicationExtension -and $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Deleting) { throw "Replication Extension '$($replicationExtensionName)' times out with Provisioning State: '$($replicationExtension.Property.ProvisioningState)'. Please re-run this command or contact support if help needed." } } # Indicate replication extension was removed if ($null -eq $replicationExtension -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Deleted) { Write-Host "Replication Extension '$($replicationExtensionName)' was removed." } } # Refresh local replication extension object if exists if ($null -ne $replicationExtension) { $replicationExtension = Az.Migrate.Internal\Get-AzMigrateReplicationExtension -InputObject $replicationExtension } # Create replication extension if not found or previously deleted if ($null -eq $replicationExtension -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Deleted) { Write-Host "Waiting 2 minutes for permissions to sync before creating Replication Extension..." Start-Sleep -Seconds 120 Write-Host "Creating Replication Extension..." $params = @{ InstanceType = $instanceType; SourceFabricArmId = $sourceFabric.Id; TargetFabricArmId = $targetFabric.Id; StorageAccountId = $cacheStorageAccount.Id; StorageAccountSasSecretName = $null; } # Setup Replication Extension deployment parameters $replicationExtensionProperties = [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Models.Api20210216Preview.ReplicationExtensionModelProperties]::new() if ($instanceType -eq $AzStackHCIInstanceTypes.HyperVToAzStackHCI) { $replicationExtensionCustomProperties = [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Models.Api20210216Preview.HyperVToAzStackHcireplicationExtensionModelCustomProperties]::new() $replicationExtensionCustomProperties.HyperVFabricArmId = $params.SourceFabricArmId } elseif ($instanceType -eq $AzStackHCIInstanceTypes.VMwareToAzStackHCI) { $replicationExtensionCustomProperties = [Microsoft.Azure.PowerShell.Cmdlets.Migrate.Models.Api20210216Preview.VMwareToAzStackHcireplicationExtensionModelCustomProperties]::new() $replicationExtensionCustomProperties.VMwareFabricArmId = $params.SourceFabricArmId } else { throw "Currently, for AzStackHCI scenario, only HyperV and VMware as the source is supported." } $replicationExtensionCustomProperties.InstanceType = $params.InstanceType $replicationExtensionCustomProperties.AzStackHCIFabricArmId = $params.TargetFabricArmId $replicationExtensionCustomProperties.StorageAccountId = $params.StorageAccountId $replicationExtensionCustomProperties.StorageAccountSasSecretName = $params.StorageAccountSasSecretName $replicationExtensionProperties.CustomProperty = $replicationExtensionCustomProperties try { Az.Migrate.Internal\New-AzMigrateReplicationExtension ` -Name $replicationExtensionName ` -ResourceGroupName $ResourceGroupName ` -VaultName $replicationVaultName ` -Property $replicationExtensionProperties ` -SubscriptionId $SubscriptionId ` -NoWait | Out-Null } catch { if ($_.Exception.Message -notmatch "Status: OK") { throw $_.Exception.Message } } # Check replication extension creation status every 30s. Timeout after 10min for ($i = 0; $i -lt 20; $i++) { Start-Sleep -Seconds 30 $replicationExtension = Az.Migrate.Internal\Get-AzMigrateReplicationExtension ` -ResourceGroupName $ResourceGroupName ` -Name $replicationExtensionName ` -VaultName $replicationVaultName ` -SubscriptionId $SubscriptionId ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $replicationExtension) { throw "Unexpected error occurred during Replication Extension creation. Please re-run this command or contact support if help needed." } # Stop if replication extension reaches a terminal state if ($replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Succeeded -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Deleted -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Canceled -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Failed) { break } } # Make sure replicationExtension is in a terminal state if (-not ( $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Succeeded -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Deleted -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Canceled -or $replicationExtension.Property.ProvisioningState -eq [ProvisioningState]::Failed)) { throw "Replication Extension '$($replicationExtensionName)' times out with Provisioning State: '$($replicationExtension.Property.ProvisioningState)' during creation process. Please re-run this command or contact support if help needed." } } if ($replicationExtension.Property.ProvisioningState -ne [ProvisioningState]::Succeeded) { throw "Replication Extension '$($replicationExtensionName)' has an unexpected Provisioning State of '$($replicationExtension.Property.ProvisioningState)'. Please re-run this command or contact support if help needed." } $replicationExtension = Az.Migrate.Internal\Get-AzMigrateReplicationExtension ` -ResourceGroupName $ResourceGroupName ` -Name $replicationExtensionName ` -VaultName $replicationVaultName ` -SubscriptionId $SubscriptionId ` -ErrorVariable notPresent ` -ErrorAction SilentlyContinue if ($null -eq $replicationExtension) { throw "Unexpected error occurred during Replication Extension creation. Please re-run this command or contact support if help needed." } elseif ($replicationExtension.Property.ProvisioningState -ne [ProvisioningState]::Succeeded) { throw "Replication Extension '$($replicationExtensionName)' has an unexpected Provisioning State of '$($replicationExtension.Property.ProvisioningState)'. Please re-run this command or contact support if help needed." } else { Write-Host "*Selected Replication Extension: '$($replicationExtensionName)'." } if ($PassThru) { return $true } } } # SIG # Begin signature block # MIInvgYJKoZIhvcNAQcCoIInrzCCJ6sCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB0hQnApn7KPKAd # NyeemKHvSsWLs5NSUKXQbJYWhSRC76CCDXYwggX0MIID3KADAgECAhMzAAADrzBA # DkyjTQVBAAAAAAOvMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjMxMTE2MTkwOTAwWhcNMjQxMTE0MTkwOTAwWjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDOS8s1ra6f0YGtg0OhEaQa/t3Q+q1MEHhWJhqQVuO5amYXQpy8MDPNoJYk+FWA # hePP5LxwcSge5aen+f5Q6WNPd6EDxGzotvVpNi5ve0H97S3F7C/axDfKxyNh21MG # 0W8Sb0vxi/vorcLHOL9i+t2D6yvvDzLlEefUCbQV/zGCBjXGlYJcUj6RAzXyeNAN # xSpKXAGd7Fh+ocGHPPphcD9LQTOJgG7Y7aYztHqBLJiQQ4eAgZNU4ac6+8LnEGAL # go1ydC5BJEuJQjYKbNTy959HrKSu7LO3Ws0w8jw6pYdC1IMpdTkk2puTgY2PDNzB # tLM4evG7FYer3WX+8t1UMYNTAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQURxxxNPIEPGSO8kqz+bgCAQWGXsEw # RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW # MBQGA1UEBRMNMjMwMDEyKzUwMTgyNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci # tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG # CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0 # MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAISxFt/zR2frTFPB45Yd # mhZpB2nNJoOoi+qlgcTlnO4QwlYN1w/vYwbDy/oFJolD5r6FMJd0RGcgEM8q9TgQ # 2OC7gQEmhweVJ7yuKJlQBH7P7Pg5RiqgV3cSonJ+OM4kFHbP3gPLiyzssSQdRuPY # 1mIWoGg9i7Y4ZC8ST7WhpSyc0pns2XsUe1XsIjaUcGu7zd7gg97eCUiLRdVklPmp # XobH9CEAWakRUGNICYN2AgjhRTC4j3KJfqMkU04R6Toyh4/Toswm1uoDcGr5laYn # TfcX3u5WnJqJLhuPe8Uj9kGAOcyo0O1mNwDa+LhFEzB6CB32+wfJMumfr6degvLT # e8x55urQLeTjimBQgS49BSUkhFN7ois3cZyNpnrMca5AZaC7pLI72vuqSsSlLalG # OcZmPHZGYJqZ0BacN274OZ80Q8B11iNokns9Od348bMb5Z4fihxaBWebl8kWEi2O # PvQImOAeq3nt7UWJBzJYLAGEpfasaA3ZQgIcEXdD+uwo6ymMzDY6UamFOfYqYWXk # ntxDGu7ngD2ugKUuccYKJJRiiz+LAUcj90BVcSHRLQop9N8zoALr/1sJuwPrVAtx # HNEgSW+AKBqIxYWM4Ev32l6agSUAezLMbq5f3d8x9qzT031jMDT+sUAoCw0M5wVt # CUQcqINPuYjbS1WgJyZIiEkBMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq # hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 # IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg # Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03 # a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr # rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg # OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy # 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9 # sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh # dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k # A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB # w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn # Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90 # lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w # ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o # ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD # VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa # BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny # bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG # AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV # HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG # AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl # AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb # C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l # hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6 # I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0 # wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560 # STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam # ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa # J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah # XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA # 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt # Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr # /Xmfwb1tbWrJUnMTDXpQzTGCGZ4wghmaAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAAOvMEAOTKNNBUEAAAAAA68wDQYJYIZIAWUDBAIB # BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIGXWZ+Lm7QziNY1edRv00VEK # /LttaBVdGfpWHh00MA19MEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A # cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB # BQAEggEAq6qUli7T5AhTt6P0QcSobAI6W71kXTqWE22mA8Ti5sPEm4HKSrWiHsS+ # rr8Swq5tMQfKbDMaxdNeGKhQrFV0aGG/KwZG2yUiNQzdqtL9VtsBHQB5Kurt/rqk # 9VZOfc81XixZ0XGffFeKgnAH1lXGUw90HiUA+xr8/Mfzg2tGtkaD1IpTJCe102JT # 0x1A4v1OmeRGZkNVOtttCtvMv1LmzAiMBrFOLh1oba2w39LU/ST074T9E1UCxbmA # B50UTagdfSl48GXoTPwi/qYb0Op13kNOLCVHzrkfJUQemEnAAl2EUcmyHVohJiF0 # Iu0EqrrYU60YK9O9soXaDr4+XeUFtqGCFygwghckBgorBgEEAYI3AwMBMYIXFDCC # FxAGCSqGSIb3DQEHAqCCFwEwghb9AgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFYBgsq # hkiG9w0BCRABBKCCAUcEggFDMIIBPwIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl # AwQCAQUABCDCGjkPvdb7O0XkL/QyKQSO4nkXxSPiVwxyzqmlTEl/IwIGZh+4i44Z # GBIyMDI0MDQyMzEzMTYyMC4yMVowBIACAfSggdikgdUwgdIxCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVs # YW5kIE9wZXJhdGlvbnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046 # MDg0Mi00QkU2LUMyOUExJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNl # cnZpY2WgghF4MIIHJzCCBQ+gAwIBAgITMwAAAdqO1claANERsQABAAAB2jANBgkq # hkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ # MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u # MSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMzEw # MTIxOTA2NTlaFw0yNTAxMTAxOTA2NTlaMIHSMQswCQYDVQQGEwJVUzETMBEGA1UE # CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z # b2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVy # YXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjA4NDItNEJF # Ni1DMjlBMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIC # IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAk5AGCHa1UVHWPyNADg0N/xtx # WtdI3TzQI0o9JCjtLnuwKc9TQUoXjvDYvqoe3CbgScKUXZyu5cWn+Xs+kxCDbkTt # fzEOa/GvwEETqIBIA8J+tN5u68CxlZwliHLumuAK4F/s6J1emCxbXLynpWzuwPZq # 6n/S695jF5eUq2w+MwKmUeSTRtr4eAuGjQnrwp2OLcMzYrn3AfL3Gu2xgr5f16ts # MZnaaZffvrlpLlDv+6APExWDPKPzTImfpQueScP2LiRRDFWGpXV1z8MXpQF67N+6 # SQx53u2vNQRkxHKVruqG/BR5CWDMJCGlmPP7OxCCleU9zO8Z3SKqvuUALB9UaiDm # mUjN0TG+3VMDwmZ5/zX1pMrAfUhUQjBgsDq69LyRF0DpHG8xxv/+6U2Mi4Zx7LKQ # wBcTKdWssb1W8rit+sKwYvePfQuaJ26D6jCtwKNBqBiasaTWEHKReKWj1gHxDLLl # DUqEa4frlXfMXLxrSTBsoFGzxVHge2g9jD3PUN1wl9kE7Z2HNffIAyKkIabpKa+a # 9q9GxeHLzTmOICkPI36zT9vuizbPyJFYYmToz265Pbj3eAVX/0ksaDlgkkIlcj7L # GQ785edkmy4a3T7NYt0dLhchcEbXug+7kqwV9FMdESWhHZ0jobBprEjIPJIdg628 # jJ2Vru7iV+d8KNj+opMCAwEAAaOCAUkwggFFMB0GA1UdDgQWBBShfI3JUT1mE5WL # MRRXCE2Avw9fRTAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNV # HR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2Ny # bC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYI # KwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAy # MDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMI # MA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAuYNV1O24jSMAS3jU # 7Y4zwJTbftMYzKGsavsXMoIQVpfG2iqT8g5tCuKrVxodWHa/K5DbifPdN04G/uty # z+qc+M7GdcUvJk95pYuw24BFWZRWLJVheNdgHkPDNpZmBJxjwYovvIaPJauHvxYl # SCHusTX7lUPmHT/quz10FGoDMj1+FnPuymyO3y+fHnRYTFsFJIfut9psd6d2l6pt # OZb9F9xpP4YUixP6DZ6PvBEoir9CGeygXyakU08dXWr9Yr+sX8KGi+SEkwO+Wq0R # NaL3saiU5IpqZkL1tiBw8p/Pbx53blYnLXRW1D0/n4L/Z058NrPVGZ45vbspt6CF # rRJ89yuJN85FW+o8NJref03t2FNjv7j0jx6+hp32F1nwJ8g49+3C3fFNfZGExkkJ # WgWVpsdy99vzitoUzpzPkRiT7HVpUSJe2ArpHTGfXCMxcd/QBaVKOpGTO9KdErMW # xnASXvhVqGUpWEj4KL1FP37oZzTFbMnvNAhQUTcmKLHn7sovwCsd8Fj1QUvPiydu # gntCKncgANuRThkvSJDyPwjGtrtpJh9OhR5+Zy3d0zr19/gR6HYqH02wqKKmHnz0 # Cn/FLWMRKWt+Mv+D9luhpLl31rZ8Dn3ya5sO8sPnHk8/fvvTS+b9j48iGanZ9O+5 # Layd15kGbJOpxQ0dE2YKT6eNXecwggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZ # AAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 # ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMyMjVa # MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT # HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEF # AAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1 # V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9 # alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmv # Haus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN7928 # jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3t # pK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74kpEe # HT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2K26o # ElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5TI4C # vEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZki1ug # poMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9QBXps # xREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0C # AwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYE # FCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtT # NRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNo # dHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5o # dG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBD # AEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZW # y4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5t # aWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAt # MDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0y # My5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pc # FLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpT # Td2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0j # VOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3 # +SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmR # sqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSw # ethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPXfx5b # RAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVXVAmx # aQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGConsX # HRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU5nR0 # W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEGahC0 # HVUzWLOhcGbyoYIC1DCCAj0CAQEwggEAoYHYpIHVMIHSMQswCQYDVQQGEwJVUzET # MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV # TWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFu # ZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjA4 # NDItNEJFNi1DMjlBMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2 # aWNloiMKAQEwBwYFKw4DAhoDFQBCoh8hiWMdRs2hjT/COFdGf+xIDaCBgzCBgKR+ # MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT # HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBBQUAAgUA # 6dIfhDAiGA8yMDI0MDQyMzE5NTIzNloYDzIwMjQwNDI0MTk1MjM2WjB0MDoGCisG # AQQBhFkKBAExLDAqMAoCBQDp0h+EAgEAMAcCAQACAhTqMAcCAQACAhFUMAoCBQDp # 03EEAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMH # oSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQEFBQADgYEAJqJG2yFz0bxZ9UyND3GA # Rhk3KhDO/vYFTou63GVkzavYLou5i9zHurrc9azczGRK1ccBvZ6xFi8Ew8NeyCr4 # 03p9hdIxMrCmcdhGIr+3dS/dLC09ePKSJHaapXGPr8+Q3aeyKam6l1Kj+Wc5kJ/L # vTpxCxxAELkxp8m9GWVNRtoxggQNMIIECQIBATCBkzB8MQswCQYDVQQGEwJVUzET # MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV # TWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1T # dGFtcCBQQ0EgMjAxMAITMwAAAdqO1claANERsQABAAAB2jANBglghkgBZQMEAgEF # AKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEi # BCCyKI4qM4P7EunT/vb8d9rUjfeDxxuz0QB/F3oz+3KNwzCB+gYLKoZIhvcNAQkQ # Ai8xgeowgecwgeQwgb0EICKlo2liwO+epN73kOPULT3TbQjmWOJutb+d0gI7GD3G # MIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAO # BgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEm # MCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAHajtXJ # WgDREbEAAQAAAdowIgQgVv+JqZpSdH596xBoeeLlrNd2rLbZu4aFLWgppMMOb4kw # DQYJKoZIhvcNAQELBQAEggIAhtz+DFa2OeXLO6bLDCmxEKbjy9mwgQd3FYPAA+BS # kcEPOgAhXP4Dr/bRYgevbSIh6dlSx/uMz/Yf/bozHXkzAhegqd/cK/T1i9Dcb6Zw # W0gTWtfXg6+2NuQiQl/0x6o8vOeYR5yiEOJjcgLtOe+bozueWdcI/tr3ZmPbaQdS # ymADI5hDOdEJkcQIHhQ3xbDCAzGGgaVx8AMHfBlCLTH+HojT/WDxjnR2AmPipWlV # XticWMMt6WxtXakrvGVzD6MCM6m1HAS4PdD22LvvXjLcvovf2jnSDq0luklR0lw2 # euAxpNeH1CG16hOe2OUCt8+LzDsDnbCSvIW6MyZgWVZCiOUR9CDxpNBkSY7i1mbV # gJ3nxnScGSB1KtBZL0aZrLefaKZY0VzYiwJMEw11tBvdqGhqjBQn8gh0tSp9pw+5 # 13RUDRlTw6Cemga1pdOQFMN8Gs/loEpQELGLjSPZsOUwWTagQK8lqVEE789f/Hni # 2JHgmfntHjX16P5eDE+0ASP1/7lpizEr+5EuTW6FmX0Ayx5N/OL+JMUWARGt4hkH # nwevM8lVhBiElRbomghtbxeL+a1HiQN/EpA9srG8zTyG9Sr2FA4fOMmb+IsOdMBS # JHmfkNtv7Y6ALnyKZ1E1PzosWZ28iAUe2ZWbXOXHNDjf3o06BVy22v/tszIAjN0g # XHo= # SIG # End signature block |