Advanced PowerShell Functions: CmdletBinding Attribute

As a follow-up to our Advanced PowerShell Functions: Begin to Process to End article, the following article will dive deeper into the CmdletBinding attribute.  

Let’s start with defining a function:

Function Test-ScriptBlock
{
	[CmdletBinding()]
	Param
	(
		[Parameter(ValueFromPipeline)]
		[int[]]
		$Numbers
	)
	BEGIN
	{
		Write-Verbose "In Begin block"
		if ($Numbers.Length -lt 1)
		{
			Write-Error "Numbers should not be empty"
		}
 
		$total = 0 # Initializing $total
	}
	PROCESS
	{
		Write-Verbose "In Process block: Total = $total"
 
		foreach ($num in $Numbers)
		{
			Write-Verbose "Current total: $total"
			Write-Debug "Adding $total + $num"
			$total += $num
		}
	}
	END
	{
		Write-Verbose "In End block"
		Write-Host "Final Total: $total"
	}
} #END Function Test-ScriptBlock

Let’s break down what this is doing.

As defined in the previous article, Test-ScriptBlock takes an array of integer values, adds them, then outputs the final result.

Let’s run the following line:

Test-ScriptBlock -Numbers 1, 2, 3

It should output the following:

Despite our function using different Write functions, the only output written was when we used the command Write-Host.

Now run the line again with the addition of the switch -Verbose:

Test-ScriptBlock -Numbers 1, 2, 3 -Verbose

The output should look something like this:

Where did the -Verbose switch come from?

Let’s try running the line one more time with another switch -Debug:

Test-ScriptBlock -Numbers 1, 2, 3 -Verbose -Debug

The output should look like this after continuing each operation:

Where did the -Debug switch come from and what is it doing?

Anytime you are unsure of a command’s parameters, it’s a good idea to look up help information. Let’s try getting help for our function:

Get-Help Test-ScriptBlock -detailed # You can also run help or man

In the syntax for the function defined above, you can see the parameter for the -Numbers as type <Int[]>, but there is an additional parameter listed we did not explicitly define. [<CommonParameters>] is something PowerShell has added.

-Verbose and -Debug came from [<CommonParameters>]. Common Parameters are added to a function when you add the [CmdletBinding()] attribute or a param block.

What is CmdletBinding?

The CmdletBinding attribute converts a standard function into an advanced function, thereby adding features that are common in compiled cmdlets written in C#.

You can use the CmdletBinding attribute to add basic cmdlet features—such as Common Parameters—to functions or make certain methods available that allow you to change the function’s behavior. [CmdletBinding()] has the following the available values:

Name                    Type                                           
----                    ----                                           
PositionalBinding       System.Boolean                                 
DefaultParameterSetName System.String                                  
SupportsShouldProcess   System.Boolean                                
SupportsPaging          System.Boolean                                 
SupportsTransactions    System.Boolean                                 
ConfirmImpact           System.Management.Automation.ConfirmImpact     
HelpUri                 System.String                                  
RemotingCapability      System.Management.Automation.RemotingCapability

SupportsShouldProcess and ConfirmImpact control how risky your function is and whether it supports risk mitigation. SupportsShouldProcess adds the common switch parameters -WhatIf and -Confirm. ConfirmImpact specifies when the action of the function should be confirmed by a call to the ShouldProcess method to require the user to confirm that action. The ConfirmImpact property should be set to the level at which the $ConfirmPreference should prompt for confirmation. You will also need to set SupportsShouldProcess in order to use ConfirmImpact. This will make it so you will be prompted to perform an action or run the function.

You can set the ConfirmImpact argument’s level to one of the following:

  • None – PowerShell will not prompt confirmation for any actions unless you use the -Confirm switch.
  • Low – Actions with low, medium, or high risk will be automatically confirmed.
  • Medium – The default level of the ConfirmImpact argument, where PowerShell prompts confirmation for actions with medium or high risk, such as deleting files.
  • High – PowerShell prompts the user as if the function was called with the -Confirm parameter.

SupportsPaging acts similar to data processing features of systems such as SQL and adds three parameters:

  • First: Gets only the first n objects.
  • Skip: Ignores the first objects and then gets the remaining objects.
  • IncludeTotalCount: Reports the number of objects in the data set (an integer) followed by the objects. If the cmdlet cannot determine the total count, it returns “Unknown total count”.

PositionalBinding and DefaultParameterSetName control how arguments are bound to your parameters. With position binding defined, parameters can be used by position rather than by name. You can use the CmdletBinding attribute to set the default parameter set name when multiple are defined. DefaultParameterSetName is the value you want PowerShell to use if there is no parameter set. Sometimes it’s not possible to determine a parameter set name without the default parameter set.

HelpUri and RemotingCapability expose information such as the URL for help information, and the types of remoting techniques employed by your code.

It’s important to note that when you add a CmdletBinding attribute to a function, you must add a Param block. It’s required with CmdletBinding, even when the function has no parameters. If you omit the Param block, you get a syntax error. This error is not very helpful, but you can eliminate it by adding Param().

What are Common Parameters?

PowerShell adds support for Common Parameters to advanced functions when using the CmdletBinding attribute, but why do we want this?

PowerShell provides multiple output streams or pipelines, these being:

  • Success, or default stream
  • Error
  • Warning
  • Verbose
  • Debug
  • Information

It is worth mentioning that there is a Progress stream, but it does not support redirection.

The streams provide channels for different types of messages. You can write to these streams using the associated cmdlet or redirection. Using Common Parameters gives the ability to manipulate these different pipelines in your functions.

Common parameters are as follows:

  • Verbose – This switch assigns the VerbosePreference variable Continue for the cmdlet, script, or function—meaning that any embedded writes to the Verbose pipeline with Write-Verbose will display output. There’s no guarantee that a cmdlet will actually produce verbose output, but the -Verbose switch will enable whatever’s in there.
  • Debug – Displays programmer-level detail about the operation done by the command. This parameter works only when the command generates a debugging message using the Write-Debug cmdlet.
  • ErrorAction – Determines how the cmdlet responds to non-terminating errors, such as those from the Write-Error cmdlet, by changing the command’s default behavior.
  • ErrorVariable – Specifies a variable name that stores errors from the command during processing. This variable is populated in addition to $error.
  • InformationAction – Overrides the value of the $InformationPreference preference variable, which by default is set to SilentlyContinue. When you use Write-Information in a script with InformationAction, Write-Information values are shown depending on the value of the InformationAction parameter. 
  • InformationVariable –  Specifies a variable that captures output when using the Write-Information command. Write-Information values are shown depending on the value of the InformationAction common parameter; if you don’t add the InformationAction common parameter, Write-Information strings are shown depending on the value of the $InformationPreference preference variable.
  • OutVariable – Stores output objects from the command in the specified variable in addition to sending the output along the pipeline.
  • OutBuffer – Determines the number of objects to accumulate in a buffer before any objects are sent through the pipeline. If you omit this parameter, objects are sent as they’re generated.
  • PipelineVariable – Allows access to the most recent value passed into the next pipeline segment by the command that uses this parameter. Any command in the pipeline can access the value using the named PipelineVariable. The value is assigned to the variable when it is passed into the next pipeline segment.
  • WarningAction – Determines how the cmdlet responds to a warning resulting from the command. Continue is the default value. This parameter works only when the command generates a warning message using the Write-Warning cmdlet.
  • WarningVariable – Stores warnings about the command in the specified variable.

All action parameters and preference variables use ActionPreference values:

  • Continue – Displays the error and continue execution.
  • SilentlyContinue – Hides error but still adds it to the ErrorVariable, if specified, and $error stack.
  • Stop – Throws an exception and halts execution. Exceptions may be caught and handled via a try / catch / finally block. Non-terminating errors cannot be handled via try / catch / finally because an exception isn’t thrown unless ErrorAction is Stop.
  • Ignore – Ignores the error happened and gives no indication it occurred. Neither ErrorVariable nor the $error stack is updated in this case.
  • Inquire – Asks the operator what to do if an error occurs.

You can use the common parameters with any cmdlet, but they might not have an effect on all cmdlets. For example, if a cmdlet doesn’t generate any verbose output, using the Verbose common parameter has no effect.

Several common parameters override system defaults or preferences that you set by using the PowerShell preference variables. Unlike the preference variables, the common parameters affect only the commands in which they’re used.

For more information, see about_Preference_Variables.

Let’s Try an Example

Using the function we defined above, let’s demonstrate ErrorAction and ErrorVariable.

Run our function:

Test-ScriptBlock

We should see our error message that was defined using Write-Error and it writing out the final total. The function continued after writing the error because the default value of $ErrorActionPreference is Continue. This means it will continue on with the function despite getting an error.

We can change how our function handles this error by changing $ErrorActionPreference or using ErrorAction.

If we run the following:

Test-ScriptBlock -ErrorAction Stop

We should no longer see the final total because the function stopped after writing out our error message.

If we want our error saved in a specific variable, we can use ErrorVariable to specify a name.

Let’s run the following lines:

Test-ScriptBlock -ErrorAction SilentlyContinue -ErrorVariable err
$err | gm
$err[0]

By running ErrorAction with the value SilentlyContinue, our error message was hidden. Our error, with type ErrorRecord, was saved to the variable $err.

It’s also worth mentioning that you can add errors to that variable by specifying a “+” in front of your variable for ErrorVariable like so:

Test-ScriptBlock -ErrorAction SilentlyContinue -ErrorVariable +err

Conclusion

A good understanding of PowerShell function capabilities will help prevent undesired results in your scripts and allow you to reap the benefits of advanced functionality. Happy scripting!

Feedback

As always, if you have any ideas, comments, or feedback, please visit our feedback forum and reference this post.