Reputation: 555
If I use .Count to check the number of items in an empty array, like this:
$theNames = @()
$theTotalNames = $theNames.Count
it finds nothing, and the numeric variable $theTotalNames is 0, as expected
But I have a situation where if I use .Count to check the contents of seemingly empty array, it is returning 1.
I'm populating the array with the results returned from the Invoke-RestMethod query like this:
$responseData = Invoke-RestMethod -Uri $url -Method Get -Headers $headers
$theNames = @($responseData.PsObject.Properties["the_field"].value.field_name)
$theTotalNames = $theNames.Count
If the query returns nothing because there were no fields found, $theTotalNames somehow equals 1. If the query returns one or more items, $theTotalItems will correctly equal 1.. or higher
When I display the contents of $theNames array after the query that returned nothing, the array seems empty.
If I check what's in the array, like this:
if ($theNames) {
"The array contains something"
}
else {
"The array contains nothing"
}
the console always says the array contains nothing.
So, why does .Count think there's at lease one item in the array?
Upvotes: 1
Views: 6780
Reputation: 217
In my instance, I had already defined the $array
variable, so mklement0's answer (checking the value of if $array
) wouldn't have worked as the variable is always defined, just not always populated, despite what .count
says.
I worked around it in the end by doing this:
if (($array | select -first 1) -eq $null) {
write-host "Array is empty"
}
In short, we get the first result from the array and see whether it is $null
. In my case this works because we never expect any of the elements in the array to be $null
.
If you are in a situation where array elements can be $null
, one option you might have is to remove these entries beforehand using where-object
, like so; you could then perform the original .count
check as all zero entries will have been removed.
$array2=$array | ? {$_ -ne $null}
Upvotes: 0
Reputation: 440317
As PetSerAl implies in a comment, the array may not be empty but may have a single element that happens to be $null
; the .Count
property reports the number of elements irrespective of the value of the elements:
@($null).Count # -> 1
Work around the problem as follows (assuming actual values are never the empty string):
$theTotalNames = if ($theNames) { $theNames.Count } else { 0 }
This relies on the fact that a single-element array that contains a "falsy" value is regarded as $False
in a Boolean context.
In PowerShell, $null
is generally a "something" (the "null scalar"), whereas there is also a "null collection", which is closer to "nothing", namely the [System.Management.Automation.Internal.AutomationNull]::Value
singleton, which is "returned" by commands that have no output at all.
The simplest way to produce it is to call an empty script block: & {}
Trying to wrap that in an array indeed yields an empty array:
@(& {}).Count # -> 0
However, in PSv3+ there is (at least?) one context in which $null
too is considered "nothing":
foreach ($el in $null) { "loop entered" } # loop is NOT entered.
I presume that the rationale for this intentional inconsistency is that uninitialized variables default to $null
and that entering the loop for uninitialized variables would be undesirable.
For more, see this GitHub discussion.
Upvotes: 2