Note: Also affects other common parameters: see #3773
$null = Get-Date -OutVariable ov; $ov.GetType().FullName
Type name System.DateTime
Type name System.Collections.ArrayList
That is, the single-object output stored in the variable targeted with -OutVariable
received an _array list_ rather than a scalar (the single-element collection wasn't unwrapped).
Also, it is type [System.Collections.ArrayList]
that is always used, in contrast with the [System.Object[]]
instances you get with _regular_ assignments.
See also: http://stackoverflow.com/a/40666568/45375
PowerShell v6.0.0-alpha (v6.0.0-alpha.15) on Darwin Kernel Version 16.4.0: Thu Dec 22 22:53:21 PST 2016; root:xnu-3789.41.3~3/RELEASE_X86_64
PowerShell v5.1.14393.693 on Microsoft Windows 10 Pro (64-bit; v10.0.14393)
IIRC it's been this way since version 1. Changing it now would be a breaking change.
Note that -OutVariable
produce live collection, you can reference to it while pipeline is still working:
1..10 | echo -OutVariable a | % { "$a" }
Using not resizable [System.Object[]]
instead of [System.Collections.ArrayList]
would be bad performance choice.
The behavior is surprising, and possibly falls into the unlikely grey area bucket.
Tagging for committee review.
@PowerShell/powershell-committee reviewed this and agree with the expected result even though it is a breaking change
While I agree that it's weird that this doesn't behave like pipeline output....
These have been collections since the very beginning.
You'll be _potentially_ breaking every single use of these in the history of PowerShell.
I'm pretty sure you're going to light up the comments on an RFC for this kind of breaking change.
Please see this RFC proposal for comments on this breaking change.
@Jaykul (Cross-posting this from the related, generalized #3773)
The only thing that PowerShell does this collection/single behavior for is pipeline output
That is not much of a restriction, however, given the pervasive use of pipelines, even in places where it is not obvious:$(...)
, @(...)
, &
, .
, script-block arguments.
To give a few examples, all of which output $True
:
$(, 1) -is [int]
(. { , 1 }) -is [int]
(& { , 1 }) -is [int]
('' | Select-Object @{ n='foo'; e = { , 1 } }).foo -is [int]
(, @{ p = , 1 }).p
There is no @(...)
example, because @(...)
by design ensures _array-valued_ output - though it would still recreate any input collection as a [object[]]
array.
@PowerShell/powershell-committee agrees on followig the RFC process specifically the RFC that @rjmholt published
As an afterthought, given that I just stumbled upon it:
Tee-Object -Variable
exhibits pipeline, logic, as expected - unlike -OutVariable
:
Single-object output produces a _scalar_ (unwraps the output collection):
# Capture output from a command that outputs a *single* object
PS> $null = Get-Item / | Tee-Object -Variable out; $out.GetType().FullName
System.IO.DirectoryInfo # *scalar* was captured
Multi-object output creates an [object[]]
array.
# Capture output from a command that outputs a *multiple* objects
PS> $null = Get-ChildItem / | Tee-Object -Variable out; $out.GetType().FullName
System.Object[]
Yeah, I called out that behavior in the RFC comments 馃槈
In fact,
Tee-Object
_already_ has the behavior you're looking for: Unlike-OutVariable
,Tee-Object
doesn't populate it's variable until the end of the pipeline. Because of that, it's able to not output a collection when there's only one item, and it outputs an array when there is (not an ArrayList).
Good point, @Jaykul, thanks - it's been so long...
That I "rediscovered" this inconsistency after all the discussion is telling, however - it baffled me anew.
Most helpful comment
While I agree that it's weird that this doesn't behave like pipeline output....
The _only_ thing that PowerShell does this collection/single behavior for is pipeline output
These have been collections since the very beginning.
You'll be _potentially_ breaking every single use of these in the history of PowerShell.
Can we follow the process and RFC this?
I'm pretty sure you're going to light up the comments on an RFC for this kind of breaking change.