What operator should be used to detect an empty psobject?
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)
use string tests & test with the $Var on the right side of the comparison so that it is coerced to the type on the left. you can also test with the [string]
methods below ... [grin]
$Test = '{ }' | ConvertFrom-Json
$Test -eq $Null
$Null -eq $Test
$Test -eq ''
''
'' -eq $Test
[string]::IsNullOrEmpty($Test)
[string]::IsNullOrWhiteSpace($Test)
output ...
False
False
False
True
True
True