PowerShell Pipeline
Anatomy of a PowerShell Parameter, Part 1
Central to your command is a parameter -- a weak parameter will end with a weak script.
Central to your command is a parameter -- a weak parameter will end with a weak script.
PowerShell commands come in all shapes and sizes that can cover something simple such as getting information about a particular item to performing a set of checks before implementing a change. The common item that all of these commands share is that at the heart of it all, they all have various parameters that are used in their command that has a variety of possible parameter metadata or parameter types that help to define what is expected of them.
There are a number of considerations when designing your parameters such as what type of parameter that you will allow, if the parameter will be required and if the parameter will support data coming from the pipeline. Also included is how the parameters will be validated (if at all) when the data being provided is passed into the script or function.
Naming Your Parameter
The parameter starts with the name. What kind of name will you use in your parameter? It really depends on its purpose and what you want to do with it. Is it going to be used for a list of computers or will it handle a path to a file? Having the right name will make it much easier for the user of the command to know what to do with it.
So how do we know what name to use? Should I use Computer or Computername to handle a list of computers? Well, I would start out by looking at what is already being used in PowerShell today. And by that I mean looking at the core cmdlets, not functions developed by other users or 3rd party vendors. The PowerShell team has put a lot of effort into naming parameters and their example should be considered in your design strategy. With that in mind, we will make sure to use Computername as the parameter name. Also, it's a good idea to avoid plural parameters as well. Computernames, while it does tell the truth on what it wants, is not a good practice and you should keep with a singular parameter name.
But we still want a Computer parameter name! Luckily you can come to a compromise by making use of the [Alias()] parameter attribute that allows you to define other names for the parameter in case you wanted more than one name for it. This attribute accepts a collection of string names so you can have more than one parameter alias if you need that.
Param (
[Alias('Computer')]
$Computername
)
Perfect! Now you have your Computername parameter with an alias name of Computer to handle those people who prefer a shorter parameter name.
What 'Type' of Parameter?
Specifying the type of parameter that you will be using in your command can be very important as it will effectively block other types from being processed and will even throw an error if it cannot coerce the type that is being presented to what it is expecting.
An example of this would be to pass a string value to Stop-Process and its InputObject parameter. The InputObject parameter is expecting an object would be of the type of System.Diagnostics.Process.
Stop-Process -InputObject 'Test'
The only exception to specifying the type of parameter to prevent other types are by using [string] or [string[]]. The reason is that anything can be cast to a string type and that means that the PowerShell will allow the data to be used in the parameter regardless of its type.
Now in this case, I am actually only looking for string computer names for my parameter.
Param (
[Alias('Computer')]
[string[]]$Computername
)
To better highlight this, I am going to use a simple function called Test-Function that will better show what I mean by this.
Function Test-Function {
Param (
[Alias('Computer')]
[string[]]$Computername
)
ForEach ($Item in $Computername) {
[pscustomobject]@{
ParameterValue = $Item
ParameterType = $Item.GetType().Fullname
}
}
}
I'm going to pass a variety of parameter values that have different types and you will see what each one will be converted to a string and displayed with their default string value and its type of [string].
Test-Function -Computername 3,'test',(Get-Process | Select-Object -First 1)
As you can see from the image above, regardless of the type of data being passed to our Computername parameter, it was converted to a string type. It doesn't matter if it is an integer or a process type, it will be converted over to a string. Also to note is that I mentioned a default string value and that is shown with the process type. When casted to a string type, it will be displayed differently based on its default ToString method result.
Use a Default value or Require a Value?
The last thing to talk about today is how we handle parameters where there has to be some sort of data supplied to it. Be it a default value or requiring a value be used is up to you to decide. It is worth noting that a default value probably should be used in rare occasions when you are completely confident that the command will still work regardless of the system or location that the command is being run from.
If you are unsure as to what to go with but absolutely need some sort of value with a parameter, then you cannot go wrong with using the Mandatory attribute for a parameter to force the user to provide some sort of input. If they elect not to supply anything, then an error will be thrown and execution of the function will stop.
Right above my [Alias()] attribute, I will add a [Parameter()] attribute that will define my mandatory declaration of the parameter.
[parameter(Mandatory=$True, HelpMessage='Please enter a computername')]
Now if I run the function without any parameter, it will prompt for the data and fail when I choose to not do anything.
You may have noticed the HelpMessage attribute as well. I can use this so when a user types !? at the prompt, it will provide a short help message to guide the user of the function into the proper use of the parameter.
That is it for today's look at parameters. The next article will continue our look at parameters and cover parameter validation and parameter sets.
About the Author
Boe Prox is a Microsoft MVP in Windows PowerShell and a Senior Windows System Administrator. He has worked in the IT field since 2003, and he supports a variety of different platforms. He is a contributing author in PowerShell Deep Dives with chapters about WSUS and TCP communication. He is a moderator on the Hey, Scripting Guy! forum, and he has been a judge for the Scripting Games. He has presented talks on the topics of WSUS and PowerShell as well as runspaces to PowerShell user groups. He is an Honorary Scripting Guy, and he has submitted a number of posts as a to Microsoft's Hey, Scripting Guy! He also has a number of open source projects available on Codeplex and GitHub. His personal blog is at http://learn-powershell.net.