vNoob 09月29日 10:48
自动化跨vCenter迁移VM的脚本
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍了一个PowerShell脚本,用于自动化将虚拟机(VM)从一个vCenter迁移到另一个vCenter的过程。作者在尝试使用原生GUI进行批量迁移时遇到了困难,因为GUI在选择目标端口组和数据存储时,未能提供源VM的当前位置信息。该脚本通过保留VM原有的网络和存储配置,简化了这一过程。脚本还包含了详尽的网络连通性检查(包括VM名称、IP地址和客户机名称),以确保迁移的成功和VM在目标环境中的正常运行。此外,脚本会自动跳过配置了多个端口组或数据存储的VM,以便手动处理。

💡 **自动化迁移的必要性与GUI的局限性:** 原生的Cross vCenter vMotion GUI在批量迁移VM时存在不足,尤其是在需要手动选择目标端口组和数据存储时,缺乏源VM位置信息,给管理员带来了不便。作者因此开发了一个PowerShell脚本,旨在自动化这一过程,并解决GUI的痛点。

⚙️ **脚本核心功能与网络检查:** 该脚本通过保留VM原有的端口组和数据存储名称,在目标vCenter中自动匹配并使用相同的配置进行迁移。为了确保迁移的稳健性,脚本在迁移前后执行了多重网络连通性测试,包括通过VM名称、解析的IP地址以及客户机操作系统中的名称和IP地址,以验证VM的网络状态。

⚠️ **脚本的限制与可扩展性:** 该脚本当前版本会自动忽略配置了多个端口组或数据存储的VM,因为这些复杂场景需要更细致的手动处理。作者也提到未来可以考虑实现自动回滚功能,以应对迁移失败的情况,并计划在GitHub上分享该脚本及更多实用工具。

🚀 **迁移过程的安全性设计:** 为了增加迁移过程的安全性,脚本在执行实际迁移操作前会向用户发出确认提示,并详细记录迁移的源信息和目标信息。迁移完成后,脚本会再次进行网络连通性检查,并标记潜在的失败情况,为后续排查提供依据。

I recently needed to migrate all VMs from one vCenter to another. I had planned to use the native Cross vCenter vMotion GUI, but I ran into a couple of issues. Although using it for one VM works fine-ish, using it for multiple VMs at a time becomes quite a burden.

The main problems stem from the GUI wants you to pick the portgroup and datastore on the destination vCenter. In theory, this makes sense as there might be differing storage at the destination vCenter. However, it doesn’t inform you during the process where the VMs currently reside. This is a bit tough to explain, so here is a screenshot:

In the picture, we see we are trying to migrate 2 VMs, and it wants destination storage to be selected. It gives no indication though of where the VMs are coming from. If identical storage is presented at both locations, and you want the VMs to land on the same datastore, there isn’t a way to do it through this GUI. You would need to first document where each VM is located before even beginning the migration process, which is silly.

If you do one VM at a time, you are given a VM Origin link during migration to check the source location:

But this doesn’t exist when migrating in batches.

With all this in mind, I created a script to assist with this process. In my case, identical storage and network port names were presented at each location so for the selection process, I only needed to have the script choose based on the port and datastore names the VM was already utilizing.

Two other caveats for this script. The first being I was paranoid about the VMs landing ok at the new vCenter. This means I have multiple networking checks both before and after the migration. Not all VMs have guest names, or even VMtools to check guest names/IPs, so I am checking networking by VMname, IP resolved by VMname, Guestname(where applicable), and Guest IP. So yeah, a little paranoid. When everything is working all right, the checks look something like this:

We can see it does check the IPv4 IP and VMname, before resolving some of the other stuff to IPv6. Regardless there were enough greens for me to proceed, where it would then do the same checks after the migration. Another thing to note is it would prompt before starting the migration, because paranoid.

The second caveat with the script is it will automatically ignore VMs with multiple portgroups or multiple datastores. In my use case, few VMs would fall into this category, and my paranoia demanded I do them manually anyway.

# Connect to Source and Target vCenter Servers$sourceVC = "SourcevCenter"$targetVC = "TargetvCenter"# Define the list of VM names to migrate#$vmNames = "SingleVM"  # Replace with the names of VMs you want to migrate$targetClusterName = "Clustername"  # Replace with the target cluster name in the target vCenter$vmhost = "VMHost" # Used for clearing out a specific ESXi host# Connect to both vCenter serversConnect-VIServer -Server $sourceVC Connect-VIServer -Server $targetVC # Get VMs hosted on the specified ESXi host from the source vCenter$vmnames = Get-VMHost $vmhost -Server $sourceVC | Get-VM # Can be modified to get all VMs on vCenter by removing vmhost reference# Loop through each VM and perform migrationforeach ($vmName in $vmNames) {        # Retrieve the VM from the source vCenter    $vm = Get-VM -Name $vmName -Server $sourceVC    "VM"    $vm    # Get VM guest information    $vmGuestInfo = Get-VMGuest -VM $vm    $ipv4Addresses = $vmGuestInfo.IPAddress | Where-Object { $_ -match '^\d{1,3}(\.\d{1,3}){3}$' } | Select-Object -First 1    # Initial network connectivity test    Write-Host "Testing initial connectivity with IP $ipv4Addresses" -ForegroundColor Yellow    $initialping = Test-NetConnection $ipv4Addresses     # Check initial ping response    if ($ipv4Addresses -eq $null) {        Write-Warning "No IPv4 Address found"    } elseif ($initialping.PingSucceeded) {        Write-Host "Initial ping succeeded" -ForegroundColor Green    } else {        Write-Warning "Initial ping failed"    }    # Test connectivity by VM Name    Write-Host "Testing connectivity with VM Name $($vm.Name)" -ForegroundColor Yellow    $pingtest = Test-NetConnection $vm.Name    if (-not $pingtest.PingSucceeded) {        Write-Warning "Ping failed for VM Name $($vm.Name)"    } else {        Write-Host "Ping succeeded for VM Name $($vm.Name)" -ForegroundColor Green    }    # Test connectivity by VM Guest Name    Write-Host "Testing connectivity with VM Guest Name $($vmGuestInfo.HostName)" -ForegroundColor Yellow    $pingtest = Test-NetConnection $vmGuestInfo.HostName    if (-not $pingtest.PingSucceeded) {        Write-Warning "Ping failed for VM Guest Name $($vmGuestInfo.HostName)"    } else {        Write-Host "Ping succeeded for VM Guest Name $($vmGuestInfo.HostName)" -ForegroundColor Green    }    # Retrieve source VM's datastore and portgroup    $sourceDatastore = (Get-HardDisk -VM $vm | Get-Datastore)    $sourcePortGroup = Get-VM $vm | Get-VirtualPortGroup -Distributed    $sourcedatastorecenter = $sourceDatastore.Uid.Split("@")[1].Split("/")[0]    Write-Host "Source Information:" -ForegroundColor Cyan    $sourcePortGroup.Name    $sourceDatastore.Name    $sourcedatastorecenter    # Validate VM network settings (Portgroup and Datastore)    if ($sourcePortGroup.Count -gt 1) {        Write-Warning "$vm has multiple portgroups, skipping."        continue    } elseif ($sourcePortGroup.Count -lt 1 -or $sourcePortGroup -eq $null) {        Write-Warning "$vm has no portgroups, skipping."        continue    }    if ($sourceDatastore.Count -gt 1) {        Write-Warning "$vm has multiple datastores, skipping."        continue    } elseif ($sourceDatastore.Count -lt 1 -or $sourceDatastore -eq $null) {        Write-Warning "$vm has no datastores, skipping."        continue    }    # Retrieve corresponding datastore and portgroup in the target vCenter    $targetDatastore = Get-Datastore -Name $sourceDatastore.Name -Server $targetVC    $targetPortGroup = Get-VirtualPortGroup -Name $sourcePortGroup -Server $targetVC -Distributed    $targetdatastorecenter = $targetDatastore.Uid.Split("@")[1].Split("/")[0]      $targetCluster = Get-Cluster -Name $targetClusterName -Server $targetVC    $targetHost = $targetCluster | Get-VMHost | Get-Random -Count 1    Write-Host "Destination Information:" -ForegroundColor Cyan    $targetPortGroup.Name    $targetPortGroup.Uid.Split("@")[1].Split("/")[0]    $targetDatastore.Name    $targetdatastorecenter    $targetHost.Name    # Confirm migration    $response = Read-Host "Are you sure you want to continue? (y/n)"    if ($response -ne "y") {        Write-Warning "Aborting migration for $vmName"        continue    }    # Execute Cross vCenter vMotion    Move-VM -VM $vm `        -Destination $targetHost `        -Datastore $targetDatastore `        -NetworkAdapter (Get-NetworkAdapter -VM $vm) `        -PortGroup $targetPortGroup `        -Confirm:$true    Write-Output "Migrated VM '$vmName' to target vCenter with portgroup '$sourcePortGroup' and datastore '$sourceDatastore'."    # Post-migration connectivity check    Start-Sleep -Seconds 2    Write-Host "Testing post-migration connectivity with IP $ipv4Addresses" -ForegroundColor Yellow    $pingtest = Test-NetConnection $ipv4Addresses    if (-not $pingtest.PingSucceeded) {        Write-Warning "Ping failed for VM, considering rollback."    } else {        Write-Host "Post-migration ping succeeded" -ForegroundColor Green    }    # Check post-migration connectivity by VM Name and Guest Name    Write-Host "Testing with VM Name $($vm.Name)" -ForegroundColor Yellow    $pingtest = Test-NetConnection $vm.Name    if (-not $pingtest.PingSucceeded) {        Write-Warning "Ping failed for VM Name $($vm.Name), considering rollback."    } else {        Write-Host "VM Name $($vm.Name) connectivity verified" -ForegroundColor Green    }    Write-Host "Testing with VM Guest Name $($vmGuestInfo.HostName)" -ForegroundColor Yellow    $pingtest = Test-NetConnection $vmGuestInfo.HostName    if (-not $pingtest.PingSucceeded) {        Write-Warning "Ping failed for VM Guest Name $($vmGuestInfo.HostName), considering rollback."    } else {        Write-Host "VM Guest Name $($vmGuestInfo.HostName) connectivity verified" -ForegroundColor Green    }}# Optional: Disconnect from vCenter Servers# Disconnect-VIServer -Server $sourceVC -Confirm:$false# Disconnect-VIServer -Server $targetVC -Confirm:$false

Some options for updates if I or someone else is ever interested, would be automatic rollback to source vCenter. In my case, with a good number of VMs “failing” tests because of inaccurate or inaccessible guest info this didn’t make sense, and with me monitoring each migrating I could manually move a VM back if necessary.

Second obvious one would be to update to account for multiple portgroups or datastores.

The script is also available on github, where I am going to start dumping more of the scripts I have written.

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

vCenter迁移 PowerShell脚本 Cross vCenter vMotion 自动化 VMware vSphere vCenter Migration PowerShell Script Cross vCenter vMotion Automation VMware vSphere
相关文章