0

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!

1 Answer 1

3

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
Sign up to request clarification or add additional context in comments.

1 Comment

I was thinking about a built-in solution but thanks for providing the code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.