To complement PetSerAl's excellent answer with a focus on the hashtable that wasn't (a hashtable), based on PetSerAl's helpful comments:
The output from Start-Job { New-Object PSObject } | Receive-Job -Wait -AutoRemoveJob
,
@{PSComputerName=localhost; RunspaceId=3e783d5f-254a-4951-bb4a-7ff6fa2812c5; PSShowComputerName=False; PSSourceJobInstanceId=1d951dec-0823-4cde-8219-4a6263550441}
only looks like a hashtable literal; in fact, it is the default output formatting for "property-less" custom objects that, in fact, do have properties, but only ones added by PowerShell itself.
This representation is suspiciously similar to a hashtable literal, but the quoting around values that would normally need it is missing - such as around localhost
.
Also note that outputting an actual hashtable results in a much nicer, two-column key-value format.
Note that PS still considers a custom object that originally had no properties property-less even after PS itself has added properties to it, such as by Receive-Job
here - see below for details.
In its original state (no properties added by PS yet), a property-less object's default output is empty (the empty string). (Try New-Object PSCustomObject
directly at the prompt.)
Once Receive-Job
has added its "meta" properties to the custom object, their existence triggers the hashtable-like output formatting.
PetSerAl has provided a link to the source code, which suggests that the "PropertyLessObject" formatting is triggered under the following conditions:
An object has no properties at all or only has properties automatically added by PowerShell in the context of remoting (which apparently also includes job-related cmdlets), as done by Receive-Object
here.
To put it differently: Properties automatically added by PS aren't taken into account when deciding whether an object is propertyless.
The source-code link will tell you the specific 3-, 4-, or 5-element sets of remoting properties that may be added during remoting and trigger the formatting, but here's a minimal (3-property) example.
Again, note that the hashtable-like formatting is only triggered because the only properties that the object has are named for remoting-related, automatically added properties:
PS> [PSCustomObject] @{PSComputerName='Hi, Mom'; RunspaceId=0; PSShowComputerName=$true}
@{PSComputerName=Hi, Mom; RunspaceId=0; PSShowComputerName=False}
Note that even though a hashtable literal is involved in the command, it is merely used to construct a custom object.
You can force a normal list or table view with Format-List -Force
or Format-Table -Force
, but note that Boolean property PSShowComputerName
never shows up and instead implicitly controls whether the associated PSComputerName
property is included in the list / table.
PetSerAl also points out that you can get the hashtable-like output format on demand for any custom object ([pscustomobject]
): simply invoke .PSObject.ToString()
(note the crucial .PSObject
part; without it, you get empty output).
PS> ([pscustomobject] @{ one = 'Hi, Mom'; two = 2 }).PSObject.ToString()
@{one=Hi, Mom; two=2}
Or, more simply, with string interpolation (which, presumably, simply calls .PSObject.ToString()
behind the scenes):
PS> "$([pscustomobject] @{ one = 'Hi, Mom'; two = 2 })"
@{one=Hi, Mom; two=2}
Note that this kind of string interpolation does not work for instances of any other types (objects not of type [System.Management.Automation.PSCustomObject]
):
PowerShell defers to their .ToString()
method even when you invoke .PSObject.ToString()
.
A directly .NET-based type (e.g., as added with Add-Type
) by default simply returns its full type name (both from .ToString()
/ .PSObject.ToString()
and as default output in PS); e.g.:
PS> (Add-Type -PassThru 'namespace net.same2u { public class SomeType {} }')::New()
net.same2u.SomeType # the full type name
The same applies to instances of custom PowerShell classes (defined with class { ... }
).