2

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
------
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
deetle
  • 197
  • 8
  • 1
    **_use the correct cmdlet for the correct thing._** [*grin*] in this case, use `Select-Object` or a `[PSCustomObject]` for your working objects ... and `Format-Table` for **_display of those objects_** – Lee_Dailey Nov 14 '20 at 20:56
  • I can use format-table , but then the subsequent select doesn't work ( select and select-object is the same thing ) . Using [PSCustomObject] still turns into a list with 5 columns or more. – deetle Nov 14 '20 at 21:53
  • 3
    use `F-T` only ... **_only_** ... for final output to a screen or a plain text file. for all other uses, keep your objects AS OBJECTS. – Lee_Dailey Nov 14 '20 at 21:59
  • Have a look at [Out-GridView](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/out-gridview) if you want a table output no matter the amount of columns – Theo Nov 15 '20 at 11:51

2 Answers2

1

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.

postanote
  • 15,138
  • 2
  • 14
  • 25
  • Still doesn't work. the cmdlt returns the first part , not $c . So I can not do the subsequent select on $c , but on what is returned. The subsequent select still fails on that. – deetle Nov 14 '20 at 22:23
  • Note, I am using your exact code post, and the results you say you want are displaying on my system as shown. I am not doing anything special/different from what you say you are doing/after. If you are not getting the above default results, then something else is happening in your environment. What PS version are you using? What OS? How are you running this (ISE/VSCode/Something else)? I've validated your posted code in all environments notes and the results are the same as shown in my answer response. – postanote Nov 14 '20 at 22:46
  • Up to 4 columns it is a table. Once you have more it turns into a list. How to always keep it a table , and make subsequent selects still work. – deetle Nov 14 '20 at 22:54
  • PSVersion 5.1.19041.610 – deetle Nov 14 '20 at 22:55
  • 1
    Correct on the more than 4 formatting things,t that is the default (though you can change that too), but that still has no bearing on your select-object effort for specific fields, as shown in the results above. Even with the format table, once you get beyond your screen resolution (width), then its use case is moot and you have no other choice but to use a list or export to CSV or Out-GridView. What Lee and I are saying, is ignore the Format-Table, you don't need it for what your stated use case is, cherry picking fileds to use. – postanote Nov 14 '20 at 23:03
  • 1
    What I am looking for is to always return a table from my cmdlet, hence the post . My cmdlet has parameters which will control the most common columns. , but then let the user for select form that as needed. All the above suggestion do not do that. But yet get-process does exactly that. It has 8 columns. – deetle Nov 15 '20 at 05:16
1

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.

mklement0
  • 382,024
  • 64
  • 607
  • 775