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

Azure VM并行恢复PowerShell脚本故障求助

Azure VM并行恢复PowerShell脚本故障排查

针对你提供的并行恢复脚本,以下是核心问题点及修复方案:

  • Runspace池初始化参数错误
    原脚本中创建RunspacePool的代码:

    $runspacePool = [RunspaceFactory]::CreateRunspacePool(1, [System.Management.Automation.Runspaces.Runspace]::DefaultRunspace)
    

    第二个参数应为最大并发数(整数),而非DefaultRunspace对象。参数类型不匹配会直接导致Runspace池创建失败。修改为:

    # 可根据实际需求调整最大并发数,示例设为10
    $runspacePool = [RunspaceFactory]::CreateRunspacePool(1, 10)
    
  • Runspace未继承Azure上下文
    每个Runspace是独立会话,默认不会继承当前PowerShell会话的Azure登录上下文。单VM恢复正常是因为在当前会话已登录,但并行Runspace中无登录信息,会导致Restore-VMAndSnapshots执行失败。
    修复方案:将当前Azure上下文传递到每个Runspace,修改脚本块部分:

    # 在函数开头获取当前Azure上下文
    $currentAzContext = Get-AzContext
    
    foreach ($vmInfo in $VMsInfo) {
        $job = [PowerShell]::Create().AddScript({
            param ($info, $azContext)
            # 切换到目标上下文
            Set-AzContext -Context $azContext | Out-Null
            Restore-VMAndSnapshots -SubscriptionId $info.SubscriptionId -ResourceGroupName $info.ResourceGroupName -VMName $info.VMName
        }).AddArgument($vmInfo).AddArgument($currentAzContext)
    
        $job.RunspacePool = $runspacePool
        $jobs += $job
    }
    
  • 自定义函数未在Runspace中加载
    Restore-VMAndSnapshots是自定义函数,默认不会被加载到新的Runspace中,导致Runspace无法找到该函数。
    修复方案:将函数定义注入到Runspace的初始化会话状态中,在创建RunspacePool前添加:

    $iss = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
    # 将自定义函数添加到会话状态
    $functionDef = Get-Content Function:\Restore-VMAndSnapshots -Raw
    $iss.Commands.Add((New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry('Restore-VMAndSnapshots', $functionDef)))
    
    # 使用初始化会话状态创建RunspacePool
    $runspacePool = [RunspaceFactory]::CreateRunspacePool(1, 10, $iss, $host)
    
  • 缺失错误处理机制
    原脚本未捕获BeginInvoke/EndInvoke过程中的错误,无法定位具体失败原因。添加错误处理:

    $results = $jobs | ForEach-Object { $_.BeginInvoke() }
    
    foreach ($job in $jobs) {
        try {
            $job.EndInvoke($results[$jobs.IndexOf($job)])
            # 检查是否有错误
            if ($job.HadErrors) {
                Write-Error "VM恢复失败: $($job.Streams.Error[0].Exception.Message)"
            }
        } catch {
            Write-Error "执行恢复时出错: $_"
        } finally {
            $job.Dispose()
        }
    }
    

修复后的完整示例脚本

# 假设Restore-VMAndSnapshots函数已在当前会话定义
function Restore-VMAndSnapshots {
    param (
        [string]$SubscriptionId,
        [string]$ResourceGroupName,
        [string]$VMName
    )
    # 原单VM恢复逻辑
    # ...
}

function Restore-VMsInParallel {
    param (
        [array]$VMsInfo
    )

    # 获取当前Azure上下文
    $currentAzContext = Get-AzContext
    # 创建初始化会话状态,注入自定义函数
    $iss = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
    $functionDef = Get-Content Function:\Restore-VMAndSnapshots -Raw
    $iss.Commands.Add((New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry('Restore-VMAndSnapshots', $functionDef)))

    # 创建正确的Runspace池,设置最小/最大并发数
    $runspacePool = [RunspaceFactory]::CreateRunspacePool(1, 10, $iss, $host)
    $runspacePool.Open()

    $jobs = @()

    foreach ($vmInfo in $VMsInfo) {
        $job = [PowerShell]::Create().AddScript({
            param ($info, $azContext)
            Set-AzContext -Context $azContext | Out-Null
            Restore-VMAndSnapshots -SubscriptionId $info.SubscriptionId -ResourceGroupName $info.ResourceGroupName -VMName $info.VMName
        }).AddArgument($vmInfo).AddArgument($currentAzContext)

        $job.RunspacePool = $runspacePool
        $jobs += $job
    }

    $results = $jobs | ForEach-Object { $_.BeginInvoke() }

    # 处理结果并捕获错误
    foreach ($job in $jobs) {
        try {
            $output = $job.EndInvoke($results[$jobs.IndexOf($job)])
            if ($job.HadErrors) {
                Write-Error "VM [$($job.Arguments[0].VMName)] 恢复失败: $($job.Streams.Error[0].Exception.Message)"
            } else {
                Write-Host "VM [$($job.Arguments[0].VMName)] 恢复成功"
            }
        } catch {
            Write-Error "处理VM [$($job.Arguments[0].VMName)] 时出错: $_"
        } finally {
            $job.Dispose()
        }
    }

    $runspacePool.Close()
    $runspacePool.Dispose()
}

# 读取CSV并转换为VM信息数组
$csvFilePath = "C:\CSV\file.csv"
$vms = Import-Csv -Path $csvFilePath

$vmInfoArray = $vms | ForEach-Object {
    [PSCustomObject]@{
        ResourceGroupName = $_.ResourceGroupName
        VMName = $_.VMName
        SubscriptionId = $_.SubscriptionId
    }
}

# 执行并行恢复
Restore-VMsInParallel -VMsInfo $vmInfoArray

内容的提问来源于stack exchange,提问作者Kalai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 05:54:58