Dealing with Parameters in Powershell
I often get asked to review code for people and I often see them use $args for argument parsing (most often with VBScript converts.) While there is nothing wrong with that method, I do not believe it is the best way. Powershell has numerous ways to pass data to scripts/functions. Today, after helping a friend understand the differences between them, I decided it would be good to blog about it.
Let’s take a look at the different ways scripts/functions can take input.
You can pass data by position parameters:
.\myscript.ps1 filename.txt corp.lab
You can pass data by named parameters:
.\myscript.ps1 -list filename.txt -domain corp.lab
Finally, you can pipe data in:
get-content filename.txt | .\myscript.ps1 -domain corp.lab
That is great… but what would the code look like foreach of these?
There is little difference between a script and a function so I will illustrate using functions.
To use positional parameters
Example: PassByPosition filename.txt corp.lab
"FileName: {0}" -f $args[0]
"Domain: {0}" -f $args[1]
}
To process Named parameters you use the Param() statement included in Powershell
Example: PassByName -list filename.txt -domain corp.lab
Param($FileName,$DomainName)
"FileName: {0}" -f $FileName
"Domain: {0}" -f $DomainName
}
To process piped data you can do something like
Example: get-content filename.txt | PassByPipe corp.lab
if($input)
{
foreach($val in $input)
{
"FileName: {0}" -f $val
"Domain: {0}" -f $args[0]
}
}
}
NOTE: This is not only way to process piped input, but it is the simplest example. If you would like to see a more efficient way to process look HERE.
It gets REALY cool when using them together
Using the script below you can do any of these
UseAllThree filename.txt corp.lab
UseAllThree -list filename.txt -domain corp.lab
get-content filename.txt | UseAllThree -domain corp.lab
Param($FileName,$DomainName)
if($input)
{
foreach($val in $input)
{
"FileName: {0}" -f $val
"Domain: {0}" -f $args[0]
}
}
else
{
"FileName: {0}" -f $FileName
"Domain: {0}" -f $DomainName
}
}
We can even have default values for the Parameters
Using the script below you can do any of these
UseAllThreewithDefaults filename.txt
UseAllThreewithDefaults -list filename.txt
get-content filename.txt | UseAllThreewithDefaults
Param($FileName = "FileName.txt",$DomainName = "Corp.lab")
if($input)
{
foreach($val in $input)
{
"FileName: {0}" -f $val
"Domain: {0}" -f $DomainName
}
}
else
{
"FileName: {0}" -f $FileName
"Domain: {0}" -f $DomainName
}
}
13 Responses to “Dealing with Parameters in Powershell”
Leave a Reply
You must be logged in to post a comment.


This is probably one of the most useful posts about PowerShell yet – thanks! Your help on Experts Exchange is always appreciated too.
Thanks! I really appreciate the kind comments.
Is there a way to have a parameter, which behaves like a switch AND an int?
So either I can just specify the param name, or specify the name with a value:
./myscript.ps1 -magic
./myscript.ps1 -magic 50
Any kind of solution is appreciated!
Define the value in the Param() statement
Param($Magic=$False)
Is there a way to enforce that the caller specifies parameters, and to error out if the wrong parameters are specified?
For example:
function test {
param([string]$branch)
echo $branch
}
If I run “test -branch hello”, it will output “hello”. However, if I run “test -wrongparam hello”, instead of giving an error, it does nothing. How can I make it generate a useful error instead?
You would do something like this
Param($branch = $(Throw ‘$branch is required’))
$branch
I’m currently in the process of trying to do something like this with a program at my work (a bit more in depth, yes).
The output from the program would go to cmd:
powershell mysync.ps1 -username Company\Username
The contents of mysync.ps1 is a work in progress. This is what I’ve pieced together so far..
#####Load Parameter from Command Line##
Param($User)
#####In case I need to set it up as a function##
#function PassByName{
# Param($User)
# “User: {0}” -f $User
#}
#####
#####Add Quest Tools to use QAD cmdlets##
add-PSSnapin quest.activeroles.admanagement
#####Set Policy Execution so it doesn’t ask you##
set-executionpolicy RemoteSigned
#####In case I want to create an export##
##########$FilePath = D:\Share\MySync\OutSync.csv##
#####Adds User to group via Quest Cmdlet##
add-QADGroupMember -identity “CN=MysyncPersonalUsers,OU=Global Groups,DC=Acosta,DC=com” -member $_.User
#####Create an Export##
##########Output-CSV $FilePath##
######Results Action##
$result = get-groupmembers -group MysyncPersonalUsers -user $_.User
if ($result -eq ’1′) {
Invoke-Command -filepath “D:\Share\MySync\SuccessTable1.ps1″
}
if ($result -eq ’0′ {
Invoke-Command -filepath “D:\Share\MySync\FailureTable1.ps1″
}Export-CSV $FilePath
#################
So, you’ll notice that at the end I’m looking to find out if the user has been added to the group and invoke another ps1 (to perform a function which adds the user to a SQL table for successful or Failed). I haven’t tested this yet and I’m sure I’m going to need to do some tweakinese on it. But, what do you think?
@Dan, I would move SuccessTable.ps1 and FailureTable.ps1 as sub functions in the main script.
What about passing from a list only if it finds a matching value? For example if I wanted to pass a list of computer descriptions to AD. But my list was a long list of computers & descriptions for example 100 computers & descriptions,
computer1, description1
computer2, description2
…
computer100, description100
and in my AD I had to populate 10 computer’s descriptions only.
Also could you recommend any great starter books?
Thanks for the blog!
Hi,
This is a nice post on using argument in powershell functions.
Is there a way, when a switch is enabled in the Param it calls a function directly
Param([switch]$help=Usage)
function Usage
{
Write-host “Help is here”
}
when i call this script and -help is passed it should not validate anything else just call usage function and exit
Regards,
Harsha
You can just do this.
If($Usage){Usage}
Thanks for the response for the previous question.
Param($a=$(throw “param ‘a’ is required”))
Is there a way to throw the message and also call the Usage function in the above statement.
Not that I am aware of