如何将多个参数传递到PowerShell中的函数?

时间:2011-02-14 01:59:53

标签: powershell

如果我有一个接受多个字符串参数的函数,则第一个参数似乎获取分配给它的所有数据,其余参数作为空传入。

快速测试脚本:

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

Test("ABC", "DEF")

生成的输出是

$arg1 value: ABC DEF
$arg2 value: 

正确的输出应该是:

$arg1 value: ABC
$arg2 value: DEF

这在多台机器上的v1和v2之间似乎是一致的,显然,我做错了什么。谁能指出究竟是什么?

14 个答案:

答案 0 :(得分:490)

PowerShell中的函数调用中的参数(所有版本)是空格分隔的,而不是以逗号分隔。此外,括号完全是不必要的,如果Set-StrictMode处于活动状态,则会在PowerShell 2.0(或更高版本)中导致解析错误。带括号的参数仅用于.NET方法。

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

ps> foo 1 2 3
a: 1; b: 2; c: 3

答案 1 :(得分:233)

已经提供了正确的答案,但这个问题似乎非常普遍,可以为想要了解细微之处的人提供一些额外的细节。我会添加这个作为评论,但我想包括一个插图 - 我从PowerShell函数的快速参考图表中删除了这个。这假设函数f的签名是f($a, $b, $c)

syntax pitfalls of a function call

因此,可以使用空格分隔的位置参数或与顺序无关的命名的参数调用函数。其他陷阱表明你需要认识到逗号,括号,白色空间。

如需进一步阅读,请参阅我刚刚在Simple-Talk.com上发表的文章Down the Rabbit Hole: A Study in PowerShell Pipelines, Functions, and Parameters。该文章还包含指向快速参考/挂图的链接。

答案 2 :(得分:41)

您不使用括号调用PowerShell函数,也不使用逗号作为分隔符。尝试使用:

   test "ABC" "DEF"

在PowerShell中,逗号(,)是一个数组运算符,例如

   $a = "one", "two", "three"

它将$ a设置为具有三个值的数组。

答案 3 :(得分:33)

这里有一些好的答案,但我想指出其他一些事情。函数参数实际上是PowerShell发光的地方。例如,您可以在高级函数中使用命名参数或位置参数,如下所示:

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

然后你可以通过指定参数名称来调用它,或者你可以只使用位置参数,因为你明确定义了它们。所以这些都可以起作用:

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

第一个示例即使Name是第二个提供的,因为我们明确使用了参数名称。第二个例子基于位置工作,所以Name需要先行。在可能的情况下,我总是尝试定义位置,以便两个选项都可用。

PowerShell还可以定义参数集。它使用它来代替方法重载,并且非常有用:

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
    )
}

现在该函数将采用名称或id,但不是两者。您可以按位置或按名称使用它们。由于它们是不同的类型,PowerShell会解决它。所以这些都可行

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

您还可以为各种参数集分配其他参数。 (这显然是一个非常基本的例子)在函数内部,您可以确定与$ PsCmdlet.ParameterSetName属性一起使用的参数集。例如:

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

然后,在相关的附注中,PowerShell中还有参数验证。这是我最喜欢的PowerShell功能之一,它使您的功能中的代码非常干净。您可以使用许多验证。几个例子是

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

在第一个示例中,ValidatePattern接受一个正则表达式,该表达式确保提供的参数与您期望的匹配。如果它没有,则抛出一个直观的异常,告诉你究竟出了什么问题。因此,在那个例子中,' Something'会很好,但夏天'不会通过验证。

ValidateRange确保参数值介于整数期望的范围之间。所以10或99会起作用,但101会抛出异常。

另一个有用的是ValidateSet,它允许您显式定义可接受值的数组。如果输入其他内容,则会抛出异常。还有其他一些,但可能最有用的是ValidateScript。这需要一个必须计算为$ true的脚本块,因此天空是极限。例如:

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

在这个例子中,我们不仅确保$ Path存在,而且它是一个文件(与目录相对)并且具有.csv扩展名。 ($ _是指在脚本块内部的参数。)如果需要该级别,您还可以传入更大的多行脚本块,或者像我在这里一样使用多个脚本块。它非常有用,并且具有良好的清洁功能和直观的异常。

答案 4 :(得分:13)

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

Test "ABC" "DEF"

答案 5 :(得分:6)

如果您不知道(或关心)您将传递给函数的参数多少,您也可以使用一种非常简单的方法,例如;

<强>代码

function FunctionName()
{
    Write-Host $args
}

那将打印出所有论点。例如:

FunctionName a b c 1 2 3

<强>输出

a b c 1 2 3

我发现这在创建使用外部命令的函数时特别有用,这些函数可能有许多不同的(和可选的)参数,但依赖于所述命令来提供有关语法错误的反馈等。

这是另一个真实世界的例子(为tracert命令创建一个函数,我不想记住截断的名字);

<强>代码

Function traceroute
{
    Start-Process -FilePath "$env:systemroot\system32\tracert.exe" -ArgumentList $args -NoNewWindow
}

答案 6 :(得分:5)

如果您尝试:

PS > Test("ABC", "GHI") ("DEF")

你得到:

$arg1 value: ABC GHI
$arg2 value: DEF

所以你看到括号分隔参数

如果您尝试:

PS > $var = "C"
PS > Test ("AB" + $var) "DEF"

你得到:

$arg1 value: ABC
$arg2 value: DEF

现在你可以找到括号的一些直接用处 - 空格不会成为下一个参数的分隔符 - 而是你有一个eval函数。

答案 7 :(得分:3)

我不知道你在使用这个函数做了什么,但是看一下使用'param'关键字。将参数传递给函数会更加强大,并使其更加用户友好。以下是微软关于它的一篇过于复杂的文章的链接。它并不像文章说得那么复杂。 Param Usage

此外,以下是此网站上thread的示例:

检查出来。

答案 8 :(得分:2)

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

Test("ABC") ("DEF")

答案 9 :(得分:2)

因为这是一个经常被查看的问题,我想提一下PowerShell函数应该使用approved verbs Verb-Noun 作为函数名称)。您还可以指定参数是必需以及参数的位置等内容:

function Test-Script
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true, Position=0)]
        [string]$arg1,

        [Parameter(Mandatory=$true, Position=1)]
        [string]$arg2
    )

    Write-Host "`$arg1 value: $arg1"
    Write-Host "`$arg2 value: $arg2"
}

要将参数传递给函数,您可以使用位置

Test-Script "Hello" "World"

指定参数名称

Test-Script -arg1 "Hello" -arg2 "World"

不要使用括号,就像在C#中调用函数一样。

我建议总是在使用多个参数时传递参数名称,因为这更像是可读

答案 10 :(得分:1)

我先说明以下内容:

常见问题是使用单数形式$arg,这是不正确的 它应始终为复数$args

问题不在于此 事实上,$arg可以是其他任何东西。问题是使用逗号和parantheses 我运行以下有效的代码,输出如下:

<强>代码:

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

测试“ABC”“DEF”

<强>输出:

$ var1值:ABC $ var2值:DEF

答案 11 :(得分:1)

Function Test {
 Param([string]$arg1, [string]$arg2)
    Write-Host $arg1
    Write-Host $arg2
}

这是适当的参数声明 https://technet.microsoft.com/en-us/library/dd347600.aspx

确实有效

答案 12 :(得分:0)

您也可以像这样在功能中传递参数

function FunctionName()
{
    Param ([string]$ParamName);
    #Operations
}

答案 13 :(得分:0)

我在这里没有看到它,但是 splatting 是一个有用的替代方法,如果您动态地为命令构建参数(而不是使用{{ 1}})。您可以使用数组表示位置参数,并使用哈希表表示命名参数。以下是一些示例:

带有数组的Splat(位置参数)

带有位置参数的测试连接

Invoke-Expression

具有阵列喷溅

Test-Connection www.google.com localhost
  

请注意,在进行splating时,我们使用$argumentArray = 'www.google.com', 'localhost' Test-Connection @argumentArray 而不是@来引用splatted变量。使用散列表进行散列时也是如此。

带有哈希表的Splat(命名参数)

带有命名参数的测试连接

$

具有哈希表样式

Test-Connection -ComputerName www.google.com -Source localhost

同时显示位置和命名参数

具有位置和命名参数的测试连接

$argumentHash = @{
  ComputerName = 'www.google.com'
  Source = 'localhost'
}
Test-Connection @argumentHash

将数组和哈希表放在一起

Test-Connection www.google.com localhost -Count 1