【问题标题】:Passing arguments as array to PowerShell function将参数作为数组传递给 PowerShell 函数
【发布时间】:2019-11-12 11:55:57
【问题描述】:

我试图弄清楚如何将多个字符串作为数组传递给 powershell 函数。

function ArrayCount([string[]] $args) {
    Write-Host $args.Count
}

ArrayCount "1" "2" "3"
ArrayCount "1","2","3"
ArrayCount @("1","2","3")

打印

2
0
0

如何将具有 3 个值的数组传递给 ArrayCount 函数? 为什么某些调用的 Count 为零?

【问题讨论】:

    标签: powershell reserved automatic-variable


    【解决方案1】:

    在 PowerShell 中,$args 是一个引用未命名 参数的自动变量。只需更改您的参数名称:

    function ArrayCount([string[]] $myParam) {
        Write-Host $myParam.Count
    }
    

    你会得到预期的输出

    1
    3
    3
    

    【讨论】:

      【解决方案2】:

      编写于:PowerShell Core 7.0.0-preview.5 / Windows PowerShell v5.1

      用一些背景信息补充Martin Brandl's helpful, to-the-point answer

      $argsautomatic variable 的一个实例,表示一个特殊变量,其值由 PowerShell 本身控制。 p>

      因此,您应该避免自定义使用自动变量,即使在它恰好起作用的情况下(见下文)。 p>

      理想情况下,PowerShell 本身会一致地阻止这种自定义使用(它只对一些自动变量这样做),并且有@987654323 @关于强制执行,但出于向后兼容性的原因,最终决定不这样做。

      相反,设计时警告关于在 Visual Studio Code 中通过PSScriptAnalyzer 安装了PowerShell extension 的自动变量的分配现在正在发出。 p>

      不幸的是,如果没有 Visual Code 的帮助,您通常无法推断变量名称是否指的是自动变量,因为它的 名称 程序化 发现它们的方式 - 阅读帮助主题是唯一的选择;请参阅下一节。


      不应该可写但事实上的自动变量列表:

      注意:

      • 列表是使用以下命令生成的,从 Windows PowerShell v5.1 开始 - 在 PowerShell Core 中,列表更短,因为删除了一些过时的变量。

        • 该命令依赖于相关帮助主题字符串解析;这种方法很脆弱,但它是目前发现自动变量的唯一方法,因为没有基于反射的方法。

        • This GitHub issue 建议实现编程可发现性,并讨论了为自动变量引入单独的保留命名空间的可能性。

      • 随着时间的推移,可能会引入新的自动变量;希望它们的只读状态(如果合适)将在引入时强制执行。

        • 由于自动变量与用户变量共享一个命名空间,因此引入任何新的自动变量都存在破坏现有代码的风险。
      • 选择几个自动变量是合法可写

        • $OFS - 字符串化数组时使用的分隔符。
        • $null - 这个特殊变量不仅在读取时表示空值,而且还设计为允许为其分配任何值以便丢弃它(而不是写入它到(成功)输出流)。
        • $LASTEXITCODE,以$global:LASTEXITCODE 的形式设置要使用的进程退出代码(尽管最好使用exit <n>)。
      • 下面列出的自动变量(例如$PID)已经实际上是只读的(它们应该是)。 下面列出的那些 - 即意外可写的 - 属于以下类别

        • 那些总是悄悄地丢弃分配的价值(例如,$Input$MyInvocation$PSCmdlet

        • 接受自定义值,但在自动分配值的上下文中覆盖(隐藏)它(例如,$args,每当有新脚本时自动将其设置为局部变量块(函数/脚本)被输入;您作为本地参数变量的使用被有效地忽略了)。

        • 混合情况,特别是 $_ / $PSItem,在自动为 $_ 赋值的任何上下文之外,分配的值会被悄悄丢弃,但在这样的上下文中,您 可以(但不应该)分配一个新值(例如,'in' | ForEach-Object { $_ = $_ + '!'; $_ } 输出 in!

      Name                          Predefined
      ----                          ----------
      _                                  False
      AllNodes                           False
      Args                                True
      Event                              False
      EventArgs                          False
      EventSubscriber                    False
      ForEach                             True
      Input                               True
      Matches                             True
      MyInvocation                        True
      NestedPromptLevel                   True
      Profile                             True
      PSBoundParameters                   True
      PsCmdlet                           False
      PSCommandPath                       True
      PSDebugContext                     False
      PSItem                             False
      PSScriptRoot                        True
      PSSenderInfo                       False
      Pwd                                 True
      ReportErrorShowExceptionClass      False
      ReportErrorShowInnerException      False
      ReportErrorShowSource              False
      ReportErrorShowStackTrace          False
      Sender                             False
      StackTrace                          True
      This                               False
      

      “预定义”是指它们是否默认存在于全局范围内。

      以下代码用于检测它们 - 您可以预先设置$VerbosePreference = 'Continue'(并在之后重置)以查看已经只读的变量:

      $autoVarNames = ((get-help about_automatic_variables) -split [environment]::newline -match '^\s*\$\w+\s*$').Trim().Trim('$') | Sort-Object -Unique
      
      foreach ($varName in $autoVarNames) {
        $var = Get-Variable $varName -ErrorAction 'SilentlyContinue'
        $exists = $?
        if ($exists -and $var.Options -match 'readonly|constant') {
          Write-Verbose "$varName`: read-only or constant"
        } elseif ($varName -in 'NULL', 'OFS', 'LastExitCode') { # exceptions
          Write-Verbose "$varName`: writable by design"
        } else {
          Set-Variable -Name $varName -Value $null -ErrorAction SilentlyContinue
          if ($?) {
            [pscustomobject] @{ Name = $varName; Predefined = $exists }
          }
        }
      }
      

      请注意,代码有一个硬编码的异常列表,以免报告确实应该可写的自动变量,例如 $OFS$LastExitCode,或可分配为安静的无操作,例如$null.

      【讨论】:

        猜你喜欢
        • 2012-10-17
        • 2012-12-07
        • 2023-03-26
        • 1970-01-01
        • 2013-01-27
        • 1970-01-01
        • 2022-10-07
        相关资源
        最近更新 更多