> 文档中心 > PowerShell: 在自定义代码中支持Tab键自动补全

PowerShell: 在自定义代码中支持Tab键自动补全

大家好,我是码农杰克~

在PowerShell中很多Cmdlet在输入参数时按tab键就可以可以自动补全,这是怎么做到的呢?

我们先来看个PowerShell自带命令:Test-Path

在PowerShell中输入下面的命令

Test-Path -Path C:\ -PathType

然后按空格,然后按Tab键,就可以看到 -PathType 后面的值会自动补全,并且总是在限定的几个值之前循环

Test-Path -Path C:\ -PathType Container

Test-Path -Path C:\ -PathType Leaf

Test-Path -Path C:\ -PathType Any

其实在PowerShell中有不止一种方法来自动补全参数。

PowerShell默认支持的自动补全

Cmdlet名

任何被加载到当前的PowerShell host中的Cmdlet在输入时按tab键都会被自动补全,如果输入的内容有多个匹配项,则在不断按Tab键时便会在多个匹配项之间切换。

比如我们输入:

Test-

再按Tab键,就有可能会得到

Test-AppLockerPolicy

继续按Tab键就可以在下面的Cmdlet之间来回切换,直到你选中你想要的

Test-Dtc
Test-NetConnection
Test-ScriptFileInfo
Test-SvnRepository
Test-AppLockerPolicy
Test-Certificate
Test-Connection
Test-DscConfiguration
Test-FileCatalog
Test-Json
Test-KdsRootKey
Test-ModuleManifest
Test-Path
Test-PnPListItemIsRecord
Test-PnPMicrosoft365GroupAliasIsUsed
Test-PnPSite
Test-PnPTenantTemplate
Test-PSSessionConfigurationFile
Test-WSMan 

当然并不是每个人的机器上都都能得到相同的结果,这取决于你当前的PowerShell中加载了那些模块。

可以使用下面的命令来查看,你的系统中输入上面的命令可以得到那些可能的Cmdlet。

 Get-Command Test-*

这是一个非常有用的Cmdlet尤其是当你记不住某些Cmdlet名字的时候可以使用这个命令来查找,它支持多个通配符比如:

Get-Command *Test*Get-Command Get-*PnP*Get-Command Set-*Item*

参数名

任何已被加载的Cmdlet在输入其参数名时,按Tab键,PowerShell也可以自动补全。

比如在PowerShell中输入下面的命令:

Get-Item -

再按Tab键,就可以自动补全下面的参数名:

Get-Item -Path

不停按Tab键,就可以在不同参数之间切换。

Get-Item [-Path] [-Filter ] [-Include ] [-Exclude ] [-Force] [-Credential ] [-Stream ] []

同样如果不想让其在其它不需要的参数之间切换,可以多输入几个字母,比如:

Get-Item -Pa

 再按Tab键就可以直接补全 -Path参数。

参数值

  • 如果Cmdlet的参数值是某个枚举,在按Tab键的时候,PowerShell会自动补全
  • 如果Cmdlet的参数值被ValidateSet所限定,按Tab键的时候,PowerShell会按照ValidateSet的限定内容自动补全
  • 如果某个参数使用了ArgumentCompleter,按Tab键可以根据ArgumentCompleter的返回值自动补全
  • 如果某个参数使用了ArgumentCompletions,按Tab键可以根据ArgumentCompletions的内容自动补全,但是和ValidateSet的区别是ArgumentCompletions并不验证,而且也不限定用户输入只在给定的范围。所以ArgumentCompletions更多的像是建议值,而ValidateSet是限定值。

各种操作符

PowerShell中的各种操作符按Tab键也是可以自动补全的。由于PowerShell中有些符号具有特殊含义,所以PowerShell中有些运算符并不想其它语言一样使用简单符号来表示。比如表示"并且",其它语言可能使用 "&&" 但是PowerShell中使用 "-and".

例如在PowerShell中输入:

1..5 -con

再按Tab键就可以得到

1..5 -contains

然后接着输入

1..5 -contains 3#结果: True

-contains 是一个非常有用的操作符,用来判断输入是否包含目标子集。

更多操作符请参见:

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_operators?view=powershell-7.2

变量

在PowerShell中只需要输入变量名的开头,再按Tab键也是可以自动补全的。变量分为系统默认变量、自动变量和用户自定义变量。

系统默认变量/自动变量

自动变量是在一些上下文中PowerShell为我们自动生成并赋值的变量

系统默认变量就是一些PowerShell启动之后系统自动生成的变量

比如:

$HOME$PSScriptRoot

 可以使用 Get-Variable来查看,当然这个命令查看的不仅是系统变量,用户自定义变量也能看到。比如刚刚启动PowerShell的时候调用这个命令就能看到系统都有那些自动生成的变量。

Get-Variable

这些命令在PowerShell中可以直接引用,并且输入开始几个字母之后按Tab键就可以自动补全。

比如输入:

$Verbose

 按Tab键就可以补全下面的变量名

$VerbosePreference

这里一定要记住使用Get-Variable得到的变量名是不带'$'符号的,我们在使用的时候要在前面加个'$'。比如上面的例子。

用户自定义变量

自定义变量就是在PowerShell窗口中用户自己定义的变量。

例如:

$processes=Get-Process

这里声明了一个变量叫"processes"并且用Get-Process的结果为其赋值。

那么我们如果要引用它,方式跟系统变量也是一样的,输入几个首字母再按Tab键,PowerShell就会自动补全剩下的变量名。

$pro

按Tab键

$processes

通过Get-Variable也能查看到刚刚声明的变量

那么如果我们在自己编写Cmdlet的时候如何使用PowerShell的自动补全功能呢?

在自定义Cmdlet中支持自动补全

Cmdlet名/参数名的自动补全

自定义的Cmdlet在导入当前的PowerShell session之后,在使用时按Tab键PowerShell就会自动补全Cmdlet名以及参数名

参数值的自动补全

自定义方法或者Cmdlet中自动补全参数值有多种方法,下面是常用的几种方式。

使用枚举

如果我们Cmdlet参数限定为枚举类型,那么我们按Tab键的时候,PowerShell会自动获取对应枚举类型的名字为我们补全值。

比如Write-Host中设置字体颜色或者背景颜色

Write-Host
     [[-Object] ]
     [-NoNewline]
     [-Separator ]
     [-ForegroundColor ]
     [-BackgroundColor ]
     []

我们可以看到-ForegroundColor和-BackgroundColor均为[ConsoleColor]这个枚举类型,所以当我们想设置字体颜色的时候输入 -ForegroundColor再按Tab键,PowerShell就会自动提取[ConsoleColor]这个枚举的所有值供我们选择啦。

运行下面的命令:

[ConsoleColor]::GetNames([ConsoleColor])

 可以看到这个枚举类型有下面这些值:

BlackDarkBlueDarkGreenDarkCyanDarkRedDarkMagentaDarkYellowGrayDarkGrayBlueGreenCyanRedMagentaYellowWhite

那如果输入:

Write-Host "red" -ForegroundColor R

再按一下Tab键,就可以自动补全成下面的命令了:

Write-Host "red" -ForegroundColor Red

使用ValidateSetAttribute

如果没有合适枚举类型,或者嫌声明枚举类型太过麻烦,还可以使用ValidateSetAttribute。ValidateSetAttribute,既限定了参数的可能值,也会做相应的验证,如果输入值不在它定义的范围内则会抛错。

具体使用见下面代码:

function Test-Foo{  param(  [ValidateSet("Jerry","Tom")]  [string]  $Name  )  Write-Host "I'm $Name."  #... Function body here}

在PowerShell中运行上面的代码,然后就可以调用Test-Foo了。当然输入参数-Name 时PowerShell就会根据ValidateSet里面的可能值进行自动补全。

输入:

Test-Foo -Name 

然后按Tab键得到补全后的命令:

Test-Foo -Name Jerry# I'm Jerry.

使用ArgumentCompletionsAttribute

使用ArgumentCompletions属性可以在用户按Tab键时给一系列的建议值。但是并不验证和限定用户的输入。这是他和ValidateSet属性的区别,ValidateSet属性不仅验证用户输入,而且还限定用户的输入必须在给定的集合内。

function Test-ArgumentCompletions {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ArgumentCompletions('Fruits', 'Vegetables')]
        $Type,

        [Parameter()]
        [ArgumentCompletions('Apple', 'Banana', 'Orange')]
        $Fruit,

        [Parameter()]
        [ArgumentCompletions('Tomato', 'Corn', 'Squash')]
        $Vegetable
    )
}

在PowerShell中运行上面的代码,然后在输入:

Test-ArgumentCompletions -Fruit 

按Tab键,就可以自动补全参数值,并且PowerShell会从'Apple', 'Banana', 'Orange'这几个值当中依次选取选取。

使用ArgumentCompleterAttribute

ArgumentCompleter提供了更加强大的方式来自动补全用户输入。ArgumentCompleter中需要用户编写相应的脚本或者类来实现自动补全的逻辑。

ArgumentCompleter中的脚本有5个参数:

  • $commandName 正在使用自动补全的对应的Cmdlet名字.
  • $parameterName 正在使用自动补全的参数名.
  • $wordToComplete 用户在按Tab键以前已经输入的值,比如 如果输入"Write-Host -ForegroundColor R" 那么这个$wordToComplete 的值就等于 "R",然后就可以在代码里面决定如何匹配对应的参数值了. 比如"Red".
  • $commandAst (Position 3) - 当前命令行里已经输入的内容比如:"Write-Host -ForegroundColor R". 这个参数非常有用,有时候可以使用这个参数对自动完成的内容做更多的判断。 更多内容请参考 AST .
  • $fakeBoundParameters (Position 4) - 用户按Tab键以前已经输入的参数以及值。参考 about_Automatic_Variables.

 因此上一节中ArgumentCompletions还可以修改为下面的代码。

function MyArgumentCompleter{
    param ( $commaName,
            $parameterName,
            $wordToComplete,
            $commandAst,
            $fakeBoundParameters )

    $possibleValues = @{
        Fruits = @('Apple', 'Orange', 'Banana')
        Vegetables = @('Tomato', 'Squash', 'Corn')
    }

    if ($fakeBoundParameters.ContainsKey('Type')) {
        $possibleValues[$fakeBoundParameters.Type] | Where-Object {
            $_ -like "$wordToComplete*"
        }
    } else {
        $possibleValues.Values | ForEach-Object {$_}
    }
}

function Test-ArgumentCompleter {
[CmdletBinding()]
 param (
        [Parameter(Mandatory=$true)]
        [ValidateSet('Fruits', 'Vegetables')]
        $Type,

        [Parameter(Mandatory=$true)]
        [ArgumentCompleter({ MyArgumentCompleter @args })]
        $Value
      )
}

ArgumentCompletions和ArgumentCompleter这两者没有孰优孰劣,只是具体使用场景不同,ArgumentCompletions使用简单方便,ArgumentCompleter使用灵活,可以自定义补全逻辑。

使用PowerShell的Prediction功能

这个需要PowerShell5.1以上版本才能支持。

在PowerShell中运行以下命令:

 Set-PSReadLineOption -PredictionSource History

然后就可以看到,我们任何在PowerShell里面输入过的命令都可以轻松的重新输入了。比如之前我输入过的Write-Host例子。当我在PowerShell中输入两个字母“wr”时,PowerShell自动提示我之前输入过的命令:

然后按方向键的向右键-> 之前输入过的命令就自动补全了。

关于这个设置的更多内容请参考:PowerShell: 为啥大神们的PowerShell窗口还有智能提示?因为他设置了这个_码农杰克-CSDN博客 

总结

熟悉和使用PowerShell的自动补全功能,可以提高我们的工作效率。同时也可以写出更加易用的PowerShell脚本,以提高工作效率。

大家好,我是码农杰克~

希望上面的介绍对你有所帮助,有PowerShell的问题都可以和我探讨。

冰雪之城