While I was writing a library of my own CmdLets I used Parameter Sets very often and in this article, I would like to share my experience and research on the topic of PowerShell Parameter Sets.
Parameter Sets in PowerShell functions enable the possibility to get the results of the function using different input parameter groups according to the needs.
Previous sentence sounds like definition but do not worry we have many examples to understand PowerShell Parameter Sets.
Table of Contents
Why Do We Want To Create PowerShell Parameter Sets
Before we dive in the steps how to create PowerShell Parameter Sets lets discuss some of the reasons why we want to have PowerShell Parameter Sets in the first place:
- to have the flexibility of getting the same result of PowerShell CmdLet or Advanced Function with different input parameters depending on the situation and when some parameter(s) are more appropriate than other(s),
- to get different results from the same PowerShell CmdLet or Advanced Function dependent on input parameters provided.
Let me quickly illustrate with a few examples.
I wanted to get information when a bunch of servers was last time restarted so I have written my own CmdLet Get-LastBootUpTime with parameter “computers” that accept a list of string arrays representing server names.
IMPORTANT: The source code for this CmdLet is here. Get-LastBootUpTime is part of the Efficiency Booster PowerShell Project which is the library of many awesome CmdLets so please check it out.
Get-LastBootUpTime CmdLet script is located here …\[My] Documents\WindowsPowerShell\Modules\03common
Here is an example to run Get-LastBootUpTime CmdLet with one server name for computers parameter:
Get-LastBootUpTime -computers 'localhost' -client "OK" -solution "FIN" -errorlog | Out-GridView
Here is the resultset:
Here is another example to run CmdLet with two server names for “computers” parameter:
Get-LastBootUpTime -computers 'localhost', 'localhost' -client "OK" -solution "FIN" -errorlog | Out-GridView
Here is the resultset:
I hope you get the picture as I add more and more server names to the “computers” parameter than the call to Get-LastBootUpTime CmdLet gets longer and longer which is not very neat in my opinion and code becomes cluttered very fast.
Wouldn’t it be nice to have another parameter in the same CmdLet that will accept the name of the text file and that text file to contain the list of servers?
Then we do not need to worry about how many servers we want to check since we can just add new servers in the text file and continue calling the same CmdLet without making it cumbersome and without changing anything in syntax when calling CmdLet.
So I have exactly done that. I have created a new parameter “filename” that accepts the name of the text file and here is an example of call with that parameter:
Get-LastBootUpTime -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose | Out-GridView
Here is the result set of that call and as you can see we have a lot more servers in the list.
If you wonder what is the content of OKFINservers.txt file and where it is located. Here is the content of the text file:
NOTE: Since I do not have a network of machines at home I have just repeated the localhost to run the same CmdLet several times just to simulate that we are on a network with a bunch of machines. In real world example we would have list of server names in this text file.
And the location of the file, if you have downloaded the zip with source code is \[My] Documents\WindowsPowerShell\Modules\01servers
As you can see we can start with one solution and as requirements are changing we can find a new solution to fulfill the new requirements and to fit our needs.
Conclusion
The solution to meet all the requirements was to have two parameter sets.
The First Parameter Sets will give us the option to call the CmdLet when just a few servers are involved. In our example, that is computers input parameter.
The Second Parameter Sets is useful when we have many servers in our environment and using array of strings as input parameter makes call to CmdLet cumbersome and cluttered. In our example, we have created filenames input parameter to accomplished just that.
Another usage of filenames input parameter is when a list of servers is segmented with some criteria, like environment for example (test, production, course, acceptance, etc). In that scenario, we can create several text files like
- OKFINTestServers,
- OKFINCourseServers,
- OKFINAllServers,
- OKFINProductionServers, etc.
How To Create PowerShell Parameter Sets (Declaring Parameter Sets)
Here are the steps to follow when you want to create a parameter set for your own CmdLet:
- Use ParameterSetName Argument within the Parameter Attribute for each input parameter of CmdLet that needs to be in the Parameter Set like in the example below:
[Parameter(ParameterSetName=’some_name‘)] - Define which Parameter Set is default as DefaultParameterSetName Argument of CmdletBinding Attribute.
[CmdletBinding(DefaultParameterSetName=’some_name’)] - Implement in the function body code ParameterSetName of $PsCmdlet automatic variable (if needed) like in the example below:
if ( $PsCmdlet.ParameterSetName -eq “FileName”) { } else { } - Test your Parameter Set code
Let’s see some examples where we will implement the steps defined above.
Example Of Parameter Sets In PowerShell Function
Let’s use one example to create Parameter Sets following the steps above. We will create a function that has two parameter sets:
- The first Parameter Set will accept a list of computer names as an array of strings.
- The second Parameter Set will accept the name of the text file that will be read and the content of that text file is a list of server names.
As an example, we will use my own Get-CPUInfo CmdLet that is part of the Efficiency Booster PowerShell Project and I encourage you to check it out. This project is a library of awesome CmdLets so please feel free to download zip code and you will be able to follow me along.
Get-CpuInfo CmdLet will be found in …\[My] Documents\WindowsPowerShell\Modules\03common folder
Step 1. We create the input parameter “computers” that belongs to the “ServerNames” Parameter Set. We have used ParameterSetName Argument with the value “ServerNames” within the Parameter Attribute when we defined the “computers” input parameter of the Get-CPUInfo function.
Function Get-CPUInfo {
[CmdletBinding()]
param (
[Parameter( ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ParameterSetName="ServerNames",
HelpMessage="List of computer names separated by commas.")]
[Alias('hosts')]
[string[]]$computers = 'localhost'
)
}
IMPORTANT: If you want to know more about how to write parameters for your own functions please read this post. I have lots of code and examples in the article so check it out.
Repeat Step 1. We create a second input parameter “filename” that belongs to the “FileName” Parameter Set. We have used ParameterSetName Argument with the value “FileName” within the Parameter Attribute when we defined the filename input parameter of the Get-CPUInfo function.
Function Get-CPUInfo {
[CmdletBinding()]
param (
[Parameter( ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ParameterSetName="ServerNames",
HelpMessage="List of computer names separated by commas.")]
[Alias('hosts')]
[string[]]$computers = 'localhost',
[Parameter( ParameterSetName="FileName",
HelpMessage="Name of txt file with list of servers. Txt file should be in 01servers folder.")]
[string]$filename
)
}
Repeat Step 1. We create a third input parameter “errorlog” that belongs to both parameter sets. Since we did not use ParameterSetName Argument within parameter declaration that means this parameter belongs to both Parameter Sets.
Function Get-CPUInfo {
[CmdletBinding()]
Param
(
[Parameter( ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ParameterSetName="ServerNames",
HelpMessage="List of computer names separated by commas.")]
[Alias('hosts')]
[string[]]$computers = 'localhost',
[Parameter( ParameterSetName="FileName",
HelpMessage="Name of txt file with list of servers. Txt file should be in 01servers folder.")]
[string]$filename,
[Parameter( Mandatory=$false,
HelpMessage="Write to error log file or not.")]
[switch]$errorlog
)
}
Step 2. We defined “ServerNames” as Default Parameter Set by implementing DefaultParametersetName Argument in the CmdletBinding Attribute.
Function Get-CPUInfo {
[CmdletBinding(DefaultParametersetName="ServerNames")]
Param
(
[Parameter( ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ParameterSetName="ServerNames",
HelpMessage="List of computer names separated by commas.")]
[Alias('hosts')]
[string[]]$computers = 'localhost',
[Parameter( ParameterSetName="FileName",
HelpMessage="Name of txt file with list of servers. Txt file should be in 01servers folder.")]
[string]$filename,
[Parameter( Mandatory=$false,
HelpMessage="Write to error log file or not.")]
[switch]$errorlog
)
}
Step 3. “FileName” Parameter Set has been implemented in the BEGIN block. Basically what the code does is to read the text file with the list of servers to make an array of strings with server names. We have used ParameterSetName property value of automatic variable $PsCmdlet to implement Parameter Set definition.
Function Get-CPUInfo {
[CmdletBinding(DefaultParametersetName="ServerNames")]
Param
(
[Parameter( ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ParameterSetName="ServerNames",
HelpMessage="List of computer names separated by commas.")]
[Alias('hosts')]
[string[]]$computers = 'localhost',
[Parameter( ParameterSetName="FileName",
HelpMessage="Name of txt file with list of servers. Txt file should be in 01servers folder.")]
[string]$filename,
[Parameter( Mandatory=$false,
HelpMessage="Write to error log file or not.")]
[switch]$errorlog
)
Begin
{
if ( $PsCmdlet.ParameterSetName -eq "FileName") {
if ( Test-Path -Path "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" -PathType Leaf ) {
Write-Verbose "Read content from file: $filename"
$computers = Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" )
} else {
Write-Warning "This file path does NOT exist: $home\Documents\WindowsPowerShell\Modules\01servers\$filename"
Write-Warning "Create file $filename in folder $home\Documents\WindowsPowerShell\Modules\01servers with list of server names."
break;
}
}
}
Process
{
}
End
{
}
}
Now we can continue with coding the rest of the function. I have not done that here since everything is in the source code that you can download here.
Step 4. We can test both Parameter Sets with different calls to Get-CPUInfo CmdLet.
NOTE: Download the source code in order to have the results as I am showing here otherwise you have to write your own code in the CmdLet.
Get-CPUInfo -computers 'localhost' -client "OK" -solution "FIN" -errorlog | Out-GridView
Get-CPUInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" | Out-GridView
How Do We Know That Function or CmdLet Has Parameter Sets
If you run Get-Command CmdLet with Syntax parameter like in the following example and as a result, you get more then one line of result that means the CmdLet has Parameter Sets.
Get-Command Get-Service -Syntax
So Get-Service CmdLet has three Parameter Sets since we got three lines in the result set.
Or another example with Get-Process CmdLet
Get-Command Get-Process -Syntax
Get-Process CmdLet has six Parameter Sets since we have six different calls to the same CmdLet and each has some parameter that is unique for that call.
How Do We Know Which Parameter Belongs To Which Parameter Set
In order to find out which parameter belongs to which parameter set we need to do the following things:
- Use Get-Help PowerShell CmdLet
- Provide the name of CmdLet for which we want to find Parameter Set for the specified input parameter.
- Use the Parameter parameter of Get-Help CmdLet with the value of input parameter for which we want to find out Parameter Set. We can use the wildcards as well like ‘*’ for all parameter instead of specific input parameter.
Example 1 – Parameter Set of computers parameter from the Get-CPUInfo CmdLet
Here is an example of my own CmdLet Get-CPUInfo:
Get-Help Get-CPUInfo -Parameter computers
Example 2 – Parameter Sets of Id parameter from Get-Process CmdLet
We can use Get-Process PowerShell CmdLet as an example. Parameter Id belongs to parameter sets: Id, and IdWithUserName
Get-Help Get-Process -Parameter Id
Example 3 – Investigate all the parameters of some PowerShell CmdLet
If we want to investigate all the parameters of Get-Process CmdLet than we should run the following command:
Get-Help Get-Process -Parameter *
Look into the Parameter Set Name field of the result to see which parameter belongs to which Parameter Set(s).
NOTE: Important to know that this result is dependent on the version of PowerShell that you are running on. Versions below 5.1 will not give us information for Parameter Set Name but versions 6 and 7 will do.
What Are The PowerShell Parameter Set Requirements
Here is the list of requirements that apply to all Parameter Sets:
- Each parameter set must have at least one unique parameter.
- A parameter set that contains multiple positional parameters must define unique positions for each parameter. The same position for two positional parameters is not allowed.
- Only one parameter in a set can declare the ValueFromPipeline keyword with a value of true.
- Multiple parameters can define the ValueFromPipelineByPropertyName keyword with a value of true.
- The parameter belongs to all parameter sets if no parameter set is specified for a parameter.
How To Tell PowerShell Which Parameter Set Should Be Default Parameter Set
In order to make one of the Parameter Sets default in PowerShell Function we will Use DefaultParameterSetName Argument within CmdletBinding Attribute.
[CmdletBinding(DefaultParameterSetName="ServerNames")]
Read more about the syntax of CmdletBinding Attribute in the next section
How To Use CmdletBinding Attribute With Parameter Sets
The CmdletBinding Attribute is an attribute of functions that makes them look and feel like CmdLets delivered with Microsoft PowerShell. Basically, allow us to utilize PowerShell Common Parameters ( Debug (db), ErrorAction (ea), ErrorVariable (ev), Verbose (vb), etc) .
CmdletBinding syntax is very simple as it is as follows:
[CmdletBinding()]
CmdletBinding should be declared in the function body right above Param construct and after function definition like in the following example:
Function Function_Name
{
[CmdletBinding()]
Param ($ParameterA)
Begin{}
Process{}
End{}
}
CmdletBinding accepts several arguments defined inside () and in the context of Parameter Sets topic, the argument that is particularly useful is DefaultParameterSetName which can be implemented like this:
[CmdletBinding(DefaultParameterSetName="ServerNames")]
It is useful to make certain Parameter Set default for the function and it will be used when PowerShell cannot determine which Parameter Set to use.
Other Arguments of CmdletBinding attribute are:
- ConfirmImpact=<String>,
- HelpURI=<URI>,
- SupportsPaging=<Boolean>,
- SupportsShouldProcess=<Boolean>,
- PositionalBinding=<Boolean>
Here is an example with implementation of DefaultParametersetName argument in CmdletBinding Attribute.
Function Get-CPUInfo {
[CmdletBinding(DefaultParametersetName="ServerNames")]
Param
(
[Parameter( ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ParameterSetName="ServerNames",
HelpMessage="List of computer names separated by commas.")]
[Alias('hosts')]
[string[]]$computers = 'localhost',
[Parameter( ParameterSetName="FileName",
HelpMessage="Name of txt file with list of servers. Txt file should be in 01servers folder.")]
[string]$filename,
[Parameter( Mandatory=$false,
HelpMessage="Write to error log file or not.")]
[switch]$errorlog
)
Begin
{
if ( $PsCmdlet.ParameterSetName -eq "FileName") {
if ( Test-Path -Path "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" -PathType Leaf ) {
Write-Verbose "Read content from file: $filename"
$computers = Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" )
} else {
Write-Warning "This file path does NOT exist: $home\Documents\WindowsPowerShell\Modules\01servers\$filename"
Write-Warning "Create file $filename in folder $home\Documents\WindowsPowerShell\Modules\01servers with list of server names."
break;
}
}
}
Process
{
}
End
{
}
}
How To Implement Parameter Sets In Your Own Code
If you want to know which Parameter Set is in use while code in the CmdLet is running and based on that information to make some decisions best approach is to read the value from the property ParameterSetName of automatic variable $PSCmdlet like in this example.
if ( $PsCmdlet.ParameterSetName -eq "FileName") {
if ( Test-Path -Path "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" -PathType Leaf ) {
Write-Verbose "Read content from file: $filename"
$computers = Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" )
} else {
Write-Warning "This file path does NOT exist: $home\Documents\WindowsPowerShell\Modules\01servers\$filename"
Write-Warning "Create file $filename in folder $home\Documents\WindowsPowerShell\Modules\01servers with list of server names."
break;
}
}
Basically, what we do here is to check if FileName Parameter Set has been used and then we test whether text file exists or not. If the text file exists we read the content of it and if not we give to the user a warning message.
Useful PowerShell Commands
Here are a few commands useful when we work with PowerShell Parameter Sets.
Get-Command Get-Service -Syntax
Get-Help Get-Process -Parameter Id
Get-Help Get-Process -Parameter *
Get-Help Get-Service
Useful PowerShell Parameter Set Articles
Here are some useful articles and resources:
Read More
- If you want to know more about how to create PowerShell Parameters with awesome examples please read How To Create Parameters In PowerShell.
- Learn how to write own PowerShell CmdLets Step by Step in the article How To Create A Custom PowerShell CmdLet (Step By Step).
- Learn how to write PowerShell Functions Fast by reading How To Write Advanced Functions Or CmdLets With PowerShell (Fast).
- PowerShell Comment-Based Help writing using PowerShell ISE Add-on has been explained here.
- How To Write PowerShell Help (Step by Step) is a more detailed approach to Comment-Based help writing.