如何使用 Format-Table cmdlet 显示所有属性

How to display all properties with Format-Table cmdlet

我有几个 [pscustomobject] 对象不能拥有所有属性。

例如:

PS>  = [pscustomobject]@{ A='a1'; B='b1' }
PS>  = [pscustomobject]@{ A='a2'; C='c2' }

我尝试像这样显示 Format-Table 的所有属性:

PS> , | Format-Table

A  B
-  -
a1 b1
a2

PS> , | Format-Table

A  C
-  -
a2 c2
a1

但每次它只显示集合中第一个对象的属性。

我想显示所有属性,就像我设置 -Property 参数 明确地

PS> , | Format-Table -Property A,B,C

A  B  C
-  -  -
a1 b1
a2    c2

设置 -Property 参数是好的,如果:

  1. 所有属性集都是预先知道的
  2. 集合很小,我可以通过 Get-Member -MemberType Properties
  3. 获取所有属性

但是我有一个巨大的集合(超过 10000 个对象)具有未知属性,所以我需要帮助。

备注: Format-Table 将仅用于小切片(10-100 个元素)。

为此,您可以使用以下函数将所有属性合并到第一个对象中:

function Complete-ObjectHeaders {
    # function to add properties to the first item in a collection of PSObjects
    # when this object is missing properties from items further down the array.
    # you may need this if you have such a collection and want to export it
    # to Csv, since Export-Csv (and also Format-Table) only looks at the FIRST
    # item to create the csv column headers.
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [PSObject[]]$Collection,

        [int]$MaxItemsToTest = -1,  # < 0 --> test all items in the collection
        [switch]$SortHeaders
    ) 

    # Try and find all headers by looping over the items in the collection.
    # The headers will be captured in the order in which they are found. 
    if ($MaxItemsToTest -gt 0) {
        $MaxItemsToTest = [math]::Min($MaxItemsToTest, $Collection.Count)
        $headers = for($i = 0; $i -lt $MaxItemsToTest; $i++) {
            ($Collection[$i].PSObject.Properties).Name
        }
        $headers = $headers | Select-Object -Unique
    }
    else {
        $headers = $Collection | ForEach-Object {($_.PSObject.Properties).Name} | Select-Object -Unique
    }

    if ($SortHeaders) { $headers = $headers | Sort-Object }

    # update the first object in the collection to contain all headers
    $Collection[0] = $Collection[0] | Select-Object $headers

    ,$Collection
}

这样使用:

 = [pscustomobject]@{ A='a1'; B='b1' }
 = [pscustomobject]@{ A='a2'; C='c2' }

# just output to console
Complete-ObjectHeaders -Collection , | Format-Table -AutoSize

# or capture the merged array of objects in a new variable you can save as CSV file for instance
$merged = Complete-ObjectHeaders -Collection ,
$merged | Export-Csv -Path 'D:\Test\Merged.csv' -NoTypeInformation

输出:

A  B  C 
-  -  - 
a1 b1   
a2    c2

感谢@theo

我用它编写了我自己的 函数 版本,它支持 流水线

function Expand-Properties {
  [Cmdletbinding()]
  param(
    [Parameter(ValueFromPipeline)]
    $InputObject,
    [Parameter()]
    [Alias('All')]
    [switch]
    $ExpandAll,
    [Parameter()]
    [switch]
    $SortHeaders
  )

  begin {
    $collection = [System.Collections.ArrayList]::new()
    $properties = [System.Collections.ArrayList]::new()
  }

  process {
    [void]$collection.Add($InputObject)
    $properties.AddRange((($InputObject.PSObject.Properties).Name))
  }

  end {
    if ($SortHeaders) {
      $properties = $properties | Sort-Object -Unique
    } else {
      $properties = $properties | Select-Object -Unique
    }
    if ($ExpandAll) {
      for ($i = 0; $i -lt $collection.Count; ++$i) {
        $collection[$i] = $collection[$i] | Select-Object -Property $properties
      }
    } else {
      $collection[0] = $collection[0] | Select-Object -Property $properties
    }
    $collection
  }
}

示例:

PS>  = [pscustomobject]@{ A='a1'; B='b1' }
PS>  = [pscustomobject]@{ A='a2'; C='c2' }
PS> ,  | Expand-Properties

A  B  C 
-  -  - 
a1 b1   
a2    c2