有没有办法以仅在将参数传递给别名时才运行的方式为 cmdlet 创建别名?

Ext*_*tor 5 powershell alias wrapper

我正在尝试创建Get-Command cmdlet的别名(命名为which),如果我不发送任何参数,它就不会运行(因为如果它在没有参数的情况下运行,它会输出所有可用的命令) .

我知道这可以使用函数来完成,但我想保留选项卡完成功能,而不必编写一个相当大的函数来放入我的$PROFILE 中

简而言之,我只希望别名在传递参数时起作用。

mkl*_*nt0 7

你不能用alias做到这一点,因为PowerShell aliases 只能引用另一个命令name 或 path,因此既不能包含arguments也不能包含自定义逻辑

因此,你确实需要一个功能,但它可以是一个短期和简单的一个

function which { if ($args.count) { Get-Command @args } else { Throw "Missing command name." } }
Run Code Online (Sandbox Code Playgroud)

请注意,虽然通过-?显示Get-Command的帮助确实有效,但参数的制表符完成不起作用。

为了获得制表符Get-Command补全,您需要编写一个包装器(代理)函数或至少复制的参数声明- 然后确实使函数定义变得可观。

如果关注的只是$PROFILE文件本身的大小,您可以编写一个代理脚本-which.ps1您也可以调用which它,假设您将它放在$env:Path[1] 中列出的目录之一中;见下一节。


定义包装器(代理)脚本或函数:

定义包装器(代理)函数或脚本是一项重要的工作,但允许您实现一个强大的包装器,该包装器支持制表符完成甚至转发到原始命令的帮助。

笔记:

  • 错误警报:正如zett42指出的那样,从 PowerShell [Core] 7.1 开始,如果目标命令是(高级)函数或脚本,则System.Management.Automation.ProxyCommand.Create忽略包含动态参数;然而,编译的cmdlet不会受到影响; 有关解决方法,请参阅GitHub 问题 #4792此答案

  • 为简单起见,下面创建一个包装脚本which.ps1以及在当前目录下保存它。如前所述,如果您将它放在 中列出的目录之一中$env:PATH,您将能够像which.

  • 下面的代码可以很容易地改为创建一个包装函数:只需获取$wrapperCmdSource下面变量的内容并将其包含在function which { ... }.

  • 从 PowerShell Core 7.0.0-preview.5 开始,自动生成的代码存在一些问题,可能会也可能不会影响您;它们将在某个时候修复;要了解更多信息并了解如何手动更正它们,请参阅GitHub 问题 #10863

# Create the wrapper scaffolding as source code (outputs a single [string])
$wrapperCmdSource = 
  [System.Management.Automation.ProxyCommand]::Create((Get-Command Get-Command))
  
# Write the auto-generated source code to a script file
$wrapperCmdSource > which.ps1
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 即使System.Management.Automation.ProxyCommand.Create需要一个System.Management.Automation.CommandMetadata实例来识别目标命令,System.Management.Automation.CommandInfo输出的实例Get-Command也可以按原样使用。

  • Re comment-based help : 默认情况下,代理功能只是转发原始cmdlet的帮助;但是,您可以选择传递一个字符串作为基于注释的帮助作为第二个参数。

    • 通过[System.Management.Automation.ProxyCommand]::GetHelpComments()与输出结合使用Get-Help,您可以从原始命令帮助的副本开始并对其进行修改: [System.Management.Automation.ProxyCommand]::GetHelpComments((Get-Help Get-Command))

您现在有一个功能齐全的which.ps1包装器脚本,它的行为与Get-Command它本身相似

您可以按如下方式调用它:

./which  # Same as: Get-Command; tab completion of parameters supported.
./which -? # Shows Get-Command's help.
Run Code Online (Sandbox Code Playgroud)

您现在可以编辑脚本文件以执行所需的自定义。

注意:自动生成的源代码包含大量样板代码;然而,通常只有一两个地方需要调整来实现自定义功能。

具体来说,将以下命令作为begin { ... }块内的第一条语句:

if (-not $MyInvocation.ExpectingInput -and -not ($Name -or $CommandType -or $Module -or $FullyQualifiedModule)) {
  Throw "Missing command name or filter."
}
Run Code Online (Sandbox Code Playgroud)

如果调用者没有通过直接参数或通过管道提供某种方式来定位特定命令或命令组,这会导致脚本抛出错误。

如果您现在不带参数调用修改后的脚本,您应该会看到所需的错误:

function which { if ($args.count) { Get-Command @args } else { Throw "Missing command name." } }
Run Code Online (Sandbox Code Playgroud)

其他常见的自定义类型是:

  • 通过简单地删除参数声明,从包装器中删除参数。

  • 通过修改begin块中的以下行,向包装命令的调用添加其他参数:

      # Add parameters, as needed.
      $scriptCmd = { & $wrappedCmd @PSBoundParameters } 
    
    Run Code Online (Sandbox Code Playgroud)
  • 在将管道输入传递给包装命令之前预处理管道输入,方法是自定义process块并替换$_为以下行中的预处理输入:

      # Replace $_ with a preprocessed version of it, as needed.
      $steppablePipeline.Process($_)
    
    Run Code Online (Sandbox Code Playgroud)

[1]买者对Linux的用户:由于Linux的文件系统是大小写是区分大小写,你的脚本的调用是行不通的病例不区分大小写,该方式通常命令在PowerShell中的工作。例如,如果您的脚本文件名是Get-Foo.ps1,则仅Get-Foo- 使用完全相同的大小写 - 将起作用,而不是get-foo,例如。