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

标签 powershell parameters parameter-passing args

问题

  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 gone 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]"
}

这样的东西有效吗?..如果不是(或者有更好的解决方案),我们将不胜感激任何帮助!

提前致谢!

最佳答案

  • automatic $args variable仅适用于简单(非高级)函数/脚本。脚本自动变为advanced一种是使用 [CmdletBinding()] 属性和/或每个参数至少一个 [Parameter()] 属性。

    • 使用$args允许函数/脚本接受开放数量的位置参数,通常代替使用显式声明的参数,但也除了使用显式声明的参数之外。

    • 但它不允许传递命名参数(以预先声明的目标参数名称为前缀的参数,例如 -Title )

  • 为了稳健性,最好使用高级(类似 cmdlet)函数或脚本;这样的函数/脚本:

    • 它们需要显式声明参数。
    • 它们除了绑定(bind)到声明参数的参数之外不接受任何参数。
      • 但是,您可以使用 [Parameter(ValueFromRemainingArguments)] 定义一个包罗万象的参数,该参数收集不绑定(bind)到任何其他预声明参数的所有位置参数。
  • 显式定义的参数默认情况下是位置参数,按照它们在 param(...) 中声明的顺序排列。阻止

    • 您可以使用 [CmdletBinding(PositionalBinding=$false)] 关闭此默认设置。
    • 然后,您可以使用 Position 选择性启用位置绑定(bind)个人属性(property)[Parameter()]属性。
  • 当您通过 PowerShell 的 CLI 调用 PowerShell 脚本时的-File参数,调用语法基本上与从内部 PowerShell 调用脚本时相同;也就是说,您可以传递命名参数和/或 - 如果支持 - 位置参数

    • 限制:
      • 参数被视为文字
      • 不支持传递数组参数(,分隔的元素)。
    • 如果您确实需要将参数解释为来自 PowerShell 内部的参数,请使用 -Command/-c相反 CLI 参数
    • 参见this answer有关何时使用的指导 -File与`-命令。

把它们放在一起:

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(核心)CLI;对于 Windows PowerShell,使用 powershell.exe ):

仅位置绑定(bind):

:: "foo" binds to $Title, "bar" to $Rest
pwsh -File ./ToastNotificationMix.ps1 foo bar

命名绑定(bind)和位置绑定(bind)的混合:

:: "bar" and "baz" both bind to $Rest
pwsh -File ./ToastNotificationMix.ps1 -Title foo bar baz

关于PowerShell - 访问从 Windows cmd shell 发送的脚本参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67653712/

相关文章:

c - C 函数中的参数传递

powershell - 通过 PowerShell 更改正在运行的进程中的 numa 组

powershell - Set-AzureDeployment 忽略相对路径

python - 带点的函数参数给出 SyntaxError

java - 我的子类正在从其父类(super class)传递值

java - 在 Java 8 Stream 中创建带参数的对象

mysql - 将数组传递给 MySQL 存储例程

C++ 将数组传递给函数

powershell - 有没有一种方法可以在Powershell中的if语句中查找哪个条件

vba - 使用环境变量在 VBA 中打开 PowerShell 脚本