Migrating Azure VMs from Classic Service Management to Resource Manager

Tutorial Hero
Microsoft recently made the migration of Azure classic (Service Management or ASM) virtual machines to Azure Resource Manager (ARM) generally available. This post will show you how to migrate your virtual machines from the ASM API to the newer ARM API.

The Process

The method used to migrate virtual machines from ASM to ARM is actually pretty simple to use. This solution migrates virtual machines from ASM to ARM inside the same Azure subscription. If you need to migrate to a different subscription, for example from Open or Direct to CSP, then you will need to consider a different solution, such as “migAz”.
Before you start the migration, you need to identify if your virtual machines are on a virtual network (VNet) or not. If they are, then things are simple; the entire virtual network will be migrated to ARM. If your virtual machines are not connected to a VNet, then you will either:

  • Perform a migration and let Azure create a VNet for you
  • Pre-create a VNet for yourself (probably best)

The process of migrating from Azure virtual machines from ASM to ARM [Image credit: Aidan Finn]
The process of migrating from Azure virtual machines from ASM to ARM [Image credit: Aidan Finn]
The simulation will:

  • Create a resource group in ARM to contain migrated and any newly required resources.
  • Deploy any required resources. For example, ARM virtual machines require NICs and a cloud service must be converted into an ARM load balancer.
  • Connect the ARM API to your existing resources that will be migrated, while retaining management via ASM.
  • Freeze the configurations of all resources being migrated.

A service that co-exists in ASM and ARM – not the “duplicates” in different resource groups [Image Credit: Aidan Finn]
A service that co-exists in ASM and ARM – not the “duplicates” in different resource groups [Image Credit: Aidan Finn]
You can remain at this stage for as long as you want – but you won’t want to stay too long because you won’t be able to make configuration changes. The idea is that you will test your resources and any management scripts/tools that you have via the ARM API. For example, you could re-write your scripts to use the AzureRM PowerShell module (from Get-AzureVM to Get-AzureRMVM).
If your tests go well, you can commit the change, which will complete the migration from ASM to ARM. Otherwise, you can abort the migration; this will remove the new resource group and everything in it, returning your subscription to the state it was in before you started the simulation (and you lose nothing).
If you are migrating from a VNet-less cloud service then your virtual machines will be powered off and they cannot be started up until the migration is committed – be aware of this!
If you commit the migration of your virtual machines, then Microsoft recommends that you complete a similar process to migrate the storage account to ARM, assuming that all virtual machines stored within are already migrated to ARM.

PowerShell Prerequisites

You are going to need the latest version of the Azure PowerShell module. I found that I needed the (Classic) Azure module that was released on July 11th, and this required me to reboot the PC. I would also recommend that you upgrade the AzureRM (ARM) PowerShell module.
The migration is completed using PowerShell, so you are going to need to sign into your Azure subscription, via ARM, prep the subscription, and then sign in via ASM to perform the migration.
To log in via ARM, sign in using:


Query your Azure subscriptions:

Get-AzureRMSubscription | Sort SubscriptionName

Select your Azure subscription. I prefer to do this using ID because names can be duplicated (note the quotes):

$SubscrID = “<Whatever the ID is of the required subscription>”
Select-AzureRMSubscription -SubscriptionID $SubscrID

Why are we in ARM? It’s because we need to register the migration resource provider in the subscription (one time only):

Register-AzureRmResourceProvider -ProviderNamespace Microsoft.ClassicInfrastructureMigrate

Microsoft says that this registration can take up to 5 minutes to complete. You can query the status of the registration using the following cmdlet and checking that RegistrationState is set to Registered:

Get-AzureRmResourceProvider -ProviderNamespace Microsoft.ClassicInfrastructureMigrate

Now we can sign into ASM:


And then you can reuse the $SubscrID variable to select your subscription:

Get-AzureSubscription –SubscriptionName $ SubscrID | Select-AzureSubscription

Now you are ready to migrate your virtual machines.

Example 1 – Virtual Machines on a VNet

In this example, we are moving ASM virtual machines that are connected to subnets in a virtual network. We must migrate the entire virtual network, including all virtual machines in the virtual network.
Store your VNet name in a variable:

$VNetName = "nw-mig"

The next step will move the cloud service into the simulated, ASM and ARM, state:

Move-AzureVirtualNetwork -Prepare -VirtualNetworkName $VNetName

A resource group will be created. Your virtual machine will appear in this resource group, as well as other required resources for ARM, such as virtual NICs for the machines.

Example 2 – Virtual Machines without a VNet

Some people have deployed cloud services without a virtual network. If this is the case we can choose to migrate the machines to ARM using an automatically created VNet – ARM requires all machines to be network-connected. We will migrate machines one cloud service at a time using this solution.
List your cloud services and identify the one that you wish to migrate:

Get-AzureService | ft ServiceName

Save the service name (note the qutoes):

$ServiceName = “<Name of the cloud ServiceName>”

Query for the name of the deployment of that cloud service:

$DeploymentName = (Get-AzureDeployment –ServiceName $ServiceName).DeploymentName

Be careful – the next step will shut down your virtual machines – a downside of have to migrate to connect the machines to a VNet for the first time. The following cmdlet prepares the simulation for the deployment of the cloud service, and connects it to an automatically created VNet.

Move-AzureService -Prepare -ServiceName $ServiceName -DeploymentName $DeploymentName -CreateNewVirtualNetwork

Example 3 – Virtual Machines without a VNet to Pre-Created VNet

This is a another scenario where an ASM cloud service was deployed without a VNet. But in this case, you want to create a new VNet, so that you have total control over the design, which is a much better idea than leaving it all up to Azure.
First you need to get the service name and deployment name, as I already showed you above in Example 2.
Then you will create your VNet, subnet(s) and anything else you require in networking.
Now you can prepare the simulation using your network’s details:

Move-AzureService -Prepare -ServiceName $ServiceName -DeploymentName $DeploymentName -UseExistingVirtualNetwork -VirtualNetworkResourceGroupName “<Name of the VNet resource group>” -VirtualNetworkName $”<Name of the VNet>” -SubnetName $”<Name of the VNet subnet>”

Query Migration State

I have done some testing of the VM migration process, and I have found that there can be some intermittent errors in the attachment of the ARM API – this does not affect your ASM deployment.
Your virtual machines should be in a prepared state; you can verify this with this snippet:

$VMs = Get-AzureVM -ServiceName $ServiceName -Name $VMName
ForEach ($VM in $VMs)
    $MigrationState = $vm.VM.MigrationState
    $VMName = $VM.Name
    Write-Host "$VMName : $MigrationState"

If you check your subscription, you should find a new resource group that was named after your cloud service. In my case, a cloud service called cs-mig was converted into a resource group called cs-mig-migrated.

Commit or Abort the Machine Migration

If I am migrating machines that were in a VNet-less cloud service, then I will run one of the below cmdlets to either commit or abort the migration:

Move-AzureService -Abort -ServiceName $ServiceName -DeploymentName $DeploymentName


Move-AzureService -Commit -ServiceName $ServiceName -DeploymentName $DeploymentName

If I was migrating ASM virtual machines from a VNet then I will use one of the following cmdlets to commit or abort the migration (note the quotes):

Move-AzureVirtualNetwork -Abort -VirtualNetworkName “<Name of the VNet>”


Move-AzureVirtualNetwork -Commit -VirtualNetworkName “<Name of the VNet>”

An abort will remove all of the ARM resources. A commit will remove all of the ASM resources, except for the storage account – any stopped virtual machines (moved from a VNet-less cloud service) will be automatically started up for you.
At this point, you should make sure that you re-create any other engineering that you require in ARM or could not be brought over from ASM.

Migrate the Storage Account

The final step is to migrate the storage account, which you can only do if it is no longer being used by ASM. Save the name of the storage account in a variable (note the qutoes):

$StorageAccountName = "<Name of the storage account>"

You can prepare a simulation (to connect ARM to the ASM resource) by running:

Move-AzureStorageAccount -Prepare -StorageAccountName $StorageAccountName

A new resource group, named after the storage account with a -migrated suffix, is created, containing an ARM link to the storage account. If you are unhappy with the migration then you can abort by running:

Move-AzureStorageAccount -Abort -StorageAccountName $StorageAccountName

Alternatively, you can commit the migration to ARM by executing:

Move-AzureStorageAccount -Commit -StorageAccountName $StorageAccountName

And that’s it! You have migrated your ASM virtual machines and all of their dependencies to ARM.