Nothing and Everything

2011.06.14

Powershell error: A positional parameter cannot be found that accepts argument

Filed under: Programming — kevenker @ 2:05 pm

One thing that is cool in C# is the params keyword. It allows you to have a arbitrary number of extra parameters, e.g.:

private void MyFunction (string blah, params string[] lotsOfPossibleBlah) ...

I had a powershell script that I wanted to extend with similar behavior. I wanted a couple of required parameters and then allow user to call with a unlimited list of optional parameters.

However, once you specify a parameter attribute, Powershell complains if you try to add extra parameters. So, for example, this works:

param ($a, $b)
write-host a= $a b= $b xtras= $args
.\foo.ps1 1 2 3 4 
a= 1 b= 2 xtras= 3 4

This does NOT work:

param
(
    [parameter(Mandatory=$true)][string]$a,
    [parameter(Mandatory=$true)][string]$b
)
write-host a= $a b= $b xtras= $args
.\foo.ps1 1 2 3 4
D:\foo.ps1 : A positional parameter cannot be found that accepts argument '3'.
At line:1 char:10
+ .\foo.ps1 <<<<  1 2 3 4 
    + CategoryInfo          : InvalidArgument: (:) [foo.ps1], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,foo.ps1

Argh. Very annoying. Nothing in the docs, ebooks, etc. that I’ve read mention this gotcha. Their examples just work because they don’t add any attributes to their parameter list. After an hour of poking around and prodding, I finally found a list of Powershell attributes you could add to a parameter (http://msdn.microsoft.com/en-us/library/ms714348(VS.85).aspx) which saved the day. It is the attribute ValueFromRemainingArguments. This tells the parameter to grab all the remaining arguments into an array, so you get behavior just like the $args param. In fact, you can name this paramer $args, though in the example below, I named it $xtras just so there would be no confusion about the actual origin of the values.

So now this works, and is exactly the behavior I wanted. 2 required parameters and an optional number of extra parameters.

param 
(
    [parameter(Mandatory=$true)][string]$a, 
    [parameter(Mandatory=$true)][string]$b,
    [parameter(ValueFromRemainingArguments=$true)]$xtras
)
write-host a= $a b= $b xtras= $xtras
.\foo.ps1 1 2 3 4 
a= 1 b= 2 xtras= 3 4
Advertisement

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Theme: Silver is the New Black. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.