Migrate-Aadds.ps1

<#PSScriptInfo
 
.VERSION 1.9
 
.GUID 723874e6-7a38-4bde-b7f5-8627c18fd10c
 
.AUTHOR aaddsfb@microsoft.com
 
.COMPANYNAME Microsoft Corporation
 
.COPYRIGHT (c) Microsoft Corporation
 
.TAGS Azure-AD-Domain-Services Migration
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
    10/18/2019 - Initial release
    12/04/2019 - Ensure well-formed subnetids during abort
    01/17/2020 - Parameter type fix
    02/12/2020 - Add support for MFA and some message fixes
    03/31/2020 - Improve retry conditions
    07/19/2020 - Minor ApiVersion fix
    08/21/2020 - Adding file based logging
    09/24/2020 - Add a reminder for reviewing online migration document
    01/21/2021 - Bug fix to find the AAD managed domain resource accurately
    02/17/2021 - Add a check for NSG setup on the target subnet
    07/30/2021 - For Abort get classic vnet using Resource Type
#>


<#
 
.SYNOPSIS
    Migrates an Azure AD Domain Services from a classic virtual network to an Azure Resource Manager virtual network.
 
.DESCRIPTION
    Migrates an Azure AD Domain Services from a classic virtual network to an Azure Resource Manager virtual network.
 
.PARAMETER Prepare [MANADATORY]
    Causes the script to prepare the classic Azure AD Domain Services resource for migration.
 
.PARAMETER Commit [MANADATORY]
    Causes the script to commit the migration for the prepared classic Azure AD Domain Services resource.
 
.PARAMETER Abort [MANADATORY]
    Causes the script to abort the migration and reverts the classic Azure AD Domain Services to a running state.
 
.PARAMETER ManagedDomainFqdn [MANADATORY]
    The fqdn of the managed domain (aadds.corp.contoso.com).
 
.PARAMETER VirtualNetworkResourceGroupName [MANDATORY]
    The name of the Azure Resource Manager resource group that hosts the virtual network to which Azure AD Domain Services will be moved.
 
.PARAMETER VirtualNetworkName [MANDATORY]
    The name of the Azure Resource Manager virtual network to which Azure AD Domain Services will be moved.
 
.PARAMETER VirtualSubnetName [MANADATORY]
    The name of the Azure Resource Manager virtual subnet to which Azure AD Domain Services will be moved.
 
.PARAMETER ClassicVirtualNetworkName [MANADATORY]
    The name of the Classic Virtual Network on which Azure AD Domain Services was enabled. This is only required for Abort case
 
.PARAMETER SubscriptionId [OPTIONAL]
    The Azure subscription that hosts the Azure AD Domain Services resource.
 
.PARAMETER Credential [OPTIONAL]
    The credentials used to authenticate to Azure.
#>

[CmdletBinding()]
Param (
    [Parameter(
        Mandatory=$true,
        ParameterSetName="Prepare")]
        [switch]
        $Prepare,
    [Parameter(
        Mandatory=$true,
        ParameterSetName="Commit")]
        [switch]
        $Commit,
    [Parameter(
        Mandatory=$true,
        ParameterSetName="Abort")]
        [switch]
        $Abort,

    [Parameter(
        Mandatory=$true,
        ParameterSetName="Prepare")]
    [Parameter(
        Mandatory=$true,
        ParameterSetName="Commit")]
    [Parameter(
        Mandatory=$true,
        ParameterSetName="Abort")]
        [string]
        $ManagedDomainFqdn,

    [Parameter(
        Mandatory=$true,
        ParameterSetName="Commit")]
        [string]
        $VirtualNetworkResourceGroupName,

    [Parameter(
        Mandatory=$true,
        ParameterSetName="Commit")]
        [string]
        $VirtualNetworkName,

    [Parameter(
        Mandatory=$true,
        ParameterSetName="Abort")]
        [string]
        $ClassicVirtualNetworkName,

    [Parameter(
        Mandatory=$true,
        ParameterSetName="Commit")]
        [string]
        $VirtualSubnetName,

    [Parameter(
        Mandatory=$false,
        ParameterSetName="Prepare")]
    [Parameter(
        Mandatory=$false,
        ParameterSetName="Commit")]
    [Parameter(
        Mandatory=$false,
        ParameterSetName="Abort")]
        [string]
        $SubscriptionId,

    [Parameter(
        Mandatory=$false,
        ParameterSetName="Prepare")]
    [Parameter(
        Mandatory=$false,
        ParameterSetName="Commit")]
    [Parameter(
        Mandatory=$false,
        ParameterSetName="Abort")]
        [pscredential]
        $Credentials
)


Process
{

    enum actionType
    {
        Unknown
        Prepare
        Commit
        Abort
    }

    ## Create a log folder where the log files will be kept.
    $currentLocation = Get-Location
    $logsDirectory = "$currentLocation\Logs"
    New-Item -ItemType Directory -Path $logsDirectory -Force | Out-Null
    $dateFormat = $($(Get-Date).ToUniversalTime().ToString('MM-dd-yyyyTHH-mm-ss'))
    $global:filePath = "$logsDirectory\MigrationLogs-$dateFormat.txt"

    Write-Host "Log File Path: $global:filePath"

    if(!(Test-Path -Path $global:filePath))
    {
        ## Create the file if it does not exists
        $global:sw = New-Object System.IO.StreamWriter $global:filePath
    }

    ## Function to write log message to a file
    Function LogToFile
    {
        Param([string]$message, [bool]$force = $false)

        if ($null -eq $global:sw.BaseStream)
        {
            $fStream = New-Object IO.FileStream $global:filePath ,'Append','Write','Read'
            $global:sw = New-Object System.IO.StreamWriter $fStream
        }

        $global:sw.WriteLine($message)

        if ($force -eq $true)
        {
            $global:sw.Close()
        }
    }

    ## Function to write log message to file as well as output
    Function LogToFileAndOutput
    {
        Param([string]$message, [string]$messageType = "Info")

        switch($messageType)
        {
            "Info"
            {
                Write-Host $message
                break
            }
            "Success"
            {
                Write-Host -ForegroundColor Green $message
                break
            }
            "Warning"
            {
                Write-Host -ForegroundColor Yellow $message
                break
            }
            "Error"
            {
                Write-Host -ForegroundColor Red $message
                break
            }
            Default
            {
                $message = "UNKNOWN MessageType: $messageType. Message: $message"
                Write-Host $message
                break
            }
        }

        LogToFile -message $message -force $true
    }

    ## Log message to output as well as file
    Function LogInfo
    {
        Param([string]$message)

        $message = "$($(Get-Date).ToUniversalTime().ToString('MM-dd-yyyyTHH-mm-ss')) :: INFO :: $message"

        LogToFileAndOutput -message $message -messageType "Info"
    }

    ## Log Progress message to output as well as file
    Function LogProgress
    {
        Param([string]$currentOp,[int]$percentComplete)

        $lastUpdateTime = $($(Get-Date).ToUniversalTime().ToString('MM-dd-yyyyTHH-mm-ss'))

        if($currentOp -eq $null)
        {
            Write-Progress -Activity "Migration" -Status ("Last Updated: $lastUpdateTime") -Completed
            $message = "$($(Get-Date).ToUniversalTime().ToString('MM-dd-yyyyTHH-mm-ss')) :: PROGRESS :: Activity: Migration. Status LastUpdated: $lastUpdateTime, Status: Completed"
        }
        else
        {
            Write-Progress -Activity "Migration" -Status ("Last Updated: $lastUpdateTime") -CurrentOperation $currentOp -PercentComplete $percentComplete
            $message = "$($(Get-Date).ToUniversalTime().ToString('MM-dd-yyyyTHH-mm-ss')) :: PROGRESS :: Activity: Migration. Status LastUpdated: $lastUpdateTime, Current Operation: $currentOp, PercentComplete: $percentComplete"
        }

        LogInfo -message $message
    }

    ## Log Success message to output as well as file
    Function LogSuccess
    {
        Param([string]$message)

        $message = "$($(Get-Date).ToUniversalTime().ToString('MM-dd-yyyyTHH-mm-ss')) :: SUCCESS :: $message"

        LogToFileAndOutput -message $message -messageType "Success"
    }

    ## Log Warning message to output as well as file
    Function LogWarning
    {
        Param([string]$message)

        $message = "$($(Get-Date).ToUniversalTime().ToString('MM-dd-yyyyTHH-mm-ss')) :: WARNING :: $message"

        LogToFileAndOutput -message $message -messageType "Warning"
    }

    ## Log Error message to output as well as file
    Function LogError
    {
        Param([string]$message)

        $message = "$($(Get-Date).ToUniversalTime().ToString('MM-dd-yyyyTHH-mm-ss')) :: ERROR :: $message"

        LogToFileAndOutput -message $message -messageType "Error"
    }

    Function GetAaddsResource
    {
        Param([string]$domainName)

        LogInfo ("Getting Resource Information for Resource Name: {0}"-f $domainName)

        $resources = Get-AzResource -ResourceType "Microsoft.AAD/DomainServices" -ExpandProperties -ApiVersion 2017-06-01 -ErrorAction SilentlyContinue

        foreach($resource in $resources)
        {
            if($resource.Name -eq $domainName)
            {
                LogInfo("Resource Found")
                return $resource
            }
            else
            {
                LogWarning("Resource: {0} did not match the domainName: {1}" -f $resource.Name, $domainName)
            }
        }

        LogError("Resource Not Found")
        return $null
    }

    $subscription = $null
    $aadds = $null
    $creds = $null
    $azProfile = $null
    $action =[actionType]::Unknown

    LogInfo("Arguments Passed")
    foreach($boundparam in $PSBoundParameters.GetEnumerator())
    {
        LogInfo("{0} :: {1}" -f $boundparam.Key,$boundparam.Value)
    }

    #
    # Check for the requested action
    if($true -eq $Prepare)
    {
        $action = [actionType]::Prepare
    }
    elseif($true -eq $Commit)
    {
        $action = [actionType]::Commit
    }
    elseif($true -eq $Abort)
    {
        $action = [actionType]::Abort
    }

    if($action -eq [actionType]::Unknown)
    {
        LogError "Unknown action type."
        return
    }

    ## check for subscriptionID
    if($SubscriptionId)
    {
        $subscription = $SubscriptionId
    }

    LogInfo ([string]::Empty)
    LogInfo ([string]::Empty)
    LogInfo "Authenticating to Azure... "

    #
    # Collect credentials from the user for authentication
    if($null -eq $Credentials)
    {
        $azProfile = Connect-AzAccount -ErrorAction SilentlyContinue
    }
    else
    {
        $azProfile = Connect-AzAccount -Credential $Credentials -ErrorAction SilentlyContinue
    }

    if($null -eq $azProfile)
    {
        # Authentication failed
        LogError "[Failed!]"
        LogError "Could not authenticate to Azure. Check your credentials and try again."
        Return
    }
    else
    {
        LogSuccess "[Success!]"
    }

    LogInfo ("Authenticated to Azure as {0}..." -f $azProfile.Context.Account.Id)

    #
    # Check for user provided subscription Id
    if($null -eq $subscription)
    {
        #
        # Locate Azure AD Domain Services in a subscription
        # Use the first instance found as there should only be one instance per tenant
        LogInfo "Searching for Azure AD Domain Services instance..."
        ($AzSubs = Get-AzSubscription) | Out-Null
        foreach($azsub in $AzSubs)
        {
            (Select-AzSubscription $azsub.Id) | Out-Null

            $aadds = GetAaddsResource -domainName $ManagedDomainFqdn

            if($null -ne $aadds)
            {
                # Found Azure AD Domain Services in this subscription
                # Add to the subscription List
                $subscription = $azsub.Id
                break
            }
        }

        if($null -eq $subscription)
        {
            LogError "[Failed!]"
            LogError ("Could not find a subscription that has the specified Azure AD Domain Services with managed domain name: {0}" -f $ManagedDomainFqdn)
            return
        }
        else
        {
            LogSuccess "[Found!]"
        }
    }
    else
    {
        Select-AzSubscription $subscription -ErrorAction SilentlyContinue

        $aadds = GetAaddsResource -domainName $ManagedDomainFqdn
    }

    #
    # Validate the resource is Azure AD Domain Services
    $pass = $true

    LogInfo "Validating AADDS Resource..."
    if($aadds -eq $null)
    {
        $pass = $false
        LogError "[Failed!]"
        LogError ("Unable to find Azure AD Domain services Resource for DomainName: {0}" -f $ManagedDomainFqdn)
    }
    else 
    {
        LogSuccess "[Pass!]"
    }

    #
    # Validate service status
    LogInfo "Validating service status..."

    #
    # If the action is commit, this should equal PreparedForMigration or FailedToPerformMigration.
    # If the action is abort, this should equal PreparedForMigration, FailedToRollbackMigration or FailedToPerformMigration.
    # If the action is prepare, this should equal Running or FailedToPrepareForMigration.
    if("commit" -eq $action)
    {
        if("PreparedForMigration" -ne $aadds.properties.serviceStatus -and "FailedToPerformMigration" -ne $aadds.properties.serviceStatus)
        {
            $pass = $false
            LogError "[Failed!]"
            LogError ("The managed domain {0} must be prepared prior to this command (Status:{1})." -f $aadds.Name, $aadds.properties.serviceStatus)
        }
        else { LogSuccess "[Pass!]" }
    }
    elseif("abort" -eq $action)
    {
        if("PreparedForMigration" -ne $aadds.properties.serviceStatus -and "FailedToRollbackMigration" -ne $aadds.properties.serviceStatus -and "FailedToPerformMigration" -ne $aadds.properties.serviceStatus)
        {
            $pass = $false
            LogError "[Failed!]"
            LogError ("The managed domain {0} must be prepared prior to this command (Status:{1})." -f $aadds.Name, $aadds.properties.serviceStatus)
        }
        else { LogSuccess "[Pass!]" }
    }
    else
    {
        if( ("FailedToPrepareForMigration" -ne $aadds.Properties.ServiceStatus -and "Running" -ne $aadds.properties.serviceStatus) )
        {
            $pass = $false
            LogError "[Failed!]"
            LogError ("The managed domain {0} is not in a state that can be prepared (Status:{1})." -f $aadds.Name, $aadds.properties.serviceStatus)
        }
        else { LogSuccess "[Pass!]" }
    }

    if($pass -eq $false)
        {
            LogError "One or more prerequisites checks failed."
            Return
        }

    #
    # Do work based on the action
    $actionStart = Get-Date

    switch($action)
    {
        "Prepare"
        {
            LogInfo ([String]::Empty)
            LogInfo "It is important you let the script complete"
            LogInfo "The preparation may take up to 30 minutes. Please wait..."
            LogInfo ([String]::Empty)
            LogWarning "IMPORTANT! Please review https://docs.microsoft.com/en-us/azure/active-directory-domain-services/migrate-from-classic-vnet carefully before you proceed with the migration. Please ensure that the virtual network, that the managed domain will be migrated to, meets the requirements (https://docs.microsoft.com/en-us/azure/active-directory-domain-services/migrate-from-classic-vnet#restrictions-on-available-virtual-networks)."
            LogInfo ([String]::Empty)
            $consent = Read-Host -Prompt ("Do you want to prepare {0} for migration: (Y/N)" -f $ManagedDomainFqdn)
            if("Y" -ne $consent)
            {
                LogWarning "[Canceled!] The user canceled the migration."
                return
            }

            LogInfo "Processing your request... "
            # Prepare the instance

            (Set-AzResource -ResourceId $aadds.ResourceId -Properties @{"subnetId" = $null} -ApiVersion 2017-06-01 -Force) | Out-Null

            LogInfo -Foreground Green "[Preparation complete!]"
            LogInfo "Validating ..."

            $confirm = $null
            $confirm = GetAaddsResource -domainName $ManagedDomainFqdn
            if($null -eq $confirm)
            {
                LogWarning "[Undetermined!]"
                LogWarning "The script could not validate the preparation status."
                LogWarning (
                    "Please run {0} and check the serviceStatus value is 'PreparedForMigration'" -f "(Get-AzResource -Name $ManagedDomainFqdn -ExpandProperties -ApiVersion 2017-06-01).Properties"
                    )
                return
            }

            ## Check the properties for successful migration
            if($confirm.properties.serviceStatus -ne "PreparedForMigration")
            {
                LogError "[Failed!]"
                LogError ("The managed domain {0} did not prepare (Status:{1}." -f $aadds.Name, $aadds.properties.serviceStatus)
            }
            else
            {
                LogSuccess "[Pass!]"
                LogInfo ([String]::Empty)
                LogInfo ([String]::Empty)
                LogInfo "Please turn off all virtual machines joined to Azure AD Domain Services."
                LogInfo "You may turn on these virtual machines after you complete the migration."
                LogInfo ([String]::Empty)
                LogInfo "When ready to complete the migration, run 'Migrate-Aadds' using the '-Commit' parameter."
                LogInfo "To complete the command, you will need to have the name of your new Azure Resource Manager virtual network and subnet."
                LogInfo ([String]::Empty)
            }

            break
        }
        "Commit"
        {
            $vnet = $null
            $subnet = $null

            #
            # Virtual network resource group name must exist to proceed
            if($null -eq $VirtualNetworkResourceGroupName)
            {
                LogError "The virtual network resource group name cannot be blank or null."
                return
            }


            #
            # Virtual network is valid
            LogInfo "Validating virtual network..."
            if($null -eq $VirtualNetworkName)
            {
                LogError "[Failed!]"
                LogError ("Missing the name of the virtual network (VirtualNetwork:{0})." -f $VirtualNetworkName)
                return
            }
            else
            {
                #
                # Get the virtual network
                $vnet = Get-AzVirtualNetwork -Name  $VirtualNetworkName -ResourceGroupName $VirtualNetworkResourceGroupName -ErrorAction SilentlyContinue
                if($null -eq $vnet)
                {
                    LogError "[Failed!]"
                    LogError ("Could not find the virtual network (VirtualNetwork:{0})." -f $VirtualNetworkName)
                    return
                }
            }
            LogSuccess "[Pass!]"

            #
            # Virtual subnet is valid
            LogInfo "Validating virtual subnet..."
            if($null -eq $VirtualSubnetName)
            {
                LogError "[Failed!]"
                LogError ("Missing the name of the virtual subnet (VirtualSubnet:{0})." -f $VirtualSubnetName)
                return
            }
            else
            {
                #
                # Get the virtual subnet
                $subnet = Get-AzVirtualNetworkSubnetConfig -Name $VirtualSubnetName -VirtualNetwork $vnet -ErrorAction SilentlyContinue
                if($null -eq $subnet)
                {
                    LogError "[Failed!]"
                    LogError ("Could not find the virtual subnet (VirtualSubnet:{0}." -f $VirtualSubnetName)
                    return
                }

                if($null -eq $subnet.NetworkSecurityGroup)
                {
                    LogError "[Failed!]"
                    LogError ("Could not find any network security group attached to the subnet (VirtualSubnet:{0}." -f $VirtualSubnetName)
                    LogError ("IMPORTANT! Please ensure that the virtual network, that the managed domain will be migrated to, meets the requirements and then try again. (https://docs.microsoft.com/en-us/azure/active-directory-domain-services/migrate-from-classic-vnet#restrictions-on-available-virtual-networks).")

                    return
                }
            }
            LogSuccess "[Pass!]"

            #
            # Commit the move to the Azure AD Domain Services resource
            LogInfo ([String]::Empty)
            LogInfo -ForegroundColor Cyan "IMPORTANT! DO NOT convert your classic virtual network while this script runs."
            LogInfo -ForegroundColor Cyan "Perform that operation after the migration is complete."
            LogInfo ([String]::Empty)
            LogInfo -ForegroundColor Cyan "It is important you let the script complete"
            LogInfo -ForegroundColor Cyan "The migration may take up to three (3) hours. Please wait..."
            LogInfo ([String]::Empty)
            LogInfo -ForegroundColor Cyan "IMPORTANT! Once started, you cannot stop the migration process nor can you revert the process once the migration completes."
            LogInfo ([String]::Empty)
            LogWarning "IMPORTANT! Please review https://docs.microsoft.com/en-us/azure/active-directory-domain-services/migrate-from-classic-vnet carefully before you proceed with the migration. Please ensure that the virtual network, that the managed domain will be migrated to, meets the requirements (https://docs.microsoft.com/en-us/azure/active-directory-domain-services/migrate-from-classic-vnet#restrictions-on-available-virtual-networks)."
            $consent = Read-Host -Prompt ("Do you want to migrate {0} (Y/N)" -f $ManagedDomainFqdn)
            if("Y" -ne $consent)
            {
                LogWarning "[Canceled!] The user canceled the migration."
                return
            }
            #
            # run the command in the background
            $job = Set-AzResource -ResourceId $aadds.ResourceId -Properties @{"subnetId" = $subnet.Id} -ApiVersion 2017-06-01 -Force -AsJob
            LogInfo "Migration in progess. Progress refreshes every 2 minutes ..."

            LogInfo ([String]::Empty)
            LogProgress -currentOp "Starting..." -percentComplete 0

            do
            {
                Start-Sleep -Seconds 120

                $properties = (Get-AzResource -ResourceId $aadds.ResourceId -ApiVersion 2017-06-01).Properties

                $migrationProgress = $properties.MigrationProperties.MigrationProgress

                [int] $percentComplete = $migrationProgress.CompletionPercentage

                #
                # Precaution to ensure Write-Progress does not error
                if(101 -lt $percentComplete)
                {
                    $percentComplete = 100
                }

                LogProgress -currentOp ("{0}" -f $migrationProgress.ProgressMessage) -percentComplete $percentComplete

            } while ("PerformingMigration" -eq $properties.ServiceStatus)

            if("Completed" -ne $job.State)
            {
                LogInfo ([string]::Empty)
                LogError "Migration did not complete successfully."
                LogError ("{0}" -f $job.ChildJobs[0].JobStateInfo.Reason)
            }
            else
            {
                LogProgress -currentOp $null -percentComplete $percentComplete
                LogSuccess "[Migration Complete!]"
            }

            #
            # Validate the migration was successful
            LogInfo "Validating ..."

            # Waiting to give time to refresh the state of Azure AD Domain Services resource.
            Start-Sleep -Seconds 10

            $confirm = $null
            $confirm = GetAaddsResource -domainName $ManagedDomainFqdn
            if($null -eq $confirm)
            {
                LogWarning "[Undetermined!]"
                LogWarning "The script could not validate the Commit status."
                LogWarning (
                    "Please run {0} and check the serviceStatus value is 'Running'" -f "(Get-AzResource -Name $ManagedDomainFqdn -ExpandProperties -ApiVersion 2017-06-01).Properties")
                return
            }

            #
            # Check the properties for successful migration
            if($confirm.properties.serviceStatus -ne "Running")
            {
                LogError "[Failed!]"
                LogError ("The managed domain {0} did not migrate successfully (Status:{1}." -f $aadds.Name, $aadds.properties.serviceStatus)
            }
            else
            {
                LogSuccess "[Pass!]"
                LogInfo ([String]::Empty)
                LogInfo ([String]::Empty)
                LogInfo "Migration of the first domain controller for Azure AD Domain Services completed successfully."
                LogInfo ("Migration of the second domain controller is active and should complete at approximately {0}." -f ([System.DateTime]::Now.AddHours(1).ToString("G")))
                LogInfo ("After the second domain controller completes its migration, please update the DNS settings on the {0} virtual network." -f $VirtualNetworkName)
                LogInfo ([String]::Empty)
            }

            break
        }
        "Abort"
        {
            #
            # use the oldSubnetID property from the instance to rollback

            LogInfo "It is important you let the script complete"

            $oldSubnetId = $aadds.Properties.migrationProperties.oldSubnetID

            if($aadds.Properties.migrationProperties.oldSubnetID -inotmatch "/")
            {
                LogInfo "Old SubnetId is not in resource format. Value: $oldSubnetId... Converting to Resource format"

                #Get Vnet ResourceId
                $classicVnet = Get-AzResource -ResourceName $ClassicVirtualNetworkName -ResourceType "Microsoft.ClassicNetwork/virtualNetworks"
                $classicVnetResourceId = $classicVnet.ResourceId
                $oldSubnetName = $aadds.Properties.migrationProperties.oldSubnetID
                $oldSubnetId = $classicVnetResourceId + "/subnets/" + "$oldSubnetName"
            }

            LogInfo "Old SubnetId: $oldSubnetID"

            LogInfo "This process may take up to 30 minutes. Please wait..."

            LogInfo ([String]::Empty)
            $consent = Read-Host -Prompt ("Do you want to abort the migration for {0} (Y/N)" -f $ManagedDomainFqdn)
            if("Y" -ne $consent)
            {
                LogWarning "[Canceled!] The user canceled the migration."
                return
            }

            LogInfo "Processing your request... "

            (Set-AzResource -ResourceId $aadds.ResourceId -Properties @{"subnetId" = $oldSubnetId} -ApiVersion 2017-06-01 -Force) | Out-Null

            #
            # Validate
            LogInfo -Foreground Green "[Process Complete!]"
            LogInfo "Validating ..."

            $confirm = $null
            $confirm = GetAaddsResource -domainName $ManagedDomainFqdn
            if($null -eq $confirm)
            {
                LogWarning "[Undetermined!]"
                LogWarning "The script could not validate the abort status."
                LogWarning (
                    "Please run {0} and check the serviceStatus value is 'Running'" -f "(Get-AzResource -Name $ManagedDomainFqdn -ExpandProperties -ApiVersion 2017-06-01).Properties")
                return
            }

            #
            # Check the properties for successful migration
            if($confirm.properties.serviceStatus -ne "Running")
            {
                LogError "[Failed!]"
                LogError ("The managed domain {0} did not abort its preparation for migration (Status:{1}." -f $aadds.Name, $aadds.properties.serviceStatus)
            }
            else
            {
                LogSuccess "[Pass!]"
                LogInfo ([String]::Empty)
                LogInfo ([String]::Empty)
                LogInfo "This instance of Azure AD Domain Services has returned to its original classic virtual network."
                LogInfo ([String]::Empty)
            }

            break
        }
        default
        {
            LogError "Unknown Command."
        }
    }

    $actionStop = Get-Date

    LogInfo "Elapsed Time: " ($actionStop - $actionStart)

} # End Process

# SIG # Begin signature block
# MIInQQYJKoZIhvcNAQcCoIInMjCCJy4CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCKDy4Ig+bpCN2b
# HMjVhENBFXrnAfTCeBZyoxgYKmx0oaCCEWQwggh2MIIHXqADAgECAhM2AAABPo8Y
# 15iaQr91AAEAAAE+MA0GCSqGSIb3DQEBCwUAMEExEzARBgoJkiaJk/IsZAEZFgNH
# QkwxEzARBgoJkiaJk/IsZAEZFgNBTUUxFTATBgNVBAMTDEFNRSBDUyBDQSAwMTAe
# Fw0yMDEwMjEyMDQ1MDNaFw0yMTA5MTUyMTQzMDNaMC8xLTArBgNVBAMTJE1pY3Jv
# c29mdCBBenVyZSBEZXBlbmRlbmN5IENvZGUgU2lnbjCCASIwDQYJKoZIhvcNAQEB
# BQADggEPADCCAQoCggEBAOuMxWqhH5huRYgRPkfQi/xsXp7/AwFq50irQOfFtD/g
# AOqiSPRgh3gUZbgB47N8jgjdo6g7LRS7Bk3ru+B6gXB22COqx1QGhkd7PsaFLjgQ
# rIuhrNwcxQtFyHNlrxWhfNeLwbT1MAwuJRPRVEawGvA5QoSWmNh58jEfnauIzVic
# yee6OTocfJK86BHE6C0Yqmz4Ltt3QWds5P7sbmXCfAzcW7x4nB6v/YBeIi3LSqCX
# 5HaTEOYN469DleuQYRJffspVnLe2hbQRmuF2288DJzTb8DmjJLg3XyCVLxG/U8Jl
# xlz7cXPSpx6Pz/aRVwf849BsMYgcOvoT41ofzQYIfuECAwEAAaOCBXcwggVzMCkG
# CSsGAQQBgjcVCgQcMBowDAYKKwYBBAGCN1sDATAKBggrBgEFBQcDAzA8BgkrBgEE
# AYI3FQcELzAtBiUrBgEEAYI3FQiGkOMNhNW0eITxiz6Fm90Wzp0SgWDigi2HkK4D
# AgFkAgEOMIICdgYIKwYBBQUHAQEEggJoMIICZDBiBggrBgEFBQcwAoZWaHR0cDov
# L2NybC5taWNyb3NvZnQuY29tL3BraWluZnJhL0NlcnRzL0JZMlBLSUNTQ0EwMS5B
# TUUuR0JMX0FNRSUyMENTJTIwQ0ElMjAwMSgxKS5jcnQwUgYIKwYBBQUHMAKGRmh0
# dHA6Ly9jcmwxLmFtZS5nYmwvYWlhL0JZMlBLSUNTQ0EwMS5BTUUuR0JMX0FNRSUy
# MENTJTIwQ0ElMjAwMSgxKS5jcnQwUgYIKwYBBQUHMAKGRmh0dHA6Ly9jcmwyLmFt
# ZS5nYmwvYWlhL0JZMlBLSUNTQ0EwMS5BTUUuR0JMX0FNRSUyMENTJTIwQ0ElMjAw
# MSgxKS5jcnQwUgYIKwYBBQUHMAKGRmh0dHA6Ly9jcmwzLmFtZS5nYmwvYWlhL0JZ
# MlBLSUNTQ0EwMS5BTUUuR0JMX0FNRSUyMENTJTIwQ0ElMjAwMSgxKS5jcnQwUgYI
# KwYBBQUHMAKGRmh0dHA6Ly9jcmw0LmFtZS5nYmwvYWlhL0JZMlBLSUNTQ0EwMS5B
# TUUuR0JMX0FNRSUyMENTJTIwQ0ElMjAwMSgxKS5jcnQwga0GCCsGAQUFBzAChoGg
# bGRhcDovLy9DTj1BTUUlMjBDUyUyMENBJTIwMDEsQ049QUlBLENOPVB1YmxpYyUy
# MEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9
# QU1FLERDPUdCTD9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2VydGlm
# aWNhdGlvbkF1dGhvcml0eTAdBgNVHQ4EFgQUl8erpNJabA/HDBLpDNLGb41KUm0w
# DgYDVR0PAQH/BAQDAgeAMEUGA1UdEQQ+MDykOjA4MR4wHAYDVQQLExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xFjAUBgNVBAUTDTIzNjE2OSs0NjI1MjEwggHUBgNVHR8E
# ggHLMIIBxzCCAcOgggG/oIIBu4Y8aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3Br
# aWluZnJhL0NSTC9BTUUlMjBDUyUyMENBJTIwMDEuY3Jshi5odHRwOi8vY3JsMS5h
# bWUuZ2JsL2NybC9BTUUlMjBDUyUyMENBJTIwMDEuY3Jshi5odHRwOi8vY3JsMi5h
# bWUuZ2JsL2NybC9BTUUlMjBDUyUyMENBJTIwMDEuY3Jshi5odHRwOi8vY3JsMy5h
# bWUuZ2JsL2NybC9BTUUlMjBDUyUyMENBJTIwMDEuY3Jshi5odHRwOi8vY3JsNC5h
# bWUuZ2JsL2NybC9BTUUlMjBDUyUyMENBJTIwMDEuY3JshoG6bGRhcDovLy9DTj1B
# TUUlMjBDUyUyMENBJTIwMDEsQ049QlkyUEtJQ1NDQTAxLENOPUNEUCxDTj1QdWJs
# aWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9u
# LERDPUFNRSxEQz1HQkw/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29i
# amVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MB8GA1UdIwQYMBaAFBtmohn8
# m+ul2oSPGJjpEKTDe5K9MB8GA1UdJQQYMBYGCisGAQQBgjdbAwEGCCsGAQUFBwMD
# MA0GCSqGSIb3DQEBCwUAA4IBAQDN+Sk5GxW5sqzIJKyksqy1jF7c7Gz4dJSCSfLe
# LnIAhBhmFfzbxEWlglWNeW/QHk9njk5U3MbXqCwylo7uuEJZXHm5mdOCAnbiHf//
# WoXIxiR6W8TfVjGLVluGBcSsDlBIAzbZLUbediCkcSKzgEQ8Q9IRCK5jtLh0aHyT
# noD0S+/giAMKAhxoBvpQaNxe6IfZJYeYW6KpXp8tyxlPNGn6rgcTfruRnKKkrlbg
# ynyAV4m+Zhv4Q+556M+pTC+sTBfERzQl136axMXY96TxTNPhsQt1qiCMFoTv1Aow
# KaG/NsaXj1ii3ImYwaaizCfuFpjMe0kJOnejNZzw/QgBn0FgMIII5jCCBs6gAwIB
# AgITHwAAABS0xR/G8oC+cQAAAAAAFDANBgkqhkiG9w0BAQsFADA8MRMwEQYKCZIm
# iZPyLGQBGRYDR0JMMRMwEQYKCZImiZPyLGQBGRYDQU1FMRAwDgYDVQQDEwdhbWVy
# b290MB4XDTE2MDkxNTIxMzMwM1oXDTIxMDkxNTIxNDMwM1owQTETMBEGCgmSJomT
# 8ixkARkWA0dCTDETMBEGCgmSJomT8ixkARkWA0FNRTEVMBMGA1UEAxMMQU1FIENT
# IENBIDAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1VeBAtb5+tD3
# G4C53TfNJNxmYfzhiXKtKQzSGxuav660bTS1VEeDDjSnFhsmnlb6GkPCeYmCJwWg
# ZGs+3oWJ8yad3//VoP99bXG8azzTJmT2PFM1yKxUXUJgi7I9y3C4ll/ATfBwbGGR
# XD+2PdkdlVpxKWzeNEPVwbCtxWjUhHr6Ecy9R6O23j+2/RSZSgfzYctDzDWhNf0P
# vGPflm31PSk4+ozca337/Ozu0+naDKg5i/zFHhfSJZkq5dPPG6C8wDrdiwHh6G5I
# GrMd2QXnmvEfjtpPqE+G8MeWbszaWxlxEjQJQC6PBwn+8Qt4Vqlc0am3Z3fBw8kz
# RunOs8Mn/wIDAQABo4IE2jCCBNYwEAYJKwYBBAGCNxUBBAMCAQEwIwYJKwYBBAGC
# NxUCBBYEFJH8M85CnvaT5uJ9VNcIGLu413FlMB0GA1UdDgQWBBQbZqIZ/JvrpdqE
# jxiY6RCkw3uSvTCCAQQGA1UdJQSB/DCB+QYHKwYBBQIDBQYIKwYBBQUHAwEGCCsG
# AQUFBwMCBgorBgEEAYI3FAIBBgkrBgEEAYI3FQYGCisGAQQBgjcKAwwGCSsGAQQB
# gjcVBgYIKwYBBQUHAwkGCCsGAQUFCAICBgorBgEEAYI3QAEBBgsrBgEEAYI3CgME
# AQYKKwYBBAGCNwoDBAYJKwYBBAGCNxUFBgorBgEEAYI3FAICBgorBgEEAYI3FAID
# BggrBgEFBQcDAwYKKwYBBAGCN1sBAQYKKwYBBAGCN1sCAQYKKwYBBAGCN1sDAQYK
# KwYBBAGCN1sFAQYKKwYBBAGCN1sEAQYKKwYBBAGCN1sEAjAZBgkrBgEEAYI3FAIE
# DB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAf
# BgNVHSMEGDAWgBQpXlFeZK40ueusnA2njHUB0QkLKDCCAWgGA1UdHwSCAV8wggFb
# MIIBV6CCAVOgggFPhiNodHRwOi8vY3JsMS5hbWUuZ2JsL2NybC9hbWVyb290LmNy
# bIYxaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraWluZnJhL2NybC9hbWVyb290
# LmNybIYjaHR0cDovL2NybDIuYW1lLmdibC9jcmwvYW1lcm9vdC5jcmyGI2h0dHA6
# Ly9jcmwzLmFtZS5nYmwvY3JsL2FtZXJvb3QuY3JshoGqbGRhcDovLy9DTj1hbWVy
# b290LENOPUFNRVJPT1QsQ049Q0RQLENOPVB1YmxpYyUyMEtleSUyMFNlcnZpY2Vz
# LENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9QU1FLERDPUdCTD9jZXJ0
# aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJp
# YnV0aW9uUG9pbnQwggGrBggrBgEFBQcBAQSCAZ0wggGZMDcGCCsGAQUFBzAChito
# dHRwOi8vY3JsMS5hbWUuZ2JsL2FpYS9BTUVST09UX2FtZXJvb3QuY3J0MEcGCCsG
# AQUFBzAChjtodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpaW5mcmEvY2VydHMv
# QU1FUk9PVF9hbWVyb290LmNydDA3BggrBgEFBQcwAoYraHR0cDovL2NybDIuYW1l
# LmdibC9haWEvQU1FUk9PVF9hbWVyb290LmNydDA3BggrBgEFBQcwAoYraHR0cDov
# L2NybDMuYW1lLmdibC9haWEvQU1FUk9PVF9hbWVyb290LmNydDCBogYIKwYBBQUH
# MAKGgZVsZGFwOi8vL0NOPWFtZXJvb3QsQ049QUlBLENOPVB1YmxpYyUyMEtleSUy
# MFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9QU1FLERD
# PUdCTD9jQUNlcnRpZmljYXRlP2Jhc2U/b2JqZWN0Q2xhc3M9Y2VydGlmaWNhdGlv
# bkF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAKLdKhpqPH6QBaM3CAOqQi8oA
# 4WQeZLW3QOXNmWm7UA018DQEa1yTqEQbuD5OlR1Wu/F289DmXNTdsZM4GTKEaZeh
# IiVaMoLvEJtu5h6CTyfWqPetNyOJqR1sGqod0Xwn5/G/zcTYSxn5K3N8KdlcDrZA
# Iyfq3yaEJYHGnA9eJ/f1RrfbJgeo/RAhICctOONwfpsBXcgiTuTmlD/k0DqogvzJ
# gPq9GOkIyX/dxk7IkPzX/n484s0zHR4IKU58U3G1oPSQmZ5OHAvgHaEASkdN5E20
# HyJv5zN7du+QY08fI+VIci6pagLfXHYaTX3ZJ/MUM9XU+oU5y4qMLzTj1JIG0LVf
# uHK8yoB7h2inyTe7bn6h2G8NxZ02aKZ0xa+n/JnoXKNsaVPG1SoTuItMsXV5pQtI
# ShsBqnXqFjY3bJMlMhIofMcjiuOwRCW+prZ+PoYvE2P+ML7gs3L65GZ9BdKF3fSW
# 3TvmpOujPQ23rzSle9WGxFJ02fNbaF9C7bG44uDzMoZU4P+uvQaB7KE4OMqAvYYf
# Fy1tv1dpVIN/qhx0H/9oNiOJpuZZ39ZibLt9DXbsq5qwyHmdJXaisxwB53wJshUj
# c1i76xqFPUNGb8EZQ3aFKl2w9B47vfBi+nU3sN0tpnLPtew4LHWq4LBD5uiNZVBO
# YosZ6BKhSlk1+Y/0y1IxghUzMIIVLwIBATBYMEExEzARBgoJkiaJk/IsZAEZFgNH
# QkwxEzARBgoJkiaJk/IsZAEZFgNBTUUxFTATBgNVBAMTDEFNRSBDUyBDQSAwMQIT
# NgAAAT6PGNeYmkK/dQABAAABPjANBglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0B
# CQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAv
# BgkqhkiG9w0BCQQxIgQg9YdCpXKmgwYPBe5YExu8Dq/JrnwU+es219+n4PNJ33Aw
# QgYKKwYBBAGCNwIBDDE0MDKgFIASAE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6
# Ly93d3cubWljcm9zb2Z0LmNvbTANBgkqhkiG9w0BAQEFAASCAQAu+gh0a30qEQ0a
# 44vUdAAmG5NN3Eshi9Jyh/6tKdzzai5Z6B1PS601RQvoO0UKaFADr6WMim5o8hi4
# W9dBEsspyQEz/wv/YSS7GQY8y27JScg4DSxCOYtj7wfxXwIaWHFn8gYMnWYDXQE9
# AJr8b/WQidao+hsIGXahPx0j46rmvjBtym8Arbv8A0R3lYwlVvgGlfd1Kx7IWS2w
# v0OZIhAiLVMBbHmMLB8bhnJb6QihQ2e/4xCW/VkT/yUdrOhFd0dlYKru2LaqFgfQ
# m8HqPyNO+nI9xpcxmUf0diNle6Z2Cq2cTfBJeh/j0bdS+AuADu6BfoKHsgBrKrwE
# vYUgUfNOoYIS+zCCEvcGCisGAQQBgjcDAwExghLnMIIS4wYJKoZIhvcNAQcCoIIS
# 1DCCEtACAQMxDzANBglghkgBZQMEAgEFADCCAVkGCyqGSIb3DQEJEAEEoIIBSASC
# AUQwggFAAgEBBgorBgEEAYRZCgMBMDEwDQYJYIZIAWUDBAIBBQAEIH0zo6NIQhrL
# NbSXq8J2FZO6LqXOhnBjv/B6aCW9E9b0AgZg92xRMMAYEzIwMjEwODAyMDQxNTEx
# LjU1N1owBIACAfSggdikgdUwgdIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMg
# TGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046MkFENC00QjkyLUZBMDEx
# JTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wggg5KMIIE+TCC
# A+GgAwIBAgITMwAAATjzlCHWYb7wKQAAAAABODANBgkqhkiG9w0BAQsFADB8MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy
# b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yMDEwMTUxNzI4MjBaFw0yMjAx
# MTIxNzI4MjBaMIHSMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQ
# MA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u
# MS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQx
# JjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjJBRDQtNEI5Mi1GQTAxMSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIBIjANBgkqhkiG9w0BAQEF
# AAOCAQ8AMIIBCgKCAQEAxbn4p6lecIMyAgKjbK7+A/vdqY+y1pmgXIjOwXGvDAjy
# 7aKPsp978FH+VPHh+3Yk9tc0ET3554bbS7TrObejbAH8bQ3UMqT7sU79nkALxKqy
# kp2lYfI/ZvrDVBecswbz1v/9CZcTdrSailbNDIg1lTfSA0LDhebTt02J+R5eCZrh
# fXedCWJP1kt1jy0E5wJUryqYOhXsrgewGdQsdH2bvp5JfRip+vg8rwVAJ78RHbbT
# 5xTof+oFLOCAgmJG0e2yC7PAItErKPMWjM86pkVKR6atoVKuA5oG4d4NWktiUzKT
# 2bynwlVkx74uu6rF7U+56udCwwk2mnNjD+OXDhyPGQIDAQABo4IBGzCCARcwHQYD
# VR0OBBYEFN/qrdzo76xTsTL7OYjFYMGeccC1MB8GA1UdIwQYMBaAFNVjOlyKMZDz
# Q3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9z
# b2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0YVBDQV8yMDEwLTA3LTAx
# LmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENBXzIwMTAtMDctMDEuY3J0
# MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZIhvcNAQEL
# BQADggEBAKN4sEhcC7G/DRKQy9LIto5OI5VZUgS3SBFZrNHsr/ZzR5MsaiY3eVxm
# 9zZmbg+m4utdCi8FcUdPScD6r8FotfHO3dF/I6rjXej/sGbNv7h8HsBPWmL3Se+m
# Z+//IQrFi5rktqxs6LSkCPirmMhYZ6hUfJgN4PgtkG/mwqSqF04f74G8A2JHwhDz
# sLBi4MYBZDT4KLJ9KAOgWZAmS4O3MAYxzsfbsN0WsjMgDMq8B2XqQNzILESwkAPR
# JKWXfX73C6IJS5MHWarGIj+BygDs5p6M28w53sXPWAKNAqt7ZGBaspG+k/t3xfWA
# m8eD4CnvEKSVM8Vffr2HwG+CUgACppowggZxMIIEWaADAgECAgphCYEqAAAAAAAC
# MA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu
# Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
# cmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRo
# b3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3MDEyMTQ2NTVaMHwxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jv
# c29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
# MIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWlCgCChfvtfGhLLF/Fw+Vh
# wna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/FgiIRUQwzXTbg4CLNC3ZOs
# 1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeRX4FUsc+TTJLBxKZd0WET
# bijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/XcfPfBXday9ikJNQFHRD5wG
# Pmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogINeh4HLDpmc085y9Euqf0
# 3GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB5jCCAeIwEAYJKwYBBAGC
# NxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvFM2hahW1VMBkGCSsGAQQB
# gjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/
# MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJ
# oEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01p
# Y1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYB
# BQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9v
# Q2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8EgZUwgZIwgY8GCSsGAQQB
# gjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL1BL
# SS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcCAjA0HjIgHQBMAGUAZwBh
# AGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUAbgB0AC4gHTANBgkqhkiG
# 9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Prpsz1Mb7PBeKp/vpXbRkw
# s8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOMzPRgEop2zEBAQZvcXBf/
# XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCvOA8X9S95gWXZqbVr5MfO
# 9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v/rbljjO7Yl+a21dA6fHO
# mWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99lmqQeKZt0uGc+R38ONiU
# 9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1klD3ouOVd2onGqBooPiRa6
# YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQHm+98eEA3+cxB6STOvdl
# R3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30uIUBHoD7G4kqVDmyW9rI
# DVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp25ayp0Kiyc8ZQU3ghvkq
# mqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HSxVXjad5XwdHeMMD9zOZN
# +w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi62jbb01+P3nSISRKhggLU
# MIICPQIBATCCAQChgdikgdUwgdIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMg
# TGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046MkFENC00QjkyLUZBMDEx
# JTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoBATAHBgUr
# DgMCGgMVAEC86zs20AKnzakuISFLJspZ5oH5oIGDMIGApH4wfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEFBQACBQDksbxGMCIYDzIwMjEw
# ODAyMDgzNTE4WhgPMjAyMTA4MDMwODM1MThaMHQwOgYKKwYBBAGEWQoEATEsMCow
# CgIFAOSxvEYCAQAwBwIBAAICGgEwBwIBAAICEWAwCgIFAOSzDcYCAQAwNgYKKwYB
# BAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGG
# oDANBgkqhkiG9w0BAQUFAAOBgQB1gfbWYNWwAj04UPN+vwWtlHML5jkty+QnW4se
# d42UnemtRWsmcHASnqGD9LEhDnygG+lDCrR0Rc4mNLWqW8FLVZFriAn667R2c3Hm
# GerNsWuyFUHms8q8ZxR/QBG2ryV8YAfkY1flFEbLWVR2AeTEefHwV52bR6xQducf
# /7BgjTGCAw0wggMJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
# AhMzAAABOPOUIdZhvvApAAAAAAE4MA0GCWCGSAFlAwQCAQUAoIIBSjAaBgkqhkiG
# 9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIP4XZkJKBZ0106A2
# vdaY7Cmf9djXOqEmEWt9nBIzSCaGMIH6BgsqhkiG9w0BCRACLzGB6jCB5zCB5DCB
# vQQgQ0CTSvl/RCqSSGLiLKbu7sbS3mjmCOpO+ith7RaPhygwgZgwgYCkfjB8MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy
# b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAATjzlCHWYb7wKQAAAAABODAi
# BCC6Lu/jh5lhcTBQNzMWvHQ/l1WE3P2kjZNPZcepm/iGgzANBgkqhkiG9w0BAQsF
# AASCAQB3sA15N7KSNWBF+XOH1yhM78hJ7uLzG8AjIQg07priRcsQ20jaGm1mkeZe
# XQ8Wbp53lpVKPIxjB3z6udz5+5hLhoxuKMmafgwFvoiwK33X8VC8DtvnwBYMofQe
# n9LiFh5x/nrGMNBpggTy3w5Smy17S5nQ1C2ct71GbRQjbEcKSfJxEPdBf4pTrkgu
# VUUeiwnU4PXOR3LyyKXD4GiRM+7wzKN3doLyKi3Sg7OChiZzaTpKUI25Q7JNZ/Vw
# rqxyot0Mq4+pWZ+NaSs/0lpBqq+OdJ7dWKs537uybduyD4QgfgtPtfskGixnS9RR
# +iwz1iUFHKtp2BO2wCCRkpbpslZO
# SIG # End signature block