'Simplicity is the ultimate sophistication' - Leonardo da Vinci



Cross-Cloud Provider Migration / Automation

Automated migrations across different cloud providers is an area that is rapidly gaining attention lately as public and hybrid clouds proliferate. What I am speaking about is the capability to leverage automation to move workloads and infrastructure around. As both Microsoft Azure and Amazon AWS provide PowerShell modules and corresponding APIs, this automation is relatively easy to accomplish.

The purpose of this post is to provide an example of the types of things that can be done across Azure and AWS clouds.  Specifically, I provide a PowerShell example that illustrates how some basic migration tasks could be accomplished. Here is the setup:

  1. I have 3 AWS instances (see below) that I need to migrate to Azure
  2. 3 of The AWS instances in the pool are tagged with the "Name" key and populated with "sktest" value
  3. I initialized the AWS account profile in PowerShell
  4. I added the Azure account in Powershell
  5. I created a prototype mapping file for demonstration purposes only.  Various IT-Pros may have differing opinions on how VM images differ across AWS and Azure as well as how compute resources map (i.e. Azure and AWS compute resources are not the same, but this a discussion for another day)

Here are the AWS instances used for this example:

I executed the Map-AwsVmsToAzureVms.ps1 script.  This script reads in all of my AWS instances and filters them by the specified Tag. The script then loads the AzureAwsMapping.json file to use as the basis to map the current AWS instances with possible Azure VM Image configurations. The script takes in the following parameters:

  1. AWS Profile Name to use for the PowerShell session
  2. The AWS Instance Tag Name that I want to filter my live AWS instances against
  3. The AWS Instance Tag Value that I will use as the filter
  4. [Optional] the AWS Region (this is defaulted)
  5. [Optional] the Action I want to take.  This is conceptual and could perform any number of tasks.

The results of the script execution are:

The script is fairly simple and honestly, getting both your AWS and Azure credentials configured in PowerShell may be the biggest share of work that needs to be done.  It's gravy from there on.  The example Switch statement is where we could do many things.  Here are some examples of things we might want to do:

  1. Take AWS snapshots for future Disk2VHD processing
  2. Record needed system configuration data for the AWS instances to be migrated
  3. Develop a price calculator that estimates similar VM infrastructure costs on Azure
  4. Provision VMs that match the tagged VMs based on the VM mapping rules
  5. many more....

Here is the content of the PowerShell script:

PowerGUI Script Editor



import-module "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\AWSPowerShell.psd1"
Initialize-AWSDefaults -ProfileName $awsProfileName -Region $awsRegion

$awsInstanceFilter = @([Amazon.EC2.Model.Filter]@{name="tag:$awsInstanceTagName";value=$awsInstanceTagValue})
$mappings= (get-content $PSScriptRoot\AzureAwsMapping.json) | Out-String | ConvertFrom-Json
$outObject = @(New-Object PSObject)
foreach ($instance in (Get-EC2Instance -filter $awsInstanceFilter).Instances)
  foreach ($imageMapping in $mappings.AwsToAzureVMConversion.ImageMapping)
    if ($imageMapping.awsAmiImageId -eq $instance.ImageId)
          $azureImageName  = Get-AzureVMImage | ?{$_.Label -eq  $imageMapping.AzureImageLabel} | select ImageName -First 1
          $azureVmImage = Get-AzureVMImage -ImageName $azureImageName.ImageName
          $azureTier = $mappings.AwsToAzureVMConversion.InstanceSizeMapping | ? {$_.awsModel -eq $instance.InstanceType}
          $Object = New-Object  PSObject
          $Object | Add-Member noteproperty AwsPrivateDNS ($instance.PrivateDnsName)
          $Object | Add-Member noteproperty AwsVPC ($instance.vpcid)
          $Object | Add-Member noteproperty CandidateAzureVmImageLabel ($azureVMImage.Label)
          $Object | Add-Member noteproperty CandidateAzureVmImageName ($azureImageName.ImageName)
          $Object | Add-Member noteproperty AzureInstance ($azureTier.azureInstance)
          $Object | Add-Member noteproperty AzureTier ($azureTier.azureTier)
          $outObject +=$Object
Switch ($action)
   "dothis" {"this"}
   "dothat" {"that"}
   "dotheother" {"the other"}
   default { Write-Output $outObject | Format-Table  }

This is the notional JSON file that maps the Image types and instance sizes:




             "InstanceSizeMapping": [

                    { "awsModel": "t2.micro", "azureInstance": "a0", "azureTier": "basic" },

                    { "awsModel": "t2.small", "azureInstance": "a1", "azureTier": "basic" },

                    { "awsModel": "t2.medium", "azureInstance": "a2", "azureTier": "basic" },

                    { "awsModel": "m3.medium", "azureInstance": "a2", "azureTier": "standard" }


             "ImageMapping": [


                           "awsAmiImageId": "ami-ba13abd2",

                           "awsAmiName": "Windows_Server-2012-R2_RTM-English-64Bit-Base-2014.10.15",

                          "AzureImageLabel": "Windows Server 2012 R2 Datacenter, September 2014"



                           "awsAmiImageId": "ami-9eaa1cf6",

                           "awsAmiName": "ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-20140927",

                           "AzureImageLabel": "Ubuntu Server 14.04 LTS"



                           "awsAmiImageId": "ami-2414ac4c",

                           "awsAmiName": "Windows_Server-2012-RTM-English-64Bit-SQL_2012_SP1_Standard-2014.10.15",

                           "AzureImageLabel": "SQL Server 2012 SP1 Standard on Windows Server 2012"