Question:
I’m sure there is a valid reason why this happens but I don’t know what it is. I have the following code
1 2 3 |
$Deleted = $Items[0].ParentNode.RemoveChild($Items[0]) Write-Output $Deleted |
If I call this code using
1 2 |
Do-Something -OutVariable Test |
I get the output on the screen and in the variable as expected, but the variable is an ArraryList
with a single element that is of type XmlElement
If Instead I run
1 2 |
$Test = Do-Something |
I don’t get the output on the screen, as expected, and the returned output is a single object of type XmlElement
Why does OutVariable
return an ArrayList
rather than return the single item the function returns?
Thanks
Answer:
As of PowerShell [Core] 7.0:
- PowerShell unexpectedly does not unwrap a command’s single-object output with
-OutVariable
: That is, even if a command outputs only one object, that object is unexpectedly stored as an array (array list) in the target variable whose name is passed to the common parameter-OutVariable
parameter (or its alias,-ov
). - Additionally, the type of the value stored in the target variable is always
[System.Collections.ArrayList]
, an array list, which is inconsistent with capturing multi-object output in a variable by regular assignment, which results inSystem.Object[]
, a regular array.
See this GitHub issue.
Here’s a concise test that demonstrates the problem:
1 2 |
$null = Get-Date -OutVariable ov; $ov.GetType().FullName |
As of the versions listed above, this outputs:
1 2 |
System.Collections.ArrayList |
even though the output is (conceptually) only a single [datetime]
([System.DateTime]
) instance.
Contrast this with a regular assignment: $v = Get-Date; $v.GetType().FullName
yields System.DateTime
.
The workaround is to wrap the output-variable reference in the subexpression operator ($(...)
), which gives you the same output as via the regular output (success) stream:
- a single-element collection is unwrapped (only outputs the element itself)
- a multi-element collection is returned as a
System.Object[]
array.
1 2 3 4 |
# Note the $(...) around $ov PS> $null = Get-Date -OutVariable ov; $($ov).GetType().FullName System.DateTime # 1-element System.Collections.ArrayList unwrapped |
Of course, you could also use $ov[0]
if you only ever expect a single output object.
A demonstration that the workaround is effective with multi-element output too:
1 2 3 |
PS> $null = Get-ChildItem / -OutVariable ov; $($ov).GetType().FullName System.Object[] # multi-element System.Collections.ArrayList converted to array |