【问题标题】:PowerShell cmdlet parameter value tab completionPowerShell cmdlet 参数值选项卡补全
【发布时间】:2023-04-10 12:40:01
【问题描述】:

如何在 PowerShell 3.0 中为 PowerShell 函数或 cmdlet(如 Get-Service 和 Get-Process)实现参数选项卡补全?

我知道ValidateSet 适用于已知列表,但我想按需生成列表。

Adam Driscoll hints that it is possible 用于 cmdlet,但遗憾的是尚未详细说明。

Trevor Sullivan shows a technique 用于函数,但据我了解,他的代码仅在定义函数时生成列表。

【问题讨论】:

标签: powershell powershell-3.0


【解决方案1】:

我对此感到困惑了一段时间,因为我想做同样的事情。我整理了一些我非常满意的东西。

您可以从 DynamicParam 添加 ValidateSet 属性。这是我从 xml 文件即时生成 ValidateSet 的示例。请参阅以下代码中的“ValidateSetAttribute”:

function Foo() {
    [CmdletBinding()]
    Param ()
    DynamicParam {
        #
        # The "modules" param
        #
        $modulesAttributeCollection = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]

        # [parameter(mandatory=...,
        #     ...
        # )]
        $modulesParameterAttribute = new-object System.Management.Automation.ParameterAttribute
        $modulesParameterAttribute.Mandatory = $true
        $modulesParameterAttribute.HelpMessage = "Enter one or more module names, separated by commas"
        $modulesAttributeCollection.Add($modulesParameterAttribute)    

        # [ValidateSet[(...)]
        $moduleNames = @()
        foreach($moduleXmlInfo in Select-Xml -Path "C:\Path\to\my\xmlFile.xml" -XPath "//enlistment[@name=""wp""]/module") {
            $moduleNames += $moduleXmlInfo.Node.Attributes["name"].Value
        }
        $modulesValidateSetAttribute = New-Object -type System.Management.Automation.ValidateSetAttribute($moduleNames)
        $modulesAttributeCollection.Add($modulesValidateSetAttribute)

        # Remaining boilerplate
        $modulesRuntimeDefinedParam = new-object -Type System.Management.Automation.RuntimeDefinedParameter("modules", [String[]], $modulesAttributeCollection)

        $paramDictionary = new-object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
        $paramDictionary.Add("modules", $modulesRuntimeDefinedParam)
        return $paramDictionary
    }
    process {
        # Do stuff
    }
}

这样我就可以打字了

Foo -modules M<press tab>

如果该模块在 XML 文件中,它将使用制表符完成“MarcusModule”。此外,我可以编辑 XML 文件,制表符完成行为将立即改变;您不必重新导入该函数。

【讨论】:

    【解决方案2】:

    查看 github 上的 TabExpansionPlusPlus 模块,由前 PowerShell 团队魔术师编写。

    https://github.com/lzybkr/TabExpansionPlusPlus#readme

    【讨论】:

      【解决方案3】:

      传统上,我使用正则表达式。

      例如,

      function TabExpansion {
      
          param($line, $lastWord) 
      
          if ( $line -match '(-(\w+))\s+([^-]*$)' )
          {
          ### Resolve Command name & parameter name
              $_param = $matches[2] + '*'
              $_opt = $Matches[3].Split(" ,")[-1] + '*'
              $_base = $Matches[3].Substring(0,$Matches[3].Length-$Matches[3].Split(" ,")[-1].length)
      
              $_cmdlet = [regex]::Split($line, '[|;=]')[-1]
      
              if ($_cmdlet -match '\{([^\{\}]*)$')
              {
                  $_cmdlet = $matches[1]
              }
      
              if ($_cmdlet -match '\(([^()]*)$')
              {
                  $_cmdlet = $matches[1]
              }
      
              $_cmdlet = $_cmdlet.Trim().Split()[0]
      
              $_cmdlet = @(Get-Command -type 'Cmdlet,Alias,Function,Filter,ExternalScript' $_cmdlet)[0]
      
              while ($_cmdlet.CommandType -eq 'alias')
              {
                  $_cmdlet = @(Get-Command -type 'Cmdlet,Alias,Function,Filter,ExternalScript' $_cmdlet.Definition)[0]
              }
      
          ### Currently target is Get-Alias & "-Name" parameter
      
              if ( "Get-Alias" -eq $_cmdlet.Name -and "Name" -like $_param )
              {
                 Get-Alias -Name $_opt | % { $_.Name } | sort | % { $_base + ($_ -replace '\s','` ') }
                 break;
              }
          }
      }
      

      参考 http://gallery.technet.microsoft.com/scriptcenter/005d8bc7-5163-4a25-ad0d-25cffa90faf5


      Posh-git 将 GitTabExpansion.ps1 中的 TabExpansion 重命名为 TabExpansionBackup。
      当完成与 git 命令不匹配时,posh-git 重新定义的 TabExpansion 调用原始 TabExpansion(TabExpansionBackup)。
      所以你所要做的就是重新定义 TabExpansionBackup。

      (cat .\GitTabExpansion.ps1 | select -last 18)
      =============================== GitTabExpansion.ps1 ================= ==============

      if (Test-Path Function:\TabExpansion) {
          Rename-Item Function:\TabExpansion TabExpansionBackup
      }
      
      function TabExpansion($line, $lastWord) {
          $lastBlock = [regex]::Split($line, '[|;]')[-1].TrimStart()
      
          switch -regex ($lastBlock) {
              # Execute git tab completion for all git-related commands
              "^$(Get-AliasPattern git) (.*)" { GitTabExpansion $lastBlock }
              "^$(Get-AliasPattern tgit) (.*)" { GitTabExpansion $lastBlock }
      
              # Fall back on existing tab expansion
              default { if (Test-Path Function:\TabExpansionBackup) { TabExpansionBackup $line $lastWord } }
          }
      }
      

      ================================================ ==================================

      重新定义 TabExpansionBackup(原 TabExpansion)

      function TabExpansionBackup {
          ...
      
          ### Resolve Command name & parameter name
      
          ...
      
          ### Currently target is Get-Alias & "-Name" parameter
      
          ...
      }
      

      【讨论】:

      • 我看到 posh-git 已经在我的环境中定义了这个函数。有没有办法扩展/子类任何现有的定义?
      猜你喜欢
      • 1970-01-01
      • 2013-04-09
      • 1970-01-01
      • 2011-02-20
      • 2010-12-05
      • 2017-03-07
      • 2011-12-14
      • 2010-09-17
      • 1970-01-01
      相关资源
      最近更新 更多