PowerShell-访问脚本参数,从Windows cmd shell发送



问题

  1. 如何访问发送到PowerShell脚本(.ps1文件)的参数
  2. 你能访问参数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/-cCLI参数
    • 有关何时使用-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

最新更新