James O'Neill's Blog

March 22, 2008

Powershell Tab expansion

Filed under: Powershell,Windows Server,Windows Server 2008 — jamesone111 @ 9:36 pm

One of the things which annoys me about Powershell is that having (in effect) extended the available commands with functions and filters, Tab expansion doesn’t find them. I was aware that people have done some clever things extending Tab-expansion (Power Tab being the obvious example), but they seemed like overkill for the one little thing I wanted.  Looking at the Powershell Community Extensions I noticed that they also change tab expansion, and a little bit of digging found there was already a function called TabExpansion. (The is also one called prompt.)

To paraphrase a line Arnie got in Predator "if it’s a function I can re-program it " So I had a look at the code for TabExpansion, Type function:\TabExpandsion | clip  and it basically goes

param($line, $lastWord)

& {
    switch -regex ($lastWord)
        # Handle property and method expansion...
        'RegularExpression' {Script block}


       # Handle variable name expansion...
        'Regular Expression' {Script block}


        # Do completion on parameters...
        'Regular Expression' {Script block}     } }

So all I needed to do was to put in some code for functions. The only complication I had was that cmdlet and file expansion is handled back the shell itself if TabExpansion() doesn’t return any results. So if I ONLY check for functions I won’t get all the things I want – e.g. typing st [tab] will return the "Start-Demo" function but not the cmdlets Start-Process Start-Service,  Start-Sleep, Start-Transcript; nor will it find stuff.csv. So I had to put some lines in to do that. What I ended up with a regular Expression {scrip block}  to go into the switch as follows.

    '^(\w+)$'{             $Commands = (get-command -type function,externalscript,alias,cmdlet "$lastWord*") +  
    (get-command "$lastWord*" | where {$_.name -match ".exe"}) 

              if ($commands -ne $null) {$Commands
get-childItem "$lastWord*" | % {$_.name} } break;             }    


This returns 3 kinds of data firstly st [tab] returns start-demo [Function] and  Start-Process Start-Service,  Start-Sleep, Start-Transcript [Cmdlets], the second Get-Command allows no [tab] to find notepad.exe (without returning lots of DLLs). And the Get-ChildItem ensures Stuff.csv is offered as well as the various starts. Originally I returned all 3 regardless but I found this replacing the expansion of filenames with something that worked less well – it didn’t put quotes round names with spaces in for a start. So I only return filenames from the function if there are also commands to return, otherwise I let the shell find files for me.

So far this is working quite well, but I’d be interested to know what other people use.

Technorati Tags: ,

This post originally appeared on my technet blog.


Create a free website or blog at WordPress.com.

%d bloggers like this: