我知道这可以使用函数完成,但我想保留标签自动完成功能,而不必编写一个需要放置到$PROFILE中的大型函数。
简而言之,我只希望在传递参数时才能使用该别名。
function which { if ($args.count) { Get-Command @args } else { Throw "Missing command name." } }
-?
以显示Get-Command
的帮助确实有效,但参数的制表符自动完成却不起作用。Get-Command
的参数声明 - 然后函数定义就会变得相当大。$PROFILE
文件本身的大小,那么您可以编写代理脚本 - which.ps1
- 您也可以使用which
来调用它,假设您将其放置在$env:Path
[1]中列出的目录之一中;请参见下一节。
定义一个包装(代理)函数或脚本 是一项不容易的任务,但可以让您实现一个强大的包装器,支持选项补全甚至转发到原始命令的帮助文档。
注意:
漏洞警报:正如zett42所指出的那样,从PowerShell [Core] 7.1开始,如果目标命令是(高级)函数或脚本,则System.Management.Automation.ProxyCommand.Create
会忽略包括动态参数;然而,编译的cmdlets不受影响;请参见GitHub问题#4792和this答案以获取解决方法。
为了简单起见,以下代码创建了一个包装器脚本,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
尽管System.Management.Automation.ProxyCommand.Create
需要一个System.Management.Automation.CommandMetadata
实例来标识目标命令,但由Get-Command
输出的System.Management.Automation.CommandInfo
实例可以直接使用。
关于基于注释的帮助:默认情况下,代理函数只是简单地转发到原始 cmdlet 的帮助;但是,您可以选择将字符串作为第二个参数传递以用作基于注释的帮助。
Get-Help
的输出中结合使用[System.Management.Automation.ProxyCommand]::GetHelpComments()
,您可以从原始命令的帮助副本开始进行修改:
[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.
begin { ... }
块内将以下命令放置为第一条语句:if (-not $MyInvocation.ExpectingInput -and -not ($Name -or $CommandType -or $Module -or $FullyQualifiedModule)) {
Throw "Missing command name or filter."
}
PS> ./which.ps1
Missing command name or filter.
...
其他常见的自定义类型包括:
Removing parameters from the wrapper, by simply removing the parameter declaration.
Adding additional parameters to the invocation of the wrapped command, by modifying the following line in the begin
block:
# Add parameters, as needed.
$scriptCmd = { & $wrappedCmd @PSBoundParameters }
Preprocessing pipeline input before passing it to the wrapped command, by customizing the process
block and replacing $_
with your preprocessed input in the following line:
# Replace $_ with a preprocessed version of it, as needed.
$steppablePipeline.Process($_)
如果你需要一个完整实现的代理函数示例,可以参考this answer。
[1] 注意事项:对于Linux用户来说,由于Linux文件系统是大小写敏感的,所以调用您的脚本时不会像在PowerShell中通常工作的命令一样忽略大小写。例如,如果您的脚本文件名为Get-Foo.ps1
,只有使用完全相同的大小写Get-Foo
才能起作用,而不是像get-foo
这样的小写。