Understanding Windows PowerShell function parameters (original) (raw)
Editor's note: Adam Bertram originally wrote the article and Brien Posey expanded it.
The PowerShell parameter is a fundamental component of most PowerShell scripts. Parameters make it possible to provide script input at runtime. If a PowerShell script's behavior must change in some way, a parameter provides an opportunity to do so without changing the underlying code.
Parameters let developers build reusable PowerShell scripts that require little code maintenance and extensibility if built correctly.
Because of this, it's important to learn how to create scripts and PowerShell function parameters, how to use them and the best practices for building parameters.
Defining parameters
Parameters can be created for scripts and functions. They are typically enclosed in a param block defined with the param keyword followed by opening and closing parentheses.
param()
The param block contains one or more parameters defined by one or more variables, as shown below.
param(
$Parameter1 )
However, to ensure the parameter accepts only the type of input you need, it's a good idea to assign a type to a script's parameters. Otherwise, someone could pass an invalid data type as a parameter, causing the script to crash. This might happen if someone were to pass string data as a parameter to a script that was intended to accept only numerical input, for instance.
You can assign a type to a parameter by enclosing the data type in brackets just before the variable name. In the example below, you can see a parameter that accepts only objects of type string. Notice, however, that the word Parameter is required to appear just before the type declaration.
param( [Parameter()] [string]$Parameter1 )
Additional parameters can be added in the same manner by separating them with a comma, as seen in this example.
param( [Parameter()] [string]$Parameter1,
[Parameter()] [string]$Parameter2 )
Write-Host "Parameter 1 value is $Parameter1" Write-Host "Parameter 2 value is $Parameter2"
Named parameters
One way to use PowerShell function parameters in a script is via a parameter name -- this method is called named parameters. When calling a script or function via named parameters, use the entire name of the parameter.
For example, perhaps the example param block above is stored in a PowerShell script called foo.ps1. If you must provide values to the Parameter1 and Parameter2 parameters using named parameters, you'd do so in the manner below. Notice that each parameter's full name is used, followed by the value being passed to it.
./foo.ps1 -Parameter1 'somevalue' -Parameter2 'someothervalue'
When you run this script, you'll see a similar output to the one below, which replaces each parameter variable with the value passed at runtime.
Values provided for parameters by name.
It's worth noting that although this script is using the names Parameter1 and Parameter2, a script that's designed for real world use should use parameter names that are more meaningful. Consider, for example, the way that individual PowerShell cmdlets are designed. Nearly all of the native PowerShell cmdlets support the use of parameters. These parameters use names that convey the parameter's use. Many PowerShell cmdlets, for instance, support the use of the ComputerName parameter, which lets you direct the cmdlet toward a specific computer on your network. That parameter's name (ComputerName) conveys what the parameter does. When designing your own scripts or functions, you should ideally take a similar approach and use parameter names that convey the expected input.
Positional parameters
Another way to use parameters is to pass values by position rather than by name. When you pass a parameter value by position, the name of the parameter isn't used. PowerShell instead matches up the values for each parameter by the position it holds in the command.
Using the previous example of the foo.ps1 script, the values for Parameter1 and Parameter2 can be passed using the positional parameters below. The parameter names aren't used. Instead, PowerShell knows Parameter1 was defined above Parameter2 in the script and automatically matches up the values in order.
./foo.ps1 'somevalue' 'someothervalue'
Running this script using positional parameters ends up with the same output result.
Values provided for parameters by position give the same result.
In the above example, both the Parameter1 and Parameter2 were defined as string types, but this isn't the only type you can use. You can use any type in the .NET class library.
Switch parameters
Another parameter you can use is the switch parameter. This parameter is used for binary or Boolean values to indicate "on" or "off." It's defined with the [switch] type.
Continuing to use the example with two parameters, add a switch parameter. Perhaps you'd like to display the output of Parameter2 only if explicitly specified. To ensure the value of Parameter2 is displayed, add a switch parameter called DisplayParameter2Value, as shown below. Notice that the switch is appended to the parameter declaration, it does not replace it. Likewise, the Parameter2 parameter is still configured to accept string input, just as it was before.
Once the switch parameter is in place, you can make a logic decision in your code by inserting an if/then construct to only run code if the switch parameter is present.
param( [Parameter()] [string]$Parameter1,
[Parameter()] [string]$Parameter2,
[Parameter()] [switch]$DisplayParameter2Value )
Write-Host "Parameter 1 value is $Parameter1" if ($DisplayParameter2Value.IsPresent) { Write-Host "Parameter 2 value is $Parameter2" }
You now have the option to display the value of Parameter2 -- or not -- as you can see below.
The switch parameter determines whether to display the Parameter 2 value.
Splatting
The above example only has three parameters. Passing values to those parameters doesn't extend too far to the right. But what if you have 10 or more parameters? And what if those parameters have long names? In that case, you must do some splatting.
Splatting is a term that describes setting up parameters for a script or function before you run a command. We've been defining and passing values to parameters at runtime. This can be problematic when you have a set of parameters that looks something like this.
param( [Parameter()] [string]$Parameter1,
[Parameter()] [string]$Parameter2,
[Parameter()] [switch]$DisplayParameter2Value,
[Parameter()]
[string]$Parameter3,
[Parameter()] [string]$Parameter4,
[Parameter()] [string]$Parameter5,
[Parameter()] [string]$Parameter6,
[Parameter()] [string]$Parameter7 )
Write-Host "Parameter 1 value is $Parameter1" if ($DisplayParameter2Value.IsPresent) { Write-Host "Parameter 2 value is $Parameter2" } Write-Host "Parameter 3 value is $Parameter3" Write-Host "Parameter 4 value is $Parameter4" Write-Host "Parameter 5 value is $Parameter5" Write-Host "Parameter 6 value is $Parameter6" Write-Host "Parameter 7 value is $Parameter7"
If you must pass values via named parameters in this new example, the command would extend far beyond a reasonable length to the right. More importantly, it's difficult to type and easily susceptible to human error.
./foo.ps1 -Parameter1 'somevalue' -Parameter2 'someothervalue' -Parameter3 'somevalue' -Parameter4 'somevalue' -Parameter5 'somevalue' -Parameter6 'somevalue' -Parameter7 'somevalue' -DisplayParameter2Value
Instead of scrolling to the right, you could define the parameter values in a separate step using a hashtable. Each parameter value can be lined up nicely, and it's much easier to see what parameters are being used.
Once the hashtable is created, you can pass all the parameters to the script or command by just specifying the name of the hashtable preceded by an @ character.
$parameters = @{ Parameter1 = 'somevalue' Parameter2 = 'someothervalue' Parameter3 = 'somevalue' Parameter4 = 'somevalue' Parameter5 = 'somevalue' Parameter6 = 'somevalue' Parameter7 = 'somevalue' DisplayParameter2Value = $true }
PS> ./foo.ps1 @parameters
This method might seem more cumbersome than just supplying parameter values in the usual way. But keep in mind that not all scripts are used by humans. Sometimes scripts are called by other scripts. Adding a hash table like the one shown above to a script that calls another script can make the script much easier to read.
PowerShell parameter attributes
Recall how, in the "Defining parameters" section above, we mentioned the [Parameter()] construct was optional but recommended? This section is one of those reasons.
There are many ways you can manipulate parameter behavior, known as parameter attributes. You can do things such as enforce that a specific parameter is used, ensure the values passed to a parameter are part of a specific set and match a regular expression. Microsoft provides a comprehensive list of advanced parameters, but to start, you only need to know the most common ones.
Mandatory parameters
It's common to have one or more PowerShell function parameters that must be used when a script is executed. In PowerShell, that parameter enforcement is called a mandatory parameter. When you make a parameter mandatory, the script or function can't run without it. Even if you forget to use the parameter, PowerShell will interactively prompt you for the value.
Consider the switch parameter example. The only difference is that Parameter1 was made mandatory by using the Mandatory keyword in the [Parameter()] construct.
param( [Parameter(Mandatory)] [string]$Parameter1,
[Parameter()] [string]$Parameter2,
[Parameter()] [switch]$DisplayParameter2Value )
Write-Host "Parameter 1 value is $Parameter1" if ($DisplayParameter2Value.IsPresent) { Write-Host "Parameter 2 value is $Parameter2" }
Before making Parameter1 mandatory, this script could have been executed like this without a problem. The value of Parameter1 would simply be empty.
./foo.ps1 -Parameter2 someothervalue
You can see what happens once the parameter is made mandatory below. PowerShell won't allow the script to run and prompts you for a value.
Mandatory parameters require a value to be added.
Parameter validation
Finally, ensure values passed to parameters are exactly what you'd expect. As a best practice you should take steps to prevent someone passing in an unexpected value to a parameter. You have various parameter validation options at your disposal to limit the values used in parameters. For a complete list, refer to advanced parameters in Microsoft's documentation.
Perhaps you know that Parameter1 should only ever be one of two values: foo and bar. You want to ensure that the value of Parameter1 will never be anything other than those values. In that case, you can use a parameter validation attribute called ValidateSet.
All parameter validation attributes are defined above the parameter name, as shown below. In this instance, ValidateSet was assigned to Parameter1. This parameter validation attribute accepts an array of values. In the below example, that's 'foo','bar'.
param( [Parameter(Mandatory,)] [ValidateSet('foo','bar')] [string]$Parameter1,
[Parameter()] [string]$Parameter2,
[Parameter()] [switch]$DisplayParameter2Value )
Write-Host "Parameter 1 value is $Parameter1" if ($DisplayParameter2Value.IsPresent) { Write-Host "Parameter 2 value is $Parameter2" }
If you were to try to pass a value other than foo or bar to Parameter1, you'd get an error like this:
Parameters with validation attributes return an error if other values are used.
Parameter validation attributes are a great way to limit what can be used.