How to disable positional parameter binding in PowerShell vNext

September 19, 2011

Windows PowerShell supports two kind of parameters: Named and Positional. In a nutshell, Named parameters must be specified on the command line while Positional parameters are inferred by the argument’s position on the command line.
The type of the parameter is controlled by the [Parameter()] attribute (see about_Parameters).

What if we wanted to disable positional parameters and force users to write the parameter name and its value?
Consider the following example, all parameters values are positional. Can you guess the parameter names?

PS> Register-ObjectEvent $timer Elapsed Timer.Random {$random = Get-Random -Min 0 -Max 100}

There is some logic in the order of values but that is a bit hard to read and involves some guess work as well as consulting the help files. It is also not recommended when writing production scripts and can cause a lot of frustration for users who are not familiar with the command.

In PowerShell v2 it was not possible to disable that behavior (see a work around at the end of this post).
By default, values on the command line where treated as positionals, but in PowerShell v3 the PowerShell team added a new
functionality to address it.

The CmdletBinding attribute is used in Advanced functions to identify them as functions that act similar to compiled cmdlets.
When we write advanced functions, we can add the CmdletBinding attribute so that Windows PowerShell will bind the parameters of the function in the same way that it binds the parameters of compiled cmdlets. Some of the known arguments of the CmdletBinding attribute are: SupportsShouldProcess, DefaultParameterSetName and ConfirmImpact.
You can read more about them in the about_Functions_CmdletBindingAttribute help topic.

In PowerShell v3 we have additional CmdletBinding attribute – PositionalBinding (there are more new attributes!).
As its name suggests, when specified it disables positional binding and force the caller to specify parameter names.
Let’s test it with the following function.

function Test-PositionalBinding             
{             
    [CmdletBinding(PositionalBinding=$false)]             
            
    param(             
       $param1,$param2             
    )             
            
    Write-Host param1 is: $param1            
    Write-Host param2 is: $param2             
}             

 


As you can see, the PositionalBinding attribute is set to $false. The function will not allow positional binding.

PS> Test-PositionalBinding -param1 one -param2 two

param1 is: one

param2 is: two


In the example above we specified parameter names and the result is as expected. Let’s try to pass the value of param1 by its position.


PS> Test-PositionalBinding one -param2 two

Test-PositionalBinding : A positional parameter cannot be found that accepts argument ‘one’.

At line:1 char:1

+ Test-PositionalBinding one -param2 two

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : InvalidArgument: (:) [Test-PositionalBinding], ParameterBindingException

    + FullyQualifiedErrorId : PositionalParameterNotFound,Test-PositionalBinding


And it fails. Check this forum thread if you need to enable similar functionality in PowerShell v2, great workaround by @mjolinor.

Want to try PowerShell v3? Download the Windows 8 Developer Preview from MSDN.















Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*