6 minutes to read


Recently we started to migrate all of our customers from Azure Service Management (also known as ASM or Azure Classic) to Azure Resource Manager (ARM). The reason we migrate everything to ARM are various. A few reasons are:

  • RBAC on resources
  • Use tags on resources
  • Easier deployments (both new and incremental)
  • No need to update PowerShell scripts

Azure Classic and Azure Resource Manager picture Azure Classic and Azure Resource Manager picture

There are different possibilities to migrate from ASM to ARM:

As we have multiple things that are not supported by Microsoft’s own solution for migrating from ASM to ARM we decided to use MigAz. As the BlobCopy of MigAz is very slow we use AzCopy to copy the content between the storage accounts – yes this requires downtime.

Migrate from ASM to ARM

I was working on a migration of a customer that uses Virtual Machines, a VNET-TO-VNET and an ExpressRoute to connect from on-premises to the Azure Virtual Machines. Migrating ExpressRoutes are not supported with the PowerShell cmdlets Microsoft provides to migrate from ASM to ARM, so I decided to use MigAz together with AzCopy. However before I could use this I needed to migrate the ExpressRoute and the gateways first.

ExpressRoute & Gateways

Moving the ExpressRoute from Classic to ARM is not that hard and well documented by Microsoft. However when you move the ExpressRoute over to ARM it is still using the Gateway from the Classic environment.

ExpressRoute Circuit co-existence ASM and ARM ExpressRoute Circuit co-existence ASM and ARM

If you want to migrate from ASM to ARM you do not want to use the Gateways from ASM. So I needed to migrate the Gateways (for ER and VNET-TO-VNET) also. However documentation about tis part was not provided by Microsoft. So what I did was using some existing documentation and some common sense.

The VNET in ARM was already created with a Gateway subent (/27 or smaller is needed for both ER and VNET-2-VNET) and the ExpressRoute was moved. Now I need to create the Gateways for both the ER and the VNET-TO-VNET. For this I used the documentation “Configure ExpressRoute and Site-to-Site coexisting connections for the Resource Manager deployment model” (only point 4 and 6).

As the gateways are created I could start removing the Circuit Link with the Gateways in the Classic environment and link the Circuit to the Gateway created in ARM.

The complete script I used for migrating the ExpressRoute

### Migrate ExpressRoute from ASM to ARM including Gateway
### Setup by using default Microsoft documents and common sense
### Copyright Hey Azure Guy! - Daniël Etten
### http://heyazureguy.com

## Move the ExpressRoute to ARM

# Login to your Azure account
Select-AzureSubscription -SubscriptionName "[Subscription name]"
Get-AzureRmSubscription -SubscriptionName "[Subscription name]" | Select-AzureRmSubscription

# Set variables
$location = "West Europe"
$resgrp = New-AzureRmResourceGroup -Name "[RG Name]" -Location $location
$vnet = New-AzureRmVirtualNetwork -Name "[VNET Name]" -ResourceGroupName $resgrp.ResourceGroupName -Location $location -AddressPrefix ""

# Move the ExpressRoute and allow classic operations
New-AzureRmResourceGroup -Name $resgrp.ResourceGroupName -Location $location
Move-AzureRmExpressRouteCircuit -Name "[New name of your ExpressRoute circuit]" -ResourceGroupName $resgrp.ResourceGroupName -Location $location -ServiceKey "[Service-key]"
$ckt = Get-AzureRmExpressRouteCircuit -Name "[New name of your ExpressRoute circuit]" -ResourceGroupName $resgrp.ResourceGroupName
$ckt.AllowClassicOperations = $true
Set-AzureRmExpressRouteCircuit -ExpressRouteCircuit $ckt

## Prepare the environment

# Setup the environment
Add-AzureRmVirtualNetworkSubnetConfig -Name "[SubnetName]" -VirtualNetwork $vnet -AddressPrefix ""
Add-AzureRmVirtualNetworkSubnetConfig -Name "GatewaySubnet" -VirtualNetwork $vnet -AddressPrefix ""
$vnet = Set-AzureRmVirtualNetwork -VirtualNetwork $vnet

# Create the gateway for the ExpressRoute
$gwSubnetER = Get-AzureRmVirtualNetworkSubnetConfig -Name "GatewaySubnet" -VirtualNetwork $vnet
$gwIPER = New-AzureRmPublicIpAddress -Name "[Public IP name for the ER]" -ResourceGroupName $resgrp.ResourceGroupName -Location $location -AllocationMethod Dynamic
$gwConfigER = New-AzureRmVirtualNetworkGatewayIpConfig -Name "ERGatewayIpConfig" -SubnetId $gwSubnetER.Id -PublicIpAddressId $gwIPER.Id
$gwER = New-AzureRmVirtualNetworkGateway -Name "[VNet Gateway Name]" -ResourceGroupName $resgrp.ResourceGroupName -Location $location -IpConfigurations $gwConfigER -GatewayType "ExpressRoute" -GatewaySku [SKU] 

# Create the gateway for the VNET-TO-VNET
$gwSubnetVPN = Get-AzureRmVirtualNetworkSubnetConfig -Name "GatewaySubnet" -VirtualNetwork $vnet
$gwIPVPN = New-AzureRmPublicIpAddress -Name "[Public IP name for the VPN]" -ResourceGroupName $resgrp.ResourceGroupName -Location $location -AllocationMethod Dynamic
$gwConfigVPN = New-AzureRmVirtualNetworkGatewayIpConfig -Name "VPNGatewayIpConfig" -SubnetId $gwSubnetVPN.Id -PublicIpAddressId $gwIPVPN.Id
New-AzureRmVirtualNetworkGateway -Name "VPNGateway" -ResourceGroupName $resgrp.ResourceGroupName -Location $location -IpConfigurations $gwConfigVPN -GatewayType "Vpn" -VpnType "RouteBased" -GatewaySku [SKU]

## Now it it time to unlink the circuit from the Classic environment
Remove-AzureVirtualNetworkGatewayConnection -ConnectedEntityId [ConnectedEntityId] -GatewayId [GatewayId] # repeat this step until all connection are removed 
Remove-AzureLocalNetworkGateway -GatewayId [GatewayId] # repeat this step until all local network gateways are removed 
Remove-AzureDedicatedCircuitLink -ServiceKey "[Service-key]" -VNetName "[VNET from classic environment]"

## As the circuit is unlinked from the Classic environment you can link it to the ARM environment
## You can also create the VNET-TO-VNET connection

# Setup the connection between the ExpressRoute and the Gateway
$ckt = Get-AzureRmExpressRouteCircuit -Name "[Your ExpressRoute]" -ResourceGroupName $resgrp.ResourceGroupName
New-AzureRmVirtualNetworkGatewayConnection -Name "[Connection Name]" -ResourceGroupName $resgrp.ResourceGroupName -Location $location -VirtualNetworkGateway1 $gwER -PeerId $ckt.Id -ConnectionType ExpressRoute

# Setup the Local Network
$MyLocalNetworkAddress = @("","","")
$localVpn = New-AzureRmLocalNetworkGateway -Name "LocalVPNGateway" -ResourceGroupName $resgrp.ResourceGroupName -Location $location -GatewayIpAddress [Public IP from on premises] -AddressPrefix $MyLocalNetworkAddress

# Setup the connection between the Local Network and the Gateway
$azureVpn = Get-AzureRmVirtualNetworkGateway -Name "VPNGateway" -ResourceGroupName $resgrp.ResourceGroupName
New-AzureRmVirtualNetworkGatewayConnection -Name "VPNConnection" -ResourceGroupName $resgrp.ResourceGroupName -Location $location -VirtualNetworkGateway1 $azureVpn -LocalNetworkGateway2 $localVpn -ConnectionType IPsec -SharedKey 

Virtual Machines

Now the ExpressRoute and Gateways are migrated to ARM I could start the migration of the Virtual Machines to ARM using MigAz and AzCopy. I used MigAz to generate the JSON file and to create the environment from scratch in ARM. I used AzCopy to copy the virtual machine disks to the Storage Account in ARM. After the copy was completed I could start the virtual machines and the migration was completed.

Do you have any questions related to this blogpost, please leave a message and I’ll get in contact with you as soon as possible!