Prof. Powershell

Functions That Act Like Cmdlets

The trick to making functions act like cmdlets? It's all in the binding.

Perhaps the biggest benefit of writing advanced functions in Windows PowerShell is the ability to create a function that for all practical purposes behaves just like a cmdlet. You can accomplish this by inserting code into your function that tells PowerShell, “Hey, treat me like a cmdlet.” And the easiest solution is to use the [cmdletBinding()] attribute at the beginning of your function or script, but before declaring any parameters:

#Requires -version 2.0
Function Set-Foo {
[cmdletBinding()]
Param(...

If your function or script isn't using parameters, then simply close the parentheses:

Param()

One of the ways to use cmdlet binding is to include support for ShouldProcess. This is what allows support for the -WhatIf parameter. To add this functionality to your PowerShell script, modify the cmdlet binding attribute:

[cmdletBinding(SupportsShouldProcess=$True)]

The first benefit is that any cmdlet that you call within your script, that supports -WhatIf will "inherit" the directive. Here's a simple example:

Function Set-Foo {
[cmdletBinding(SupportsShouldProcess=$True)]
Param([string]$path=$env:temp)
dir $path | remove-item
}

When this function is loaded in my PowerShell session, I automatically get -WhatIf. If I run the function with -WhatIf, it is also passed to Remove-Item:

PS C:\work> set-foo $env:temp\*.txt
What if: Performing operation "Remove File" on Target "C:\Users\Jeff\AppData\Local\Temp\foo.txt".

However, you can also include your own ShouldProcess handling with the intrinsic $pscmdlet object. Here's a variation on my demo function.

Function Set-Foo {
[cmdletBinding(SupportsShouldProcess=$True)]
Param([string]$path=$env:temp)
if ($pscmdlet.ShouldProcess($path)) {
  Write-Verbose "Setting something"
  #insert your code here
  }
}

The if statement is evaluated when -WhatIf is called. The argument for the ShouldProcess() method is used to show what object the function would have processed. You can use any value you want, although I tend to use a value from one of the parameters. This is what it looks like:

PS C:\work> set-foo $env:temp\*.txt

What if: Performing operation "Set-Foo" on Target "C:\Users\Jeff\AppData\Local\Temp\foo.txt".

Notice the operation is now the name of my function. There is also no limit to the number of ShouldProcess() statements you can include. Either those from cmdlets like Stop-Process or $pscmdlet.ShouldProcess() If you run help for your function, you'll automatically get -WhatIf and also -Confirm, as a bonus!

So if you are writing scripts or functions that are changing something, take advantage of SupportsShouldProcess and cmdlet binding.

[Editor's note: This article has been updated to correct a wee little mistake in the first paragraph, noted by a reader via e-mail to Jeff directly, and which also escaped this editor, who should have caught the mistake in the first place and saved Jeff much embarrassment. Apologies to readers and to Jeff.]

About the Author

Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.

comments powered by Disqus
Most   Popular