What operator should be used to detect an empty psobject?

powershell convert null to empty string
powershell check if property exists
powershell check if property is empty

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"

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.

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().

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.

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  You can create as many key-value pairs as you like for each PSObject. Creating a PSObject. As mentioned, the PowerShell PSObject uses a key & value pair type structure. To store data in the PSObject all you need to do is define a key and then store a value in the key. The examples below creates a new PSObject and stores some data in the object

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)

Add-Member, You can also use the Export-Clixml cmdlet to save the instance of the object, Add-Member -InputObject <PSObject> -TypeName <String> [-PassThru] [<​CommonParameters>] $A = Get-ChildItem C:\Temp\test.txt $A | Add-Member -​MemberType To determine whether an object is a PSObject object, use the -is operator. 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:

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

Measure-Object, You can use Measure-Object to count objects or count objects with a specified When you use Import-Csv to import the file, the result is a PSCustomObject with Import-Csv d:\test\serviceyrs.csv | Measure-Object -Property years -Minimum  PowerShell has a comparison operator called –is. The –is operator simply response True or False when you use it to verify the data type of a value. The valid data types in PowerShell are: [string] Fixed-length string of Unicode characters [char] A Unicode 16-bit character

Everything you wanted to know about $null, If you use $null in a string, then it will be a blank value (or empty string). The -​eq will check every value in the array and returns the $null that is matched (This One important exception is the [PSCustomObject] in Windows  You can use the New-Object cmdlet to generate an object of any type. The two choices for custom objects are PSObject and Object PSObject creates an object of class System.Management.Automation.PSCustomObject Object creates an object of class System.Object While PSObject requires a bit more overhead, it is generally preferred.

Everything you wanted to know about arrays, One cool little trick worth mentioning is that you can use Write-Output to quickly PS> $empty = $null SP> $empty[0] Error: Cannot index into a null array. The -​contains operator will allow you to check an array of values to see if it By default, an array in PowerShell is created as a [PSObject[]] type. If the ImmediateBaseObject is another PSObject, this property. will return its BaseObject. Applies to. Is this page helpful? Yes No. Any additional feedback? Skip Submit.

Improved PS Object and Object Literal Support · Issue #9086 , Make a new object $o = New-Object PSObject # Ugly # Check a if the hashtable has a key P1 that will be used for the parameter P1 and if it If PS had ?. as an operator, as requested in issue #3240, that's likely I think PS tries to convert that and comes back with an empty string, but I could be wrong. This works well for me because I use hashtables for just about everything. But there are times when I would like Powershell to treat hashtables more like an object and this does it. The first place you notice the difference is when you want to use Format-Table or Export-CSV and you realize that a hashtable is just a collection of key/value pairs.

Comments
  • How about something like: If ($test -eq "") {Write-Host "It's empty!"} ELSE {Write-Host "It's not empty!"}
  • Not cheap, as you state, but conceptually clearer (+1). You can avoid the $null proplem more concisely by adding -ErrorAction Ignore to the Get-Member call: [Bool]($Test | Get-Member -ErrorAction Ignore -MemberType NoteProperty) or, as a single command: [bool] (Get-Member -InputObject $Test -MemberType NoteProperty -ErrorAction Ignore)