Search
Joe Pruitt - A Software Architect's take on Network Security
You are here: DevCentral > Weblogs

posted on Tuesday, January 13, 2009 10:55 AM

PowerShell Welcome to this addition of the PowerShell ABC's where you'll find 26 posts detailing a component of the PowerShell scripting language, one letter at a time.  Today's letter is the letter "P" and for it I'll cover the basics of defining input values, or Parameters.

Parameters (or arguments) are how you customize the actions of a command.  There are 4 types of commands in PowerShell, scripts, functions, Cmdlet's, and External Commands. 

Scripts and Functions are the areas I'm going to focus on here and I'll show you how parameters are defined in those two command types.

Scripts

Scripts, for those that don't know, are essentially a text file with a series of PowerShell commands.  PowerShell scripts typically end with the .ps1 extension and can be executed by the PowerShell interactive console by just typing in the script name.  For anyone with any scripting background at all, you will know that you can't get much done without being able to make the script more dynamic by allowing input from the user to change the behavior or the script.  Whether this is a subcommand to execute or login credentials to a service the script is trying to access, having the ability to pass them is fairly important to making the script a success. 

$args

Script level parameters can be accessed in two ways.  The first is with the $args variable which is a built-in variable that is auto-populated with an array of objects containing the values passed to the script.

---- Begin script foo.ps1 ----
Write-Host "Num Args:" $args.Length;
foreach ($arg in $args)
{
  Write-Host "Arg: $arg";
}
----  End script foo.ps1  ----
PS C:\> .\foo.ps1
Num Args: 0
PS C:\> .\foo.ps1 foo bar
Num Args: 2
Arg: foo
Arg: bar

This is very similar to how other scripting languages work such as Perl.  While the $args variable is a simple way to get at the arguments to a script, it requires a bit of work to do anything beyond simple examples. 

The param statement

PowerShell provides a much more convenient way to declare formal parameters for a script with the param statement.  The param statement must be the first executable line in the script with only comment or empty lines preceding it.  The format of the param statement is 

param([type]$p1 = <expr>, [type]$p2 = <expr>, ...)

Where the type literal "[type]" and initialization values "= <expr>" are optional components to allow for type specification and specifying initial values respectively.

There are three types of parameters in PowerShell


Parameter Type | Formal name in Powershell | Example

Switches Switch Parameters Get-ChildItem -Recurse
Options Parameters Get-ChildItem -Filter *.cs
Arguments Positional Parameters Get-ChildItem *.cs

Internet_argumentArguments are positional parameters becuase they are always associated with a parameter name but it's permitted to leave the name out and let the interpreter figure out what parameter is it from it's position on the command line. 

Switch parameters are just the opposite in that you specify the parameter but the argument is left out.  The interpreter assigns the parameter a value based on whether the parameter is present or not.  To specify a switch type parameter, you should use the "[switch]" type literal in the parameter declaration.

The following script is functionally equivalent to the one above, but now the parameters are declared and strongly typed.

---- Begin script foo.ps1 ----
param([string]$foo = "foo", [string]$bar = "bar")
Write-Host "Arg: $foo"
Write-Host "Arg: $bar"
----  End script foo.ps1  ----
PS C:\> .\foo.ps1 -foo "foo" -bar "bar"
Arg: foo
Arg: bar

In this example the arguments can be treated as Options or Arguments by including or omitting the "-name" qualifiers in the command execution.

Functions

Functions are defined by the function statement:

function <name> (<parameter list>) {<statement list>}

The format of the parameter list is identical to that of the param statement.  The above script can be converted to a function as follows

function foo([string]$foo = "foo", [string]$bar = "bar")
{
Write-Host "Arg: $foo";
Write-Host "Arg: $bar";
}

The param statement is supported in functions as well so if you do not wish to specify it in the function declaration, you can do so in the first line of the function as follows:

function foo()
{
param([string]$foo = "foo", [string]$bar = "bar");
Write-Host "Arg: $foo";
Write-Host "Arg: $bar";
}

Scriptblocks

In PowerShell, the key to metaprogramming (or writing programs that write or manipulate other programs), is something called the scriptblock. This is a block of script code that exists as an object reference but does not require a name.  The Where-Object and Foreach-Object Cmdlets rely on scriptblocks for their implementation.  Scriptblocks are also known as anonymous functions or lambda expressions in other languages.  A scriptblock is defined with the following syntax

{ param(<parameter list>) <statement list> }

This looks similar to a function definition above without the function keyword, name, and parameter list in the declaration.  In the case of scriptblocks, parameters are defined with the param statement as the first command in the scriptblock.

Keeping with the above example, I'll show that functionality defined within a script block.

PS C:\>& {param([string]$foo = "foo", [string]$bar = "bar") Write-Host "Arg: $foo"; Write-Host "Arg: $bar"; }
Arg: foo
Arg: bar

If you were wondering about the "&" in there, that's how you tell PowerShell to invoke that literal as a block of code.



Feedback

5/4/2009 10:57 AM
Gravatar Nice article. Its very informative and provides quick solution of parameters handling for any beginners on PS. Thanks for writing this.
bijul
5/4/2009 10:59 AM
Gravatar Glad you enjoyed it!

-Joe
Joe Pruitt
8/16/2009 10:22 AM
Gravatar When I am in a Cmd.Exe, and execute foo.ps1, it always says there are 0 arguments, regardless of whether I run "foo.ps1", "foo.ps1 fred", "foo.ps1 fred barney" etc. I need to be able to invoke PowerShell scripts from the Cmd.Exe world, and pass command-line arguments.
stupid questioner
9/2/2009 7:14 AM
Gravatar Hi great post, thanks for the pointers.
I'm a total n00b :-( These are basic additions, but here they are...

A few things I found after this post were:

# required (btw # = comment)
[string]$dst = $(throw "-dst is required.")

# switch - false if missing true if present
[switch]$r

Also $foo sets up -foo, so for $r the switch is -r...
Ben
9/2/2009 8:11 AM
Gravatar For stupid questioner:
it is a power shell run it in Power shell console.
if *.ps1 is associated with power shell you can run it from explorer too.
Nik
9/2/2009 10:56 AM
Gravatar There are no stupid questions... A .PS1 file is just a text file that contains a script to be run by the PowerShell.exe command line app. I'm sure you could configure explorer to associate .PS1 to the PowerShell.exe process but I haven't tried it since I live in the shell.

Good luck!

-Joe
Joe
9/2/2009 10:57 AM
Gravatar Great additions Ben, thanks for passing them along.

-Joe
Joe
2/3/2010 6:01 PM
Gravatar You can run a WPS script from cmd.exe prompt with this syntax:
powershell.exe path\ScriptName.ps1 arg1 arg2

If ScriptName.ps1 is in the current directory, you must use .\ScriptName.ps1 as the qualified name.

I create a .cmd file that contains the required syntax and passes parameters to the script.

I prefere to associate the PS1 extension with an editor for safety.
Mike
3/3/2010 3:02 PM
Gravatar I am having a problem specifying an optional option parameter.

I have a test script:
---------------------------------------
param([parameter(ValueFromRemainingArguments=$true)][String[]]$files, `
[alias("l")][String][ValidateSet("0", "1", "2", "3", "4")]$log_level = 1)
Write-Host "Switch (-l): $log_level"
foreach ($x in $files) {
Write-Host "Extra arg: $x"
}
---------------------------------------

What I am trying to achieve is a situation where if I specify "-l 2" on the command line $log_level is set to 2, but if I omit "-l n" $log_level is set to the default (i.e. 1).

I find the following:
---------------------------------------
PS > .\args.ps1 -l 2 a x
Switch (-l): 2
Extra arg: a
Extra arg: x
PS > .\args.ps1 a x -l 2
Switch (-l): 2
Extra arg: a
Extra arg: x
PS > .\args.ps1 a x
.\args.ps1 : Cannot validate argument on parameter 'log_level'. The argument "a" does not belong to the set
"0,1,2,3,4" specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again.
PS >
---------------------------------------

Is there a way to make "-l n" truly optional?

Thanks for your insights.

Leigh.
Leigh
1/11/2011 1:31 PM
Gravatar You can also use this free utility, PShellExec to handle your script and function parameters in a secure environment: www.slideshare.net/infospectruminc/p-shell-exec2
Les
5/9/2011 12:13 PM
Gravatar yea, but how do you pass a boolean-type param to a script file. I've tried, for example, the following (and nothing else) in my x.ps1 file:
#-----------------------------------------------
param
(
[int]$Param1 = 0,
[switch]$Param2 = $false
)

write-host $Param1, $param2
#-----------------------------------------------

Ran this as follows, with the following results:

C:\test>powershell -FILE x.ps1 0 $true
0 False

No matter the value I pass to $param2, $false is the value it persists.

If I invoke x.ps1 as with named parameters, i get $true for $param2 no matter what the actual parameter value I pass. i.e.

C:\test>powershell -file x.ps1 -Param1 -342342 -Param2 $false
-342342 True

Thus, it seems that passing boolean values to a powershell script is absolutely quite unpredictable.

AJC
5/9/2011 12:23 PM
Gravatar @AJC, any ready you aren't using the "boolean" type?

A "switch" type doesn't take a value, it's "true" if you pass the "-Param2" param is passed in without values.

By using the "boolean" type I get the following results.

#--------------------------
param([int]$Param1 = 0, [boolean]$Param2);
Write-Host $Param1, $Param2;
#--------------------------
PS > .\test-bool.ps1 123 $false
123 False
PS > .\test-bool.ps1 123 0
123 False
PS > .\test-bool.ps1 123 $true
123 True
PS > .\test-bool.ps1 123 1
123 True
PS > .\test-bool.ps1 123 123456
123 True

Hope this helps...

-Joe
Joe
1/2/2012 8:01 PM
Gravatar It would be nice if you can provide some working examples aswel

like ...
in PS1


what to type in powershell to execute PS1
<line of code>

By the way nice article :)
vinodkumar G B
1/26/2012 3:09 PM
Gravatar is there a way to declare an array of parameters?
what i'd like to do is to is have at least one of the parameter required for input and the rest would be optional. so this will allow user to input from 1 to (let's say) 10 keys.
venviq

Let Me Know What You Think


Please use the form below if you have any comments, questions, or suggestions.

Title:
 
Name:
 
Email: (so we can show your gravatar)
Website:
Comment: Allowed tags: blockquote, a, strong, em, p, u, strike, super, sub, code
 
Please add 1 and 5 and type the answer here:

Blog Stats

Posts:379
Comments:1067
Stories:1
Trackbacks:301
  

Article Categories

  iRules
  

Image Galleries

  

Joe's bookshelf: read

The Lost Gate
4 of 5 stars
This one started slow but I got really got into it about 1/3 of the way through. If you are an Ender's Game fan, you'll probably like this one as well.

goodreads.com


82,243 Members in 102 Countries and Growing!

Join DevCentral Today!

About DevCentral

DevCentral has been a successful, thriving community for many years. We have always strived to bring you the best technical documentation, discussion forums, blogs, media and much more that we can.

So dive in, get familiar with DevCentral. We hope you like it, we hope it makes your job easier, and lets you get that much more power out of the community. To learn more, make sure to check out the Getting Started section. And if you have any problems, or think something could be easier to use, drop us a line to let us know.

Got It !

We've received your comment and transmitted it directly to DevCentral HQ.

Thanks for taking time to let us know what's on your mind. At DevCentral | Community Matters!

Get In Touch With Us

Have questions, suggestions or just want to get something off your chest?

Use our handy form below to Direct Connect with DevCentral Mission Control.

Send Us Feedback       or