代码之家  ›  专栏  ›  技术社区  ›  David Gard

PowerShell函数不接受对象数组

  •  3
  • David Gard  · 技术社区  · 7 年前

    在PowerShell中,我有一个需要传递给函数的对象数组。该函数随后将循环遍历数组中的所有对象,但它似乎没有正确接受参数值。

    以下面的示例为例,其中我传递了一个包含两个对象的数组。我希望数组的计数在函数之前和函数内部都是2,但一旦它到达函数,计数就是1,我的输入就不符合预期;只发现最后一个对象。

    我是在这里遗漏了什么,还是这是PowerShell中的一个bug?

    示例代码

    ### I've also tries '[object]', '[array]' and '[array[]]' as the type for '$testArr'.
    function Test-PassArrayOfObjects
    {
        param(
            [parameter(Mandatory,ValueFromPipeline)]
            [object[]]$testArr
        )
        Write-Host "In function count: $($testArr.Count)"
        $testArr | ForEach-Object { $_ }
    }
    
    $test1 = New-Object –TypeName PSObject
    $test1 | Add-Member -MemberType NoteProperty -Name Test1 -Value Value1
    $test2 = New-Object –TypeName PSObject
    $test2 | Add-Member -MemberType NoteProperty -Name Test2 -Value Value2
    $testArr = @($test1, $test2)
    
    $testArr.GetType() | Format-Table
    Write-Host "Before function count: $($testArr.Count)"
    $testArr | Test-PassArrayOfObjects
    

    示例代码的输出

    IsPublic IsSerial Name     BaseType                                                                                                                                                                                              
    -------- -------- ----     --------                                                                                                                                                                                              
    True     True     Object[] System.Array                                                                                                                                                                                          
    
    
    Before function count: 2
    In function count: 1
    
    Test2 
    ----- 
    Value2
    

    工作修复程序

    根据下面的答案,我有一个工作示例,我能够将其应用到我的实际生活场景中。

    function Test-PassArrayOfObjects
    {
        param(
            [parameter(Mandatory,ValueFromPipeline)]
            [object]$testArr
        )
        Process {
            Write-Host "In function count: $($testArr.Count)"
            $testArr
        }
    }
    
    $test1 = New-Object –TypeName PSObject
    $test1 | Add-Member -MemberType NoteProperty -Name Test1 -Value Value1
    $test1 | Add-Member -MemberType NoteProperty -Name Test2 -Value Value2
    $test2 = New-Object –TypeName PSObject
    $test2 | Add-Member -MemberType NoteProperty -Name Test1 -Value Value1
    $test2 | Add-Member -MemberType NoteProperty -Name Test2 -Value Value2
    $testArr = @($test1, $test2)
    
    $testArr.GetType() | Format-Table
    Write-Host "Before function count: $($testArr.Count)"
    $testArr | ForEach-Object { $_ | Test-PassArrayOfObjects }
    
    1 回复  |  直到 7 年前
        1
  •  7
  •   Mark Wragg    7 年前

    通过管道向函数发送输入时,函数应包括 Process 块:

    function Test-PassArrayOfObjects
    {
        param(
            [parameter(Mandatory,ValueFromPipeline)]
            [object[]]$testArr
        )
        Process {
            Write-Host "In function count: $($testArr.Count)"
            $testArr | ForEach-Object { $_ }
        }
    }
    

    这是必要的,因为我相信管道处理集合的方式。它会自动展开并一次处理一个项目,因此您的 ForEach-Object 没有得到整个系列 $testArr 变量

    您经常看到这样的函数仍然包含 ForEach 不过,如果输入是通过参数发送的,那么它会一次收到。例如: Test-PassArrayOfObjects -TestArr @(1,2,3) .

    数组有两个具有不同属性的对象,这一事实进一步混淆了您的问题。这会在输出中造成混淆,因为PowerShell决定如何基于第一个对象设置输出格式,并在输出第二个对象时使用相同的格式,但您看不到它,因为它不共享任何相同的属性(我认为这就是正在发生的情况……)。

    您可以看到,这两个对象都是通过放置 | Format-List $_ 强制将两个输出单独格式化为列表输出。请注意,这当然不是实际功能场景中的良好实践。另一种方法是在两个对象上都设置属性名称 Test1 . 然后,您将看到您可能期望的输出,而不使用 Format-List .