【问题标题】:Access Parent Property Within Pipeline访问管道内的父属性
【发布时间】:2016-11-09 22:00:10
【问题描述】:

我有一个 PSObject[],我们可以称之为 $DeviceFW,它有两个我关心的孩子:Bay(字符串)和Components(Object[]),它本质上只是一个数组的哈希表。我要做的是将组件导出到 CSV,每行列出相应的 Bay。

$DeviceFW.Components | Export-Csv "FW.csv" -NoTypeInformation 几乎是完美的,只是它缺少 Bay 列和信息。

$DeviceFW | Select Bay,Components | Export-Csv "FW.csv" -NoTypeInformation 具有 Bay 列和正确的信息,但 Components 仅在单个列中显示为“System.Management.Automation.PSObject[]”

不知何故,我需要一种方法来导出扩展的组件,同时为各个托架添加一列。我想到的是一些神奇的方法来从组件选择管道中解决父级的其他属性(Bay),例如:#$DeviceFW.Components | Select-Object @{Name='Bay';Expression={$_.Parent.Bay}},*。不过,我对 PowerShell 还是很陌生,所以我确信这完全不适用。也许我应该只用循环解决它,而放弃管道?

以下是我所追求的示例...

$DeviceFW:
    Bay: 1
    Components: {@{Name=ROM;Ver=A;ISO=A},@{Name=PWR;Ver=B;ISO=B}}
    Bay: 2
    Components: {@{Name=ROM;Ver=C;ISO=C},@{Name=PWR;Ver=D;ISO=D}}

... 应输出为:

Bay | Name | Ver | ISO
-----------------------
1   | ROM  |  A  |  A
-----------------------
1   | PWR  |  B  |  B
-----------------------
2   | ROM  |  C  |  C
-----------------------
2   | PWR  |  D  |  D

【问题讨论】:

  • 组件的数量是否总是相同的?如果对象名称与Export-CSV 所期望的名称相同,这只会在没有循环的情况下起作用
  • 从您的示例中,$DeviceFW 是一个对象数组,而不是对象本身。准确吗?

标签: powershell csv


【解决方案1】:

从您提供的示例中,我构建了您的数组/对象,如下所示:

$DeviceFW = @(
[PSCustomObject]@{
    'Bay' = '1'
    'Components'=@(
        [pscustomobject]@{'Name'='ROM';'Ver'='A';'ISO'='A'},
        [pscustomobject]@{'Name'='PWR';'Ver'='B';'ISO'='B'}
    )},
[PSCustomObject]@{
    'Bay' = '2'
    'Components'=@(
        [pscustomobject]@{'Name'='ROM';'Ver'='C';'ISO'='C'},
        [pscustomobject]@{'Name'='PWR';'Ver'='D';'ISO'='D'}
    )}
)

那是一个对象数组,每个对象包含两个属性,Bay是一个字符串,Components是一个对象数组。 Components 中的每个对象都包含三个属性,NameVerISO,每个属性都是一个字符串。当我执行$DeviceFW|FL 时,我得到:

Bay        : 1
Components : {@{Name=ROM; Ver=A; ISO=A}, @{Name=PWR; Ver=B; ISO=B}}

Bay        : 2
Components : {@{Name=ROM; Ver=C; ISO=C}, @{Name=PWR; Ver=D; ISO=D}}

到目前为止,这与您的示例相匹配。为了获得您想要的所需 CSV,我会将其通过 ForEach 循环:

Foreach($record in $DeviceFW){
    $record.components|select @{l='Bay';e={$record.bay}},*|Export-Csv c:\temp\output.csv -NoTypeInformation -Append
}

即输出文件:

"Bay","Name","Ver","ISO"
"1","ROM","A","A"
"1","PWR","B","B"
"2","ROM","C","C"
"2","PWR","D","D"

【讨论】:

  • 哇,事后看来如此清晰!这很好用,谢谢。
【解决方案2】:
$DeviceFW | ForEach-Object{
    $props = @{}
    $props.bay = $_.Bay
    $_.Components | ForEach-Object{
        $_.GetEnumerator() | ForEach-Object{
            $props.($_.Name) = $_.Value
        }
        New-Object -TypeName PsCustomObject -Property $props
    }

} | Select-Object Bay,Name,Ver,ISO | Export-Csv "FW.csv" -NoTypeInformation

使用上述内容创建具有示例属性的对象。我试图把它做成一个单线,但它很快就变得复杂了。

对于每一个$DeviceFW,我都构建了一个新的属性哈希表,该哈希表首先填充了 Bay #。获取组件并将它们传递到 for each 循环中,以将它们分解为您拥有的两个哈希表。使用每个哈希表枚举它们以作为对象获取访问权限,以便我们可以使用每个组件的名称和值对填充$props。每个组件都通过管道发送,其 Bay 编号作为参数。使用 select 语句强制字段顺序并发送到Export-Csv。这可以通过获取组件并使用 Add-Member 添加 Bay 来简化。

更短的

$DeviceFW | ForEach-Object{
    $Bay = $_.Bay
    $_.Components | ForEach-Object{
        New-Object PSObject -property $_ | Add-Member -MemberType NoteProperty -Name "Bay" -Value $Bay -PassThru
    }  
} | Select-Object Bay,Name,Ver,ISO | Export-Csv "FW.csv" -NoTypeInformation

我愚蠢地试图重新发明轮子。由于每个组件已经是一个哈希表,我不需要重新创建它。取出每个组件并用它制作一个对象。获取该对象并为当前托架添加一个成员。

导出前的输出

我的两个例子都是一样的。这应该很好地导出到 csv。

             Bay Name                 Ver                  ISO                
             --- ----                 ---                  ---                
               1 ROM                  A                    A                  
               1 PWR                  B                    B                  
               2 ROM                  C                    C                  
               2 PWR                  D                    D       

仅供参考

我使用以下内容创建了我的示例对象以供上述代码处理。

$DeviceFW = @()
$DeviceFW += [pscustomobject]@{
    Bay = 1
    Components = @{Name="ROM";Ver="A";ISO="A"},@{Name="PWR";Ver="B";ISO="B"}
}
$DeviceFW += [pscustomobject]@{
    Bay = 2
    Components = @{Name="ROM";Ver="C";ISO="C"},@{Name="PWR";Ver="D";ISO="D"}
}

【讨论】:

  • 感谢您的回答,马特!我最终使用了@TheMadTechnician 的解决方案来解决这个特殊情况,但我仍然从你的帖子中获得了一些非常有用的见解。我很感激!
【解决方案3】:

我喜欢上面给出的两个答案,它们都帮助我理解了如何实现这一点。我尝试将它们结合起来创建一个解决方案,根据马特的回答只使用一行,但根据 TheMadTechnician 的回答稍微简单一些。使用 TheMadTechnician 的答案中创建的 $DeviceFW 对象(我更喜欢这个,因为组件是一个对象数组,而不是 Matt 的答案中的哈希表数组,因此在使用时每天遇到的对象更典型PowerShell)我最终得到了以下解决方案。

$DeviceFW|ForEach-Object{$Bay = $_.Bay;$_.components|ForEach-Object{$_|Select-Object *,@{label='Bay';expression={$Bay}}}}|Export-Csv "FW.csv" -NoTypeInformation

【讨论】:

    猜你喜欢
    • 2020-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多