I'm trying to format all arguments passed to a PowerShell function:
function lf {
if ($args) {
(0..($args.Count - 1) | ForEach-Object { "$args[$_]" }) -join ','
(0..($args.Count - 1) | ForEach-Object { "$($args[$_])" }) -join ','
} else {
...
}
}
lf pdf png txt
The output is:
[0],[1],[2]
,,
I expected both expressions to produce `pdf,png,txt`. Direct indexing such as `$args[0]` works, so why does indexing with the pipeline variable fail in the first expression?
2 Answers
A cleaner approach is to declare the function’s arguments with a `param` block instead of relying on the automatic `$args` variable. For example:
function lf {
param(
[Parameter(ValueFromRemainingArguments)]
[string[]] $FileTypes
)
if ($FileTypes) {
$FileTypes -join ','
} else {
...
}
}
This makes the expected inputs explicit and eliminates the ambiguity around `$args`.
In an expandable PowerShell string, `$args[$_]` is parsed as the variable `$args` followed by literal text like `[0]`, rather than as an evaluated array lookup. That’s why the first expression produces `[0],[1],[2]`. Wrapping the expression in a subexpression forces PowerShell to evaluate the index operation: `$($args[$_])`. You can also avoid indexing entirely and pipe the arguments directly:
($args | ForEach-Object { $_ }) -join ','
That explains the different output. The subexpression form works; I was mainly confused because `$args[0]` works when the index is written as a literal.

Agreed. Using a named parameter is easier to understand and gives the function a clearer interface.