【问题标题】:Wrapper function for cmdlet - pass remaining parameterscmdlet 的包装函数 - 传递剩余参数
【发布时间】:2020-06-28 12:13:47
【问题描述】:

我正在编写一个使用 ValueFromRemainingArguments 包装 cmdlet 的函数(如 here 所述)。

下面的简单代码演示了这个问题:

  • 作品
function Test-WrapperArgs {
    Set-Location @args
}
Test-WrapperArgs -Path C:\ 
  • 不起作用
function Test-WrapperUnbound {
    Param(
        [Parameter(ValueFromRemainingArguments)] $UnboundArgs
    )

    Set-Location @UnboundArgs
}
Test-WrapperUnbound -Path C:\
Set-Location: F:\cygwin\home\thorsten\.config\powershell\test.ps1:69
Line |
  69 |      Set-Location @UnboundArgs
     |      ~~~~~~~~~~~~~~~~~~~~~~~~~
     | A positional parameter cannot be found that accepts argument 'C:\'.

我尝试从PowerShell Community Extensions 解决GetTypeEchoArgs 的问题,但无济于事。目前我几乎正在考虑一个错误(可能与this ticket??有关)。

【问题讨论】:

    标签: powershell parameters wrapper


    【解决方案1】:

    高级功能的最佳解决方案(使用[CmdletBinding()] 属性和/或[Parameter()] 属性的功能)是搭建代理(wrapper) 函数通过 PowerShell SDK,如this answer 所示。 这主要涉及复制目标命令的参数声明(尽管是以自动但静态的方式)。

    如果您确实想要使用这种方法,您唯一的选择是执行您自己的解析$UnboundArgs数组(从技术上讲,它是[System.Collections.Generic.List[object]]) 的一个实例,但是这很麻烦,而且并非万无一失:

    function Test-WrapperUnbound {
      Param(
          [Parameter(ValueFromRemainingArguments)] $UnboundArgs
      )
    
      # (Incompletely) emulate PowerShell's own argument parsing by 
      # building a hashtable of parameter-argument pairs to pass through
      # to Set-Location via splatting.
      $htPassThruArgs = @{}; $key = $null
      switch -regex ($UnboundArgs) {
        '^-(.+)' { if ($key) { $htPassThruArgs[$key] = $true } $key = $Matches[1] }
        default {  $htPassThruArgs[$key] = $_; $key = $null }
      }
      if ($key) { $htPassThruArgs[$key] = $true } # trailing switch param.
    
      # Pass the resulting hashtable via splatting.
      Set-Location @htPassThruArgs
    
    }
    

    注意:

    • 这不是万无一失的,因为您的函数将无法区分实际参数名称(例如,-Path)和恰好看起来像参数名称的字符串文字(例如,'-Path'

    • 此外,与顶部提到的基于脚手架的代理功能方法不同,您不会获得任何传递参数的制表符完成,传递参数不会与-? / Get-Help / Get-Command -Syntax.

    如果您不介意既没有制表符补全也没有语法帮助和/或您的包装函数必须支持传递到 multiplenot-known-in-高级 目标命令,使用带有@args简单(非高级)函数(如您的工作示例;另见下文)是最简单的选项,假设您的函数本身不需要支持common parameters(这需要高级函数)。
    使用 simple 函数还意味着公共参数被传递给包装的命令 only(而 advanced 函数会将它们解释为 em>本身,尽管它们的效果 usually 会传播到函数内部的调用;但是,它们具有公共参数,例如 -OutVariable,但区别很重要)。


    至于你尝试了什么

    虽然PowerShell 原则上确实通过数组(或类似数组的集合,例如[System.Collections.Generic.List[object]])支持splatting,但只有在以下情况下才能按预期工作所有元素都将作为 positional 参数传递和/或如果目标命令是 外部程序(关于其参数结构,PowerShell 一无所知,并且总是通过作为令牌列表/数组的参数)。

    为了将带有 命名参数 的参数传递给其他 PowerShell 命令,您必须使用基于 hashtable 的 splatting,其中每个条目的键标识目标参数和参数(参数)的值。

    尽管automatic $args variable 在技术上也是一个数组 ([object[]]),PowerShell 有内置的魔法 允许与@args 一起飞溅也可以使用命名参数 - 这适用于任何自定义数组或集合。

    请注意,自动 $args 变量会收集声明了 no 参数的所有参数 - 仅在 simple 中可用 em>(非高级)函数和脚本; advanced functions and scripts - 使用[CmdletBinding()] 属性和/或[Parameter()] 属性的那些 - 要求声明所有潜在参数。

    【讨论】:

    • 关于 splatting 数组和哈希表之间的区别以及简单和高级函数中参数的特殊情况的点解释非常有用。在我的情况下,我实际上可以使用@args,因为它不包含所有参数,而只包含那些未分配的参数(使用一个简单的函数)。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-03
    • 2020-06-09
    • 2021-11-15
    • 2015-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多