如何在变量中存储 powershell 作业信息

How to store powershell job information in a variable

我目前有一个 powershell (v2) 脚本,它获取主机 PC 列表,远程检查一些 files/software 是否在它们应该在的位置,并在完成后通过电子邮件发送一串结果。但是,当尝试在 100 多个房间中一次一个地依次执行此操作时,脚本需要相当长的时间才能完成。

为了加快速度,我一直在尝试通过使用作业报告每个主机名来使脚本成为多线程。为了清楚起见,我将代码的主要部分放在下面,并删除了一些较大的不相关部分。

$pcHostNames = Get-Content "$scriptPath\HostNames.txt"

$scriptBlock = {
    Param(pcHostName)

    $softwareInstalled = $false

    # Test to see if host can be reached
    If (Test-Connection -ComputerName $pcHostName -Quiet)
    {
        # Multiple lines of code to check if different files/software are installed on each remote PC
        # If they are installed, set $softwareInstalled to true

        if (-not $softwareInstalled)
        {
            $reportList += "$pcHostName`: Not installed`n"
        }
        else
        {
            $reportList += "$pcHostName`: Fully installed`n"
        }
    }
    else
    {
        $reportList += "$pcHostName`: Error - Connection failed`n"
    }
} # End - $scriptBlock  

$pcHostNames | % { Start-Job -Scriptblock $scriptBlock -ArgumentList $_ } | Get-Job | Wait-Job | Receive-Job

目前,该脚本对 PC 执行 ping 命令,然后检查是否安装了各种 files/software,并将一个字符串添加到 $reportList,然后在电子邮件中使用该字符串在我的代码的另一部分发送报告。

由于 $reportList 超出了每个作业的范围,我得到的只是脚本末尾的空白电子邮件。由于无法从作业中将字符串值添加到变量,有没有办法将我的作业管道代码编辑为 return 一个字符串值,然后我可以将其添加到变量?

我认为这个问题可能与我的代码的最后一行有关,所以我尝试了几种不同的执行作业变体,但我在网上找到的东西并没有太多运气。

或者,是否有更好的方法通过其他方法多线程处理此脚本?

变量存在于它们被创建的范围内。

当您在作业中声明变量时,它们仅存在于该作业的范围内。

如果您想将详细信息从子作业传回给调用者,您需要使用 Write-Output。然后使用Get-Job监控作业的状态,直到完成,然后使用Receive-Job获取输出。

start-job {write-output "hello world"}
get-job | receive job

编辑:

以您的示例代码块为例,下面使用 write-output 从作业中获取 return 结果,过滤成功完成的作业,接收作业的输出并将它们存储在$reportList 变量

$pcHostNames = Get-Content "$scriptPath\HostNames.txt"

$scriptBlock = {
    Param(pcHostName)

    $softwareInstalled = $false

    # Test to see if host can be reached
    If (Test-Connection -ComputerName $pcHostName -Quiet)
    {
        # Multiple lines of code to check if different files/software are installed on each remote PC
        # If they are installed, set $softwareInstalled to true

        if (-not $softwareInstalled)
        {
            Write-Output "$pcHostName`: Not installed`n"
        }
        else
        {
            Write-Output "$pcHostName`: Fully installed`n"
        }
    }
    else
    {
        Write-Output "$pcHostName`: Error - Connection failed`n"
    }
} # End - $scriptBlock  

$pcHostNames | % {
    Start-Job -Scriptblock $scriptBlock -ArgumentList $_
}

$reportList = Get-Job | Wait-Job | ?{$_.state -eq "Completed"} | Receive-Job