Reputation: 203
Following this post about how to best create a (ternary operator)-ish expression in PowerShell, I've tried to convert this:
if ($condition)
{
$accessList = @()
}
else
{
$accessList = $accessControl.AllowedItems
}
into this:
$accessList = if ($condition) { @() } else { $accessControl.AllowedItems }
The one-liner fails to initialize an empty array. The resulting $accessList
doesn't have any array properties/methods and $NULL -eq $accessList
returns True. This version doesn't work either:
$accessList = $(if ($condition) { @() } else { $accessControl.AllowedItems })
Oddly enough, if I attempt to initialize a non-empty array, the one-liner works. It probably has something to do with variable evaluation and how the pipeline works, but after googling for a bit, I've found no detailed explanation of this particluar case. Please help understand the mechanics behind it.
Upvotes: 1
Views: 730
Reputation: 439193
You need to prevent the implicit enumeration of your empty array in the (implicitly used) pipeline, the simplest solution to which is to wrap it in an aux., transitory array, which you can construct with the unary form of ,
, the array constructor operator:
$accessList = if ($condition) { , @() } else { $accessControl.AllowedItems }
PowerShell 7+ offers a way to bypass the problem, by using ?:
, the ternary conditional operator, which acts as an expression (see explanation below):
$accessList = $condition ? @() : $accessControl.AllowedItems
Background information:
The distinction is subtle:
In:
$accessList = @()
@()
is an expression and therefore assigned as-is.
In:
$accessList = if ($condition) { @() }
if ($condition) { @() }
is an entire statement, and as such its output (@()
) implicitly uses the pipeline, where an array is implicitly enumerated and its elements are sent to the pipeline; in the case of an empty array, there is nothing to enumerate, and therefore nothing is output ( which is technically represented as the [System.Management.Automation.Internal.AutomationNull]::Value
singleton).
Wrapping the array in an aux., transitory array as shown at the top makes the pipeline enumerate only that aux. array, so the wrapped array is output as a whole.
The same applies to outputs from commands, notably if you try to output an array as a whole from a script or function.
Generally, though, note that PowerShell commands are not expected to output collections as a whole and to instead enumerate them.
Also note that if two or more elements are enumerated in the pipeline and you assign the output to a variable, PowerShell implicitly collects them in an [object[]]
array, whereas a single element is assigned as-is (no array wrapper). See this answer for more information.
Upvotes: 5