Moving Managed Disks to different Azure Region

Moving Managed Disks to different Azure Region

Migrating Azure Resources between Resource Groups, Subscriptions, Tenants, and Regions was significantly improved recently. However, some things are still problematic. I am not going to try to summarize it all in this one article. Instead, we will solve one particular problem – migration of Managed Disk to different Azure Region.

There are a few ways how this can be done. The most common scenario is migrating disks with the VM, which you can easily do with the Azure Resource Mover. Moving VM will also move the attached disks.

However, Resource Mover can’t move disks as resources, only as part of a VM. So if you need to be more flexible and move VMs without a network or you need to move a single unattached disk, Resource Moves is not your friend. Service is constantly improving and this might change in the future.

Moving Azure Disk to a different Azure Region

One of the ways to do migrate the disk is to do the following steps:

  1. Move disk to different subscription if needed
  2. Export managed disk as VHD
  3. Move VHD file to a temporary storage account container that is in the target Azure Region
  4. Convert it back to a Managed Disk
  5. Attach disk to VM or build a VM from the OS disk
  6. Clean up old resources

Let’s do this together. Naturally, with Azure PowerShell.

Here we should define some variables first:

$SourceSubscriptionName = "Sub1" 
$TargetSubscriptionName = "Sub2" 
$TargetResourceGroupName = "RG2" 
$TargetLocationName="West US 2" 
$DiskName = "VM01_disk1"

And then login, set context and validate input:


$SourceSubscription = Get-AzSubscription -SubscriptionName $SourceSubscriptionName
$TargetSubscription = Get-AzSubscription -SubscriptionName $TargetSubscriptionName
Set-AzContext -SubscriptionObject $SourceSubscription
#Get disk information: 
$SourceDisk = Get-AzDisk -DiskName $DiskName
Get Target Location: 
$TargetLocation =  (Get-AzLocation | Where-Object { $_.DisplayName -eq $TargetLocationName }).Location
#Validate if target Resource Groups exists and if not create it:
if (-not (Get-AzResourceGroup -Name $TargetResourceGroupName -ErrorAction SilentlyContinue)) {
New-AzResourceGroup -Name $TargetResourceGroupName -Location $TargetLocation -Force | Out-Null 

Move resource to a different subscription

If ($SourceSubscription.TenantId -eq $TargetSubscription.TenantId) {     
Move-AzResource -DestinationResourceGroupName $TargetResourceGroupName -DestinationSubscriptionId $TargetSubscription.Id -Resource
Set-AzContext -SubscriptionObject $TargetSubscription
#Get disk information from the new subscription:
$SourceDisk = Get-AzDisk -DiskName $DiskName

Create a temporary Storage Account and Container in target Azure Region

$storageAccountParams = @{     
ResourceGroupName = $TargetResourceGroupName     
Location          = $TargetLocation     
SkuName           = 'Standard_LRS'     
Name              = 'satemp{0:yyyyMMddHHmmssff}' -f (Get-Date) 
$targetStorage = New-AzStorageAccount @storageAccountParams

$storageContextParams = @{
StorageAccountName = $targetStorage.StorageAccountName
StorageAccountKey  = (
Get-AzStorageAccountKey -ResourceGroupName $targetStorage.ResourceGroupName -Name $targetStorage.StorageAccountName)[0].Value
}; $storageContext = New-AzStorageContext @storageContextParams
New-AzStorageContainer -Name vhd -Context $storageContext | Out-Null

Export Managed Disk

#Generate SAS token with duration 1 hour and Read access
$osDiskAccessParams = @{
ResourceGroupName = $TargetResourceGroupName
DiskName          = $SourceDisk.Name
DurationInSecond  = 3600
Access            = 'Read'
}; $osDiskSAS = Grant-AzDiskAccess @osDiskAccessParams

Copy disk to Storage Account in new Azure Region

$blobCopyParams = @{
AbsoluteUri   = $osDiskSAS.AccessSAS
DestContainer = 'vhd'
DestContext   = $storageContext
DestBlob      = ('{0}_Disk.vhd' -f $Disk.Name) #Define your disk name here
}; Start-AzStorageBlobCopy @blobCopyParams | Out-Null
#Because this action is going to take some time, let's monitor the progress:
do {
Start-Sleep -Seconds 30
$copyState = Get-AzStorageBlobCopyState -Blob $blobCopyParams.DestBlob -Container 'vhd' -Context $storageContext
$progress = [Math]::Round((($copyState.BytesCopied / $copyState.TotalBytes) * 100))
Write-Host ('WAITING: {0:HH:mm:ss} - Waiting for the {1} blob copy process to complete ({2} %)' -f (Get-Date), $DestinationBlob, $progress) -ForegroundColor Yellow
} until ($copyState.Status -ne [Microsoft.Azure.Storage.Blob.CopyStatus]::Pending)

Disk copy can also be performed with AZCopy.

Create new Managed Disk from VHD in Storage Account

$disksDetails = @{ } 
            SkuName = $SourceDisk.Sku.Name
            Caching = "ReadWrite"
$newDiskConfigParams = @{
CreateOption     = 'Import'
StorageAccountId = $targetStorage.Id
SkuName          = ($disksDetails[($SourceDisk.Name)]).SkuName
OsType           = "Windows"
Location         = $TargetLocation
SourceUri        = 'https://{0}{1}_Disk.vhd' -f $targetStorage.StorageAccountName, $SourceDisk.Name
}; $newDiskConfig = New-AzDiskConfig @newDiskConfigParams
$newDiskParams = @{
    Disk              = $newDiskConfig
    ResourceGroupName = $TargetResourceGroupName
    DiskName          = 'NewDisk_{0}' -f $SourceDisk.Name
    }; $newOsDisk = New-AzDisk @newDiskParams

Using the disk

Now that we completed the migration, the two last steps are to create a VM or attach it to an existing VM and test it out. The original disk still exists in the source Subscription, and you can now clean that up.


With many different types of subscription offers and various dependencies for each resource type, migrating resources can sometimes be tricky. I hope this guide was helpful.

Join the discussion