Powershell Custom Object Confusion

When I do a Get-Member, it seems to just show one object.

Get-Member shows information about the distinct types in the collection of inputs, which means that the first occurrence of each type is reported on, with subsequent occurrences skipped.

In your case, both input objects are of type [System.Management.Automation.PSCustomObject], so Get-Member will report just that one shared type.

For instance, 1, 2 | Get-Member reports information about System.Int32 once.


one object is a custom object like above, but the other it a selected.system.int32. When I try to output one after the other only the first one outputs.

PowerShell’s default output formatting defaults to implicit use of Format-Table for custom objects with up to 4 properties.

If you output multiple objects that have different types, and the first object defaults to implicit Format-Table output, that first object’s type alone determines what properties (columns) to show in the resulting table.

  • Note: If the first object’s type happens to have formatting data associated with it (as reported by Get-FormatData), subsequent objects do print, albeit invariably via implicit Format-List formatting.

If subsequent objects do not have any of the same properties that the first object has, they simply print a blank line; if they have some of the same properties, only those are printed; any additional properties are ignored.

It is important to note that this is just a display problem, however: all objects that were output are still present; if you send the output to another command for further processing instead of directly to the console, they’ll all be there.

A simple example:

PS> [pscustomobject] @{ one = 1; two = 2 }, [pscustomobject] @{ three = 3 }
    
one two
--- ---
  1   2
 

Note how the 2nd custom object resulted in just a blank line, because it has neither properties .one nor .two.

You can work around the problem by using explicit formatting commands applied to each object to output:

PS> [pscustomobject] @{ one = 1; two = 2 }, [pscustomobject] @{ three = 3 } |
      ForEach-Object { Format-Table -InputObject $_ }

one two
--- ---
  1   2



three
-----
    3

The same approach as individual output commands:

[pscustomobject] @{ one = 1; two = 2 } | Format-Table
[pscustomobject] @{ three = 3 } | Format-Table

As Mark Wragg’s blog post explains, all output produced by a given script – even across separate commands – is sent to the same pipeline.
(You can think of a command line submitted interactively as an implicit script.)

For a more detailed discussion of how a mix of types in a single pipeline is handled in terms of display formatting, see this answer.


Why using an explicit formatting command helps:

By explicitly piping to a Format-* cmdlet (e.g, [pscustomobject] @{ one = 1; two = 2 } | Format-Table), you’re actually sending formatting objects (various [Microsoft.PowerShell.Commands.Internal.Format.*] types) to the pipeline, and PowerShell then effectively passes them through for display.

An alternative is to use a generic workaround: if you pipe to Out-Host instead (e.g., [pscustomobject] @{ one = 1; two = 2 } | Out-Host), in which case:

  • you bypass the pipeline and print directly to the console (if you’re running PowerShell in a regular console window),
  • and the object’s default formatting view is applied.

It is important to note that these workarounds are suitable only for display purposes, because the original objects are lost in the process:

  • When you pipe to a Format-* cmdlet explicitly, you replace the original object with objects containing formatting instructions, which are useless for further processing.

  • When you pipe to Out-Host, you send nothing to the script’s pipeline.

Leave a Comment