Most documentation available around uploading Windows machines to Azure only talks about the officially supported method that consists of the following steps:

  • Run a sysprep on premises
    • OOBE
    • Generalize
    • Shut Down
  • Upload the VHD
  • Run an image deployment from the VHD

Find out more: https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-windows-classic-createupload-vhd/

Customers often ask me about the option to lift and shift Windows workloads without a sysprep. This is possible, but does not usually get specifically advertised, because it can lead to all sorts of issues, if it is not done correctly.

If it runs in Hyper-V it runs on Azure, right?

The answer to this question is “kind of”. Most generation 1 VMs will work after a lift and shift, but other factors need to be considered.

What about generation 2 Hyper-V machines?

Because of the different bootloader Azure IaaS will not support them by default. The easiest way to lift and shift a generation 2 Hyper-V VM is via Azure Recovery Vault. When failing over into Azure from ASR the machine is converted into a generation 1 machine. Alternatively this conversion can be done manually on the user’s premises.

What about dynamic disks?

These are not supported. Before the upload the VMs disk(s) should be converted to VHDs with static file sizes. (up to 1 TB)

Can I upload a VMWare machine?

Absolutely. Its disks need to be converted to the VHD format first however. I would advise to test the disks in Hyper-V, to ensure they work, before doing a lenghtly upload to Azure.

Should I make any changes on the machine, before starting the upload?

  • Make sure RDP is enabled and that the security policy for RDP is not too restrictive
  • Install the Azure Agent (this will allow you to install script extensions, enable diagnostics, and use other Azure platform features
  • Shut the machine down

You can download the agent from within your VM by going to this link: http://go.microsoft.com/fwlink/p/?LinkId=394789

Example Script: VHD Upload

# for RDFE deployment
Add-AzureAccount
Add-AzureVHD -Destination "<RDFEStorageAccountURL>/<Container>/<VHDName>.vhd" -LocalFilePath "<VHDPath>.vhd"

# for ARM deployment
Login-AzureRmAccount
Add-AzureRmVhd -Destination "<ARMStorageAccountURL>/<Container>/<VHDName>.vhd" -LocalFilePath "<VHDPath>.vhd"

Example Script: Creating a classic VM from VHD

Add-AzureAccount
Select-AzureSubscription -SubscriptionId 0000-0000-0000-0000-0000

Add-AzureDisk -OS "Windows" -DiskName "migratedDisk" -MediaLocation "https://storage.blob.core.windows.net/vhds/VHDLocation.vhd" -Label "migratedDisk"
$migratedVM = New-AzureVMConfig -Name "MachineName" -InstanceSize "MachineSize" -DiskName "migratedDisk"
New-AzureVM -ServiceName "CloudServiceName" -Location "Location" -VMs $migratedVM

Example Script: Creating an ARM VM from VHD

Login-AzureRmAccount
Select-AzureRmSubscription -SubscriptionId 0000-0000-0000-0000-0000

# create a new NIC for the machine in the VNet that you want it to join
# the NIC holds information about public IP, DNS, subnet, etc.
# if you do not add a NIC to the VM you will not be able to connect to it
# NICs are easily created through the portal
$nic = Get-AzureRmNetworkInterface -ResourceGroupName "ResourceGroup" -Name "NICName"

$migratedVM = New-AzureRmVMConfig -VMName "MachineName" -VMSize "MachineSize"
$migratedVM = Add-AzureRmVMNetworkInterface -VM $migratedVM -Id $nic.Id

$osDiskUri = "https://storage.blob.core.windows.net/vhds/VHDLocation.vhd"

$migratedVM = Set-AzureRmVMOSDisk -VM $migratedVM -Name "migratedDisk" -VhdUri $osDiskUri -CreateOption attach -Windows
New-AzureRMVM -ResourceGroupName "ResourceGroup" -VM $migratedVM -Verbose -Debug