I had a customer the other week who had a Hyper-V environment and wanted to move to Azure, however they had Windows Server 2012 (non R2) which Azure Site Recovery doesn’t support. They had to start the procedures to move VMs manually to Azure.
So I made up a JSON template which they can use to help move their VM workloads to Azure. All they need to do is to start the beginning phases on-prem themselves to prepare the disks. They need to convert their VHDX disks to VHD using Convert-VHD.
Convert-VHD –Path c:\test\MY-VM.vhdx –DestinationPath c:\test\MY-NEW-VM.vhd -VHDType Fixed
Follow the steps to prepare the disk to copy to Azure – https://docs.microsoft.com/en-us/azure/virtual-machines/windows/prepare-for-upload-vhd-image – please note, the image doesn’t really need to be generalised.
Then upload the VHD disk to a blob storage account in the same region and subscription as to where they want to create the Azure VM. Pick an existing storage account or create a new storage account, then create a storage container to copy the VHD to, and give the container public read access and copy the URI for the actual VHD disk itself, use the free Azure Storage Explorer, to do all of this as this is the easiest storage tool to use. The URI copied to the clipboard will need to be fed into the JSON template below as a parameter value when run.
When run, the JSON template below will allow the customer to specify the VHD blob storage URI for the VHD file in their blob storage account and choose an existing vNet for which to deploy the VM to. The VHD disk specified would then be converted to a managed disk automatically and then a new VM would be provisioned from this new managed disk.
Done….
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", | |
"contentVersion": "1.0.0.0", | |
"parameters": { | |
"vmName": { | |
"type": "string", | |
"metadata": { | |
"description": "Name of the VM" | |
} | |
}, | |
"osType": { | |
"type": "string", | |
"allowedValues": [ | |
"Windows", | |
"Linux" | |
], | |
"metadata": { | |
"description": "Type of OS on the existing vhd" | |
} | |
}, | |
"osDiskVhdUri": { | |
"type": "string", | |
"metadata": { | |
"description": "Uri of the existing VHD in ARM standard or premium storage in the same subscription" | |
} | |
}, | |
"vmSize": { | |
"type": "string", | |
"metadata": { | |
"description": "Size of the VM" | |
} | |
}, | |
"existingVirtualNetworkName": { | |
"type": "string", | |
"metadata": { | |
"description": "Name of the existing VNET" | |
} | |
}, | |
"existingVirtualNetworkResourceGroup": { | |
"type": "string", | |
"metadata": { | |
"description": "Name of the existing VNET resource group" | |
} | |
}, | |
"subnetName": { | |
"type": "string", | |
"metadata": { | |
"description": "Name of the subnet in the virtual network you want to use" | |
} | |
}, | |
"dnsNameForPublicIP": { | |
"type": "string", | |
"metadata": { | |
"description": "Unique DNS Name for the Public IP used to access the Virtual Machine." | |
} | |
} | |
}, | |
"variables": { | |
"OSDiskName": "[concat(parameters('vmName'), uniqueString('disk'))]", | |
"diagStorageAccountName": "[concat(uniquestring(resourceGroup().id), 'specvm')]", | |
"networkSecurityGroupName": "[concat('NSG', uniqueString(parameters('vmName')))]", | |
"api-version": "2015-06-15", | |
"publicIPAddressType": "Dynamic", | |
"vnetID": "[resourceId(parameters('existingVirtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', parameters('existingVirtualNetworkName'))]", | |
"subnetRef": "[concat(variables('vnetID'),'/subnets/', parameters('subnetName'))]", | |
"nicName": "[parameters('vmName')]", | |
"publicIPAddressName": "[parameters('vmName')]" | |
}, | |
"resources": [ | |
{ | |
"apiVersion": "[variables('api-version')]", | |
"type": "Microsoft.Network/publicIPAddresses", | |
"name": "[variables('publicIPAddressName')]", | |
"location": "[resourceGroup().location]", | |
"tags": { | |
"displayName": "PublicIPAddress" | |
}, | |
"properties": { | |
"publicIPAllocationMethod": "[variables('publicIPAddressType')]", | |
"dnsSettings": { | |
"domainNameLabel": "[parameters('dnsNameForPublicIP')]" | |
} | |
} | |
}, | |
{ | |
"apiVersion": "[variables('api-version')]", | |
"type": "Microsoft.Network/networkInterfaces", | |
"name": "[variables('nicName')]", | |
"location": "[resourceGroup().location]", | |
"dependsOn": [ | |
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", | |
"[concat('Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroupName'))]" | |
], | |
"tags": { | |
"displayName": "NetworkInterface" | |
}, | |
"properties": { | |
"ipConfigurations": [ | |
{ | |
"name": "ipconfig1", | |
"properties": { | |
"privateIPAllocationMethod": "Dynamic", | |
"publicIPAddress": { | |
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]" | |
}, | |
"subnet": { | |
"id": "[variables('subnetRef')]" | |
} | |
} | |
} | |
], | |
"networkSecurityGroup": { | |
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" | |
} | |
} | |
}, | |
{ | |
"apiVersion": "2017-03-30", | |
"type": "Microsoft.Compute/disks", | |
"name": "[variables('OSDiskName')]", | |
"location": "[resourceGroup().location]", | |
"tags": { | |
"displayName": "Disks" | |
}, | |
"properties": { | |
"creationData": { | |
"createOption": "Import", | |
"sourceUri": "https://marcplayvic.blob.core.windows.net/temp/abcd.vhd" | |
}, | |
"diskSizeGB": 128 | |
}, | |
"dependsOn": [ | |
] | |
}, | |
{ | |
"apiVersion": "2017-03-30", | |
"type": "Microsoft.Compute/virtualMachines", | |
"name": "[parameters('vmName')]", | |
"location": "[resourceGroup().location]", | |
"tags": { | |
"displayName": "VirtualMachine" | |
}, | |
"properties": { | |
"hardwareProfile": { | |
"vmSize": "[parameters('vmSize')]" | |
}, | |
"storageProfile": { | |
"osDisk": { | |
"name": "[variables('osDiskName')]", | |
"caching": "ReadWrite", | |
"osType": "[parameters('osType')]", | |
"createOption": "Attach", | |
"managedDisk": { | |
"id": "[resourceId('Microsoft.Compute/disks',variables('osDiskName'))]" | |
} | |
//"diskSizeGB": 128 | |
} | |
}, | |
"networkProfile": { | |
"networkInterfaces": [ | |
{ | |
"id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]" | |
} | |
] | |
}, | |
"diagnosticsProfile": { | |
"bootDiagnostics": { | |
"enabled": true, | |
"storageUri": "[concat(reference(concat('Microsoft.Storage/storageAccounts/', variables('diagStorageAccountName')), '2016-01-01').primaryEndpoints.blob)]" | |
} | |
} | |
}, | |
"dependsOn": [ | |
"[resourceId('Microsoft.Compute/disks/', variables('OSDiskName'))]", | |
"[resourceId('Microsoft.Storage/storageAccounts/', variables('diagStorageAccountName'))]", | |
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" | |
] | |
}, | |
{ | |
"apiVersion": "2016-01-01", | |
"type": "Microsoft.Storage/storageAccounts", | |
"name": "[variables('diagStorageAccountName')]", | |
"location": "[resourceGroup().location]", | |
"tags": { | |
"displayName": "StorageAccount" | |
}, | |
"sku": { | |
"name": "Standard_LRS" | |
}, | |
"kind": "Storage", | |
"properties": {} | |
}, | |
{ | |
"name": "[variables('networkSecurityGroupName')]", | |
"type": "Microsoft.Network/networkSecurityGroups", | |
"apiVersion": "2016-09-01", | |
"location": "[resourceGroup().location]", | |
"tags": { | |
"displayName": "NSG" | |
}, | |
"properties": { | |
"securityRules": [ | |
{ | |
"name": "default-allow-rdp", | |
"properties": { | |
"priority": 1000, | |
"sourceAddressPrefix": "*", | |
"protocol": "Tcp", | |
"destinationPortRange": "3389", | |
"access": "Allow", | |
"direction": "Inbound", | |
"sourcePortRange": "*", | |
"destinationAddressPrefix": "*" | |
} | |
} | |
] | |
} | |
} | |
] | |
} |