There are different ways to represent (display) an object in PowerShell but when it comes to complex objects it is either very verbose or quiet useless:
$Object = @{ 'a' = 1; 'b' = 2 }
Just outputting (Format-Host
, or Format-List
) returns a multiline output, as:
$Object
Name Value
---- -----
a 1
b 2
Converting it to a string "$Object"
or $Object.ToString()
doesn't reveal anything about its contents:
System.Collections.Hashtable
Converting it to Json $Object |ConvertTo-Json -Compress
, gets close to what I would like to see (but a little too expressive cmdlet for what I need):
{"a":1,"b":2}
I wonder whether there is a way access the representation formatting used by PowerShell display cmdlets, as e.g. the value behind the ImmediateBaseObject
and BaseObject
:
$Object.PSObject
Members : {System.Object Item(System.Object key) {get;set;}, bool IsReadOnly {get;}, bool IsFixedSize {get;}, bool IsSynchronized {get;}…}
Properties : {bool IsReadOnly {get;}, bool IsFixedSize {get;}, bool IsSynchronized {get;}, System.Collections.ICollection Keys {get;}…}
Methods : {Add, Clear, Clone, Contains…}
ImmediateBaseObject : {[a, 1], [b, 2]} # <-- This representation
BaseObject : {[a, 1], [b, 2]} #
TypeNames : {System.Collections.Hashtable, System.Object}
Wishful thinking, I would like to be able to do something like this:
[PowerShellFormat]$Object
And get the same formatting back for any (complex) object as shown behind BaseObject
for $Object.PSObject
.
As for this case:
{[a, 1], [b, 2]}
JosefZ has provided the crucial pointer:
Call .GetEnumerator()
on your dictionary in order to enumerate its entries, which are key-value pairs, such as of type [System.Collections.DictionaryEntry]
in hashtable
instances.
Unlike dictionaries as a whole, their entries stringify meaningfully, in the form [<key>, <value>]
- though it's important to note that this is just a for-display representation, not suitable for programmatic processing.
When PowerShell's formatting system stringifies a dictionary stored in a property of an input object, it treats it as an array of entries, and stringifies that array similarly to how arrays are stringified in expandable strings:
The difference is that the whole representation is enclosed in {...}
and that the (stringified) elements are separated with ,
. You saw this in the display formatting of @{ 'a' = 1; 'b' = 2 }.psobject
(.ImmediateBaseObject
and .BaseObject
properties).
I'm not aware of a public method that would produce this format, but it isn't hard to produce it yourself:
# -> '{[a, 1], [b, 2]}'
'{' + (@( @{ 'a' = 1; 'b' = 2 }.GetEnumerator() ) -join ', ') + '}'
Note:
The .GetEnumerator()
call must be wrapped in @(...)
to force actual enumeration, resulting in an array.
It follows that you can use the above for arrays as inputs too.
Getting an analogous string representation or [pscustomobject]
instances is much simpler: Use string interpolation, i.e. embed the object in an expandable (double-quoted) string ("..."
):
$obj = [pscustomobject] @{ 'a' = 1; 'b' = 2 }
"$obj" # -> '@{a=1; b=2}'
Note:
Unlike hashtables/dictionaries, [pscsutomobject]
instances stringify the same way in expandable strings and as properties of formatted object representations.
Note the difference in formats compared to the hashtable visualization, with the property name-value pairs separate with =
(and no whitespace), multiple properties separated with ;
, and @{
as the opening delimiter.
Curiously, this format is very similar to the syntax of a hashtable literal.
Finally, just to demonstrate that PowerShell's formatting system indeed produces the representations above for hashtables and [pscustomobject]
instances used as properties:
@{
hashtable = @{ 'a' = 1; 'b' = 2 }
pscustomobject = [pscustomobject] @{ 'a' = 1; 'b' = 2 }
}
Output:
Name Value
---- -----
pscustomobject @{a=1; b=2}
hashtable {[a, 1], [b, 2]}