Dynamic Argument Completion (Part 5)

by Mar 19, 2020

In our previous tip we looked at sophisticated completion code that completed application paths. Collecting the completion values could take some time and had the potential of timing out IntelliSense. For completion values that are unlikely to change, it is much better to calculate the values once and then use cached values.

This way, installing the completers will cost a second or two, but after that you enjoy rapid IntelliSense:

# define a function without argument completer
function Start-Software {
    param(
        [Parameter(Mandatory)]
        [string]
        $Path
    )

    Start-Process -FilePath $Path
}

# define the code used for completing application paths
$code = {
        

}

# calculate the completion values once, and reuse the values later
# store results in a script-global variable
$script:applicationCompleter = & {
# get registered applications from registry    
$key = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\*", 
    "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\*"

[System.Collections.Generic.List[string]]$list = 
    Get-ItemProperty -Path $key | 
    Select-Object -ExpandProperty '(Default)' -ErrorAction Ignore 

# add applications found by Get-Command
[System.Collections.Generic.List[string]]$commands = 
    Get-Command -CommandType Application | 
    Select-Object -ExpandProperty Source
$list.AddRange($commands)

# add descriptions and compose completionresult entries
$list |
    # remove empty paths
    Where-Object { $_ } |
    # remove quotes and turn to lower case
    ForEach-Object { $_.Replace('"','').Trim().ToLower() } |
    # remove duplicate paths
    Sort-Object -Unique |
    ForEach-Object {
        # skip files that do not exist
        if ( (Test-Path -Path $_))
        {
            # get file details
            $file = Get-Item -Path $_ 
            # quote path if it has spaces
            $path = $_
            if ($path -like '* *') { $path = "'$path'" }
            # make sure tooltip is not null
            $tooltip = [string]$file.VersionInfo.FileDescription
            if ([string]::IsNullOrEmpty($tooltip)) { $tooltip = $file.Name }
            # compose completion result
            [Management.Automation.CompletionResult]::new(
                # complete path
                $path,
                # show friendly text in IntelliSense menu
                ('{0} ({1})' -f $tooltip, $file.Name),
                # use file icon
                'ProviderItem',
                # show file description
                $tooltip
                )
        }
    }
}

# instead of complex code, simply return the cached results when needed
$code = { $script:applicationCompleter }

# tie the completer code to all applicable parameters of own or foreign commands
Register-ArgumentCompleter -CommandName Start-Software -ParameterName Path -ScriptBlock $code
Register-ArgumentCompleter -CommandName Start-Process -ParameterName FilePath -ScriptBlock $code

When you run the code above and then use the Start-Software or Start-Process commands, you get highly responsive IntelliSense. In contrast to built-in completion, you need to manually press CTRL+SPACE though.

 


You are a PowerShell Professional, passionate about improving your code and skills? You take security seriously and are always looking for the latest advice and guidance to make your code more secure and faster? You’d love to connect to the vibrant PowerShell community and get in touch with other PowerShell Professionals to share tricks and experience? Then PowerShell Conference EU 2020 might be just the right place for you: https://psconf.eu (June 2-5, 2020 in Hanover, Germany).

It’s a unique mixture of classic conference with three parallel tracks filled with fast-paced PowerShell presentations, and advanced learning class with live discussions, Q&A and plenty of networking.

Secure your seat while they last: https://psconf.eu/register.html. The speakers and agenda is available here: https://psconf.eu/schedule.

Twitter This Tip! ReTweet this Tip!