tl;dr
In PowerShell conditionals / implicit Boolean contexts:
Single-element arrays are treated like scalars: that is, their one and only element itself is interpreted as a Boolean.[1]
2+-element arrays are always $true, irrespective of their content.
With an array as the LHS, array-aware operators such as -eq invariably also output an array.
Since your array elements are all $null and you compare to $null, your comparison is an effective no-op - e.g., @( $null ) -eq $null results in @( $null ) - and your conditionals are equivalent to:
[bool] @( $null, $null ) # -> $true - array with 2+ elements is always $True
[bool] @( $null ) # -> $false(!) - treated like: [bool] $null
Perhaps surprisingly, the implicit Boolean logic applies pipeline logic to an array:
That is, a single-element array is (conceptually) unwrapped and its element is interpreted as a Boolean.
Therefore, [bool] @( $null ) is treated the same as [bool] $null, which is $false.
Generally, @( <one-and-only-element> ) (or , <one-and-only-element>) is treated the same as <one-and-only-element> in a Boolean context.
By contrast, if an array has 2 or more elements, it is always $true in a Boolean context, even if all its elements would individually be considered $false.
Workaround for testing whether an arbitrary array is empty:
Base your conditional on the .Count property:
if ( (<array>).Count ) { $true } else { $false }
You could append -gt 0, but that's not strictly necessary, because any nonzero value is implicitly $true.
Applied to your example:
PS> if ( ( @($null) -eq $null ).Count ) { $true } else { $false }
True
Testing an arbitrary value for being a (scalar) $null:
if ($null -eq <value>) { $true } else { $false }
Note how $null must be used as the LHS in order to prevent the array-filtering logic from taking effect, should <value> be an array.
That's also the reason why Visual Studio Code with the PowerShell extension advises "$null should be on the left side of comparisons" if you write something like $var -eq $null.
[1] To-Boolean conversion summary:
- Among scalars:
The following are implicitly $false:
''/"" (empty string)
0 (of any numeric type).
$null
Pitfall: Comparing $null to a Boolean explicitly with -eq is always $false, even with $null as the RHS (despite the RHS normally getting coerced to the type of the LHS):
$false -eq $null # !! $false - unlike `$false -eq [bool] $null`
Pitfall: Any non-empty string evaluates to $true
e.g., [bool] 'False' is $true
Note that this differs from explicit string parsing: [bool]::Parse('false') does return$false (and $true for 'true', but recognizes nothing else).
Instances of any other (non-collection) type are implicitly $true, including of type [pscustomobject] and [hashtable] (which PowerShell treats as a single object, not as a collection of entries).
- Unfortunately, this includes types that define explicit
[bool] .NET conversion operators, meaning that these operators are - mostly - not honored; see this answer.
- Among collections such as arrays (more accurately, collection-like types that implement the
IList interface - see the source code):
Empty collections are always $false, as is the special "enumerable null" value indicating the absence of output from a command, [System.Management.Automation.Internal.AutomationNull]::Value - see this answer for background information.
Pitfall: Single-element collections evaluate to:
2+-element collections are always $true, irrespective of their element values.
- E.g.,
[bool] @($null, $false) is $true.