#########################################################################################
## 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 #
#########################################################################################
$sourceVcenterName="vcenter-old.nomblot.org" # select source 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
$migratedVMsPool="Migrated VMs" # ressource Pool where VM are stored when migration is done
$secureMode = $true # if $true, only migrate powered off VMs
$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)
}