As of date, there is not direct way to move Azure Virtual Machine to another region in another subscription directly. However I had a task which involved doing so. Also for our usecase, resource mover was also not an option as it works across all public regions while we had to move resources to one of a private azure region.
Considering the requirement and number of systems in scope (200+) we had to do it via script (powershell scripts of course).
We had almost no time for planning, so we chose the known path. Something which we have already done as team. We broke down the task into 4 pieces:
1) Take snapshot of OS and data disks (in source region/subscription)- Manual
2) Move snapshot vhd files to storage account in target region/subscription
3) Create disks from vhd files in storage account in target region/subscription
4) Create VM from disks in target region/subscription- Manual
First and the last tasks were done manually as we could not get time to complete the script. But we managed to write 3 scripts for 2nd and 3rd step. Will definitely try to do other manual steps via script as and when I get sometime to give it a try.
2.1 ) Powershell script to move snapshot as vhd file to storage account
# Please NOTE : We dont need to login to destination subscription (via powershell) in this whole copying process as we are using the storage key of the dest account. Hence first login to source tenant and set your subscription and that's it. #This script will copy the snapshot in .vhd format to your destination storage account.
#Provide the name of Source subscription where snapshot is created
$subscription = Read-Host "Enter source subscription name"
# Set the context to the subscription Id where Snapshot is created
Select-AzSubscription -Subscription $subscription
#Provide destination storage account name where you want to copy the snapshot.
$storageAccountName = Read-Host "Enter target storage account name where snapshots are to be copied. Note: Public access should be enabled on storage account: "
#Provide Shared Access Signature (SAS) expiry duration in seconds e.g. 3600.
#More about SAS here: https://docs.microsoft.com/en-us/Az.Storage/storage-dotnet-shared-access-signature-part-1
#For vhd files/disks with upto 600GB size, it might take more time to copy. Choose it wisely. During our activity we found transfer speeds around 300GB/hour. This is set in seconds
$sasExpiryDuration = "7200"
#Name of the storage container where the downloaded snapshot will be stored
$storageContainerName = Read-Host "Enter container name where snapshots are to be copied as vhd. Note: Ensure that the container exists before running this script: "
#Provide the key of the destination storage account where you want to copy snapshot.
$storageAccountKey = Read-Host "Enter target storage account key: "
# Import list of snapshots in csv file
$snaps=Import-Csv (Read-Host "Enter Path of file containing snapshot details: snapname, snaprg,
foreach ($snap in $snaps) {
$i++
Write-Host "Working on Snapshot #"$i
Write-Host "Snapshot Name-> "$snap.snapname
#Provide the name of your resource group where snapshot is created
$resourceGroupName =$snap.snaprg
#Provide the snapshot name
$snapshotName = $snap.snapname
#Provide the name of the VHD file to which snapshot will be copied. Ensure you give .vhd extension to file name.
$destinationVHDFileName = $snap.snapname+'.vhd'
Write-Host "Creating SAS"
#Generate the SAS for the snapshot
$sas = Grant-AzSnapshotAccess -ResourceGroupName $snap.snaprg -SnapshotName $SnapshotName -DurationInSecond $sasExpiryDuration -Access Read
Write-Host "Setting destination context"
#Create the context for the storage account which will be used to copy snapshot to the storage account
$destinationContext = New-AzStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey
Write-Host "Start blob copy job"
#Copy the snapshot to the storage account
Start-AzStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestContainer $storageContainerName -DestContext $destinationContext -DestBlob $destinationVHDFileName
Write-Host "Started snapshot transfer for -> "$snap.snapname
}
2.1.1 ) Powershell script to check blob copy status
Below command did not provide us a tabular view of completion status but gave us overview of completion % for each snapshot. Atmost 10 copy operations run simultaneously. We had to wait till this completed for all snapshots.
#Below commands are to be executed in the context of target subscription where snapshot vhd files are being copied.
#Provide the name of target subscription where new VMs are to be created
$subscription = Read-Host "Enter source subscription name"
# Set the context to the target subscription where storage account is present
Select-AzSubscription -Subscription $subscription
#Provide destination storage account name where you want to copy the snapshot.
$storageAccountName = Read-Host "Enter storage account name where snapshots are being copied: "
#Name of the storage container where the snapshot vhd file is copied
$storageContainerName = Read-Host "Enter container name where snapshots are copied as vhd: "
#Provide the key of target storage account where snapshots are copied to
$storageAccountKey = Read-Host "Enter target storage account key: "
$destinationContext = New-AzStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey
#We will loop through the same list of snapshots which we created csv file for when starting blob copy operation. csv file containing snapname and snaprg. So no need to import csv to variable again
# $snaps=Import-Csv (Read-Host "Enter Path of file containing source snapshot details (snapname, snaprg columns): "
$i=0
foreach ($snap in $snaps){
$i++
Write-Host "Checking status for Snap #" $i
Write-Host "Snap Name-> " $snap.snapname
$total=(Get-AzStorageBlobCopyState -Context $destinationContext -Blob ($snap.snapname+'.vhd') -Container $storageContainerName).TotalBytes
$copied=(Get-AzStorageBlobCopyState -Context $destinationContext -Blob ($snap.snapname+'.vhd') -Container $storageContainerName).BytesCopied
Write-Host "Completed % -->" (($copied/$total)*100)
}
3.1) Creating disk from snapshot vhd files
#Specify target subscription details
$subscription = Read-Host "Enter target subscription name: "
Set-AzContext -Subscription $subscription
$location = Read-Host "Enter target region where new disks are to be created. ex: indiacentral : "
# Set hypervisor generation This should be same as of source machine. Put this in csv if all systems do not have same version
$version= Read-Host "Enter hypervisor generation of virtual machines to be created: "
$storageAccountName = Read-Host "Enter target storage account name where snapshots are copied as vhd: "
$storageContainerName = Read-Host "Enter container name where snapshots copied: "
$storageAccountId = Read-Host "Enter storage account resource id. sample: /subscription/<subid>/resourcegroups/<rgid>/providers/Microosft.Storage/Storageaccounts/<storageaccountname>: "
$i=0
# Import list of snapshots in csv file
$snaps=Import-Csv (Read-Host "Enter Path of file containing source snapshot details and destination disk details (snapname, snaprg,diskname, diskrg, size, disksku,ostype columns): "
foreach ($snap in $snaps){
$i++
Write-Host "Working on Snap #" $i
Write-Host "Snapshot Name-> " $snap.snapname
$resourceGroupName = $snap.diskrg
$diskName = $snap.diskname
$diskSizeGB = $snap.size
$sku = $snap.disksku
#Creating vhd URL from storage account name, container name and vhd file name
$vhdUri = "https://" + $storageAccountName + ".blob.core.windows.net/" + $storageContainerName + "/" + $snap.snapname+'.vhd'
if ($snap.ostype -eq "linux" -or $snap.ostype -eq "windows"){
Write-Host "Creating OS Disk config"
$diskConfig = New-AzDiskConfig -SkuName $sku -Location $location -DiskSizeGB $diskSizeGB -StorageAccountId $storageAccountId -SourceUri $vhdUri -CreateOption Import -ostype $snap.ostype -HyperVGeneration $version
}
else {
Write-Host "Creating OS Disk config"
$diskConfig = New-AzDiskConfig -SkuName $sku -Location $location -DiskSizeGB $diskSizeGB -StorageAccountId $storageAccountId -SourceUri $vhdUri -CreateOption Import -HyperVGeneration $version
}
Write-Host "Creating Disk"
New-AzDisk -ResourceGroupName $resourceGroupName -DiskName $diskName -Disk $diskConfig
}