Virtualization‎ > ‎

VMware : Cross vCenter migration script

This minimalist script can handle VM migration between 2 VMware vCenter infrastructures talking to two vCenter at the same time and reconnect network interfaces, put in target Folder, cluster.

Requirements are : 
  • VMs files (vmx, vmdk, etc...) must be accessibles  on  the 2 vCenters (via NFS shares, FC storage , etc...)
  • same folder structure must exist on both vCenter (you can use a script to create folder structure on target vCenter).
  • folders, ressources Pool, DVswitch must exist only once and on both vcenters with same names
  • you must have a valid admin account on the 2 vcenters
What is done here which is not handled by Veeam is that this script connect all network interfaces on VMs.
 
Script is given as is without any support, use at your own reponsability.



#########################################################################################
## PowerCLI VM migration script over NFS (VMX must be visible on all ESX, same LANs)    #
##                                                                                      #
## - for VM on sourceVcenter where selected criteria math:                              #
## -    stop VM on source vCenter                                                       #            
## -    register VM on target vcenter in same folder (must exist only once)             #
## -    foreach VM network interface                                                    #
## -      connect network interface in right VLAN                                       #
## -    start VM on target vcenter if previously started                                #
## -    move VM on source in specific ressource pool (to ease unregistring if required) #
##                                                                                      #
## Patrick Nomblot                                                                      #
#########################################################################################

## parameters :

$sourceVcenterName="vcenter-old.nomblot.org"        # select source vcenter Name on which to register VM on
$targetVcenterName="vcenter-new.nomblot.org"        # select target vcenter Name on which to register VM on
$targetDatacenterName="My CLOUD"                    # select target datacenter name on which to register VM on
$targetClusterName="My Cluster Name"                # select target cluster name on which to register VM on
$targetDVSwitchName="dvSwitch-prod"                                     # select target DVswicth to connect VM on 
$migratedVMsPool="Migrated VMs"                     # ressource Pool where VM are stored when migration is done


$Confirm=$false                                     # confirm actions ?
$secureMode = $true                                 # if $true, only migrate powered off VMs


#$sourceVcenterName = Read-Host "OLD vCenter name (FQDN)"
#$targetVcenterName = Read-Host "NEW vCenter name (FQDN)"
$login = $host.ui.PromptForCredential("vCenters login", "Please enter your user name and password.", "", "NetBiosUserName")



#########################################################################################################
## Load PowerCLI modules
Write-Host "Loading Vmware Modules, Please, wait ...."
Get-Module –ListAvailable VM* | Import-Module
if ($? -eq $false){
  Write-Host "Error loading VMware modules !"
  exit
}


#########################################################################################################
# disconnect all vcenters
Disconnect-VIServer -server "*" -force -Confirm:$Confirm -ErrorAction SilentlyContinue 

#########################################################################################################
#Connect to source and target vCenters 
foreach ($vc in @($sourceVcenterName,$targetVcenterName)) {
   try{
     Connect-VIServer -Server $vc -Credential $login -ErrorAction Stop | Out-Null
     $si = get-view ServiceInstance
     $sm = Get-View $si.Content.SessionManager
     $sm.SetLocale("en")
     Write-Host "connected to vCenter Server $vc"     
   }
   catch{
     Write-Host "Failed to connect to vCenter Server $vc"
     #exit #Exit script on error 
   } 
 }


#################################################################################################################################
$targetDatacenter = Get-Datacenter -Server $targetVcenterName -Name $targetDatacenterName
$targetCluster = Get-Cluster -Server $targetVcenterName $targetClusterName
 
#################################################################################################################################
function Cross-Vcenter-Migrate($sourceVM) {
  Write-Host "Working on VM $($sourceVM.Name) in folder $($sourceVM.Folder) vCenter $($sourceVcenterName)"

  # check if VM already exist on new Vcenter
  $targetVM = $targetDatacenter|Get-VM -Server $targetVcenterName -Location $targetDatacenter -Name "$($sourceVM.Name)" -ErrorAction SilentlyContinue 
  if ($targetVM) { 
    Write-Host "WARNING : VM $($sourceVM.Name) already exist on new vCenter $($targetVcenterName)"
    continue
  }

  # check if Folder on target Vcenter
  switch ( @(Get-Folder -Type VM  -Server $targetVcenterName -Name "$($sourceVM.Folder)" -ErrorAction SilentlyContinue).Count)
    { 
     1       { Write-Host "OK : one target folder $($sourceVM.Folder) of VM $($sourceVM.Name) found on vCenter $($targetVcenterName)" }
     0       { Write-Host "ERROR : target folder $($sourceVM.Folder) of VM $($sourceVM.Name) does not exist on vCenter $($targetVcenterName)" ; break}
     default { Write-Host "ERROR : more than one target folder $($sourceVM.Folder) of VM $($sourceVM.Name) exist on vCenter $($targetVcenterName)" ; break }
    }


  # stop VM to migrate on old vcenter
  if ( $sourceVM.PowerState -like "PoweredOn" ) {
    if ( $secureMode ) { 
      # for tests/security, abort all if VM is running
      Write-Host "SECURITY : source VM is running, please stop selected VM !"
      break
    } else {
      $sourceVMRestart = $true
      Write-Host "STOPPING VM $($sourceVM.Name) ..."
      $sourceVM |Shutdown-VMGuest -Confirm:$Confirm 
      Start-Sleep -Seconds 10
      $sourceVM | Stop-VM -Confirm:$Confirm
    }
  } else {
    $sourceVMRestart = $false
  }


  # register VM on New vcenter$targetVM
  $sourceRP = "$($sourceVM | Get-ResourcePool)"
  if ( $sourceRP  -like "Resources" ) {
      write-Host "ERROR : $sourceVM is not in a ressource Pool."
      break
  }
     
  $targetVM = $targetDatacenter|Get-VM -server $targetVcenterName -Name "$($sourceVM.Name)" -ErrorAction SilentlyContinue 
  if (!$targetVM) { 
    $targetRP = Get-ResourcePool -Location $targetCluster -Name "$($sourceVM.ResourcePool)"
    $targetFolder = Get-Folder -Type VM -Server $targetVcenter -Location $targetDatacenter  -Name "$($sourceVM.Folder)"
    
    Write-Host "Registering VM $($sourceVM.Name) on vcenter $targetVcenterName in folder $targetFolder"
    try{
      New-VM -server $targetVcenterName -VMFilePath "$($sourceVM.Extensiondata.Config.Files.VmPathName)" -Location $targetFolder -ResourcePool $targetRP
    }
    catch{
      Write-Host "Failed to register VM $($sourceVM.Name) to vCenter $($targetVcenterName)"
      break
    }  
  }

  # reconnect network interfaces
  $targetVM = $targetDatacenter|Get-VM -server $targetVcenterName -Name $sourceVM.Name
  if ($targetVM) { 
    foreach ($sourceNetwork in @(Get-NetworkAdapter $sourceVM)) {
      Write-Host "connecting network interface : $($sourceNetwork.name) / $($sourceNetwork.NetworkName)"
      ##$myNetworkAdapter = Get-VM -server $targetVcenterName -Name "$($targetVM.Name)" | Get-NetworkAdapter -server $targetVcenterName -Name "$($sourceNetwork.Name)"
      $myNetworkAdapter = $targetVM | Get-NetworkAdapter -Name "$($sourceNetwork.Name)"
      #####$dvSwitch = $sourceVM | Get-VirtualSwitch 
      #####Get-VDSwitch -server $targetVcenterName "$($dvSwitch)"
      $dvSwitch = Get-VDSwitch -server $targetVcenterName "$targetDVSwitchName"
      $pg = Get-VDSwitch -server $targetVcenterName $dvSwitch | Get-VDPortgroup -Name "$($sourceNetwork.NetworkName)"
      Set-NetworkAdapter -server $targetVcenterName -NetworkAdapter $myNetworkAdapter -PortGroup $pg -Confirm:$Confirm
      Set-NetworkAdapter -server $targetVcenterName -NetworkAdapter $myNetworkAdapter -StartConnected:$true -Confirm:$Confirm
    }
  } else {
    Write-Host "Error, new VM $($sourceVM.Name) not found on new vCenter $($targetVcenterName)"
    break
  }

  $migratedRP = Get-ResourcePool -server $sourceVcenterName -name $migratedVMsPool
  Move-VM -VM $sourceVM -Destination $migratedRP

  $sourceVMRestart = $true
  # start VM on new vcenter (if required)
  if ( $sourceVMRestart -eq $true -and $targetVM.PowerState -like "PoweredOff" ) {
    $targetVM | Start-VM -Confirm:$Confirm
    Start-Sleep -Seconds 2
    Get-VMQuestion -VM $targetVM | Set-VMQuestion -Option button.uuid.movedTheVM -Confirm:$confirm
  }

}







#################################################################################################################################
#################################################################################################################################
#################################################################################################################################
# Usage examples :
# ----------------
#
# foreach ($sourceVM in Get-Folder -Type VM -Server $sourceVcenterName | Where-Object { $_.Name -like '*MyNiceFolder*'} | where-Object {$_.Name -notlike '*StrangeVmName*'} | Get-VM ) {
# foreach ($sourceVM in Get-Folder -Type VM -Server $sourceVcenterName | Where-Object { $_.Name -like 'ARCHIVED'} | Get-VM ) {
# foreach ($sourceVM in (Get-VM -Server $sourceVcenterName | Where-Object { $_.Name -like 'srv*'})[0..2] ) {


foreach ($sourceVM in (Get-VM -Server $sourceVcenterName | Where-Object { $_.Name -like 'srv*'})[0..2] ) {
  $sourceVM
  # comment line below to check VM list before running
  Cross-Vcenter-Migrate($sourceVM)
}


 




Comments