You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 22:10:08