问题
- 如何访问发送到PowerShell脚本(.ps1文件)的参数
- 你能访问参数A:按名称,B:按位置,C:两者的混合吗
上下文
我最近尝试编写一个PowerShell脚本(.ps1),该脚本将从Windows批处理文件(.bat)(或可能是cmd shell或AutoHotKey脚本)调用,它将参数传递到.ps1脚本中供其使用(显示toast通知)。由于ss64.com上的说明,我过去曾使用$args
来做这种事情,但由于某种原因,我可以通过这种方式访问参数(尽管传递了参数$args[0] = ''
(空字符串)和$args.Count = 0
),因此最终不得不删除所有$args
代码,代之以Param()
脚本。
我仍然不太确定为什么,但我认为这是我在写下一个剧本之前应该弄清的事情。。。
代码示例1:Args(未命名参数)
ToastNotificationArgs.ps1
-------------------------
Write-Debug "The script has been passed $($args.Count) parameters"
If (!$args[0]) { # Handle first parameter missing }
If (!$args[1]) { # Handle second parameter missing }
Import-Module -Name BurntToast
New-BurntToastNotification -Text "$args[0], $args[1]"
^我认为上面的代码是正确的,但正如我所说,由于某种原因,我一直在努力访问参数,不知道为什么。(如果有人能发现我做错了什么,请大喊!)
$args[]是一种有效的方法吗考虑到它使用的是ss64.com,我想是这样,但也许我需要注意一些陷阱/限制?
代码示例2:Param(命名参数)
ToastNotificationParams.ps1
---------------------------
Param(
[Parameter(Mandatory=$false, Position=0, ValueFromPipeline=$true)] [string]$Title,
[Parameter(Mandatory=$false, Position=1, ValueFromPipeline=$true)] [string]$Message
)
Import-Module -Name BurntToast
New-BurntToastNotification -Text "$Title, $Message"
^这是让我的剧本最终发挥作用的唯一方法。然而,当我传入参数时,我的调用cmd脚本按位置发送参数,即(pwsh.exe -File "ToastNotificationParams.ps1" "This is the title" "Message goes here"
),而不是按命名对发送参数。(不确定这是否是最佳实践,但我的脚本最初是如何被用来暂时保留的)。
虽然Param()这次让我的脚本正常工作(我也意识到基于位置的参数的固有危险),但有时可能需要基于位置的方法(例如,参数的数量未知)。。。
代码示例3:混合
ToastNotificationMix.ps1
------------------------
Param(
[Parameter(Mandatory=$false, Position=0, ValueFromPipeline=$true)] [string]$Title
)
Import-Module -Name BurntToast
For ( $i = 1; $i -lt $args.count; $i++ ) {
New-BurntToastNotification -Text "$Title, $args[i]"
}
这样的东西有效吗。。如果没有(或者有更好的解决方案),任何帮助都将不胜感激!
提前感谢!
-
自动
$args
变量仅在简单(非高级)函数/脚本中可用。通过使用[CmdletBinding()]
属性和/或每个参数至少一个[Parameter()]
属性,脚本自动变为高级脚本。-
使用
$args
允许函数/脚本接受开放数量的位置参数,通常不是,但也可以使用显式声明的参数。 -
但它不允许传递命名的参数(以预先声明的目标参数名称为前缀的参数,例如
-Title
)
-
-
为了健壮性,最好使用高级(类似cmdlet)函数或脚本;这样的函数/脚本:
- 它们需要显式地声明参数
- 它们不接受任何参数,只接受绑定到声明参数的参数
- 但是,您可以使用
[Parameter(ValueFromRemainingArguments)]
定义一个catch-all参数,该参数收集不绑定到任何其他预定义参数的所有位置参数
- 但是,您可以使用
-
显式定义的参数在默认情况下是位置的,按照它们在
param(...)
块内声明的顺序。-
您可以使用
[CmdletBinding(PositionalBinding=$false)]
关闭此默认设置 - 然后允许您使用单个
[Parameter()]
属性的Position
属性选择性地启用位置绑定
-
您可以使用
-
当您通过PowerShell的CLI的
-File
参数调用PowerShell脚本时,调用语法与从PowerShell内部的调用脚本时基本相同;也就是说,您可以传递命名的参数和/或-如果支持-位置参数。- 限制:
- 参数被视为文字
- 不支持传递数组参数(以
,
分隔的元素)
- 如果确实需要将参数解释为来自PowerShell内部的,请改用
-Command
/-c
CLI参数 - 有关何时使用
-File
与`-Command的指导,请参阅此答案
- 限制:
将其放在一起:
ToastNotificationMix.ps1
:
[CmdletBinding(PositionalBinding=$false)]
Param(
[Parameter(Position=0)]
[string]$Title
,
[Parameter(Mandatory, ValueFromRemainingArguments)]
[string[]] $Rest
)
Import-Module -Name BurntToast
foreach ($restArg in $Rest) {
New-BurntToastNotification -Text "$Title, $restArg"
}
然后,您可以从cmd.exe
调用脚本,如下所示,例如(我使用的是pwsh.exe
,PowerShell(Core)CLI;对于Windows PowerShell,请使用powershell.exe
):
仅位置绑定:
:: "foo" binds to $Title, "bar" to $Rest
pwsh -File ./ToastNotificationMix.ps1 foo bar
命名装订和定位装订的混合:
:: "bar" and "baz" both bind to $Rest
pwsh -File ./ToastNotificationMix.ps1 -Title foo bar baz