- EC2 Image Builder: Build your golden VM images on AWS - Wed, Jan 19 2022
- Configuring DFS Namespaces for Amazon FSx for Windows file servers - Fri, Jan 7 2022
- AWS Systems Manager Session Manager: Securely connect EC2 instances - Wed, Dec 22 2021
- Prerequisites
- Install the AzureRM PowerShell module
- Signing in to Azure
- Specify the resource group
- Specify the path to the Disk2VHD tool
- Download the Disk2VHD tool
- Extract the Disk2VHD tool
- Specify the path to the converted disks
- Specify the drives
- Start the conversion
- Specify the storage account
- Create a storage container
- Upload the VHD
- Create the OS disk
- Specify the virtual network and subnet
- Create a network security group (NSG)
- Create a network interface card (NIC)
- Select the VM size
- Create the VM on Azure
- Troubleshooting
- Summary
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
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.
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
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
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 }
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 }
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'
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.