Default Parameters - Save Yourself A Few Headaches

I was recently asked by a co-worker to review a script they were working on. The script involved updating and validating user accounts in Active Directory. The environment I work in has a multitude of AD servers which the cmdlets could run against, and I offered the suggestion that either each of the commands be ran against the same AD server in order to ensure that the data is accurate during the validation phase or a short rest be inserted between the set and get operations to ensure replication has properly occurred.

I offered this suggestion due to having learned the lesson the hard way while working on a large user provisioning application a few years ago. The environment that I built the application in had considerably less domain controllers than my current job's and I would routinely run into issues where updates would occur on server A while the validation operation would occur on server B. I was a lot more inexperienced at the start of the project and learned a lot going through it - including how much fun AD replication can be at times.

My coworker took the advice, and started to add the server parameter to all of the AD commands in their script. When I mentioned they could set a default parameter value for all of the commands, they mentioned they were unaware that this could be done. I had worked with this person before and knew their skill set, and they were no slouch when it came to PowerShell - so if they had no idea this feature existed I thought there may be even more people that are newer to using PowerShell who may have no idea the option even exists.

The beauty of using default parameters values is that they are simple to use and offer a simple solution for making sure that all commands are using the correct parameters every time they are called without having to type the same thing over and over again.

Setting a default parameter is done using $PSDefaultParameterValues. From the Microsoft website regarding information on $PSDefaultParamterValues

The $PSDefaultParameterValues preference variable lets you specify custom default values for any cmdlet or advanced function. Cmdlets and functions use the custom default value unless you specify another value in the command.>

In other words, $PSDefaultParamterValues lets you specify a value for any cmdlet or function that is called - and is particularly helpful when there are multiple calls to the same command or multiple calls from the same module which use the same parameter in multiple functions.

A simple illustration of how $PSDefaultParamterValues makes life easier is below to highlight how much simpler and easier to read a segment of code can be when using this trick.

Example 1:

The AD server has to be declared each time we run an AD cmdlet to ensure all commands run against the same server to prevent AD replication issues from causing issues with our script. In the below example, if the parameter -server is not used, there is a possibility that the initials property may not be set to "e" yet due to replication timing.

get-aduser -identity "john.smith" -server "ad01.contosco.com" | `
set-aduser -initials "e" -server "ad01.contosco.com"

if((get-aduser -identity "john.smith" -server "ad01.contosco.com" `
-properties initials).initials -eq "e")
{
     out-CustomLog -message "Initials updated correctly" -mirrormessage -type information
}

Example 2:

The AD server has been set as "ad01.contosco.com" and all subsequent AD commands are run against the domain controller set in the first line.

$PSDefaultParameterValues["*-ad*:server"] = "ad01.contosco.com"
get-aduser -identity "john.smith" | set-aduser -initials "e"

if((get-aduser -identity "john.smith" -properties initials).initials -eq "e")
{
     out-CustomLog -message "Initials updated correctly" -mirrormessage -type information
}

After example 2 is run, you can validate that the value is working correctly by running the command:

get-addomaincontroller | select-object name

In the above example, the name returned will be "ad01.contosco.com" no matter how many times it's run. If $PSDefaultParamtervalues as defined above is not run, each time get-addomaincontroller is run a new domain controller is selected.

Like everything else in PowerShell, the $PSDefaultParameterValues can either be set manually (through a script or command line) or can be configured in the PowerShell profile.