In this article, I want to show you how to force your users to pass the proper arguments to your PowerShell scripts depending on data. I found this way for creating more readable code using fewer lines of code and get the proper parameters from the users showing them the ones the have to type.
You probably know about required parameters in PowerShell and how to declare them but if you don't, please, take a look at this article. The Mandatory parameter attribute appeared on PowerShell 2.0 and made easier to declare required parameters instead of evaluating it in code and throwing the proper error messages to the user when running it.
param(
[Parameter(Mandatory)]
[String] $Message
)
Write-Host $Message
But, what happens when my script could have mandatory parameters depending on the value of other parameters? Let's say I have a script to prepare my morning tea every day. I like tea with milk and sugar or just alone with honey. So, how to code this?
param(
[Switch] $Honey,
[Switch] $Milk,
[int] $Sugar
)
If($Honey -eq $true) {
Write-Host "Your tea with honey is ready"
} ElseIf($Milk -eq $true -and $Sugar -gt 0) {
Write-Host "Your tea with milk and sugar is ready"
} Else {
Throw "Wrong information"
}
Is this a good approach? It depends on your requirements. In my opinion, this is something I would not comfortable with, I cannot see which parameters are mandatory or the paths the code has so, imagine all these issues in a production environment where different tasks must have been implemented.
One of the solutions you might do is to separate the code into two different scripts, one for tea with milk and the other for tea with honey. This will grow your PowerShell scripts library and it will seem that you have functionality repeated.
To solve these problems, the ParameterSetName attribute helps us to have different groups of parameters and define their behavior for each case. Take a look at this article for a complete explanation. It appeared in PowerShell 2.0 for the first time to help coders to create groups of parameters for their scripts. As an example, let's think when requesting API's methods, we could have GET requests with empty bodies and POST requests with body information as a must. The script is the same and covers the same functionality in both cases but parameters could be different depending on what we need to do.
Coming back again to my tea preparation script, we will use the ParemeterSetName attribute to set two groups of parameters with Honey, in the first case, as mandatory, and Milk and Sugar mandatory for the second case. Let's see how the code is more readable and simple in the following example:
param(
[Parameter(ParameterSetName="Honey", Mandatory)]
[Switch] $Honey,
[Parameter(ParameterSetName="Milk", Mandatory)]
[Switch] $Milk,
[Parameter(ParameterSetName="Milk", Mandatory)]
[int] $Sugar
)
Switch ($PsCmdlet.ParameterSetName) {
"Honey" {
Write-Host "Your tea with honey is ready"
}
"Milk" {
Write-Host "Your tea with milk and sugar is ready"
}
}
This approach is safer for your code because parameter checking relies on the PowerShell engine and you don't have to worry about it. Another advantage appears when you get the information of your script using the Get-Help
command. It will show you the two ways the script could be called giving the clues about the parameters you can use:
PS > Get-Help Prepare-MyMorningTea.ps1
Prepare-MyMorningTea.ps1 -Honey [<CommonParameters>]
Prepare-MyMorningTea.ps1 -Milk -Sugar <int> [<CommonParameters>]
But it makes you focus on what you need to focus on: parameter definition and the code for each parameter group. This is the most important thing to me, you don't need to worry about checking for chain parameters and spend some time coding something aside to the real objective of the script.
I hope you enjoyed reading this article and wondering about the use of ParameterSetName attribute for your next PowerShell script. Leave any comment if you have any questions or want to share anything.
Top comments (1)
A footnote for people stuck in ancient environments, PowerShell v2 attribute arguments cannot be implicitly enabled. You need to use
Mandatory = $true