How do I pass multiple parameters into a function

2018-12-31 07:48发布

If I have a function which accepts more than one string parameter, the first parameter seems to get all the data assigned to it, and remaining parameters are passed in as empty.

A quick test script:

Function Test([string]$arg1, [string]$arg2)
{
    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

Test("ABC", "DEF")

The output generated is

$arg1 value: ABC DEF
$arg2 value: 

The correct output should be:

$arg1 value: ABC
$arg2 value: DEF

This seems to be consistent between v1 and v2 on multiple machines, so obviously, I'm doing something wrong. Can anyone point out exactly what?

标签: powershell
14条回答
梦该遗忘
2楼-- · 2018-12-31 07:52
Function Test {
 Param([string]$arg1, [string]$arg2)
    Write-Host $arg1
    Write-Host $arg2
}

This is proper params declaration https://technet.microsoft.com/en-us/library/dd347600.aspx

And it indeed works

查看更多
余生无你
3楼-- · 2018-12-31 07:53

Parameters in calls to functions in PowerShell (all versions) are space-separated, not comma separated. Also, the parentheses are entirely unneccessary and will cause a parse error in PowerShell 2.0 (or later) if Set-StrictMode is active. Parenthesised arguments are used in .NET methods only.

function foo($a, $b, $c) {
   "a: $a; b: $b; c: $c"
}

ps> foo 1 2 3
a: 1; b: 2; c: 3
查看更多
看风景的人
4楼-- · 2018-12-31 07:55

I don't know what you're doing with the function, but have a look at using the 'param' keyword. It's quite a bit more powerful for passing parameters into a function, and makes it more user friendly. Below is a link to an overly complex article from Microsoft about it. It isn't as complicated as the article makes it sound. Param Usage

Also, here is an example from a thread on this site:

Check it out.

查看更多
骚的不知所云
5楼-- · 2018-12-31 08:00

If you don't know (or care) how many arguments you will be passing to the function, you could also use a very simple approach like;

Code:

function FunctionName()
{
    Write-Host $args
}

That would print out all arguments. For example:

FunctionName a b c 1 2 3

Output

a b c 1 2 3

I find this particularly useful when creating functions that use external commands that could have many different (and optional) parameters, but relies on said command to provide feedback on syntax errors etc.

Here is a another real-world example (creating a function to the tracert command, which I hate having to remember the truncated name);

Code:

Function traceroute
{
    Start-Process -FilePath "$env:systemroot\system32\tracert.exe" -ArgumentList $args -NoNewWindow
}
查看更多
冷夜・残月
6楼-- · 2018-12-31 08:02

If you're a C# / Java / C++ / Ruby / Python / Pick-A-Language-From-This-Century developer and you want to call your function with commas, because that's what you've always done, then you need something like this:

$myModule = new-module -ascustomobject { 
    function test($arg1, $arg2) { 
        echo "arg1 = $arg1, and arg2 = $arg2"
    }
}

Now call:

$myModule.test("ABC", "DEF")

and you'll see

arg1 = ABC, and arg2 = DEF
查看更多
心情的温度
7楼-- · 2018-12-31 08:11

Some good answers here, but I wanted to point out a couple other things. Function parameters are actually a place where PowerShell shines. For example, you can have either named or positional parameters in advanced functions like so:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=1)]
         [int] $Id
    )
}

Then you could either call it by specifying the parameter name, or you could just use positional parameters, since you explicitly defined them. So either of these would work:

Get-Something -Id 34 -Name "Blah" 
Get-Something "Blah" 34

The first example works even though Name is provided second, because we explicitly used the parameter name. The second example works based on position though, so Name would need to be first. When possible, I always try to define positions so both options are available.

PowerShell also has the ability to define parameter sets. It uses this in place of method overloading, and again is quite useful:

function Get-Something
{
    [CmdletBinding(DefaultParameterSetName='Name')]
    Param
    (
         [Parameter(Mandatory=$true, Position=0, ParameterSetName='Name')]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=0, ParameterSetName='Id')]
         [int] $Id
    )
}

Now the function will either take a name, or an id, but not both. You can use them positionally, or by name. Since they are a different type, PowerShell will figure it out. So all of these would work

Get-Something "some name"
Get-Something 23
Get-Something -Name "some name"
Get-Something -Id 23

You can also assign additional parameters to the various parameter sets. (That was a pretty basic example obviously) Inside of the function, you can determine which parameter set was used with the $PsCmdlet.ParameterSetName property. For example:

if($PsCmdlet.ParameterSetName -eq "Name")
{
    Write-Host "Doing something with name here"
}

Then, on a related side note, there is also parameter validation in PowerShell. This is one of my favorite PowerShell features, and it makes the code inside your functions very clean. There are numerous validations you can use. A couple examples are

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [ValidatePattern('^Some.*')]
         [string] $Name,
         [Parameter(Mandatory=$true, Position=1)]
         [ValidateRange(10,100)]
         [int] $Id
    )
}

In the first example, ValidatePattern accepts a regular expression that assures the supplied parameter matches what you're expecting. If it doesn't, an intuitive exception is thrown, telling you exactly what is wrong. So in that example, 'Something' would work fine, but 'Summer' wouldn't pass validation.

ValidateRange ensures that the parameter value is in between the range you expect for an integer. So 10 or 99 would work, but 101 would throw an exception.

Another useful one is ValidateSet, which allows you to explicitly define an array of acceptable values. If something else is entered, an exception will be thrown. There are others as well, but probably the most useful one is ValidateScript. This takes a script block that must evaluate to $true, so the sky is the limit. For example:

function Get-Something
{
    Param
    (
         [Parameter(Mandatory=$true, Position=0)]
         [ValidateScript({ Test-Path $_ -PathType 'Leaf' })]
         [ValidateScript({ (Get-Item $_ | select -Expand Extension) -eq ".csv" })]
         [string] $Path
    )
}

In this example, we are assured not only that $Path exists, but that it is a file, (as opposed to a directory) and has a .csv extension. ($_ refers to the parameter, when inside your scriptblock.) You can also pass in much larger, multi-line script blocks if that level is required, or use multiple scriptblocks like I did here. It's extremely useful, and makes for nice clean functions and intuitive exceptions.

查看更多
登录 后发表回答