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' | ...