Weekend Scripter: Cmdletbinding Attribute Simplifies PowerShell Functions

Weekend Scripter: Cmdletbinding Attribute Simplifies PowerShell Functions

  • Comments 7
  • Likes

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 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Good blog, Ed, very informative.

  • @BigTeddy thank you. I am glad you found it informative and that you liked it! This makes my day.

  • A very good introduction to the CmdletBinding attribute!

    Thanks, Ed!

  • Is cmdletbinding also available in Powershell 2.

  • Perfect timing, I needed to be able to explain this for my user group meeting tomorrow.

  • @Rebecca Yes, the attribute is also available in PowerShell 2.0

    @R Jason Morgan I am glad you find the article helpful. Good luck with your PowerShell User Group tomorrow -- we will see you there :-)

  • "if($args.count -gt 0) {Write-Error "unhandled arguments supplied"}"

    _I_ know what "unhandled arguments supplied" means but even I don't like seeing dry, techie text like that. Can we still not, as programmers/scripters, write something a little more 'human'?

    "if($args.count -gt 0) {Write-Error "I'm sorry, but while I've been designed to accept the first two bits of information you've given me, I haven't been written to handle any more than that, so I'm afraid I have to quit out now."}"

    I know that's not really in scope for this article, so my comments should absolutely NOT be taken as a criticism of the article, but I still think it's an important principle that error messages should be written to be less obscure.

    Just saying.

    Still a very good article though, thanks! :-)