12

PowerShell 3.0 の Get-Service や Get-Process などの PowerShell 関数またはコマンドレットのパラメーター タブ補完をどのように実装しますか?

ValidateSetが既知のリストに対して機能することは理解していますが、必要に応じてリストを生成したいと考えています。

Adam Driscollは、コマンドレットで可能であるとほのめかしていますが、残念ながら詳細には触れていません。

Trevor Sullivanが関数のテクニックを示していますが、私が理解しているように、彼のコードは関数が定義された時点でのみリストを生成します。

4

3 に答える 3

7

私は同じことをしたかったので、しばらくこれについて戸惑いました。とても満足できるものをまとめました。

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 ファイルを編集すると、タブ補完の動作がすぐに変わります。関数を再インポートする必要はありません。

于 2013-12-27T18:16:30.567 に答える
2

古典的に、私は正規表現を使用しました。

例えば、

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に変更します。
また、posh-gitの再定義されたTabExpansionは、補完がgitコマンドと一致しない場合、元の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

    ...
}
于 2013-02-13T12:29:46.007 に答える