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?
Its 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
You can reorder the operands:
$null -eq $foo
Note that -eq
in PowerShell is not an equivalence relation.
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.
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.
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.
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