PowerShell Cookbook

Twitter Updates

    follow me on Twitter

    Search

    Categories

     

    On this page

    PowerShell 'Suggestion Mode'

    Archive

    Blogroll

    Disclaimer
    I work for Microsoft.

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

    RSS 2.0 | Atom 1.0 | CDF

    Send mail to the author(s) E-mail

    Total Posts: 252
    This Year: 3
    This Month: 0
    This Week: 0
    Comments: 736

    Sign In

     Monday, September 08, 2008
    Monday, September 08, 2008 8:48:59 PM (Pacific Daylight Time, UTC-07:00) ( )

    One bit of feedback we frequently get is that PowerShell's learning curve has some steeper bumps than we would like. Or simply, is strongly affected by habits learned from other languages or shells.

    Interestingly enough, many of these problems aren't new to us -- we just don't have a good way (aside from help) of exposing them to the user. This was something I touched on in the footnotes of a blog in 2005, and started implementing personally shortly after that. Here's an example of its output:

    [C:\temp]
    PS:14 > "c:\temp\has space\test.ps1"
    c:\temp\has space\test.ps1

    Suggestion: Did you mean to run the command in quotes?  If so, try using & "<command>"

    The core of this is implemented by a script, Get-TrainingSuggestion.ps1. It retrieves the last item from your history, and runs a bunch of regular expression comparisons against it. If it finds a match in the list of training rules, it outputs the suggestion that corresponds to that rule.

    ############################################################################## 
    ## Get-TrainingSuggestion.ps1 
    ## Retrieve a training suggestion (if applicable) for the last command 
    ## you typed. 
    ############################################################################## 

    $history = get-history -Count 1 

    $suggestions = @{ 
       "/\?"="To get help on a topic, use -? instead of /?.`nAlternatively, use get-help <command>."
       ".length"="Try using the .Count property instead of the .Length property.  Although .Length " + 
           "often works, .Count is the more consistent way to get the number of objects in a collection."
       ";[ \t]*$"="Semicolons are not required as line terminators in PowerShell.  Try your command without one."
       "Regex.*]::Match"="PowerShell's -match evaluator is much more efficent than calling it through the .NET API."
       "^`".*`"$"="Did you mean to run the command in quotes?  If so, try using & `"<command>`""
       "start "="Are you trying to run the program associated with that path?  If so, try invoke-item <path>"
       "%.*%"="To access environment variables, try `"`$env:variable`" instead of `"%variable%`""
       "ren[^ ]* [^ ]+ .*:\.*"="Rename-item takes only a name as its second argument.  Unless you want the " + 
           "name to have those path characters, do not include them."
       "dir.*/s.*"="To get a recursive directory listing, try `"dir . * -rec`"."
       "dir.*/ad"="To get a list of directories, try `"dir | where { `$_.PsIsContainer }`"" 
       "^get-childitem.*/s.*$"="To get a recursive directory listing, try `"get-childitem . * -rec`"."
       "^grep"="To search files for text patterns, use the match-string cmdlet."


    $helpMatches = "" 

    if($history

       $lastCommand = $history.CommandLine 

       ## Get the suggestions from the baked list 
       foreach($key in $suggestions.Keys) 
       { 
        if($lastCommand -match $key
        { 
            $helpMatches += "`nSuggestion: " + $suggestions[$key
        } 
       } 


    $helpMatches 


     

    To use this, simply update your PROMPT function to call Get-TrainingSuggestion.ps1.

    function prompt
    {
        $suggestion = Get-TrainingSuggestion
        if($suggestion)
        {
            Write-Host $suggestion
            Write-Host
        }

        "PS >"
    }

    Comments [0] | | #