Creating a VM in Azure based on an uploaded .vhd

I’ll show how to upload a .vhd to Azure as a blob and how to create a Virtual Machine from it using the Powershell AzureRM Cmdlets.
Recently I needed to move a couple of Azure virtual machines from one Azure subscription to another, and to my surprise I found that neither uploading a virtual harddisk nor creating a new virtual machine from it can be accomplished through the ‘new’ Azure portal. Knowing that Powershell support for Azure is excellent, I took a stab at doing it this way, and it isn’t too hard – once you know which of the 990(!) Cmdlets you need…
Note that Azure has 2 sets of Cmdlets: The Azure module, which corresponds to the old manage.windowsazure.com
portal, and the Azure Resource Manager modules that correspond to portal.azure.com
(i.e. the current way of doing things) – I’m using the latter, in combination with Powershell 5.0.
By the way, note that the .vhd I’m using was already created in Azure, so I don’t know what issues you’ll run into if you try to upload .vhd’s that were created outside of Azure.
Setting up the Azure cmdlets
Powershell 5.0 ships with the PowerShellGet module, which makes installing the AzureRM module as easy as:
Install-Module AzureRM
Because the AzureRM module is basically the root of a whole tree of dependencies, installing it can take a couple of minutes.
Once installed, use the following to log into Azure in an interactive fashion:
1
|
Login-AzureRmAccount |
The AzureRM cmdlets only operate on the resources in the subscription that is currently marked as active. In case you have access to more than one subscription, make sure you select the correct one, for example by subscription name.
1
|
Get-AzureRmSubscription -SubscriptionName "Visual Studio Enterprise" | Select-AzureRmSubscription |
Uploading a .vhd as a blob
Next, determine the resource group and storage account url where the .vhd should be uploaded to. I find it easiest to just use the Azure portal to find an existing VM’s .vhd and base the url on that:
To perform the upload of the .vhd, use Add-AzureRmVhd
. Prior to uploading, it determines where the zero-padded blocks are in the file and only transfers the parts with actual data, most likely saving you some bandwith:
1
2
3
4
5
6
|
$resourceGroupName = "seventh-resource" $sourceVhd = "E:\Azure backups\AcmeSrv-AcmeSrv-2014-11-23.vhd" Add-AzureRmVhd -LocalFilePath $sourceVHD -Destination $destinationVHD ` -ResourceGroupName $resourceGroupName -NumberOfUploaderThreads 5 |
When the uploading has completed, you should see the .vhd as part of the blobs in the Blob service.
Creating a virtual machine based on a .vhd
Defining a virtual machine consists of piecing together a couple of resources. I’ll be referring to an existing Virtual network, which can be created through the Azure portal if you don’t have one already. (N.B. To list the available networks, run Get-AzureRmVirtualNetwork
without parameters):
1
2
3
4
|
$virtualNetworkName = "SeventhNetwork" $locationName = "westeurope" $virtualNetwork = Get-AzureRmVirtualNetwork -ResourceGroupName $resourceGroupName ` -Name $virtualNetworkName |
We first need to define a network interface with a public IP address through which our new VM can be accessed:
1
2
3
4
5
|
$publicIp = New-AzureRmPublicIpAddress -Name "AcmeSrv" -ResourceGroupName $ResourceGroupName ` -Location $locationName -AllocationMethod Dynamic $networkInterface = New-AzureRmNetworkInterface -ResourceGroupName $resourceGroupName ` -Name "AcmeSrv123" -Location $locationName -SubnetId $virtualNetwork .Subnets[0].Id -PublicIpAddressId $publicIp .Id |
Now we can start preparing the VM configuration. To list the available VMSizes for your location, use:
1
|
Get-AzureRmVMSize $locationName | Out-GridView |
I’ll attach the .vhd we already uploaded, tell Azure it should be treated as a Windows machine, and attach the network interface we just created:
1
2
3
4
|
$vmConfig = New-AzureRmVMConfig -VMName "AcmeSrv" -VMSize "Standard_DS1" $vmConfig = Set-AzureRmVMOSDisk -VM $vmConfig -Name "AcmeSrv" -VhdUri $destinationVhd ` -CreateOption Attach -Windows $vmConfig = Add-AzureRmVMNetworkInterface -VM $vmConfig -Id $networkInterface .Id |
Now we have all the parts ready to create the actual virtual machine. This call may take a while, but you should be able to follow progress through the Azure portal’s virtual machine overview.
1
|
$vm = New-AzureRmVM -VM $vmConfig -Location $locationName -ResourceGroupName $resourceGroupName |
And that’s it; your new virtual machine is good to go.