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?
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.