PowerCLI优化:如何在多台主机上并行执行远程脚本
优化PowerCLI脚本实现多VM并行操作
问题背景
需要维护大量Windows服务器,现有PowerCLI脚本只能串行处理单台VM,每台执行完成后才开始下一台,整体耗时过长,希望改为并行处理所有VM,提升效率。
解决方案
将单VM的处理逻辑封装为独立函数,利用PowerShell的并行执行能力(ForEach-Object -Parallel 或 Start-Job)同时处理多台VM。以下是优化后的脚本:
优化后完整脚本
# 连接vCenter(只需执行一次) Connect-VIServer "XXXXXXXXX" -User "XXXXX\user" -Password "P@ssword123!" # 定义需要处理的VM列表 $vmList = @("VM1", "VM2", "VM3") # 替换为你的VM名称集合 # 封装单VM处理逻辑为函数 function Process-VM { param( [string]$VMName, [string]$vCenterServer, [PSCredential]$vCenterCred, [string]$TempUser, [SecureString]$TempPass ) try { # 在并行会话中重新连接vCenter(确保会话隔离) Connect-VIServer $vCenterServer -Credential $vCenterCred -ErrorAction Stop | Out-Null $vm = Get-VM -Name $VMName -ErrorAction Stop switch($vm.PowerState){ 'PoweredOn' { Shutdown-VMGuest -VM $vm -Confirm:$false # 等待VM关机完成 do { Start-Sleep 5 $vm = Get-VM -Name $VMName } while($vm.PowerState -eq 'PoweredOn') Write-Host "$VMName 已关机,准备配置" } Default { Write-Host "VM '$VMName' 当前未开机!" } } # 创建快照 $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $snapshotName = "Pre_Upgrade_snapshot $timestamp" $description = "Pre_Upgrade_snapshot $timestamp" New-Snapshot -Name $snapshotName -VM $VMName -Description $description -Memory:$false -Quiesce:$true -ErrorAction Stop Start-Sleep 45 # 启动VM $vm = Start-VM -VM $VMName -Confirm:$false -ErrorAction Stop Start-Sleep 45 # 等待Guest操作就绪 do { Start-Sleep 5 $vm.ExtensionData.UpdateViewData('Guest') } while(-not $vm.ExtensionData.Guest.GuestOperationsReady) Write-Host "$VMName 已开机,Guest操作就绪" -BackgroundColor Cyan Start-Sleep 45 # 执行Guest内脚本 $HashArguments = @{ VM = $VMName ScriptText = "C:\InplaceUpgrade\setup.ps1" GuestUser = $TempUser GuestPassword = $TempPass ScriptType = "Powershell" ErrorAction = "Stop" } Invoke-VMScriptWrapper -VMScriptParams $HashArguments Write-Host "$VMName 脚本执行完成" # 断开当前会话 Disconnect-VIServer $vCenterServer -Confirm:$false | Out-Null } catch { Write-Host "处理VM '$VMName' 时出错: $_" -ForegroundColor Red } } # 准备vCenter凭据(避免硬编码,建议实际使用Get-Credential) $vCenterCred = New-Object System.Management.Automation.PSCredential("XXXXX\user", (ConvertTo-SecureString "P@ssword123!" -AsPlainText -Force)) $updateTempPass = ConvertTo-SecureString 'XXXXXX' -AsPlainText -Force # 使用PowerShell 7+的并行处理(推荐) $vmList | ForEach-Object -Parallel { Process-VM -VMName $_ -vCenterServer "XXXXXXXXX" -vCenterCred $using:vCenterCred -TempUser "XXXXX" -TempPass $using:updateTempPass } -ThrottleLimit 10 # 控制并行数量,避免vCenter压力过大 # 若使用PowerShell 5.x,可改用Start-Job方式: # $jobs = @() # foreach ($vm in $vmList) { # $job = Start-Job -ScriptBlock ${function:Process-VM} -ArgumentList $vm, "XXXXXXXXX", $vCenterCred, "XXXXX", $updateTempPass # $jobs += $job # } # # 等待所有作业完成并获取结果 # $jobs | Wait-Job | Receive-Job # # 清理作业 # $jobs | Remove-Job
关键优化点说明
- 函数封装:将单VM的完整处理流程(关机、快照、开机、执行脚本)封装为
Process-VM函数,便于复用和并行调用 - 并行执行:
- 推荐使用
*ForEach-Object -Parallel*(需PowerShell 7及以上版本),语法简洁性能更好,通过-ThrottleLimit控制并行数量,避免给vCenter造成过大压力 - 若使用PowerShell 5.x,可改用
*Start-Job*实现并行,需手动管理作业的创建、等待和清理
- 推荐使用
- 会话隔离:在并行函数内部重新连接vCenter,避免跨会话的连接冲突
- 时间戳优化:统一格式化时间戳,避免字符串拼接的冗余写法
- 错误处理:保留原有的错误捕获逻辑,确保单VM处理失败不影响其他VM
内容的提问来源于stack exchange,提问作者Arbelac
相关产品推荐
相关产品推荐

