Upload Custom Linux Hyper-V Image for Gen 2 VM in Azure


This is Andrew Coughlin and I am a Customer Engineer at Microsoft focusing on Azure IaaS. In this blog I will focus on upload a custom 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 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.  Are you looking for the process for Windows VMs, head over to my post here that covers this same process but for Windows VMs.


  • 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.
  • Review Generic image documentation here.
  • Review the specific distribution preparation documentation:
    • Debian is located here.
    • Oracle is located here.
    • OpenBSD is located here.
    • Redhat is located here.
    • SUSE is located here.
    • Ubuntu is located 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, 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 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 CentOS7-Image-V2, in the resource group called rg-images, with a disk image called CentOS7-Image-V2.

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


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

$diskconfig = New-AzDiskConfig -SkuName ‘Standard_LRS' -OsType ‘Linux' -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”, we 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 we 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 we will type the following and wait for the process to complete:


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


After the upload has completed, we will revoke access from the disk as we no longer need the shared access signature we created above, we 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 we will type the following:

$imageConfig = New-AzImageConfig -Location $location -HypervGeneration V2
$imageConfig = Set-AzImageOsDisk -Image $imageConfig -OsState Generalized -OsType Linux -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 linux 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 are not supported under any Microsoft standard support program or service. The sample 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.


This article was originally published by Microsoft's Core Infrastructure and Security Blog. You can find the original article here.