More Advanced Functions
Want to add some more functionality to our scripts and functions? Want your scripts to operate like the standard Powershell cmdlet’s, with the same Common Parameters? Well you can, and it’s not difficult at all. Read on to add these abilities to your scripts!
What Are Common Parameters?
Any time you look at the help of a cmdlet you’ll almost always see at the end [<CommonParameters>]. Which is great, but if you don’t actually know what those are it’s a bit useless. Luckily, Powershell help is pretty good and you can find very detailed information about what they are by typing:
Get-Help About_CommonParameters
The most important part of these, in my humble opinion of course, are the actual parameters available:
-Verbose -Debug -WarningAction -WarningVariable -ErrorAction -ErrorVariable -OutVariable -OutBuffer and -WhatIf -Confirm
Some of the most common ones you’ll use are -Verbose, -ErrorAction, -WhatIf and -Confirm. What I want to talk about today is turning on the -WhatIf and -Confirm functionality.
ShouldProcess
The key to turning on Common Parameters is the [CmdletBinding()] statement. You’ll often see scripts putting this statement on the first line to activate these advanced settings. Both the -Whatif and -Confirm parameters use ShouldProcess, but we have to do one additional thing to [CmdletBinding()] so we can use those parameters.
[CmdletBinding(SupportsShouldProcess=$true)]
Now we can start using these parameters!
In Action
So let’s put it to the test and see what we get. Here’s a very simple script that needs a UserName as a parameter and will set that user’s password to never expire. TSA stands for The Surly Admin, of course!
[CmdletBinding(SupportsShouldProcess=$true)] Param ( [string]$User ) Set-ADUser $User -PasswordNeverExpires $true
And when we run this script with the -WhatIf parameter, here’s what we see.
Nothing actually done, but we get the standard What If text with our custom information in it. Notice how target is now our $User variable, and the standard action text actually comes first in the message. But we can’t stop here, we have to see what running this with -Confirm looks like.
That’s all there is to it, Powershell will take care of everything for you. But what if you want to generate you’re own messages? That’s where ShouldProcess comes into play. Here’s the code you can use.
$PSCmdlet.ShouldProcess(target,action)
We use the above in an If() statement to execute our code. The statement will return a $true unless -WhatIf has been specified, in which case it will display our message–action being performed on target–and then move on. If you have -Confirm specified it will show you the action to target and then prompt you if you want to actually perform the action.
[CmdletBinding(SupportsShouldProcess=$true)] Param ( [string]$User ) If ($PSCmdlet.ShouldProcess($User,"Set password to never expire")) { Set-ADUser $User -PasswordNeverExpires $true }
This works great in our -WhatIf scenario, as you can see.
But falls down a little when using it with -Confirm.
As you can see, we’re now getting prompted twice! This is because -Confirm tells Powershell to ask for a confirmation anytime you want to use a cmdlet that changes the state of something, like a set* cmdlet. So not only do you get prompted when use the PSCmdlet.ShouldProcess method you then get prompted when changing state. No good solution for this that I’ve found, so if you know one please let me know!
One nice addition this is when you use the -Verbose parameter you will now get feedback from your cmdlet.
And the feedback is using your custom text, which is really nice. So I guess 2 out of 3 ain’t bad?!
[…] Before we can move direct reports we need a way to set them in the first place. You can always use ADUC, of course, but we need a way to do this quickly and easily. Especially for testing! Hence Set-SAADManager was born. This function takes user input from the pipeline–from multiple sources–and assigns these users to whatever manager you assign with the -NewManager parameter. I also wanted to give the function the same range of options that any cmdlet has, so that meant support -WhatIf, -Verbose and -Confirm. This took advantage of the techniques I’ve built up here and here. […]
My best workaround for the “double confirm” is to pass a -Confirm:$false to the cmdlet itself in code. This keeps your custom confirm text, but if you confirm that it silently does the actual operation.
So your example function would be like:
[CmdletBinding(SupportsShouldProcess=$true)]
Param (
[string]$User
)
If ($PSCmdlet.ShouldProcess($User,”Set password to never expire”))
{ Set-ADUser $User -PasswordNeverExpires $true -Confirm:$false
}
I had a similar problem, this, “-Confirm:$false” worked like a charm. Thanks Steve Bernard Jr.