Upload Custom Windows Hyper-V Image for Gen 2 VM in Azure
Published Sep 14 2020 12:00 AM 11.3K Views



This is Andrew Coughlin and I am a Customer Engineer at Microsoft focusing on Azure IaaS. In this blog I will focus on how to upload a custom windows Hyper-V image for generation 2 virtual machines in Azure. Support for generation 2 virtual machines in Azure was released on November 4, 2019, these systems use UEFI boot, SCSI, supported on VMs that support premium storage compared to generation 1 which use PCAT boot, IDE and are available on all VM sizes.  Generation 2 VMs provide for OS disk size greater than 2TB in size and build larger VMs, up to 12TBs. To get additional information about generation 2 virtual machines in Azure please visit this post.


If you have ever uploaded a custom image in Azure in the past you will notice the process is very similar.



  • Review the Support for generation 2 VMs on Azure.
  • Install Azure PowerShell as documented here.
  • Create Hyper-V Gen 2 machine to be used as the image.
  • Prepare your Windows Hyper-V image is documented here.
  • Convert VHDX to VHD as documented here.
  • Download and Install azcopy as documented here.
  • Sign in with Azure as documented here.
  • Select Azure subscription to upload image as documented here.


Upload Hyper-V Image to Managed Disk

First you want to determine which resource group the image will reside in or if you will create a new resource group. As a reminder a resource group is a container that holds related solutions: virtual machines, storage accounts, disks virtual networks, etc. for your Azure solutions. A resource group can include all resources for your solutions or only those resources that you want to be managed together. For documentation on how to create a new resource group, this can be found on this page. In this example I’m going to use the resource group called “rg-images”.




First, we need to open an elevated PowerShell command prompt.




Next, we will set some variables as we will need these throughout the process, in this example. We are going to be creating this image in Central US, with the image name W2K19-Image-V2, in the resource group called rg-images, with a disk image called W2K19-Image-V2.

  • $location = 'Central US'
  • $imageName = 'W2K19-Image-V2'
  • $rgName = 'rg-images'
  • $diskname = 'W2K19-Image-V2'




Next, we want to create an empty managed disk, you will type the following commands:



$vhdSizeBytes = (Get-Item "<full File Path>").length

$diskconfig = New-AzDiskConfig -SkuName 'Standard_LRS' -OsType 'Windows' -UploadSizeInBytes $vhdSizeBytes -Location $location -CreateOption 'Upload'

New-AzDisk -ResourceGroupName $rgName  -DiskName $diskname -Disk $diskconfig





NOTE: You can replace the Standard_LRS, with Premium_LRS or StandardSSD_LRS.  At the writing of this blog Ultra disks are currently not supported.


Next, we need to confirm the disk status is equal to “ReadyToUpload”, you will type the following:



$disk = Get-AzDisk -ResourceGroupName $rgName -DiskName $diskname






NOTE: The disk status must be set to “ReadyToUpload”, if it is not you need to check what was typed in the “New-AzDiskConfig” command.


Now we want to create the writable shared access signature (SAS) for the managed disk we just created.  Then we will get the disk status and make sure it is equal to “ActiveUpload”, to do this you will type the following:



$diskSas = Grant-AzDiskAccess -ResourceGroupName $rgName -DiskName $diskname -DurationInSecond 86400 -Access 'Write'

$disk = Get-AzDisk -ResourceGroupName $rgName -DiskName $diskname






Now we are ready to upload our disk to Azure, to do this you will type the following and wait for the process to complete:



cd <location of Azcopy>

.\azcopy.exe copy "<location of vhd>" $diskSas.AccessSAS --blob-type PageBlob





When the upload is completed you will get the following results:




After the upload has completed, you will revoke access from the disk as this is not needed, you will type the following:



Revoke-AzDiskAccess -ResourceGroupName $rgName -DiskName $diskname




Create Image from Managed Disk

We now have the managed disk uploaded to the cloud.  The next step is to create an image from that managed disk.  When the image is created, we want to make sure to specify this image will be a V2 image.  To do this you will type the following:



$imageConfig = New-AzImageConfig -Location $location -HypervGeneration V2

$imageConfig = Set-AzImageOsDisk -Image $imageConfig -OsState Generalized -OsType Windows -ManagedDiskId $disk.Id

$image = New-AzImage -ImageName $imageName -ResourceGroupName $rgName -Image $imageConfig





Verify in the portal that our image is now created from our managed disk.  We can now start provisioning generation 2 virtual machines with this image.





There you have it, we have just uploaded a custom windows image and now we can use that image to deploy generation 2 virtual machines in your Azure environment.  Thank you for taking the time to read this blog, I hope this helps you and see you next time.



The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.

Version history
Last update:
‎Sep 14 2020 05:28 AM
Updated by: