While:
you can use expressions as the first segment of a pipeline (e.g.,
1..2 | Tee-Object -Variable result
),
you cannot use compound statements (aka language statements) such as if
, while
, foreach
, and do
as-is, unfortunately.
That is, such compound statements aren't true expressions, even though in the context of assignments they can act a such. That is, you could do $result = while ($true) ...
- without enclosing the while
in (...)
- yet you cannot send the while
loop directly through a pipeline.
See GitHub issue #6817, which discusses this problematic "half-expression status" of compound statements, and asks if it's feasible to make them full expressions; as it turns out, the fundamentals of PowerShell's grammar prevent that.
Workarounds:
If you want your looping compound statement to stream, i.e. to output its objects one by one to the pipeline, as they become available - i.e. if you want the standard, streaming pipeline behavior:
- Wrap your compound statement in
& { ... }
(or . { ... }
, if you want to run directly in the current rather than in a child scope).
- E.g.,
& { foreach ($i in 1..2) { $i } } | Tee-Object -Variable result
If you want to collect all outputs from your looping compound statement up front, before sending them through the pipeline:
- Wrap your compound statement in
$(...)
, the subexpression operator.
- E.g.,
$(foreach ($i in 1..2) { $i }) | Tee-Object -Variable result
- Note:
- While using
$(...)
over & { ... }
can speed up your pipeline, it does so only slightly, and it potentially comes at the expense of memory consumption, given that all outputs are invariably collected in memory first.
- The same applies to
@(...)
, the array-subexpression operator and (...)
, the grouping operator, but note that (...)
only works with a single expression or command. This answer contrasts (...)
, $(...)
and @(...)
in detail.
Applied to your case:
$result = & {
while ($true) {
<# Generating long list of psobject #>
}
} | Tee-Object -FilePath 'fname.csv' | ...