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

Nas*_*sir 406 powershell

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

快速测试脚本:

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

Test("ABC", "DEF")
Run Code Online (Sandbox Code Playgroud)

生成的输出是

$arg1 value: ABC DEF
$arg2 value: 
Run Code Online (Sandbox Code Playgroud)

正确的输出应该是:

$arg1 value: ABC
$arg2 value: DEF
Run Code Online (Sandbox Code Playgroud)

这似乎在多台机器上的v1和v2之间是一致的,所以很明显,我做错了.任何人都可以指出究竟是什么?

x0n*_*x0n 540

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
Run Code Online (Sandbox Code Playgroud)

  • 最重要的是最终帮助"坚持"在我脑海中的是最后一句:"括号中的参数仅用于.NET方法." (16认同)
  • @samyi No.将`(1,2,3)`传递给函数实际上被视为一个数组; 一个论点.如果要使用OO方法样式参数,请使用模块:`$ m = new-module -ascustomobject {function Add($ x,$ y){$ x + $ y}}; $ m.Add(1,1)` (6认同)
  • 我更喜欢使用括号和逗号分隔.. 是否可以在 powershell 中执行此操作? (2认同)
  • Powershell是一种shell语言,shell语言通常使用空格作为令牌分隔符。我不会说`Powershell`在这里有所不同,它与其他系统默认的shell一样,例如`cmd`,`sh`,`bash`等。 (2认同)

Mic*_*ens 251

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

函数调用的语法缺陷

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

有关进一步阅读,请参阅我刚刚在Simple-Talk.com上发表的文章Down the Rabbit Hole:PowerShell管道,函数和参数的研究.该文章还包含指向快速参考/挂图的链接.

  • 谢谢你,这让我精神不理解我做错了什么.当我最终做对了,我渴望解释这种行为. (6认同)
  • 这是一个更好的答案.它应该是进一步的. (3认同)
  • 使用更详细的语法调用每个参数并为其赋值的解释确实巩固了它.谢谢! (2认同)

use*_*949 44

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

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

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

Get-Something -Id 34 -Name "Blah"
Get-Something "Blah" 34
Run Code Online (Sandbox Code Playgroud)

即使名称是第二个提供,第一个示例仍然有效,因为我们明确使用了参数名称.第二个例子基于位置工作,所以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
    )
}
Run Code Online (Sandbox Code Playgroud)

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

Get-Something "some name"
Get-Something 23
Get-Something -Name "some name"
Get-Something -Id 23
Run Code Online (Sandbox Code Playgroud)

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

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

然后,在相关的附注中,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
    )
}
Run Code Online (Sandbox Code Playgroud)

在第一个示例中,ValidatePattern接受一个正则表达式,该表达式确保提供的参数与您期望的匹配.如果没有,则会抛出一个直观的异常,告诉您究竟出了什么问题.所以在那个例子中,'Something'可以正常工作,但'Summer'不会通过验证.

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
    )
}
Run Code Online (Sandbox Code Playgroud)

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

  • +1用于演示`My_Function -NamedParamater"ParamValue"`函数调用样式.这是一种模式,为了便于阅读,应遵循更多的PS脚本代码. (2认同)

Tod*_*odd 43

您可以在不使用括号的情况下调用PowerShell函数,也不使用逗号作为分隔符.尝试使用:

test "ABC" "DEF"
Run Code Online (Sandbox Code Playgroud)

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

$a = "one", "two", "three"
Run Code Online (Sandbox Code Playgroud)

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


小智 14

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

Test "ABC" "DEF"
Run Code Online (Sandbox Code Playgroud)


Rya*_*ton 10

如果您是C#/ Java/C++/Ruby/Python/Pick-A-Language-From-This-Century开发人员,并且您想用逗号调用您的函数,因为这是您一直以来所做的,那么您需要一些东西像这样:

$myModule = New-Module -ascustomobject { 
    function test($arg1, $arg2) { 
        echo "arg1 = $arg1, and arg2 = $arg2"
    }
}
Run Code Online (Sandbox Code Playgroud)

现在打电话:

$myModule.test("ABC", "DEF")
Run Code Online (Sandbox Code Playgroud)

你会看到的

arg1 = ABC, and arg2 = DEF
Run Code Online (Sandbox Code Playgroud)

  • 假设使用公历,Java、C++、Ruby 和 Python 并不是本世纪的产物(只有 C#)(尽管其中一些比其他的发展得更多)。 (3认同)

Mar*_*ndl 9

因为这是一个经常查看的问题,所以我想提一下 PowerShell 函数应该使用批准的动词动词-名词作为函数名称)。名称的动词部分标识 cmdlet 执行的操作。名称的名词部分标识执行操作的实体。此规则为高级 PowerShell 用户简化了 cmdlet 的使用。

此外,您可以指定参数是否为强制参数以及参数的位置等内容:

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"
}
Run Code Online (Sandbox Code Playgroud)

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

Test-Script "Hello" "World"
Run Code Online (Sandbox Code Playgroud)

或者您指定参数名称

Test-Script -arg1 "Hello" -arg2 "World"
Run Code Online (Sandbox Code Playgroud)

您不像在 C# 中调用函数时那样使用括号


我建议在使用多个参数时始终传递参数名称,因为这样更具可读性


小智 8

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

代码

function FunctionName()
{
    Write-Host $args
}
Run Code Online (Sandbox Code Playgroud)

那会打印出所有参数。例如:

FunctionName a b c 1 2 3
Run Code Online (Sandbox Code Playgroud)

输出量

a b c 1 2 3
Run Code Online (Sandbox Code Playgroud)

在创建使用可能具有许多不同(和可选)参数的外部命令的函数时,我发现这特别有用。

这是另一个真实的示例(为tracert命令创建一个函数,我讨厌必须记住截断的名称);

代码

Function traceroute
{
    Start-Process -FilePath "$env:systemroot\system32\tracert.exe" -ArgumentList $args -NoNewWindow
}
Run Code Online (Sandbox Code Playgroud)


Ben*_*est 8

我没有看到这里提到它,但是展开你的参数是一个有用的替代方法,并且如果你动态地构建命令的参数(而不是使用Invoke-Expression),它会变得特别有用。您可以使用数组作为位置参数,使用哈希表作为命名参数。这里有些例子:

注意:您可以相对轻松地将位置 splats 与外部命令参数一起使用,但命名 splats 对于外部命令不太有用。它们可以工作,但程序必须接受以下-Key:Value格式的参数,因为每个参数都与哈希表键/值对相关。此类软件的一个示例是choco来自 Windows 的 Chocolatey 包管理器的命令。

Splat 与数组(位置参数)

带有位置参数的测试连接

Test-Connection www.google.com localhost
Run Code Online (Sandbox Code Playgroud)

使用数组泼溅

$argumentArray = 'www.google.com', 'localhost'
Test-Connection @argumentArray
Run Code Online (Sandbox Code Playgroud)

@请注意,在展开时,我们使用 an而不是 a 来引用 splatted 变量$。使用 Hashtable 进行 splat 时也是一样。

Splat With Hashtable(命名参数)

带有命名参数的测试连接

Test-Connection -ComputerName www.google.com -Source localhost
Run Code Online (Sandbox Code Playgroud)

使用哈希表泼溅

$argumentHash = @{
  ComputerName = 'www.google.com'
  Source = 'localhost'
}
Test-Connection @argumentHash
Run Code Online (Sandbox Code Playgroud)

同时 Splat 位置参数和命名参数

使用位置参数和命名参数进行测试连接

Test-Connection www.google.com localhost -Count 1
Run Code Online (Sandbox Code Playgroud)

将数组和哈希表放在一起

$argumentHash = @{
  Count = 1
}
$argumentArray = 'www.google.com', 'localhost'
Test-Connection @argumentHash @argumentArray
Run Code Online (Sandbox Code Playgroud)


小智 5

我不知道你在用这个函数做什么,但看看使用“param”关键字。它对于将参数传递给函数来说更加强大,并且更加用户友好。以下是 Microsoft 发布的一篇关于此问题的过于复杂的文章的链接。它并不像文章听起来那么复杂。

参数使用

另外,这里是本网站上一个问题的示例:

一探究竟。


RaS*_*Sor 5

如果你试试:

PS > Test("ABC", "GHI") ("DEF")
Run Code Online (Sandbox Code Playgroud)

你得到:

$arg1 value: ABC GHI
$arg2 value: DEF
Run Code Online (Sandbox Code Playgroud)

所以你看到括号分隔参数

如果你试试:

PS > $var = "C"
PS > Test ("AB" + $var) "DEF"
Run Code Online (Sandbox Code Playgroud)

你得到:

$arg1 value: ABC
$arg2 value: DEF
Run Code Online (Sandbox Code Playgroud)

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

  • Parens不分离参数.他们定义数组. (4认同)