Reputation: 10091
Given this function and invocation:
function Foo($bar) {
Write-Host "bar=$bar, other args = $args"
}
Foo -b baz -quux quuux
Powershell will treat the -b
argument as an alias for the $bar
argument and print
bar=baz, other args = -quux quuux
I don't want it to do this! My function needs to work with both named arguments and arbitrary additional arguments; if one of those arbitrary arguments is -b
, I don't want it assigned to $bar
. That is, I want it to print:
bar=, other args = -b baz -quux quuux
Can I suppress the default parameter aliasing that powershell does?
I'm using powershell 2.0
Upvotes: 1
Views: 215
Reputation: 8019
PowerShell has no way of disabling support for unambiguous prefix matching of parameters.
There are a few options though with various tradeoffs.
Option 1 - parse arguments yourself:
function foo {
param()
# $args has all of the parameters and arguments
}
This is more difficult for you to write, but solves the problem you hope to solve because you will completely own parameter/argument binding.
The other downside is no tab completion for parameters, at least not without some extra corresponding help in TabExpansion or TabExpansion2 (e.g. using a module like TabExpansion++ or PowerTab).
Note in this example you don't want cmdlet binding even if you have a parameter that is "value from remaining arguments" because cmdlet binding will add the common parameters and those parameters will be bound if an unambiguous prefix is used.
Option 2 - Require the caller to do something different
There are several cmdlets with a similar problem, e.g. Invoke-Command or Get-Command. Both accept an array of arguments. Users must quote parameters:
icm { param($a,$b) $b } -ArgumentList '-b','hello'
These cmdlets use -ArgumentList because they really must accept arbitrary arguments that might conflict with the cmdlet's arguments.
If your problem is more constrained, there might be another option, but it's requires some uncommonly used syntax and will still have problems with some parameters. An example:
function foo
{
param([Parameter(ValueFromRemainingArguments=$true)]$ArgumentList)
$ArgumentList
}
foo -- -A 1 -Ar 2 -Arg 3
The special token '--' tells PowerShell everything after is an argument. This way, arguments that look like parameters are treated as arguments.
This approach could be confusing if callers forget '--'.
Upvotes: 2
Reputation: 68301
You can stop the parser from interpreting the -b as a parameter alias by quoting it:
function Foo($bar) {
Write-Host "bar=$bar, other args = $args"
}
Foo '-b' baz -quux quuux
bar=-b, other args = baz -quux quuux
Upvotes: 2
Reputation: 28174
AFAIK, you can't have it both ways. You can use a "basic" function that exhibits the behavior you see here, or you can use an advanced function with named parameters which will validate the parameter names strictly.
"Arbitrary parameters" get really, really ugly and IMHO should be avoided for a number of reasons (some of which involve code security - could you end up executing unknown arbitrary code?).
Make Foo
an advanced function, and make your "arbitrary" arguments a collection of Objects
which is optional.
function Foo {
[cmdletBinding()]
param (
[Parameter(Mandatory=$True)]
[string]$bar,
[Parameter(Mandatory=$False)]
[object[]]$args
)
Write-Output "bar=$bar";
# Test for $args here and process each item in it
}
Upvotes: 2