Summary: Microsoft Scripting Guy, Ed Wilson, talks about using the cmdletbinding attribute to simplify Windows PowerShell functions.
Microsoft Scripting Guy, Ed Wilson, is here. This morning I was sitting around playing with Windows PowerShell, and I realized that I had not written much about the cmdletbinding attribute. So here goes…
The first step in creating an advanced function is to add the cmdletbinding attribute. This single addition adds several capabilities such as additional parameter checking, and the ability to easily use the Write-Verbose cmdlet.
To use the cmdletbinding attribute, you place the attribute in a square bracket attribute tag and include it in the first non-commented line in the function. In addition, the cmdletbinding attribute requires the use of param keyword. If your advanced function requires no parameters, you can use the keyword without specifying any parameters. This technique is shown here:
function my-function
{
[cmdletbinding()]
Param()
}
When you have the basic outline of the advanced function, you can begin to fill in the blanks. For example, to use the Write-Verbose cmdlet only requires adding the following command.
function my-function
{
[cmdletbinding()]
Param()
Write-Verbose "verbose stream"
}
Easy verbose messages
When loaded, the function permits the use of the verbose switched parameter. Use of this parameter causes each Write-Verbose statement to write to the Windows PowerShell console output. When the function runs without the verbose switch, no output displays from the verbose stream.
The great thing about using Write-Verbose is that detailed information (such as the progress in making remote connections, loading modules, and other operations that could cause a script to fail) outputs as events happen. This provides a built-in diagnostic mode for the advanced function with virtually no additional programing.
Automatic parameter checks
The default behavior for a Windows PowerShell function is that additional values specified to an unnamed argument are available in the automatic $args variable. This behavior, although potentially useful, easily becomes a source of errors for a script. The following function illustrates this behavior.
function my-function
{
#[cmdletbinding()]
Param($a)
$a
#$args
}
When this function runs, any value supplied to the –a parameter appears in the output as shown here:
PS C:\Users\ed.IAMMRED> my-function -a 1,2,3,4
1
2
3
4
On the other hand, when you call the function, if you omit the first comma, no error generates, but the output displayed does not meet expectations. This is shown here:
PS C:\Users\ed.IAMMRED> my-function -a 1 2,3,4
1
The remaining parameters appear in the automatic $args variable. Placing the $args variable in the function illustrates this. First, add the $args automatic variable as shown here:
function my-function
{
#[cmdletbinding()]
Param($a)
$a
$args
}
Now, when calling the function, whilst omitting the first comma, the following output appears.
PS C:\Users\ed.IAMMRED> my-function -a 1 2,3,4
1
2
3
4
Although interesting, you may not want this behavior. One way to correct it is to check the number of arguments that are supplied to the function. You can do this by monitoring the count property of the $args variable as shown here:
function my-function
{
#[cmdletbinding()]
Param($a)
$a
$args.count
}
When passing multiple arguments to the function, the value of the count property increases. In the output that is shown here, the first number 1, returns from the –a position. The number 3 is the count of extra arguments (that is, those not supplied for the named argument).
PS C:\Users\ed.IAMMRED> my-function 1 2 3 4
1
3
By using this feature, and checking the count property of $args, one line of code prevents extra arguments coming to the function. This change is shown here:
function my-function
{
#[cmdletbinding()]
Param($a,$b)
$a
$b
if($args.count -gt 0) {Write-Error "unhandled arguments supplied"}
}
When run, as shown in the following code, the first two parameters supplied are accepted for the –a and the –b parameters. The two remaining parameters go into the $args automatic variable. This increases the count property of $args to a value greater than 0, and therefore an error occurs.
PS C:\Users\ed.IAMMRED> my-function 1 2 3 4
1
2
my-function : unhandled arguments supplied
At line:1 char:12
+ my-function <<<< 1 2 3 4
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,my-
function
The easiest way to identify unhandled parameters supplied to a Windows PowerShell function is to use the cmdletbinding attribute. One of the features of using the cmdletbinding attribute is that it generates an error when unhandled parameter values appear on the command line. The following function illustrates the cmdletbinding attribute.
function my-function
{
[cmdletbinding()]
Param($a,$b)
$a
$b
}
When calling the above function with too many arguments, the following error appears:
PS C:\Users\ed.IAMMRED> my-function 1 2 3 4
my-function : A positional parameter cannot be found that accepts argument '3'.
At line:1 char:12
+ my-function <<<< 1 2 3 4
+ CategoryInfo : InvalidArgument: (:) [my-function], ParameterBindingE
xception
+ FullyQualifiedErrorId : PositionalParameterNotFound,my-function
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy