powershell cmdlet always outputting a table whose columns are selectable by the user

Viewed 116

If the below only has 4 columns, I get a table that can be further trimmed with select. But if I add more fields, the output becomes a list.

How to make this always a table without breaking the subsequent select as Format-table does? The initial table will come from a cmdlet and the user will do the subsequent select returns a table like I want

$c = New-Object System.Collections.ArrayList

for($i = 0; $i -lt 5; $i++)
{
    $temp = New-Object System.Object
    $temp | Add-Member -MemberType NoteProperty -Name "Field1" -Value "Value1"
    $temp | Add-Member -MemberType NoteProperty -Name "Field2" -Value "Value2"
    $temp | Add-Member -MemberType NoteProperty -Name "Field3" -Value "Value3"
    $temp | Add-Member -MemberType NoteProperty -Name "Field4" -Value "Value4"
    $c.Add($temp) | Out-Null
}
$c
Field1 Field2 Field3 Field4
------ ------ ------ ------
Value1 Value2 Value3 Value4
Value1 Value2 Value3 Value4
Value1 Value2 Value3 Value4
Value1 Value2 Value3 Value4
Value1 Value2 Value3 Value4

I can still use select

$c | select Field1
Field1
------
Value1
Value1
Value1
Value1
Value1

More fields will not give me a table , but a list

$c = New-Object System.Collections.ArrayList
for($i = 0; $i -lt 10; $i++)
{
    $temp = New-Object System.Object
    $temp | Add-Member -MemberType NoteProperty -Name "Field1" -Value "Value1"
    $temp | Add-Member -MemberType NoteProperty -Name "Field2" -Value "Value2"
    $temp | Add-Member -MemberType NoteProperty -Name "Field3" -Value "Value3"
    $temp | Add-Member -MemberType NoteProperty -Name "Field4" -Value "Value1"
    $temp | Add-Member -MemberType NoteProperty -Name "Field5" -Value "Value2"
    $temp | Add-Member -MemberType NoteProperty -Name "Field6" -Value "Value3"
    $temp | Add-Member -MemberType NoteProperty -Name "Field7" -Value "Value1"
    $temp | Add-Member -MemberType NoteProperty -Name "Field8" -Value "Value2"
    $temp | Add-Member -MemberType NoteProperty -Name "Field9" -Value "Value3"

    $c.Add($temp) | Out-Null
}
$c


Field1 : Value1
Field2 : Value2
Field3 : Value3
Field4 : Value1
Field5 : Value2
Field6 : Value3
Field7 : Value1
Field8 : Value2
Field9 : Value3
.... 

Using format-table I can make this look like a table

$c = New-Object System.Collections.ArrayList
for($i = 0; $i -lt 5; $i++)
{
    $temp = New-Object System.Object
    $temp | Add-Member -MemberType NoteProperty -Name "Field1" -Value "Value1"
    $temp | Add-Member -MemberType NoteProperty -Name "Field2" -Value "Value2"
    $temp | Add-Member -MemberType NoteProperty -Name "Field3" -Value "Value3"
    $temp | Add-Member -MemberType NoteProperty -Name "Field4" -Value "Value4"
    $temp | Add-Member -MemberType NoteProperty -Name "Field5" -Value "Value5"
    $c.Add($temp) | Out-Null
}
$c2

Field1 Field2 Field3 Field4 Field5
------ ------ ------ ------ ------
Value1 Value2 Value3 Value4 Value5
Value1 Value2 Value3 Value4 Value5
Value1 Value2 Value3 Value4 Value5
Value1 Value2 Value3 Value4 Value5
Value1 Value2 Value3 Value4 Value5

But now I can not further select

$c2 | select Field1

Field1
------
2 Answers

Update Remove previous reponse

As per your last comment in our exchange:

What I am looking for is to always return a table from my cmdlet, ... My cmdlet has parameters which will control the most common columns. , but then let the user for select form that as needed. ...

As we've shared, anything greater than 4 columns will become a list by default unless you alter the default PowerShell formatting code, or you send to Out-GridView or you send it to a CSV etc.

If you are saying, you want the user to be able to select any field(s), regardless of the amount and only get back a table in a screen display only, then you have to code for that using the default Out-GridView or a custom Out-GridView object or Format-Table.

So, you present the dataset you want the user to select from, get the count of that selection, then use logic to check for the count. If it is 4 or below, then accept the default output, else use Format-Table or Out-GridView

If ($c.Count -le 4)
{
    # Do default
}
Else
{
    # Do custom formatting
}
  

So, this...

$c = New-Object System.Collections.ArrayList

for($i = 0; $i -lt 5; $i++)
{
    $temp = New-Object System.Object
    $temp | Add-Member -MemberType NoteProperty -Name "Field1" -Value "Value1"
    $temp | Add-Member -MemberType NoteProperty -Name "Field2" -Value "Value2"
    $temp | Add-Member -MemberType NoteProperty -Name "Field3" -Value "Value3"
    $temp | Add-Member -MemberType NoteProperty -Name "Field4" -Value "Value4"
    $c.Add($temp) | Out-Null
}

$c
# Results
<#
Field1 Field2 Field3 Field4
------ ------ ------ ------
Value1 Value2 Value3 Value4
Value1 Value2 Value3 Value4
Value1 Value2 Value3 Value4
Value1 Value2 Value3 Value4
Value1 Value2 Value3 Value4

#>

If ($c.Count -le 4)
{
    # Do default
    $c
}
Else
{
    # Do custom formatting
    $c |
     FOrmat-Table -AutoSize
}

# Results
<#
Field1 Field2 Field3 Field4
------ ------ ------ ------
Value1 Value2 Value3 Value4
Value1 Value2 Value3 Value4
Value1 Value2 Value3 Value4
Value1 Value2 Value3 Value4
Value1 Value2 Value3 Value4
#>

$c = New-Object System.Collections.ArrayList

for($i = 0; $i -lt 5; $i++)
{
    $temp = New-Object System.Object
    $temp | Add-Member -MemberType NoteProperty -Name "Field1" -Value "Value1"
    $temp | Add-Member -MemberType NoteProperty -Name "Field2" -Value "Value2"
    $temp | Add-Member -MemberType NoteProperty -Name "Field3" -Value "Value3"
    $temp | Add-Member -MemberType NoteProperty -Name "Field4" -Value "Value4"
    $temp | Add-Member -MemberType NoteProperty -Name "Field5" -Value "Value5"
    $c.Add($temp) | Out-Null
}
$c
# Results
<#
Field1 : Value1
Field2 : Value2
Field3 : Value3
Field4 : Value4
Field5 : Value5

...
#>

If ($c.Count -le 4)
{
    # Do default
    $c
}
Else
{
    # Do custom formatting
    $c |
     Format-Table -AutoSize
}
# Results
<#
Field1 Field2 Field3 Field4 Field5
------ ------ ------ ------ ------
Value1 Value2 Value3 Value4 Value5
Value1 Value2 Value3 Value4 Value5
Value1 Value2 Value3 Value4 Value5
Value1 Value2 Value3 Value4 Value5
Value1 Value2 Value3 Value4 Value5
#>

Or

$C | 
Out-GridView -Title 'You selected the listed fields.' -PassThru 

or the same thing using a custom object (as Lee suggests) if you are trying to stay in the console, vs sending to a GUI.

Btw, in PSCore (v7) there is a new console version of Out-GridView. Before you ask, no, it will not be backported.

Your other option is to leverage: Powershell Format-Custom, but that to is a coding effort.

To override PowerShell's default output formatting rules - implied Format-Table for types with 4 or fewer (public) properties, implied Format-List for 5 or more - you need to:

This will make PowerShell automatically format instances of your self-chosen type per the instructions provided in the formatting data, without the need to use Format-* cmdlet calls explicitly, whose output would prevent further programmatic processing.

Here's a self-contained example, using self-chosen type name MyType, which formats instances of that type in tabular format based on 5 columns:

# Create a formatting-data file for self-chosen type 'MyType',
# defining a 5-column tabular view as the (implied) default.
@'
<Configuration>
<ViewDefinitions>
    <View>
      <Name>MyTypeTable</Name>
      <ViewSelectedBy>
        <TypeName>MyType</TypeName>
      </ViewSelectedBy>
      <TableControl>
        <TableRowEntries>
          <TableRowEntry>
            <TableColumnItems>
              <TableColumnItem>
                <PropertyName>Prop1</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Prop2</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Prop3</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Prop4</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Prop5</PropertyName>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
  </ViewDefinitions>
</Configuration>
'@ > MyType.Format.ps1xml

# Load the formatting data into the current session.
Update-FormatData -AppendPath MyType.Format.ps1xml

# Create and output an instance of self-chosen type 'MyType',
# which will render in tabular form as per the formatting data
# defined and loaded above.
[pscustomobject] @{ 
  PSTypeName = 'MyType'
  Prop1 = 1
  Prop2 = 2
  Prop3 = 3
  Prop4 = 4
  Prop5 = 5
}

The above outputs the following to the console (host), showing that the explicitly defined formatting data took effect:


Prop1 Prop2 Prop3 Prop4 Prop5
----- ----- ----- ----- -----
1     2     3     4     5


[1] See the bottom section of this answer for more information about the [psobject] / [pscustomobject] type.

Related