在PowerShell中如何使用另一个Cmdlet的参数定义?

4
在Bash中,我有一堆别名可以为现有的程序/函数添加参数,例如:
alias grep='grep --color'

我知道这不是最好的类比,但在Powershell中有简单的方法吗?似乎Set-Alias不允许您指定参数。

您可以为cmdlet创建别名,但不能为由cmdlet及其参数组成的命令创建别名。

他们建议创建一个新的cmdlet来实现,但我希望能够传递附加参数,而不必在新的cmdlet中硬编码所有允许的参数(就像New-ProxyCommand似乎要求您这样做一样)。这样,我就不必知道代理/别名cmdlet参数何时更改并在我的代理cmdlet中进行更改。
那么什么是最佳解决方案?
  • 不要静态复制别名/代理cmdlet的参数定义。让原始cmdlet进行验证或动态引用它。
  • 使用别名/不同命名的cmdlet,以便必须明确执行某些操作才能获得不同的行为
  • 使别名/新cmdlet将值传递给别名/代理cmdlet中的现有参数

我能想到的最接近的是以下内容,但语法可能不正确。似乎与管道的兼容性不太好,但可以通过某种方式解决。

& $proxiedcommand $additionaldefaultparams $rawparamsfromread-host

还是说有没有一种方法可以使用 代理 cmdlet 的内容来动态实例化参数,就像下面这样?

function aliased-cmdlet
{
[CmdletBinding((Get-Command Original-Cmdlet)._cmdletBindingsettings_)]
Param(
(Get-Command Original-Cmdlet)._paramsettings_)
)

Original-Cmdlet -CustomDefault Value -Whatever Else
}

1
这个由Jeff Hicks演示的示例或者Don Jones的演示文稿关于代理函数的内容可能会有所帮助。 - BenH
你可能想考虑编写一个脚本函数,使用 $myinvocation,特别是 $myinvocation.line,并解析它以获取任何可能已提供的参数,您需要修改或覆盖这些参数。例如,请参阅 MSDN 上的 “获取所有参数” 页面。 - Jeff Zeitlin
@BenH,我更新了一下我的问题。我认为代理命令接近解决方案,但不能处理过时的参数。似乎解决方案是更多地了解代理cmdlet生成动态。对于我觉得应该是一个简单的解决方案来说,这似乎有点过度设计和脆弱。 - undefinedvariable
1个回答

6

如果您想要覆盖的唯一更改是默认参数值,已经有一个内置的工具可以实现。使用$PSDefaultParameterValues自动变量:

PS C:\> ('a a a' |Select-String 'a').Matches.Count
1
PS C:\> $PSDefaultParameterValues['Select-String:AllMatches']=$true
PS C:\> ('a a a' |Select-String 'a').Matches.Count
3

如果您希望在某些情况下覆盖默认参数值,但不更改cmdlet的默认行为,请创建代理命令并为代理命令设置默认值:

# Gather required info
$OriginalCommand = Get-Command Select-String
$NewCommandName = 'Select-AllMatches'
$Metadata = [System.Management.Automation.CommandMetadata]::new($OriginalCommand)

# Create proxy command
$ProxyString = [System.Management.Automation.ProxyCommand]::Create($Metadata)
New-Item -Path function:\ -Name $NewCommandName -Value $ProxyString

# Set default parameter values for proxy command
$PSDefaultParameterValues["$NewCommandName`:AllMatches"] = $true

现在参数默认值仅适用于Select-AllMatches

PS C:\> ('a a a' |Select-String 'a').Matches.Count
1
PS C:\> ('a a a' |Select-AllMatches 'a').Matches.Count
3

谢谢提供这个内容。我觉得我可能可以用它来解决我心中的这个具体问题。然而,将参数与 cmdlet 名称绑定并在会话全局设置的要求似乎有点局限性。如果我想要有两个别名来设置不同的参数或相同参数的不同值,那么这似乎不是最兼容的。 - undefinedvariable
此外,这意味着我需要要求用户明确执行某些操作才能调用原始 cmdlet 而不使用自定义默认值。这就是为什么最好使用别名的原因,以便不改变原始 cmdlet 的默认行为。 - undefinedvariable
这已经接近了,但我仍然需要动态地执行,否则命令生成的参数将是该 cmdlet 的快照。请参见我的上面的评论。 - undefinedvariable
1
@undefinedvariable 你所说的“动态”具体是什么意思?你可以将上述内容简单封装在一个函数中,该函数接受原始命令、别名和表示要覆盖的参数值的哈希表作为参数,这样就可以实现与bashalias相同的功能。 - Mathias R. Jessen
尽管 $Metadata = [System.Management.Automation.CommandMetadata]::($OriginalCommand) 对我无效,但 $Metadata = New-Object System.Management.Automation.CommandMetaData $OriginalCommand 是有效的。不确定是版本差异还是其他原因。 - undefinedvariable
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接