Using the following example:
$test = '{ }' | ConvertFrom-Json
How can I detect that $test is empty?
Does not work:
$test -eq $null
-not $test
This does work, but does not feel right:
$test.ToString() -eq ''
This is a simplified example, but my use-case is the response I get from a REST api using invoke-restmethod, certain properties come back as empty psobjects.
It is the simplest solution to test for an empty (property-less) custom object ([pscustomobject]
) via its string representation, but you need to use an expandable string (string interpolation, "..."
) rather than .ToString()
to obtain it:
# Returns $True, if custom object $test is empty, i.e. has no properties
-not "$test"
Note: -not $test.ToString()
should be equivalent, but currently (as of PowerShell Core 6.1) isn't, due to a bug. With the bug present, any [pscustomobject]
instance returns the empty string from.ToString()
.
Another workaround is to use .psobject.ToString()
.
Only an empty (property-less) custom object stringifies to the empty string inside an expandable string, and coercing an empty string to a Boolean in PowerShell yields $False
, whereas any nonempty string yields $True
.
The alternative is to compare against an empty string as the LHS, which implicitly forces the [pscustomobject]
on the RHS to be stringified:
# NOTE: Works ONLY with '' on the LHS.
'' -eq $test
A conceptually clearer approach, though it relies on the hidden .psobject
property PowerShell adds to all objects, containing reflection information:
0 -eq @($test.psobject.Properties).Count
Note the need to use @(...)
to force enumeration of the properties so that they can be counted - see next section.
The above methods are convenient, but if $test
is a large object with many properties, it can be expensive - though in absolute terms that will propbably rarely matter in practice.
A less expensive, but more obscure solution is to access the .psobject.Properties
collection without enumerating all its members:
# Returns $true, if $test has no properties
-not $test.psobject.Properties.GetEnumerator().MoveNext()
The .psobject.Properties
collection is apparently lazily enumerated and therefore doesn't have a .Count
property; using .GetEnumerator().MoveNext()
is therefore a way to limit enumeration to the first property, if any.
As for what you tried:
$test -eq $null
$test
is still an object, even if it happens to have no properties, and an object is by definition never $null
.
-not $test
PowerShell's implicit to-Boolean conversion treats any [pscustomobject]
instance as $True
, whether or not it happens to have properties; e.g., [bool] ([pscustomobject] @{})
yields $True
.
To see how other data types are coerced to Booleans, see this answer.
Probably more expensive, but less obscure; is using the the native Get-Member
cmdlet:
[Bool]($Test | Get-Member -MemberType NoteProperty)
Note that $Test
should not be $Null
(rather than an empty object) otherwise it will produce an error (as with using methods on $Null
). To avoid this you might also consider using:
$Test -and ($Test | Get-Member -MemberType NoteProperty)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With