How to test for $null array in PowerShell

PowershellNull

Powershell Problem Overview


I'm using an array variable in PowerShell 2.0. If it does not have a value, it will be $null, which I can test for successfully:

PS C:\> [array]$foo = $null
PS C:\> $foo -eq $null
True

But when I give it a value, the test for $null does not return anything:

PS C:\> [array]$foo = @("bar")
PS C:\> $foo -eq $null
PS C:\>

How can "-eq $null" give no results? It's either $null or it's not.

What is the correct way to determine if an array is populated vs. $null?

Powershell Solutions


Solution 1 - Powershell

It's an array, so you're looking for Count to test for contents.

I'd recommend

$foo.count -gt 0

The "why" of this is related to how PSH handles comparison of collection objects

Solution 2 - Powershell

You can reorder the operands:

$null -eq $foo

Note that -eq in PowerShell is not an equivalence relation.

Solution 3 - Powershell

if($foo -eq $null) { "yes" } else { "no" }

help about_comparison_operators 

displays help and includes this text:

> All comparison operators except the > containment operators (-contains, > -notcontains) and type operators (-is, -isnot) return a Boolean value when the input to the operator (the value > on the left side of the operator) is a > single value (a scalar). When the > input is a collection of values, the > containment operators and the type > operators return any matching values. > If there are no matches in a > collection, these operators do not > return anything. The containment > operators and type operators always > return a Boolean value.

Solution 4 - Powershell

If your solution requires returning 0 instead of true/false, I've found this to be useful:

PS C:\> [array]$foo = $null
PS C:\> ($foo | Measure-Object).Count
0

This operation is different from the count property of the array, because Measure-Object is counting objects. Since there are none, it will return 0.

Solution 5 - Powershell

How do you want things to behave?

If you want arrays with no elements to be treated the same as unassigned arrays, use:

[array]$foo = @() #example where we'd want TRUE to be returned
@($foo).Count -eq 0

If you want a blank array to be seen as having a value (albeit an empty one), use:

[array]$foo = @() #example where we'd want FALSE to be returned
$foo.PSObject -eq $null

If you want an array which is populated with only null values to be treated as null:

[array]$foo = $null,$null
@($foo | ?{$_.PSObject}).Count -eq 0 

NB: In the above I use $_.PSObject over $_ to avoid [bool]$false, [int]0, [string]'', etc from being filtered out; since here we're focussed solely on nulls.

Solution 6 - Powershell

The other answers address the main thrust of the question, but just to comment on this part...

> PS C:> [array]$foo = @("bar") > PS C:> $foo -eq $null > PS C:> > > How can "-eq $null" give no results? It's either $null or it's not.

It's confusing at first, but that is giving you the result of $foo -eq $null, it's just that the result has no displayable representation.

Since $foo holds an array, $foo -eq $null means "return an array containing the elements of $foo that are equal to $null". Are there any elements of $foo that are equal to $null? No, so $foo -eq $null should return an empty array. That's exactly what it does, the problem is that when an empty array is displayed at the console you see...nothing...

PS> @()
PS> 

The array is still there, even if you can't see its elements...

PS> @().GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array


PS> @().Length
0

We can use similar commands to confirm that $foo -eq $null is returning an array that we're not able to "see"...

PS> $foo -eq $null
PS> ($foo -eq $null).GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array


PS> ($foo -eq $null).Length
0
PS> ($foo -eq $null).GetValue(0)
Exception calling "GetValue" with "1" argument(s): "Index was outside the bounds of the array."
At line:1 char:1
+ ($foo -eq $null).GetValue(0)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : IndexOutOfRangeException

Note that I am calling the Array.GetValue method instead of using the indexer (i.e. ($foo -eq $null)[0]) because the latter returns $null for invalid indices and there's no way to distinguish them from a valid index that happens to contain $null.

We see similar behavior if we test for $null in/against an array that contains $null elements...

PS> $bar = @($null)
PS> $bar -eq $null
PS> ($bar -eq $null).GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array


PS> ($bar -eq $null).Length
1
PS> ($bar -eq $null).GetValue(0)
PS> $null -eq ($bar -eq $null).GetValue(0)
True
PS> ($bar -eq $null).GetValue(0) -eq $null
True
PS> ($bar -eq $null).GetValue(1)
Exception calling "GetValue" with "1" argument(s): "Index was outside the bounds of the array."
At line:1 char:1
+ ($bar -eq $null).GetValue(1)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : IndexOutOfRangeException

In this case, $bar -eq $null returns an array containing one element, $null, which has no visual representation at the console...

PS> @($null)
PS> @($null).GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array


PS> @($null).Length
1

Solution 7 - Powershell

Watch out for switch. It will never run with a null array, for example as the output of an empty directory.

switch ( $null ) { default { 'yes' } }
yes

switch ( @() ) { default { 'yes' } }  # no output

mkdir foo
switch ( dir foo ) { default { 'yes' } }  # no output

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMark BerryView Question on Stackoverflow
Solution 1 - PowershellTaylor BirdView Answer on Stackoverflow
Solution 2 - PowershellJoeyView Answer on Stackoverflow
Solution 3 - PowershellJohn WeldonView Answer on Stackoverflow
Solution 4 - PowershellAnthony NeaceView Answer on Stackoverflow
Solution 5 - PowershellJohnLBevanView Answer on Stackoverflow
Solution 6 - PowershellLance U. MatthewsView Answer on Stackoverflow
Solution 7 - Powershelljs2010View Answer on Stackoverflow