Are you ready to take your PowerShell skills to the next level and unleash the true power of advanced functions? Look no further! In this blog post, we will guide you through the fascinating world of the PowerShell CmdletBinding attribute, a game-changing attribute that can supercharge your scripting capabilities.
Requirements
- A computer with Windows PowerShell 5.1 or PowerShell 7.x and later.
- A script editor, such as Visual Studio Code or PowerShell ISE.
Simple vs. Advanced Functions
Have you ever wondered how the compiled cmdlets, like the built-in ones, including Get-Process, Get-Service, etc., have a default set of parameters? Parameters like -ErrorAction, -WarningAction, and -Verbose, to name a few. That’s because they included the CmdletBinding attribute when they were developed and compiled.
But you don’t have to write cmdlets in Microsoft .NET to access these advanced features. You can use the CmdletBinding attribute in your scripts and functions.
So what’s the difference between simple and advanced functions? For reference, I have two functions conveniently named Simple-Function and Advanced-Function.
To illustrate the difference, I’ll display the syntax for both:
Get-Command Simple-Function -Syntax Get-Command Advanced-Function -Syntax
The result shows that the advanced function has more parameters, such as -WhatIf and -Confirm. It also has access to the PowerShell common parameters. Furthermore, the parameter is assigned a specific data type (string) and can be set as mandatory.
We’ll explore how you can use these advanced function parameters with the PowerShell CmdletBinding attribute.
Turning a Simple Function to Advanced by Adding the CmdletBinding Attribute
Let’s start with creating a simple function called Kill-Pokemon. This function starts out with this code:
Function Kill-Pokemon { param ( $Name ) Write-Output "You just killed $Name." }
When you execute this function, you’ll get the following result.
Checking its syntax, you can confirm that it is not an advanced function.
Get-Command Kill-Pokemon -Syntax
So how do we make this function advanced? Two things: Add the CmdletBinding attribute and parameter block.
Function Kill-Pokemon { [CmdletBinding()] param ( [Parameter()] [String] $Name ) Write-Output "You just killed $Name." }
The function now has access to the common parameters, and the parameter is strongly typed.
Meaning the function now has these additional parameters.
Adding the SupportsShouldProcess Argument
The SupportsShouldProcess argument in the CmdletBinding attribute exposes two new parameters to the function.
- -WhatIf — This parameter displays a message about what the function will do without executing it.
- -Confim — This parameter prompts the user to confirm the pending action the function will take. If the user confirms, the action will continue. If the user does not confirm, the action will stop.
Now let’s update the function.
Function Kill-Pokemon { [CmdletBinding( SupportsShouldProcess )] param ( [Parameter()] [String] $Name ) if ($PSCmdlet.ShouldProcess($Name)) { Write-Output "You just killed $Name." } }
In this example, the SupportsShouldProcess argument is inserted in the CmdletBinding attribute. To apply this argument, you must reference it using this line: $PSCmdlet.ShouldProcess($Name), where $Name is the parameter involved.
Test the -WhatIf parameter:
Kill-Pokemon -Name Bulbasaur -WhatIf
As you can see, the result tells you what the operation would have done to the target.
Now, test the -Confirm parameter.
Kill-Pokemon -Name Bulbasaur -Confirm
With it, the function prompts for confirmation. Answering with Y or A will confirm the operation.
Adding the ConfirmImpact Argument
In the previous section, we added the ShouldProcess argument that exposed the -Confirm parameter. But the confirmation is only triggered when you specify the -Confim parameter during execution.
On the other hand, the ConfirmImpact argument automatically shows the confirmation prompt if the impact level matches the $ConfirmPreference variable (Low, Medium, High).
In this example, the $ConfirmPreference value is High.
Let’s modify the function to add the ConfirmImpact argument and set it to level High.
Function Kill-Pokemon { [CmdletBinding( SupportsShouldProcess, ConfirmImpact = 'High' )] param ( [Parameter()] [String] $Name ) if ($PSCmdlet.ShouldProcess($Name)) { Write-Output "You just killed $Name." } }
When you execute the function, the confirmation prompt is activated even if you don’t use the -Confirm parameter.
The confirmation was triggered because we expressly set the function’s impact level to High. If we set the function’s impact level to something lower, like, Medium, the confirmation should not be triggered.
The confirmation did not show because the function’s impact level is lower (Medium) than the $ConfirmPreference value (High).
Using Advanced Parameter Attributes
The PowerShell CmdletBinding attribute has opened more opportunities to customize and control your functions. One is the ability to control parameter attributes, like making them mandatory, including them in a unique parameter set, defining their position, and allowing them to accept values from the pipeline.
Enforcing Mandatory Parameters
You can make a parameter mandatory in a function by adding the Mandatory = $false argument. You can also use the shorthand version Mandatory.
In this example, let’s make the $Name variable mandatory.
param ( [Parameter( Mandatory )] [String] $Name )
So if you run the function without specifying the -Name parameter, you will be prompted to enter it.
Setting the Parameter Position
You can specify the position of a parameter by adding the Position = n argument. When a parameter is positional, specifying the parameter name before the value becomes optional.
param ( [Parameter( Mandatory, Position = 1 )] [String] $Name, [Parameter( Position = 2 )] [String] $Type )
In the above example, the Name parameter is in position 1, while the Type parameter is in position 2. So instead of issuing the following command:
Kill-Pokemon -Name Pikachu -Type Electric
You can drop the parameter name and just provide the parameter value following their positions.
Kill-Pokemon Pikachu Electric
And the result will be the same.
Accepting Values from the Pipeline
Another advanced function feature is accepting a value from the pipeline. To enable this feature, you must add the ValueFromPipeline attribute to the parameter. For example, to make the -Name parameter accept its value from the pipeline:
[Parameter( Mandatory, Position = 1, ValueFromPipeline )]
What does this mean? Instead of running this command by specifying the -Name parameter.
Kill-Pokemon -Name Pikachu
You can do this instead.
"Pikachu" | Kill-Pokemon
The function will produce the same result.
Validating Parameters
One more excellent use of advanced functions with CmdletBinding is parameter validation. There are many parameter validation attributes, but one is the ValidateSet attribute.
Out function currently have two parameters: Name and Type. Suppose you want to restrict the types only to accept a pre-defined set of values; then, you can use the ValidateSet attribute to define them.
In this example, the [ValidateSet()] block contains only four values in the set.
[Parameter( Position = 2 )] [ValidateSet( 'Eletric', 'Flying', 'Poison', 'Ground' )] [String] $Type
The effect is you can now only enter the four values.
What if you forcefully entered a value not included in the ValidateSet block? You’ll get the following error.
Because “Ghost” is not in the ValidateSet block, it is an invalid value, and the function fails.
Conclusion
The PowerShell CmdletBinding attribute revolutionizes the way developers create advanced functions. With CmdletBinding, we can enhance our functions with features such as supporting common parameters, enabling pipeline input, and implementing advanced error handling. We have control over mandatory, optional, and dynamic parameters to build functions that meet specific requirements.
CmdletBinding’s ValueFromPipeline parameter attribute facilitates seamless integration with the PowerShell pipeline. Functions can effortlessly accept input from the pipeline, enabling smooth interaction with other PowerShell commands.
Parameter validation further enhances function flexibility and reliability. Validation attributes enforce input constraints, preventing errors and unexpected behaviors. In summary, the CmdletBinding attribute empowers PowerShell developers to create versatile, efficient, and user-friendly advanced functions.
Leveraging its capabilities leads to cleaner and maintainable code, saving time and effort in the long run. Embrace this powerful feature and elevate PowerShell scripting to new heights.
What you learned in this post barely scratches the surface and is intended to give you a starting point for implementing advanced functions. There is much more to discover, and it’s up to you to discover and use them. Good luck!