Recreating VMs in Azure

From this article I’m going to explain how to destroy VMs, keep their disks on the backburner and re-create them later.

Why would you do that?

After all, you can shut down VMs and not be charged for it.  You can later restart them and incur the compute cost only once it’s started.  So why destroy / recreate VMs?

In general, because you get an allocation failure.  I did touch upon that in a past article.

Azure Data Centers are packaged in stamps (group of physical servers).  A dirty secret of Azure is that your VM stays in a stamp even if you shut it down.  So if you need to move your VM, you need to destroy it and recreate it.

Two typical use cases:

Frankly, this is all sad and I wish it will be addresses in a future service update.  In the mean time, we do need a way to easily destroy / recreate VMs.

Before I dive into it, there is of course no magic and you have to make sure the Azure region you deploy in support the service you’re trying to deploy.  Many services aren’t available everywhere (e.g. G-series VMs, Cortana Analytics services, etc.).  Consulting the list of services per region to validate your choice.

The technique I show here is based on a my colleague’s article.  Alexandre published that article before the Export Template feature was made available.  This article will therefore use ARM templates generated by Export Template in order to resuscitate VMs.

An alternative approach would be to use PowerShell scripts to recreate the VMs.

Also I based this article on the deployment of a SQL Server Always on Cluster (5 VMs).

Exporting current state

I assume you have a running environment within an Azure Resource Group.

The first step is to export your Azure Resource Group as an ARM Template.  Refer to this article for details.

Save the JSON template somewhere.

Deleting VMs

You can now delete your VMs.  You might want to hook that to a Run Book as I did in Shutting down VMs on schedule in Azure (e.g. to shut down the VMs frequently) or might just do it once (e.g. to resize VM once).

One way to do it, with PowerShell, is to use the following command:

Get-AzureRmVM | Where-Object {$_.ResourceGroupName -eq "NAME OF YOUR RESOURCE GROUP"} | Select-Object Name, ResourceGroupName | ForEach-Object {Remove-AzureRmVM -ResourceGroupName $_.ResourceGroupName -Name $_.Name -Force}

Here I basically list the VMs within one resource group and delete them.

This will not delete the disks associated to them.  It will simply shut down the compute and de-allocate the compute resource.  Everything else, e.g. networks, subnets, availability sets, etc. stay unchanged.

If you’re afraid to delete VMs you didn’t intend to delete you can call the Remove-AzureRmVM explicitly on each VM.

Adapting ARM Template

Export Template does the heavy lifting.  But it can’t be used as is.

We have to make several changes to the template before being able to use it to recreate the VMs.

  1. Remove SecureString password parameters.  We will remove all reference to those so you shouldn’t need it.  The reason is the admin password of your VM is stored on disks and will restored with those disks.  This isn’t essential, but it will avoid you being prompted for password when you’ll run the template.
  2. Change all the createOption attributes to Attach.  This tells Azure to simply take the disks in storage as opposed to creating a disk from a generalized image.
  3. Just next to the createOption for the os-disk, add a osType attribute of value either Windows or Linux.
  4. Remove (or comment out) a few properties:
    • imageReference:  that is under storageProfile
    • osProfile:  that is after storageProfile
    • diskSizeGB:  that is under each dataDisks

Here’s how the osDisk property should look after modifications

"osDisk": {
"name": "osdisk",
"osType": "Windows",
"createOption": "Attach",
"vhd": {

After this little massage of the ARM template you should be able to run the template and recreate your VMs as is.

Making your own modifications

In some cases you might want to modify the ARM template some more.  For instance, by changing the size of VMs.  You can do this now.

Caveat around availability set

There are some funny behaviours around availability sets and VM size I found while writing this article.

One thing is that you can’t change the availability set of a VM (as of this writing).  So you need to get it right the first time.

Another is that a load balancer needs to have VMs under the same availability set.  You can’t have two or VMs without availability sets.

The best one is that you can’t have an availability set with VMs of different size families.  In the case I used, i.e. the SQL Always on cluster, the SQL availability set has two SQL nodes and one witness in it.  The original template let you only configure those as D-series.  You can’t change them to G-series later on and this is one of the reason you’ll want to use the technique laid out here.  But…  even then, you can’t have your witness as a D-series and the SQL nodes as G-series.  So you need to have at least a GS-1 as the witness (which is a bit ridiculous considering what a witness does in a SQL cluster).

That last one cost me a few hours so I hope reading this you can avoid wasting as much on your side!

Running the template

You can then run the template.

My favorite tool for that is Visual Studio but you can do it directly in the portal (see this article for guidance).


Destroying / recreating your VMs will ensure you to have a more robust restart experience.

It also allows you to get around other problems such as re-configuring multiple VMs at once, e.g. changing the size of all VMs in an availability set.

Thanks to Export Template feature, it isn’t as much work as it used to be a few months ago.

2 responses

  1. Per 2017-03-06 at 11:27

    Can you describe the same process with managed disks?

  2. Vincent-Philippe Lauzon 2017-03-29 at 09:18

    We could but first I would try the new “redeploy me now” feature instead which removes a lot of complexity described here.


Leave a comment