No official way exists to migrate virtual machines (VMs) from Amazon Web Services (AWS) to Azure. However, with the help of the Disk2VHD tool, you can convert the VM to a virtual hard disk (VHD) and then upload the VHD to Azure Storage. After uploading it, you can create a VM from the VHD. In this post, I show you how to automate this task using PowerShell.

Prerequisites ^

First, you need to meet the following prerequisites:

  • Turn off IE Enhanced Security Configuration. You can do so by navigating to Server Manager > Local Server > IE Enhanced Security Configuration and selecting Off.
  • If you're running an earlier Windows Server version than Windows Server 2012 R2, set the PowerShell execution policy to Remote Signed. You can do so by running the following PowerShell cmdlet: Set-ExecutionPolicy RemoteSigned.
  • Make sure the VM has internet access.

Install the AzureRM PowerShell module ^

At the beginning, the script will install the Azure Resource Manager (AzureRM) PowerShell module so it can use all the Azure-related cmdlets.

Install-PackageProvider -Name NuGet -Force
Install-Module AzureRM –Force
Installing the AzureRM PowerShell module

Installing the AzureRM PowerShell module

Signing in to Azure ^

After that, you need to log in to your Azure subscription by running the following cmdlet:

Login-AzureRmAccount

It will prompt you to enter the subscription credentials as shown in the following figure.

Signing in Azure

Signing in Azure

Specify the resource group ^

It will then ask you to enter the name of the resource group to migrate your resources to. It will use the resource group name to store all properties of the resource group named $RG so it can retrieve the Resource Group Name and Location later.

$RGName = Read-Host "Please Enter the resource group name"
$RG = Get-AzureRmResourceGroup -Name $RGName

Specify the path to the Disk2VHD tool ^

Since we will be using the Disk2VHD tool, we need to download it, but we have to make sure there is a directory where we will store the tool. The following commands will ask you to specify a path in which to store the Disk2VHD tool. If the folder does not exist, the commands will create the folder.

$Path = Read-Host "Please Enter a Path to Download Disk2VHD to"
if (!(Test-Path -path $Path))
 {
 New-Item $Path -type directory
 Write-Host "A New Directory with the following path has been created`
  $path" -ForegroundColor Green
 }

Download the Disk2VHD tool ^

Once you specify the path, the script will download the tool with these commands:

$object = New-Object Net.WebClient
$Disk2VHDURL = 'https://download.sysinternals.com/files/Disk2vhd.zip'
$object.DownloadFile($Disk2VHDURL, "$Path\Disk2vhd.zip")

Extract the Disk2VHD tool ^

Next, we have to extract the tool:

Add-Type -AssemblyName System.IO.Compression.FileSystem
function Unzip
{
    param([string]$zipfile, [string]$outpath)

    [System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath)
}

Unzip "$Path\Disk2vhd.zip" $Path
Write-Host "Disk2VHD has been unzipped" -ForegroundColor Green
cd $Path

Specify the path to the converted disks ^

After extracting the tool, the script will ask you to specify the path in which to store the VHD after conversion.

$VHDPath = Read-Host " Please enter the path in which to store the VHD file converted from the VM."
if (!(Test-Path -path "$VHDPath"))
 {
 New-Item "$VHDPath" -type directory
 Write-Host "The following new path will store the converted VMs"
 $VHDPath" -ForegroundColor Green
 }

Specify the drives ^

You might have drives you want to include and others you do not, so after running the following command, you can specify the drives in the format C: D: E: and so on, as shown in the following figure.

$Drives = Read-Host " Please specify the drives to convert in the format C: D: E: and so on."

Start the conversion ^

After specifying the drives, you can start conversion by running the following command:

$cmd  = @"
"$ScriptDir.\disk2vhd.exe" $Drives $VHDPath\$env:computername.vhd /accepteula
"@
& cmd.exe /c $cmd
Converting the disks to a VHD

Converting the disks to a VHD

Specify the storage account ^

You will need a storage account to upload the VHD to, so the following script block will prompt you to specify whether you have a storage account. If you have one, it will ask you to enter the name of the storage account. If not, it will ask you to enter a name for the storage account. It will then go through a loop to make sure it meets Azure storage account requirements. Then it will prompt you to select the stock keeping unit (SKU) of the storage account. Finally, the script will create the storage account.

$a = new-object -comobject wscript.shell
$SAAnswer = $a.popup("Do you have a storage account to upload the VM to?",0,"Storage Account Existence",4)
If ($SAAnswer -ne 6) 
        {
            Do {
                $SAName = Read-Host "The name must meet these conditions: `
                                     1- Unique across all the storage account names in Azure`
                                     2- 3 to 24 characters long`
                                     3- Only contains lower case characters and numbers`
                                     "
                $SAAvail = (Get-AzureRmStorageAccountNameAvailability -Name $SAName).NameAvailable
                }
            Until ($SAAvail -eq "True")
                
                $Menu = [ordered]@{
                    1 = 'Premium_LRS'
                    2 = 'Standard_GRS'
                    3 = 'Standard_LRS'
                    4 = 'Standard_RAGRS'
                    5 = 'Standard_ZRS'
                }

                $Result = $Menu | Out-GridView -PassThru  -Title 'Select the Storage SKU'

                Switch ($Result)  {

                {$Result.Name -eq 1} {'Premium_LRS'}
                {$Result.Name -eq 2} {'Standard_GRS'}
                {$Result.Name -eq 3} {'Standard_LRS'}
                {$Result.Name -eq 3} {'Standard_RAGRS'}
                {$Result.Name -eq 3} {'Standard_ZRS'}      
                                   }
            $SA = New-AzureRmStorageAccount -ResourceGroupName $RG.ResourceGroupName -Name $SAName -SkuName $Result.Value -Location $RG.Location
            Write-Host "A new Storage Account named $SAName has been created" -ForegroundColor Green
        }

ElseIf ($SAAnswer -eq 6)
        {
                $SAName = Read-Host "Please Enter the Storage Account Name"
                $SA = Get-AzureRmStorageAccount -Name $SAName -ResourceGroupName $RG.ResourceGroupName
Specify whether you have a storage account

Specify whether you have a storage account

Specify the storage account SKU

Specify the storage account SKU

Create a storage container ^

In the storage account, you must create a container to upload the VHD to. For this, you have to retrieve the storage account key and the context to use it in to create the container. The following commands show this:

$SAKey = (Get-AzureRmStorageAccountKey -ResourceGroupName $RG.ResourceGroupName  Name $SA.StorageAccountName) | ? {$_.KeyName -eq "key1"}
$StorageContext = New-AzureStorageContext -StorageAccountName $SAName  StorageAccountKey $SAKey.Value
$ContainerName = "migartedvhds"
$ContainerName = New-AzureStorageContainer -Name $ContainerName -Permission Blob  Context $StorageContext

Upload the VHD ^

By specifying the URL and local path to the image, you can start the upload. It will first calculate the MD5 hash to make sure after uploading that it is the same VHD on Azure as on the VM to avoid any undesired intervention. Then the upload starts as shown in the following figure.

$urlOfUploadedImageVhd = ('https://' + $Sa.StorageAccountName + '.blob.core.windows.net/' + $ContainerName.Name + '/' + $env:computername)
$localpath = "$VHDPath\$env:computername.vhd"
Add-AzureRmVhd -ResourceGroupName $RG.ResourceGroupName -Destination $urlOfUploadedImageVhd -LocalFilePath $localpath

Create the OS disk ^

After that, the script will create an OS disk named after the VM:

$osDiskName = $env:computername
$osDisk = New-AzureRmDisk -DiskName $osDiskName -Disk (New-AzureRmDiskConfig  AccountType $Result.Value `
    -Location $RG.Location -CreateOption Import -SourceUri $urlOfUploadedImageVhd)  ResourceGroupName $RG.ResourceGroupName

Specify the virtual network and subnet ^

The following command block will ask you to specify whether you have a virtual network and subnet. If so, it will ask you to enter their names. If not, it will ask you to enter a name and address prefix for the subnet and virtual network as shown in the following figure.

$SubAnswer = $a.popup("Do you have a Virtual Network and a Subnet to assign the VM to?",0,"Networking",4)
If ($SubAnswer -ne 6) 
        {
            $subnetName = Read-Host "Please enter a name for the subnet"
            $SubAddressPrefix = Read-Host "Please enter an address prefix for the subnet"
            $Subnet = New-AzureRmVirtualNetworkSubnetConfig -Name $subnetName -AddressPrefix $SubAddressPrefix
            Write-Host "The $subnetName subnet has been created" -ForegroundColor Green
            $vnetName = Read-Host "Please enter a name for the virtual network"
            $vnetPrefix = Read-Host "Please enter an address prefix for the virtual network"
            $vnet = New-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $RG.ResourceGroupName -Location $RG.Location `
                    -AddressPrefix $vnetPrefix -Subnet $Subnet
            $Subnet = Get-AzureRmVirtualNetworkSubnetConfig -Name $subnetName -VirtualNetwork $VNet
            Write-Host "The $vnetName Virtual Network has been created" -ForegroundColor Green
            
        }
ElseIf ($SubAnswer -eq 6)
        {
            $vnetName = Read-Host "Please enter a name for the virtual network"
            $subnetName = Read-Host "Please enter a name of the subnet"
            $VNet = Get-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $RG.ResourceGroupName        
            $Subnet = Get-AzureRmVirtualNetworkSubnetConfig -Name $subnetName -VirtualNetwork $VNet
        }
Entering the subnet and virtual network name and address prefix

Entering the subnet and virtual network name and address prefix

Create a network security group (NSG) ^

If you want to connect to the VM via Remote Desktop Protocol (RDP), you need to create an NSG that allows RDP:

$nsgName = "NSG"
$rdpRule = New-AzureRmNetworkSecurityRuleConfig -Name RDPRule -Description "Allow RDP" -Access Allow -Protocol Tcp -Direction Inbound -Priority 110 `
    -SourceAddressPrefix Internet -SourcePortRange * -DestinationAddressPrefix *  DestinationPortRange 3389

$nsg = New-AzureRmNetworkSecurityGroup -ResourceGroupName $RG.ResourceGroupName  Location $RG.Location `
   -Name $nsgName -SecurityRules $rdpRule

Create a network interface card (NIC) ^

You'll also need a NIC with a public IP address for the NSG created earlier:

$ipName = "PIP"
$pip = New-AzureRmPublicIpAddress -Name $ipName -ResourceGroupName $RG.ResourceGroupName -Location $RG.Location `
       -AllocationMethod Static

$nicName = "NIC"
$nic = New-AzureRmNetworkInterface -Name $nicName -ResourceGroupName $RG.ResourceGroupName -Location $RG.Location -SubnetId $Subnet.Id `
   -PublicIpAddressId $pip.Id -NetworkSecurityGroupId $nsg.Id

Select the VM size ^

As you know, Azure VMs are available in different sizes. So once you run the following script block, a form will pop up with a list of Azure VM sizes:

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$form = New-Object System.Windows.Forms.Form
$form.Text = 'Select a VM Size'
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'

$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Point(10,135)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = 'OK'
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)

$VMSize = New-Object System.Windows.Forms.Label   
    $VMSize.Text = "Azure VM Sizes:"; $VMSize.Top = 50; $VMSize.Left = 5; $VMSize.Autosize = $true  
    $form.Controls.Add($VMSize)  
    Write-Host "Building List of available Sizes" -ForegroundColor Green
    
    $VMSizeLB = New-Object System.Windows.Forms.ListBox  
        $VMSizeLB.Top = 50; $VMSizeLB.Left = 160; $VMSizeLB.Height = 120 
        $VMSizeLB.TabIndex = 1 
        
        $SizeArr = Get-AzureRmVMSize -Location $RG.Location 
        $i=0    
        foreach ($element in $SizeArr) { 
            [void] $VMSizeLB.Items.Add($element.Name) 
            $i ++ 
        } 
         
        $form.Controls.Add($VMSizeLB) #Add listbox to form 
        


$form.Topmost = $true

$VSResult = $form.ShowDialog()

if ($VSResult -eq [System.Windows.Forms.DialogResult]::OK)
{
    $x = $VMSizeLB.SelectedItem
    $x
}
Select the VM size

Select the VM size

Create the VM on Azure ^

Finally, the following commands create the VM:

$vmConfig = New-AzureRmVMConfig -VMName $env:computername -VMSize $x
$vmName = "$env:computername"
$vm = Add-AzureRmVMNetworkInterface -VM $vmConfig -Id $nic.Id
$vm = Set-AzureRmVMOSDisk -VM $vm -ManagedDiskId $osDisk.Id -StorageAccountType $Result.Value `
    -DiskSizeInGB 128 -CreateOption Attach -Windows
Write-Host "Creating the VM..." -ForegroundColor Green
New-AzureRmVM -ResourceGroupName $RG.ResourceGroupName -Location $RG.Location -VM $vm

Troubleshooting ^

After creating the VM, PowerShell will not be able to know its state because there is no VM agent installed. It will thus generate an error:

New-AzureRmVM : Long running operation failed with status 'Failed'

Error due to the VM agent

Error due to the VM agent

However, this means the script created the VM successfully. You now need to log in to the VM using the old credentials you used on AWS. You can then install the VM agent, which you can download here.

You can download the script from Github or Technet Gallery.

Summary ^

Migrating from AWS to Azure is a very challenging task. The script discussed in this post will help automate the task. However, I highly recommend using it only in production after testing it thoroughly.

If you want to migrate your VMs from Azure to AWS, you can read Adam Bertram's article.

0 Comments

Leave a reply

Your email address will not be published.

*

© 4sysops 2006 - 2022

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account