Home CloudAzure PowerShell, Azure: Migrate a Windows VM from vCenter to Azure

PowerShell, Azure: Migrate a Windows VM from vCenter to Azure

by Kliment Andreev
4.6K views

Recently, I had to migrate a VM from vCenter to Azure. Unlike the migration from vCenter to AWS, this migration is a little bit trickier and involves many steps. There is probably a better way with Azure Site Recovery, but you have to pay for that. See my other post for that.
We’ll use PowerShell for the migration. There are several prerequisites for the migration and they are listed in the comments section.
I have a resource group called rgTest, a virtual network called vnetTest and a subnet that spans all of the virtual network address space called subTest.

In addition, I’ve created a storage account called sablogtest and a container called conttest.


On my local machine, I have the VMDK files downloaded from vCenter in a folder called VM and I have another folder called VHD where the converted files will be stored. For the script, use the names of the VMDK files that are 1K in size.

The script works if the OS has one or two drives. If you have more drives, you’ll have to modify the script. It should be very straightforward.
I’ve noticed that if I run the script in PowerShell cmd, then the script waits sometimes for the user to hit any key. In Windows ISE PowerShell, I didn’t have these problems. Make sure you are local admin on the machine. It’s needed because of the VMDK to VHD conversion.
The VM will power up automatically. When you RDP to it, the data drive won’t be accessible. Make sure you run diskmgmt.msc and then online the drive.

################################################################################
## Kliment Andreev 2017 - (c) BSD License
################################################################################
## 1. Converts VMDK file(s) to VHD
## 2. Uploads the VHD(s) to an existing container
## 3. Creates a bootable disk and/or data disk
## 4. Creates a VM with a public and private IP
################################################################################
# Pre-req:
#       Microsoft CLI 2.0 for Azure
#       Microsoft Virtual Machine Converter 3.0
#       VMDK file(s) and enough storage to convert it/them to VHD
#       Existing subscription in azure
#       Known location of your subscription e.g East US
#       Existing resource group
#       Existing storage account and a container inside
#       Existing vNet where server will reside
#       Existing subnet where the server will reside
#       Existing security group that allows RDP
#       Make sure the OS is set for DHCP
#       Make sure the OS uses E1000, don't use vmxnet NIC
#       Make sure you know your local admin password
#       Make sure you have RDP enabled
################################################################################
# If for some reason the script fails 
# and you are starting from scratch,
# make sure you delete the VHD files.
# Otherwise the converter will create a new
# VHD file with (1) as suffix and the VM
# won't convert/upload properly
################################################################################
# Define your resources/variables here
# None of these can be empty except:
# $myDataVMDKFile and $myDataVHDFile
################################################################################
# Define where is your OS VMWare VMDK file, e.g. c:\users\name\desktop\server.vmdk
$myOSVMDKFile = "C:\Users\klimenta\Desktop\VM\testvm.vmdk"
# Define where is your DATA VMWare VMDK file, e.g. c:\users\name\desktop\server.vmdk
# If you have only C: drive, the string below can be empty e.g. ""
$myDataVMDKFile = "C:\users\klimenta\desktop\VM\testvm_1.vmdk"  
#$myDataVMDKFile = "" 
# Where do you want your OS VHD file created locally, e.g. c:\users\name\desktop\server.vhd
$myOSVHDFile = "C:\Users\klimenta\Desktop\VHD\testvm.vhd"   
# Where do you want your Data VHD file created locally, e.g. c:\users\name\desktop\server.vhd
$myDataVHDFile = "C:\Users\klimenta\Desktop\VHD\testvm_1.vhd"   
#$myDataVHDFile=""
# Virtual Machine Converter PS module
$ConverterFile = "C:\Program Files\Microsoft Virtual Machine Converter\MvmcCmdlet.psd1"
# Existing subscription name
$mySubscription = "Pay-As-You-Go"
# Existing location
$myLocation = "East US"
# Existing resource group
$myResourceGroup = "rgTest"
# Name of the existing storage account (it shoould be unique)
$myStorageAcct = "sablogtest"
# Name of the existing container
$myContainer ="conttest"
# Name of the existing VNET
$myVNET = "vnettest"
# Name of the existing subnet
$mySubnet = "subtest"
# Name of the existing security group
$mySecurityGroup = "sgAllowRDP"
# VM size
$myVMSize = "Standard_A2"
################################################################################
# If Standard_A2
# doesn't suit your needs
# check other sizes in a region with:
# Get-AzureRmVMSize -Location "East US" | Sort-Object Name
################################################################################
# Start the counter
################################################################################
$StartDate = (Get-Date)
# Check if any of the variables are blank
if (!(($myOSVMDKFile) -and ($myOSVHDFile) -and ($ConverterFile) -and ($mySubscription) -and `
    ($myLocation) -and ($myResourceGroup) -and ($myStorageAcct) -and ($myContainer) -and ($myVNET) -and `
    ($mySubnet) -and ($mySecurityGroup) -and ($myVMSize))) {
    Write-Host "Some of the required variables are empty. Exiting..." -ForegroundCOlor Red
    Exit
}
# Check if the OS VMDK exists
if (-not(Test-Path -Path $myOSVMDKFile)) {
        Write-Host "Error: VMDK file does not exist. Exiting..." -ForegroundColor Red
        Exit
}
# Check if the Data VMDK exists but only if defined
if ($myDataVMDKFile -ne "")
{
    if (-not(Test-Path -Path $myDataVMDKFile)) {
            Write-Host "Error: VMDK file does not exist. Exiting..." -ForegroundColor Red
            Exit
    }
}
################################################################################
# Check the VHD
################################################################################
$extension = ([IO.Path]::GetExtension($myOSVHDFile)).ToUpper()
if ($extension -ne ".VHD") {
    Write-Host "Error: Not a VHD file. Exiting..." -ForegroundColor Red
    Exit
}
################################################################################
# Import Virtual Machine Converter
################################################################################
if (-not(Test-Path -Path $ConverterFile)) {
        Write-Host "Error: Microsoft Virtual Machine Converter not installed. Exiting..." -ForegroundColor Red
        Exit
}
Import-Module $ConverterFile
# Get the VHD file name only and the URL of the container
$VHDOSFileName = [io.path]::GetFileName($myOSVHDFile)
$VHDDataFileName = [io.path]::GetFileName($myDataVHDFile)
$urlOS = "https://" + $myStorageAcct + ".blob.core.windows.net/" + $myContainer + "/" + $VHDOSFileName
$urlData = "https://" + $myStorageAcct + ".blob.core.windows.net/" + $myContainer + "/" + $VHDDataFileName
################################################################################
# Log in to your Azure account
################################################################################
Write-Host "Waiting...Login prompt coming up..." -ForegroundColor Yellow
try {
    Login-AzureRmAccount
}
catch {
    Write-Host $_.Exception.Message -ForegroundColor Red
    Exit
}
################################################################################
# Check if you can log to the specified subscription
################################################################################
try {
    if(Get-AzureRmSubscription -SubscriptionName $mySubscription -ErrorAction Stop) {}
}
catch {
    Write-Host $_.Exception.Message -ForegroundColor Red
    Write-Host "Error: The name of the subscription is incorrect or you don't have rights. Exiting..." -ForegroundColor Red
    Exit
}
Get-AzureRmSubscription -SubscriptionName $mySubscription | Select-AzureRmSubscription
Write-Host "Your current subscription is set to" $mySubscription -ForegroundColor Yellow
################################################################################
# Check if the resource group exists
################################################################################
try {
    if(Get-AzureRmResourceGroup -ResourceGroupName $myResourceGroup -ErrorAction Stop) {}
}
catch {
    Write-Host $_.Exception.Message -ForegroundColor Red
    Write-Host "Error: The name of the resource group is incorrect or you don't have rights. Exiting..." -ForegroundColor Red
    Exit
}
################################################################################ 
# Converting from VMDK to VHD (OS)
# If you get an error from Azure that the blob is corrupted, use 
# -VhdType FixedHardDisk
################################################################################
try {
    Write-Host "Converting VMDK OS Disk to VHD in progress... Hit any key when no progress on top." -ForegroundColor Yellow
    if(ConvertTo-MvmcVirtualHardDisk -SourceLiteralPath $myOSVMDKFile -DestinationLiteralPath $myOSVHDFile `
    -VhdType DynamicHardDisk -VhdFormat Vhd -ErrorAction Stop) {}
}
catch {
    Write-Host $_.Exception.Message -ForegroundColor Red
    Write-Host "Error: The VMDK file is most likely corrupt, access violation or incorrect VMDK format. Exiting..." -ForegroundColor Red
    Exit
}
################################################################################
# Converting from VMDK to VHD (Data)
# If you get an error from Azure that the blob is corrupted, use 
# -VhdType FixedHardDisk
################################################################################
if ($myDataVMDKFile -ne "")
{
    try {
        Write-Host "Converting VMDK Data Disk to VHD in progress... Hit any key when no progress on top." -ForegroundColor Yellow
        if(ConvertTo-MvmcVirtualHardDisk -SourceLiteralPath $myDataVMDKFile -DestinationLiteralPath $myDataVHDFile `
        -VhdType DynamicHardDisk -VhdFormat Vhd -ErrorAction Stop) {}
    }
    catch {
        Write-Host $_.Exception.Message -ForegroundColor Red
        Write-Host "Error: The VMDK file is most likely corrupt, access violation or incorrect VMDK format. Exiting..." -ForegroundColor Red
        Exit
    }   
}   
################################################################################
# Upload the OS VHD to the existing blob/container
################################################################################
Write-Host "Uploading OS VHD to" $urlOS -Foreground Yellow
Add-AzureRmVhd -ResourceGroupName $myResourceGroup -Destination $urlOS -LocalFilePath $myOSVHDFile -OverWrite
# Upload the Data VHD to the existing blob/container
if ($myDataVMDKFile -ne "")
{
    Write-Host "Uploading Data VHD to" $urlData -Foreground Yellow
    Add-AzureRmVhd -ResourceGroupName $myResourceGroup -Destination $urlData -LocalFilePath $myDataVHDFile -OverWrite
}
################################################################################
# Create the OS disk
################################################################################
Write-Host "Creating OS disk from VHD..." -Foreground Yellow
$VHDOSFileNameOnly = [io.path]::GetFileNameWithoutExtension($VHDOSFileName)
try {
    $osDisk = New-AzureRmDisk -DiskName $VHDOSFileName -Disk `
        (New-AzureRmDiskConfig -AccountType StandardLRS  -Location $myLocation -CreateOption Import `
        -SourceUri $urlOS) `
        -ResourceGroupName $myResourceGroup
}
catch {
    Write-Host $_.Exception.Message -ForegroundColor Red
    Write-Host "Error: Something went wrong when creating the OS disk. Exiting..." -ForegroundColor Red
    Exit
}
################################################################################
# Create the Data disk
################################################################################
if ($myDataVMDKFile -ne "")
{
    Write-Host "Creating data disk from VHD..." -Foreground Yellow
    $VHDDataFileNameOnly = [io.path]::GetFileNameWithoutExtension($VHDDataFileName)
    try {
        $dataDisk = New-AzureRmDisk -DiskName $VHDDataFileName -Disk `
            (New-AzureRmDiskConfig -AccountType StandardLRS  -Location $myLocation -CreateOption Import `
            -SourceUri $urlData) `
            -ResourceGroupName $myResourceGroup
    }
    catch {
        Write-Host $_.Exception.Message -ForegroundColor Red
        Write-Host "Error: Something went wrong when creating the data disk. Exiting..." -ForegroundColor Red
        Exit
    }
}
################################################################################
# Create and assign a public IP
################################################################################
$ipName = "ip" + $VHDOSFileNameOnly
Write-Host "Creating and assigning a public IP" $ipName -Foreground Yellow
try {
    $pip = New-AzureRmPublicIpAddress -Name $ipName -ResourceGroupName $myResourceGroup -Location $myLocation `
        -AllocationMethod Dynamic
}
catch {
    Write-Host $_.Exception.Message -ForegroundColor Red
    Write-Host "Error: Something went wrong with the IP. Exiting..." -ForegroundColor Red
    Exit
}
################################################################################
# Create the NIC
################################################################################ 
$nicName = "nic" + $VHDOSFileNameOnly
Write-Host "Creating the NIC" $nicName -Foreground Yellow
try {
    $VNET = Get-AzureRmVirtualNetwork -Name $myVNET -ResourceGroupName $myResourceGroup -ErrorAction Stop
}
catch {
    Write-Host $_.Exception.Message -ForegroundColor Red
    Write-Host "Error: Something went wrong with the NIC. Check the vNet name. Exiting..." -ForegroundColor Red
    Exit
}
try {
    $nic = New-AzureRmNetworkInterface -Name $nicName -ResourceGroupName $myResourceGroup `
        -Location $myLocation -SubnetId $VNET.Subnets[0].Id -PublicIpAddressId $pip.Id -NetworkSecurityGroupId $mySecurityGroup.Id
}
catch {
    Write-Host $_.Exception.Message -ForegroundColor Red
    Write-Host "Error: Something went wrong with the NIC. Exiting..." -ForegroundColor Red
    Exit
}
################################################################################
# Create the VM config
################################################################################
$vmName = $VHDOSFileNameOnly
Write-Host "Creating the VM config for" $VHDOSFileNameOnly -Foreground Yellow
try {
    $vmConfig = New-AzureRmVMConfig -VMName $vmName -VMSize $myVMSize -ErrorAction Stop
}
catch {
    Write-Host $_.Exception.Message -ForegroundColor Red
    Write-Host "Error: Something went wrong with the VM Config. Exiting..." -ForegroundColor Red
    Exit
}
################################################################################
# Attach the NIC
################################################################################
Write-Host "Attaching the NIC to" $VHDOSFileNameOnly -Foreground Yellow
$vm = Add-AzureRmVMNetworkInterface -VM $vmConfig -Id $nic.Id
################################################################################
# Add the OS disk
################################################################################
Write-Host "Adding the OS disk to" $VHDOSFileNameOnly -Foreground Yellow
try {
    $vm = Set-AzureRmVMOSDisk -VM $vm -ManagedDiskId $osDisk.Id -StorageAccountType StandardLRS `
         -CreateOption Attach -Windows
}
catch {
    Write-Host $_.Exception.Message -ForegroundColor Red
    Write-Host "Error: Something went wrong with the OS disk. Exiting..." -ForegroundColor Red
    Exit
}

################################################################################
# Create the VM
################################################################################
Write-Host "Creating the VM. This will take some time...Hit any key." $VHDOSFileNameOnly -Foreground Yellow
try {
    New-AzureRmVM -ResourceGroupName $myResourceGroup -Location $myLocation -VM $vm
}
catch {
    Write-Host $_.Exception.Message -ForegroundColor Red
    Write-Host "Error: Something went wrong with the VM creation. Exiting..." -ForegroundColor Red
    Exit
}
################################################################################
# Add the Data disk
################################################################################
if ($myDataVMDKFile -ne "")
{
    Write-Host "Adding the Data disk to" $VHDDataFileNameOnly -Foreground Yellow
    try {
        $vm = Get-AzureRmVM -Name $VHDOSFileNameOnly -ResourceGroupName $myResourceGroup
        $vm = Add-AzureRmVMDataDisk -VM $vm -ManagedDiskId $DataDisk.Id -StorageAccountType StandardLRS `
             -CreateOption Attach -Lun 1
        Update-AzureRmVM -VM $vm -ResourceGroupName $myResourceGroup
    }
    catch {
        Write-Host $_.Exception.Message -ForegroundColor Red
        Write-Host "Error: Something went wrong with the Data disk. Exiting..." -ForegroundColor Red
        Exit
    }
}
################################################################################
# Finalize
################################################################################
$publicIP = Get-AzureRmPublicIpAddress -Name $ipName -ResourceGroupName $myResourceGroup
$EndDate = (Get-Date)
Write-Host "========================================================================" -ForegroundColor Yellow
Write-Host "CREATION OF THE VM COMPLETED. The IP address is" $publicIP.ipaddress -ForegroundColor Yellow
Write-Host "========================================================================" -ForegroundColor Yellow
Write-Host "=> TOTAL TIME:"($EndDate - $StartDate).Days "days," ($EndDate - $StartDate).Hours "hours," ($EndDate - $StartDate).Minutes "minutes."

Related Articles

Leave a Comment

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More