如何将-PipelineVariable参数与并行处理其输入的cmdlet一起使用?

时间:2014-11-08 00:54:33

标签: powershell pipeline powershell-remoting powershell-v4.0

我正在查询Active Directory以获取计算机列表,并使用Invoke-Command从每个计算机中检索数据。因为我为每台计算机调用Invoke-Command两次 - 一次使用-FilePath参数,一次使用-ScriptBlock参数 - 我使用New-PSSession为每台计算机创建一个会话时间由于要处理的计算机列表可能很长,我依赖的事实是,当将-ComputerName参数的多个值传递给New-PSSession cmdlet时,它会并行启动连接。

每台计算机的输出为PSObject,其中包含对Invoke-Command的调用结果以及有关计算机的信息;我使用-PipelineVariable通用参数来保存管道中较早的信息。但是,我发现,在我的最后ForEach-Object块中,$_变量(PSSession对象)并不总是与$computerInfo变量匹配(管道对象存储Active Directory计算机信息);我在具有不同会话的行中$computerInfo多次迭代获得相同的值。我插入了一些调试代码,用于说明在调用$computerInfo之前和之后New-PSSession的值如何不同:

$sessionOption = New-PSSessionOption -NoMachineProfile;

Get-ADComputer -Filter $computerFilter -Properties 'Description', 'OperatingSystem' `
    | Where-Object -Property 'DistinguishedName' -Match -Value $DistinguishedNamePattern `
        -PipelineVariable 'computerInfo' `
    | Select-Object -First 10 `
    | ForEach-Object {
        Write-Host "Before New-PSSession: $($computerInfo.Name)";

        return $_;
    } `
    | Select-Object -ExpandProperty 'Name' `
    | New-PSSession -SessionOption $sessionOption `
    | ForEach-Object {
        Write-Host " After New-PSSession: $($computerInfo.Name)";

        $session = $_;    
        try
        {
            New-Object -TypeName 'PSObject' -Property @{
                DistinguishedName   = $computerInfo.DistinguishedName;
                Computer            = $computerInfo.Name;
                OperatingSystem     = $computerInfo.OperatingSystem;
                Description         = $computerInfo.Description;
                InvokeScriptResult1 = Invoke-Command -FilePath    $scriptPath  -Session $session;
                InvokeScriptResult2 = Invoke-Command -ScriptBlock $scriptBlock -Session $session;
            };
        }
        finally
        {
            Remove-PSSession -Session $session;
        }
    };

以下是一些示例控制台输出:

Before New-PSSession: COMPUTER1
Before New-PSSession: COMPUTER2
Before New-PSSession: COMPUTER3
 After New-PSSession: COMPUTER3
 After New-PSSession: COMPUTER3
Before New-PSSession: COMPUTER4
 After New-PSSession: COMPUTER4
Before New-PSSession: COMPUTER5
Before New-PSSession: COMPUTER6
Before New-PSSession: COMPUTER7
Before New-PSSession: COMPUTER8
 After New-PSSession: COMPUTER8
 After New-PSSession: COMPUTER8
Before New-PSSession: COMPUTER9
 After New-PSSession: COMPUTER9
Before New-PSSession: COMPUTER10
 After New-PSSession: COMPUTER10
 After New-PSSession: COMPUTER10
 After New-PSSession: COMPUTER10

请注意,在Before New-PSSession行中,所有十台计算机只出现一次,而在After New-PSSession行中,计算机3,8和10是重复的,计算机是1,2,5,6和7缺失。我也尝试将-ThrottleLimit 1传递给New-PSSession并获得类似的结果。

我怀疑这是同步问题。由于New-PSSession同时打开多台计算机的会话,因此每当它从管道中的早期提取计算机时,它将覆盖该计算机的$computerInfo。在我正在进行处理的管道中,它会看到相同的$computerInfo变量,因此当它处理输入序列中$computerInfo之前的会话时,包含刚开始连接的任何计算机New-PSSession至。这是一个错误吗?或者-PipelineVariableNew-PSSession这样的cmdlet不兼容?有没有办法可以在$_之后立即“捕获”$computerInfoNew-PSSession,以便它们始终保持同步?这就是我期望-PipelineVariable工作的方式,但似乎整个管道有一个$computerInfo实例,而不是每个对象通过管道传递一个。

1 个答案:

答案 0 :(得分:0)

在某些情况下,New-PSSession可能会在其EndProcessing覆盖中输出对象。很难说如果在这种情况下发生这种情况,但要解决这个问题,请更换:

| New-PSSession -SessionOption $sessionOption `

| Foreach {New-PSSession -Name $_ -SessionOption $sessionOption} `