cmdlet 的包装函数 - 传递其余参数
Wrapper function for cmdlet - pass remaining parameters
我正在编写一个使用 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 to no avail. At the moment I'm almost considering a bug (maybe related to this ticket??) 中解决 GetType
和 EchoArgs
的问题。
高级函数的最佳解决方案(使用[CmdletBinding()]
属性and/or一个[Parameter()]
属性)是为了 通过 PowerShell SDK 搭建一个代理(包装器)函数,如 所示。
这实质上涉及 复制 目标命令的参数声明(虽然是自动的,但是是静态的)。
如果您不想使用这种方法,您唯一的选择是执行您自己的解析 $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
.
如果您不介意既没有制表符补全也没有语法帮助 and/or 您的包装函数必须支持传递给 multiple 或事先未知目标命令,使用简单(非高级)函数和@args
(如在您的工作示例中;另见下文) 是最简单的选项,假设您的函数 本身 不需要支持 common parameters(需要高级函数)。
使用 simple 函数还意味着将公共参数传递给包装命令 only(而 advanced 函数会将它们解释为 本身 ,尽管它们的效果 usually 传播到函数内部的调用;然而,使用 -OutVariable
等公共参数,区别很重要)。
至于你试过的:
虽然 PowerShell 通过 arrays(或类似数组的集合,例如 [System.Collections.Generic.List[object]]
)支持 splatting原则上,如果所有元素都作为 positional arguments and/or 如果目标命令是 external,则此 仅按预期工作program(PowerShell 对其参数结构一无所知,并且始终将参数作为 list/array 个标记传递)。
为了将带有 命名参数 的参数传递给其他 PowerShell 命令,您必须使用基于 hashtable 的展开,其中每个条目的键标识目标 参数,值标识参数 value(参数)。
尽管 automatic $args
variable 在技术上也是一个 数组 ([object[]]
),PowerShell 具有 内置-在 magic 中允许使用 @args
进行拼接也可以使用命名参数 - 这 not 可以使用任何自定义数组或集合。
请注意自动 $args
变量,它收集声明了 no 参数的所有参数 - 是 仅在简单(非高级)函数和脚本中可用; advanced functions and scripts - 使用 [CmdletBinding()]
属性的那些 and/or [Parameter()]
属性 - 要求声明 所有 个潜在参数。
我正在编写一个使用 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 to no avail. At the moment I'm almost considering a bug (maybe related to this ticket??) 中解决 GetType
和 EchoArgs
的问题。
高级函数的最佳解决方案(使用[CmdletBinding()]
属性and/or一个[Parameter()]
属性)是为了 通过 PowerShell SDK 搭建一个代理(包装器)函数,如
如果您不想使用这种方法,您唯一的选择是执行您自己的解析 $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
.
如果您不介意既没有制表符补全也没有语法帮助 and/or 您的包装函数必须支持传递给 multiple 或事先未知目标命令,使用简单(非高级)函数和@args
(如在您的工作示例中;另见下文) 是最简单的选项,假设您的函数 本身 不需要支持 common parameters(需要高级函数)。
使用 simple 函数还意味着将公共参数传递给包装命令 only(而 advanced 函数会将它们解释为 本身 ,尽管它们的效果 usually 传播到函数内部的调用;然而,使用 -OutVariable
等公共参数,区别很重要)。
至于你试过的:
虽然 PowerShell 通过 arrays(或类似数组的集合,例如 [System.Collections.Generic.List[object]]
)支持 splatting原则上,如果所有元素都作为 positional arguments and/or 如果目标命令是 external,则此 仅按预期工作program(PowerShell 对其参数结构一无所知,并且始终将参数作为 list/array 个标记传递)。
为了将带有 命名参数 的参数传递给其他 PowerShell 命令,您必须使用基于 hashtable 的展开,其中每个条目的键标识目标 参数,值标识参数 value(参数)。
尽管 automatic $args
variable 在技术上也是一个 数组 ([object[]]
),PowerShell 具有 内置-在 magic 中允许使用 @args
进行拼接也可以使用命名参数 - 这 not 可以使用任何自定义数组或集合。
请注意自动 $args
变量,它收集声明了 no 参数的所有参数 - 是 仅在简单(非高级)函数和脚本中可用; advanced functions and scripts - 使用 [CmdletBinding()]
属性的那些 and/or [Parameter()]
属性 - 要求声明 所有 个潜在参数。