Migrating virtual machines using PowerCLI

In my current role as a VMware architect, I architected a greenfield VMware vSphere 6.5 environment.
The ‘old’ environment, who I architected 4 year ago, is VMware vSphere 5.5. As the old environment was never updated, the time and risk of upgrading this environment was too high. That’s why, we decided to go for a greenfield installation.
As the new environment was accepted by the customer system administrators, we had to migrate 700 virtual machines to the new environment.
The old environment was using NFS datastores, as the new environment is using hyperconverged.
As the old environment was vSphere 5.5 U1, we weren’t able to vMotion virtual machines to the new cluster, using Cross vCenter vMotion.

To make the migration as painless as possible, I create a PowerCLI script to do the hard work for us.

The script is very straight forward.

  1. Read ini-file for configuration options
  2. Read hosts.txt file for a list with ESXi hosts to configure
  3. Configure ESXi
    1. DNS
    2. IPv6
    3. NTP
    4. Syslog (see below for sample)
    5. Power Policy
    6. Network (including migration to DVS)
  4. Reboot ESXi

Everything is logged to a logfile in the current directory.


; configuration file for VMwareConfig.ps1
; version 1.0
; parameters are case sensitive!!!
dns1=[dns server]
dns2=[dns server]
suffix=[dns domain]
ntp=[ntp server]
vcenter=[VC Server]
datacenter=[Datacenter name]
cluster=[cluster name]
dvs=[DVS name]
dvportgroupmgmt=[Management DV Portgroup]
portgroupmgmt=Management Network
dvportgroupvmotion=[vMotion DV Portgroup]



#Config VMware vSphere
#Versie: 1.0
#Author: M. Wilmsen

//Log everything
Start-Transcript -Path ".\log.txt"
function Get-IniFile
        [parameter(Mandatory = $true)] [string] $filePath 
    $anonymous = "NoSection"
    $ini = @{} 
    switch -regex -file $filePath 
        "^\[(.+)\]$" # Section 
            $section = $matches[1] 
            $ini[$section] = @{} 
            $CommentCount = 0 
        "^(;.*)$" # Comment 
            if (!($section)) 
                $section = $anonymous 
                $ini[$section] = @{} 
            $value = $matches[1] 
            $CommentCount = $CommentCount + 1 
            $name = "Comment" + $CommentCount 
            $ini[$section][$name] = $value 
        "(.+?)\s*=\s*(.*)" # Key 
            if (!($section)) 
                $section = $anonymous 
                $ini[$section] = @{} 
            $name,$value = $matches[1..2] 
            $ini[$section][$name] = $value 
    return $ini 
#Get variables from config.ini
$iniFile = Get-IniFile .\config.ini
$username = "$env:USERNAME"+'@grid-ota.internal'
$dns1 = $iniFile.dns.dns1
$dns2 = $iniFile.dns.dns2
$suffix = $iniFile.dns.suffix
$syslog = $iniFile.servers.syslog
$ntp = $iniFile.servers.ntp
$ipv6 = $iniFile.defaults.ipv6
$powerpolicy = $iniFile.defaults.powerpolicy
$reboot = $iniFile.defaults.reboot
$subnetmask = $iniFile.defaults.subnetmask
$vcenter = $iniFile.servers.vcenter
$datacenter = $iniFile.vcenter.datacenter
$cluster = $iniFile.vcenter.cluster
$dvSwitch = $iniFile.vcenter.dvs
$ESXiPassword = $iniFile.defaults.esxipassword
$dvUplink1 = $iniFile.vcenter.dvuplink1
$dvUplink2 = $iniFile.vcenter.dvuplink2
$dvPortgroupMGMT = $iniFile.vcenter.dvportgroupmgmt
$portgroupMGMT = $iniFile.vcenter.portgroupmgmt
$dvportgroupVMotion = $iniFile.vcenter.dvportgroupvmotion
#if ( $ipv6 -notlike "$*" ) { $ipv6 = "$" + $ipv6 }
$username = "administrator@vmgrid.internal"
Write-Host "The following config will be used..."
Write-Host "************************************"
Write-Host "ESXi root password: " $ESXiPassword
Write-Host "vCenter username: " $username
Write-Host "vCenter server: " $vcenter
Write-Host "vCenter datacenter: " $datacenter
Write-Host "vCenter cluster: " $cluster
Write-Host "vCenter DVS: " $dvSwitch
Write-Host "dvUplink1: " $dvUplink1
Write-Host "dvUplink2: " $dvUplink2
Write-Host "dvPortgroup Management: " $dvPortgroupMGMT
Write-Host "Portgroup Management: " $portgroupMGMT
Write-Host "dvPortgroup vMotion: " $dvPortgroupVMotion
Write-Host "DNS servers: " $dns1"," $dns2
Write-host "DNS suffix: " $suffix
Write-Host "Syslog server: " $syslog
write-host "NTP Server" $ntp
Write-Host "IPv6 enabled: " $ipv6
Write-Host "PowerPolicy: " $powerpolicy
Write-Host "Default Subnetmask :" $subnetmask
Write-Host "Reboot: "$reboot
Write-Host "************************************"
while( "y","Y","n","N" -notcontains $answer )
  $answer = Read-Host "Are these setting correct? [y/n]"
if ( $answer -eq "n" -or $answer -eq "N" ) {
  Write-Host "Please correct settings in config.ini"
Write-Host "Oke, here we go!"
Write-Host ""
$hosts = "./hosts.txt"
Write-Host "Configuring the following ESXi host(s):" -ForegroundColor Yellow
Get-Content $hosts | ForEach-Object {
  Write-Host $_ -ForegroundColor Magenta
#Define vCenter Password
$Password = Read-Host "Enter your vCenter password" -AsSecureString
$VCPasswordDec = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))
#Connect vCenter Server
#write-host $username $VCPasswordDec
Connect-VIServer $vcenter -User $username -Password $VCPasswordDec
Remove-Variable VCPasswordDec
$VIserverlist = $Global:DefaultVIServer
if ( $VIserverlist -eq $null )
  Write-host "No connection to vCenter server $vcenter. Exiting..."
Get-Content $hosts | ForEach-Object {
  $esxi = $_
  $fqdn = $esxi + "." + $suffix
  Write-Host "Configuring ESXi: " $fqdn -ForegroundColor Yellow
  if ( Test-Connection -ComputerName $fqdn -Quiet ) {
    Write-Host "ESXi host response to ping"
    $PingESXi = $true
  else {
    Write-Host "Cannot contact ESXi, skipping" -ForegroundColor Red
    $PingESXi = $false
  if ( $PingESXi ) {
    Write-Host "Add ESXi $fqdn to vCenter: $vcenter ..." -ForegroundColor Magenta
    Add-VMHost $fqdn -Location (Get-Datacenter $datacenter | Get-Cluster $cluster) -User root -Password $ESXiPassword -RunAsync -force:$true
    Start-Sleep -s 20
    $vmhost = get-vmhost -Name $fqdn
    Write-Host "Configuring DNS..." -ForegroundColor Magenta
    $vmhost | Get-VMHostNetwork | Set-VMHostNetwork -DomainName $suffix -DNSAddress $dns1 , $dns2 -SearchDomain $suffix -Confirm:$False
    Write-Host "Configuring IPv6..." -ForegroundColor Magenta
    $vmhost | Get-VMHostNetwork | Set-VMHostNetwork -IPv6Enabled ([System.Convert]::ToBoolean($ipv6)) -Confirm:$False
    Write-Host "Configuring NTP..." -ForegroundColor Magenta
    #$ntpold = Get-VMHostNtpServer -VMHost $fqdn
    #Remove-VMHostNTPServer -NtpServer $ntpold -VMHost $fqdn -Confirm:$false | Out-Null
    Add-VMHostNTPServer -NtpServer $ntp -VMHost $fqdn -Confirm:$false
    Get-VMHostService -VMHost $fqdn | where{$_.Key -eq "ntpd"} | Set-VMHostService -policy "on" -Confirm:$false
    Get-VMHostService -VMHost $fqdn | where{$_.Key -eq "ntpd"} | Restart-VMHostService -Confirm:$false
    Write-Host "Configuring syslog..." -ForegroundColor Magenta
    Get-AdvancedSetting -Entity $vmhost -Name Syslog.global.logHost | Set-AdvancedSetting -Value $syslog -Confirm:$false
    #Power Policy
    Write-Host "Configuring Power Policy..." -ForegroundColor Magenta
    $vmhostview = Get-View -ViewType Hostsystem -Filter @{"Name"=$($vmhost).Name} -Property ConfigManager.PowerSystem
    $powerpolicyconfig = Get-View $vmhostview.ConfigManager.PowerSystem
    switch ( $powerpolicy )
      'High Performance'{ Write-Host "Configuring PowerPolicy to High Performance" -ForegroundColor Magenta; $powerpolicyconfig.ConfigurePowerPolicy(1) }
      'Balanced' { Write-Host "Configuring PowerPolicy to Balanced" -ForegroundColor Magenta; $powerpolicyconfig.ConfigurePowerPolicy(2) }
      'Low Power' { Write-Host "Configuring PowerPolicy to Low Power" -ForegroundColor Magenta; $powerpolicyconfig.ConfigurePowerPolicy(3) }
      'Custom' { Write-Host "Configuring PowerPolicy to Custom" -ForegroundColor Magenta; $powerpolicyconfig.ConfigurePowerPolicy(4) }
      default { Write-Host "No valid value of Power Policy: $powerpolicy" -ForegroundColor Red }
    #Configuring Network
    Write-host "Add host $fqdn to dvSwitch $dvSwitch" -ForegroundColor Magenta
    Add-VDSwitchVMHost -VDSwitch $dvSwitch -VMhost $vmhost -Confirm:$false
    #Start-Sleep -s 60
    #Migrate VMNIC0 to DVS
    Write-Host "Migrate VMNIC0 to DVS $dvSwitch" -ForegroundColor Magenta
    $vmhostNetworkAdapter = Get-VMHost $vmhost | Get-VMHostNetworkAdapter -Physical -Name $dvUplink1.toUpper()
    Get-VDSwitch $dvSwitch | Add-VDSwitchPhysicalNetworkAdapter -VMHostNetworkAdapter $vmhostNetworkAdapter -confirm:$false
    Start-Sleep -s 3
    #Migrated VMNIC1 to DVS
    Write-Host "Add $dvUplink2 to DVS $dvSwitch" -ForegroundColor Magenta
    $vmhostNetworkAdapter = Get-VMHost $fqdn | Get-VMHostNetworkAdapter -Physical -Name $dvUplink2.toUpper()
    Get-VDSwitch $dvSwitch | Add-VDSwitchPhysicalNetworkAdapter -VMHostNetworkAdapter $vmhostNetworkAdapter -confirm:$false
    Start-Sleep -s 3
    Clear-variable -Name "answer"
    while( "y","Y","n","N" -notcontains $answer )
      $answer = Read-Host "Continue? [y/n]"
    if ( $answer -eq "n" -or $answer -eq "N" ) {
      Write-Host "Exiting"
    #Migrage Management vmk0 to DVS
    Write-Host "Migrate vmk0 (Management) to DVS $dvSwitch" -ForegroundColor Magenta
    $vmk = Get-VMHostNetworkAdapter -Name vmk0 -VMHost $vmhost
    Set-VMHostNetworkAdapter -Portgroup $dvPortgroupMGMT -VirtualNic $vmk -confirm:$false
    #Add vMotion vmk
    $fqdnVMotion = $esxi + "vmt.grid.internal"
    $vmotionIP = [System.Net.Dns]::GetHostAddresses("$fqdnVMotion").IPAddressToString
    $dvs = Get-VDSwitch -Name $dvSwitch
    Write-Host "Adding VMotion vmk to $dvSwitch, dvPortgroup $dvportgroupVMotion with address: $vmotionIP / $subnetmask" -ForegroundColor Magenta
    New-VMHostNetworkAdapter -VMHost $vmhost -PortGroup $dvportgroupVMotion -VMotionEnabled $true -VirtualSwitch $dvs -IP $vmotionIP -SubnetMask $subnetmask
    #Remove Standard portgroups and vSwitches
    Write-Host "Remove virtual Switch vSwitch0 including portgroups"
    $vswitch = Get-VirtualSwitch -VMHost $vmhost -Name vSwitch0
    Write-Host "Removing vSwitch portgroup $portgroupMGMT ..." -ForegroundColor Magenta
    $mgmt_pg = Get-VirtualPortGroup -Name $portgroupMGMT -VirtualSwitch $vswitch
    Remove-VirtualPortGroup -VirtualPortGroup $mgmt_pg -confirm:$false
    Write-Host "Removing vSwitch portgroup VM Network..." -ForegroundColor Magenta
    $vm_pg = Get-VirtualPortGroup -Name "VM Network" -VirtualSwitch $vswitch
    Remove-VirtualPortGroup -VirtualPortGroup $vm_pg -confirm:$false
    Write-Host "Removing vSwitch portgroup Backplane Network ..." -ForegroundColor Magenta
    $bp_pg = Get-VirtualPortGroup -Name "Backplane Network" -VirtualSwitch $vswitch
    Remove-VirtualPortGroup -VirtualPortGroup $bp_pg -confirm:$false
    #Remove vSwitch0
    Write-Host "Removing standard vSwitch vSwitch0" -ForegroundColor Magenta
    Remove-VirtualSwitch -VirtualSwitch $vswitch -confirm:$false
    if ( [System.Convert]::ToBoolean($reboot) ) {
      #Shutdown Nutanix CVM in order to reboot ESXi host
      Start-Sleep -s 60
      Write-Host "Restart ESXi..." -ForegroundColor Magenta
      $vmhost | Restart-VMHost -Force -Confirm:$false
Write-Host "Disconnect vCenter server $vcenter" -ForegroundColor Magenta
Disconnect-VIServer -Server $vcenter -Confirm:$false
Write-Host "Done!" -ForegroundColor Magenta


About Michael
Michael Wilmsen is a experienced VMware Architect with more than 20 years in the IT industry. Main focus is VMware vSphere, Horizon View and Hyper Converged with a deep interest into performance and architecture. Michael is VCDX 210 certified, has been rewarded with the vExpert title from 2011, Nutanix Tech Champion and a Nutanix Platform Professional.

RSS feed for comments on this post.

Leave a Reply

You must be logged in to post a comment.