What you're looking for is similar to Ruby's .inspect
method. It's something I always loved in Ruby and do miss in PowerShell/.Net.
Unfortunately there is no such thing to my knowledge, so you will somewhat have to roll your own.
The closest you get in .Net is the .ToString()
method that, at a minimum, just displays the object type (it's inherited from [System.Object]
).
So you're going to have to do some checking on your own. Let's talk about the edge case checks.
Arrays
You should check if you're dealing with an array first, because PowerShell often unrolls arrays and coalesces objects for you so if you start doing other checks you may not handle them correctly.
To check that you have an array:
$obj -is [array]
1 -is [array] # false
1,2,3 -is [array] # true
,1 -is [array] #true
In the case of an array, you'll have to iterate it if you want to properly serialize its elements as well. This is basically the part where your function will end up being recursive.
function Format-MyObject {
param(
$obj
)
if ($obj -is [array]) {
# initial array display, like "@(" or "["
foreach ($o in $obj) {
Format-MyObject $obj
}
# closing array display, like ")" or "]"
}
}
Nulls
Simply check if it's equal to $null
:
$obj -eq $null
Strings
You can first test that you're dealing with a string by using -is [string]
.
For empty, you can compare the string to an empty string, or better, to [string]::Empty
. You can also use the .IsNullOrEmpty()
method, but only if you've already ruled out a null value (or checked that it is indeed a string):
if ($obj -is [string) {
# pick one
if ([string]::IsNullOrEmpty($obj)) {
# display empty string
}
if ($obj -eq [string]::Empty) {
# display empty string
}
if ($obj -eq "") { # this has no advantage over the previous test
# display empty string
}
}
Alternative
You could use the built-in XML serialization, then parse the XML to get the values out of it.
It's work (enough that I'm not going to do it in an SO answer), but it removes a lot of potential human error, and sort of future-proofs the approach.
The basic idea:
$serialized = [System.Management.Automation.PSSerializer]::Serialize($obj) -as [xml]
Now, use the built in XML methods to parse it and pull out what you need. You still need to convert some stuff to other stuff to display the way you want (like interpreting <nil />
and the list of types to properly display arrays and such), but I like leaving the actual serialization to an official component.
Quick example:
[System.Management.Automation.PSSerializer]::Serialize(@(
$null,
1,
'string',
@(
'start of nested array',
$null,
'2 empty strings next',
'',
([string]::Empty)
)
)
)
And the output:
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="0">
<TN RefId="0">
<T>System.Object[]</T>
<T>System.Array</T>
<T>System.Object</T>
</TN>
<LST>
<Nil />
<I32>1</I32>
<S>string</S>
<Obj RefId="1">
<TNRef RefId="0" />
<LST>
<S>start of nested array</S>
<Nil />
<S>2 empty strings next</S>
<S></S>
<S></S>
</LST>
</Obj>
</LST>
</Obj>
</Objs>