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

无法将脚本块传入ForEach-Object与Invoke-Command循环的问题

解决PowerShell中ForEach-Object -Parallel传递命令字符串到Invoke-Command的问题

问题原因

你的代码存在两层脚本块嵌套:ForEach-Object -Parallel的并行块,以及Invoke-Command的远程执行块。$using:作用域只能穿透一层脚本块边界,直接在远程脚本块里用$using:s会因为作用域无法识别而报错;而直接写{$s}的话,远程会话里不存在s变量,所以无报错但不会执行任何操作。

修正后的代码(方案一:通过参数传递)

Write-Host "Enter your administrative credentials" -ForegroundColor Blue
$credential = Get-Credential ''
$s = Read-Host "Enter your cmd script here"
$complist = Get-Content "C:\PowershellCMDs\Temp\searchresults.txt"

$complist | ForEach-Object -Parallel {
    Invoke-Command -ComputerName $_ -Credential $using:credential -ScriptBlock {
        param($command)
        # 针对cmd命令,用cmd /c执行
        cmd /c $command
    } -ArgumentList $using:s
} -ThrottleLimit 16

Write-Host "Task Complete" -BackgroundColor Green

修正后的代码(方案二:中间变量中转)

Write-Host "Enter your administrative credentials" -ForegroundColor Blue
$credential = Get-Credential ''
$s = Read-Host "Enter your cmd script here"
$complist = Get-Content "C:\PowershellCMDs\Temp\searchresults.txt"

$complist | ForEach-Object -Parallel {
    # 先把外层的$s通过$using:拿到并行块本地
    $localCmd = $using:s
    Invoke-Command -ComputerName $_ -Credential $using:credential -ScriptBlock {
        # 再从并行块本地传递到远程会话
        cmd /c $using:localCmd
    }
} -ThrottleLimit 16

Write-Host "Task Complete" -BackgroundColor Green

关键说明

  1. 因为你输入的是cmd命令(比如sfc /scannow),所以远程脚本块里需要用cmd /c来执行,否则PowerShell会把命令当作PS命令解析,可能出现错误。
  2. 方案一通过Invoke-Command的-ArgumentList参数传递命令字符串,远程脚本块用param接收后执行,是最稳妥的跨会话参数传递方式。
  3. 方案二先在并行块内把外层变量存入本地变量,再通过$using:传递到远程会话,适合多层嵌套场景。

后续跟踪执行进度的思路

可以通过PowerShell作业来跟踪每台机器的命令执行状态,示例代码如下:

Write-Host "Enter your administrative credentials" -ForegroundColor Blue
$credential = Get-Credential ''
$s = Read-Host "Enter your cmd script here"
$complist = Get-Content "C:\PowershellCMDs\Temp\searchresults.txt"

# 创建并行作业
$jobs = $complist | ForEach-Object -Parallel {
    $localCmd = $using:s
    $localCred = $using:credential
    # 为每个机器创建独立作业,命名便于识别
    Start-Job -Name "Cmd_$_" -ScriptBlock {
        param($computer, $cred, $command)
        try {
            $result = Invoke-Command -ComputerName $computer -Credential $cred -ScriptBlock {
                cmd /c $command 2>&1
            }
            return @{Computer = $computer; Status = 'Success'; Output = $result}
        } catch {
            return @{Computer = $computer; Status = 'Failed'; Error = $_.Exception.Message}
        }
    } -ArgumentList $_, $localCred, $localCmd
} -ThrottleLimit 16

# 实时跟踪作业进度
do {
    $runningCount = ($jobs | Where-Object {$_.State -eq 'Running'}).Count
    $completedCount = ($jobs | Where-Object {$_.State -in 'Completed', 'Failed'}).Count
    Write-Host "Progress: $completedCount completed / $runningCount running"
    Start-Sleep -Seconds 3
} while ($runningCount -gt 0)

# 接收所有作业结果
$allResults = $jobs | Receive-Job -Wait -AutoRemoveJob
# 输出结果
$allResults | Format-Table Computer, Status, Output, Error -AutoSize

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 21:43:15