mrt
mrt

Reputation: 317

Powershell: Format-Table on object of objects?

I have a array list of PSCustomObjects that I can output with Format-Table and looks like expected.

Name    Property1   Property2   Property3
----    ---------   ---------   ---------
name1   value1      value2      value3

Now it happens, that one property of the PSCustomObject needs to hold two (or more) values, so I decided to follow an object-oriented approach and change that property to a PSCustomObject also, ending up in a list of objects containing objects, then the output looks like this:

Name    Property1   Property2                     Property3
----    ---------   ---------                     ---------
name1   value1      @{Sub1=valueX; Sub2=valueY}   value3

What I am searching for is some sort of recursively output of Format-Table, which expands the object inside, to look something like this:

Name    Property1   Sub1     Sub2     Property3
----    ---------   ----     ----     ---------
name1   value1      valueX   valueY   value3

Is this possible anyhow? Or do I have to fallback to "normal" lists when building up that object list?

thank you!

Upvotes: 0

Views: 1518

Answers (1)

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174485

All you need to do recursively is discover that "paths" to the leaf values and then generate property expression selectors for them:

function Format-FlatTable {
  [CmdletBinding()]
  param(
    [Parameter(ValueFromPipeline=$true)]
    [psobject]$InputObject
  )

  begin {
    function Get-FlatSelector {
      param(
        [psobject]$Object,
        [string]$Prefix
      )

      # Enumerate all properties
      $object.psobject.Properties |ForEach-Object {
        # Nested custom object, let's recurse
        if($_.Value -is [System.Management.Automation.PSCustomObject]){
          Get-FlatSelector $_.Value -Prefix $_.Name 
        }
        else {
          if($prefix){
            # We're not at the root level anymore, construct a property expression table
            @{Name="$prefix.$($_.Name)";Expression=[scriptblock]::Create("`$_.$prefix.$($_.Name)")}
          }
          else{
            # Still at the root level, we can select value properties by name alone
            $_.Name
          }
        }
      }
    }
  }

  process
  {
    # Use the first input object to determine how to flatten
    $selectors = Get-FlatSelector $InputObject[0]

    # Use `Format-Table` to only select flattened property values
    $InputObject |Format-Table $selectors
  }
}

Which would produce a table format like the one you want, but without any naming collisions:

[pscustomobject]@{
  Name='Name1'
  Property1 = 'value1'
  Property2 = [pscustomobject]@{
    Sub1 = 'valueX'
    Sub2 = 'ValueY'
  }
  Property3 = 'value3'
} |Format-FlatTable

Output:

Name  Property1 Property2.Sub1 Property2.Sub2 Property3
----  --------- -------------- -------------- ---------
Name1 value1    valueX         ValueY         value3

Upvotes: 3

Related Questions