Why Does Array Indexing Behave Differently Inside a PowerShell String?
Asked by
MellowCedar47
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?
Answers
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 ','
Reply to this answer
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`.
BriskLantern6: Agreed. Using a named parameter is easier to understand and gives the function a clearer interface.
Reply to this answer
You donโt need the numeric range at all if the goal is simply to join every argument. `$args -join ','` handles one or multiple values, so the function can be reduced to that expression after checking whether arguments were supplied.
Reply to this answer
Add your answer
Answers are reviewed before publication.
MellowCedar47: 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.