Posts RSS Comments RSS 253 Posts and 411 Comments till now

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

function PassByPosition{
  "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

function PassByName{
    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

function PassByPipe{
    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

function UseAllThree{
    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

function 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”

  1. on 14 Dec 2008 at 8:59 pmChris

    This is probably one of the most useful posts about PowerShell yet – thanks! Your help on Experts Exchange is always appreciated too. 🙂

  2. on 15 Dec 2008 at 6:32 amtshell

    Thanks! I really appreciate the kind comments.

  3. on 27 Jul 2009 at 2:09 amDaniel

    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!

  4. on 27 Jul 2009 at 5:50 amtshell

    Define the value in the Param() statement

    Param($Magic=$False)

  5. on 09 Aug 2009 at 11:17 pmJohn

    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?

  6. on 10 Aug 2009 at 7:33 amtshell

    You would do something like this

    Param($branch = $(Throw ‘$branch is required’))
    $branch

  7. on 29 Apr 2010 at 12:42 pmDan

    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?

  8. on 29 Apr 2010 at 3:08 pmtshell

    @Dan, I would move SuccessTable.ps1 and FailureTable.ps1 as sub functions in the main script.

  9. on 08 May 2010 at 5:55 pmAdminicrater

    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!

  10. on 09 Jun 2010 at 12:21 amHarsha

    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

  11. on 09 Jun 2010 at 9:29 amtshell

    You can just do this.

    If($Usage){Usage}

  12. on 10 Jun 2010 at 1:41 amHarsha

    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.

  13. on 16 Jun 2010 at 2:52 pmtshell

    Not that I am aware of

Trackback this post | Feed on Comments to this post

Leave a Reply

You must be logged in to post a comment.