Upload VHD files to Azure: The sysprepped and non-sysprepped way

There’s basically two different ways to handle a VHD file you upload to Azure. Most tutorials I see on the subject only list the “sysprep method” so I thought I should clarify a bit.

The Azure disk mysterium
Before going ahead and uploading stufs, it might make sense to explain the different variations if a disk in Azure terms.

Disks live in Blob Storage. Which means that the first thing you need when you want to upload your VHD is a storage account. The location of the storage account will dictate where your VM can run, so make sure you select a storage account which lives in the right place.

I’m going to play with two VHD files. One is my custom tweaked super-important webserver, and the other one is just generated from the Windows Server 2012R2 ISO using the convert-windowsimage script (which you can find here: http://gallery.technet.microsoft.com/scriptcenter/Convert-WindowsImageps1-0fe23a8f#content) – I’m actually just pretending, I’m using two copies of the same file, but forget about that for now.

In either case, the first thing we have to to is to upload the VHD files to Azure. I’m using the Add-AzureVHD cmdlet to do this. Make sure to specify a container ( in my case, the container is named “vhds”) and the filename of the VHD in Azure. If you get an error, 9 out of 10 times is because you’re trying to upload your VHD to the root “folder” of the storage account, which isn’t allowed. You need a container:

Add-AzureVhd -LocalFilePath .\WinSrv2012R2.vhd -NumberOfUploaderThreads 36 -Destination "https://mysuperduperblob.blob.core.windows.net/vhds/WinSrv2012R2.vhd"

Note that you need to put your vhd into a container inside the storage account. My container is named vhds, as you can see from the url. On a side note, the NumberOfUploaderThreads defaults to 8, but I figured more is always better. I have no idea how much performance gain this gives me, but you know. Can’t hurt.

My relatively fast home network uploads at a decent speed. It’s still gonna take time. I’m gonna do the dishes in the meantime:
2014-08-18 18_42_05-Administrator_ Windows PowerShell ISE

Note that while your VHD file can have a dynamic size of pretty much anything (up to the limit of roughly 2TB according to the VHD file spec. As far as I know, Azure sets a hard limit of 1TB per VHD file, so that’s your real limit), you won’t be able to further expand your VHD once it’s uploaded. Since you only pay for actual usage in Azure anyway, be sure to err on the safe side. There is absolutely no point in uploading a 30GB Windows VHD just to realize that once you’ve set up the VM you’re out of space on the C drive. Go big!

Also note that a good way to test this is to actually perform the VHD generation and upload from within an Azure VM. That way you don’t have to clog up your own uplink while waiting for the upload to complete.

After the upload has completed, you’ll find your newly uploaded VHD in the management portal, by browsing to your storage account and opening the container you uploaded to:
2014-08-18 23_02_48-Storage - Windows Azure

Once that’s done the next part depends on whether the VHD you uploaded was a sysprepped VHD meant to be used for multiple azure VMs, or if it was a single special kind of VM (for example a domain-joined VM you just wanted to move out of your datacenter).

if you want to take a backup of your VHD first (in case something goes wrong), you can do that by using the following few lines of PowerShell. Note that you’ll need the container name and access key for your storage account, which you’ll find by clicking the “Manage Access Keys” after you’ve selected the storage account in the Azure portal.

#Authenticate to the storage account
$context = New-AzureStorageContext -StorageAccountName "MySuperduperstorage" -StorageAccountKey YepYepYepYep123 -Protocol Http
$containername = "vhds"
$blobname = "WinSrv2012R22.vhd"
#get the VHD's blob
$blob = Get-AzureStorageBlob -Context $context -Container $containername -Blob $blobname
if (!($blob))
{
    throw "blob not found"
}
$uri = $context.BlobEndPoint + $containername +"/"
Start-AzureStorageBlobCopy -SrcUri "$uri$($blob.Name)" -DestContext $context -DestContainer $containername -DestBlob "WinSrv2012R22-backup.vhd"

#Use this to check for completion. If it fails, the copy job has completed
$blob | Get-AzureStorageBlobCopyState

Lets have a look at the sysprepped procedure first (just pretend our uploaded vhd was a sysprepped VM):

Spinning up VMs based on a sysprepped VHD (create an Image)

In the Azure portal, under Virtual Machines, switch to “Images” and hit “Create” at the bottom of the page:
2014-08-18 23_22_16-Virtual machines - Windows Azure

Use the dialog to name your VM, choose the uploaded VHD and be sure to hit “I have run sysprep…”
2014-08-18 23_24_37-Virtual machines - Windows Azure

After that’s done, your VM Image should show up as “Available” in the list:
2014-08-18 23_25_53-Virtual machines - Windows Azure

We can now go ahead and create a VM from this image, by using the “Create from Gallery” option and click the “My Images” link in the “Choose an Image” screen:
2014-08-18 23_27_09-Virtual machines - Windows Azure

Notice that since I uploaded the VHD to a storage account located in West Europe, that’s the only location I’ll be able to choose from for this VM (in addition to any Affinity Groups and Virtual Networks within the same region, if you have any):
2014-08-18 23_28_59-Virtual machines - Windows Azure

Also notice that you can spin up as many VMs you want from this image. It is a sysprepped image, so Azure will be able to specialize it and spin up individual VMs from it. Just like you would do using regular VM Templates in VMM or vSphere.

Spinning up unique or “non-sysprepped” VMs (create a disk)

The other variant is to upload and spin up a unique vm. In this scenario you don’t want Azure to do anything to your vm apart from giving it network access. Let’s use our backed-up VHD for this:

Instead of going to the “Images” tab, click the “Disks” tab under “Virtual Machines” in the Azure portal. Hit “Create” at the bottom of the screen:
2014-08-18 23_34_56-Virtual machines - Windows Azure

This time you won’t get any questions regarding sysprep. Azure simply needs to know what OS type the VHD contains. if you don’t check the “VHD contains an OS”, you’ll be able to use the VHD as a data disk. But that’s not relevant to us right now.

If you once again create a VM from the gallery, you’ll now find your newly created disk under the “My Disks” folder (or whatever it is):
2014-08-18 23_37_24-Virtual machines - Windows Azure

Notice that when you’re stepping through the wizard, Azure will not ask your for the username/password of the admin user. It is (logically enough) assumed that you already have this info – and goes to show that Azure will not perform any specialization on the disk, it will simply spin it up for you.

So there you have it:
Images: Template VHDs you can use to create VMs to your heart’s desire. VM disks will be copies of the image.
Disks: One-off VHDs you can attach to a VM and spin up as-is. The VHD is attached to the VM you create (no copies made)

I know a lot of folks find the whole process cumbersome. It is actually quite easy when you think about it: Upload your VHD to a blob, and then register that blob as either an image or a disk, depending on your needs. It gives us a super-flexible way of dealing with both template images and disks, and everything’s of course scriptable so that you can automate the entire process easily.

Also note that VHDs generated by using the convert script will mostly not boot, especially not if using the “non-sysprepped” method. There are tons of guides on how to create a “valid” Azure VHD, be sure to follow those.