Home > Software engineering >  Powershell - Get object properties displayed in console
Powershell - Get object properties displayed in console

Time:03-21

The point is to populate a variable with a Powershell object's property name displayed in a console. Meaning, if I run Get-Process, I only want the eight object's properties returned in the console which are 'Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName'.

Get-Member command is not helpful here.

Can anyone help me with that?

Thank you all!

CodePudding user response:

To get the column names - which may or may not be property names - of the table view that is presented for a given .NET type if it has predefined formatting data (that includes a table view) associated with it:

  • Note:
    • The following is a proper, but nontrivial solution that derives the column names from the formatting data, using the first table-view definition found. It also has conceptual background information.
    • See the bottom section for a quick-and-dirty solution, which uses text parsing to extract the column names directly from a given command's formatted output.
# Determine the .NET type of interest.
$type = (Get-Process)[0].GetType()

# Extract the names of the column headers from the *first* table-view definition.
Get-FormatData $type -PowerShellVersion $PSVersionTable.PSVersion | 
  ForEach-Object FormatViewDefinition | 
    Where-Object Control -is [System.Management.Automation.TableControl] | 
      Select-Object -First 1 |
        ForEach-Object { 
          $i = 0
          $rows = $_.Control.Rows
          foreach ($colLabel in $_.Control.Headers.Label) {
            if ($colLabel) { $colLabel } # Explicit label, typically with a calculated column value
            else            { $rows.Columns[$i].DisplayEntry.Value } # Property name, with its value as the column value.
              $i
          }
        }

Caveat: The above limits output to the first table-view definition found - which may or may not apply to a given command. Which definition is chosen by default is potentially governed by criteria associated with the definitions that select based on runtime conditions, including selecting by specific input type, given that a single instance of formatting data can cover multiple types. Also note that views may involve grouping (as you see in Get-ChildItem's formatted output, for instance), and the grouping criterion isn't covered by the command above.
Note that even for a single type multiple views may be defined, and in order to use a non-default one you must request it explicitly, via Format-Table's -View parameter, assuming you know the name,[1] e.g. Get-Process | Format-Table -View StartTime).

  • See also:
    • This answer for how to inspect formatting data in full.
      • You can alternatively pipe Get-FormatData output to Export-FormatData in order to export formatting data to an XML file, which has the disadvantage of being hard to read, but has the advantage of matching the XML schema used for authoring formatting data - see next point - whereas the in-memory types used to represent formatting data partially use property names that don't match the underlying XML elements.
    • As for authoring formatting data, which as of PowerShell 7.2.2 requires XML files (*.Format.ps1xml):

Note:

  • Using -PowerShellVersion $PSVersionTable.PSVersion with Get-FormatData is only needed in Windows PowerShell, for certain types, to work around a bug that is no longer present in PowerShell (Core) 7.1

  • While column names typically correspond to the property names of the type instances being formatted, that isn't always the case, such as with the [System.Diagnostics.Process] instances output by Get-Process.

    • A general caveat, as zett42 notes, is that display formatting of types isn't part of the public contract regarding breaking changes, so formatting definitions are allowed to change over time.
  • If a given type has no predefined formatting data associated with it (in which case Get-FormatData is a quiet no-op):

    • The names of its (public) instance properties are used as column names.

    • You only get a table view by default if there are 4 or fewer properties but you can request it explicitly with Format-Table (With 5 or more properties, Format-List is applied by default).

    • To get the names of all (public) instance properties of a given object, use the intrinsic .psobject property, which is a rich source of reflection; e.g.:

      • (Get-Process | Select-Object -First 1).psobject.Properties.Name

Quick-and-dirty solution:

The following uses Out-String -Stream in conjunction with Select-String to extract the column names from a given command's formatted output, which relies on two assumptions:

  • The column names have no embedded spaces
  • The command actually produces table-formatted output by default; however, you can insert a Format-Table call before Out-String, if desired.
Get-Process | Out-String -Stream | Select-String -List '^\s*-- ' -Context 1, 0 |
  ForEach-Object { -split $_.Context.PreContext[0] }

Output:

NPM(K)
PM(M)
WS(M)
CPU(s)
Id
SI
ProcessName

[1] While tab-completion does offer view names, they appear to be out of sync with the actually available ones, as of PowerShell 7.2.2. To see the latter, provoke an error with a dummy name, and the error message will list the available ones; e.g. Get-Process | Format-Table -View NoSuch lists the following available views in the resulting error message: process, Priority, StartTime

  • Related