Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / PowerShell

bash-like prompt in PowerShell and app run

0.00/5 (No votes)
11 Jul 2011GPL33 min read 23.6K   123  
An article describing some of the tricks of PowerShell scripts and profile that enables you to get a bash like prompt in PowerShell and run applications more flexibly.

Sample Image

Introduction

In batch scripts, writing code to do simple things was tedious. PowerShell lets us do things easier where it also excels providing strong support to access and control system resources using the .NET Framework. I cannot but mention some of the code snippets I had written and was of good use.

Background

I was missing the bash prompt of Unix/Linux when I moved to PowerShell. The bash prompt does not show the entire directory path and has a home dir sign. That keeps the terminal clean. Due to security reasons, many restrictions have been applied in PowerShell. For example, you have a script delay.ps1. You cannot run it by entering a delay though execution policy is enabled. I rather decided to use a prefix ss to run all these programs. Now with the provided script, we can enter ss scriptname to run a script simply (works if we even omit the extension or .\).

Using the code

Put the code of the file Microsoft.PowerShell_profile.ps1 in your profile and ss.ps1 where you want to keep your scripts.

You need to have the execution policy enabled on your PC to run PowerShell scripts. To enable this for the current user, you can run PS > set-executionpolicy Unrestricted -scope currentuser.

Inside the scripts

If we want to use Unix like prompt in our Windows PowerShell, we use the following code which includes two functions, prompt and get-diralias. The get-diralias function returns a grave sign in case it meets our set home directory, which is E:\Scripts here.

If it is not a home directory, then we find a backward slash (\). Take only the last part after that slash as a substring. Otherwise if we find that the current location string ends with \, we know that we are in the root of a drive. In that case, we return only the drive and the colon.

$env:homedir=E:\Scripts
# get the last part of path
function get-diralias ([string]$loc) {
    # check if we are in our home script dir
    # in that case return grave sign
    if ($loc.Equals($env:homedir)) {
        return "~"
    }
    
    # if it ends with \ that means we are in root of drive
    # in that case return drive
    $lastindex = [int] $loc.lastindexof("\")
    if ($loc.EndsWith("\")) {
        return $loc.Remove($lastindex, 1)
    }
    
    # Otherwise return only the dir name
    $lastindex += 1
    $loc = $loc.Substring($lastindex)
    return $loc
}

# Set prompt
function prompt {
    return "[sa@matrix $(get-diralias($(get-location)))]$ "
}

We add another function ss which provides the following functions:

# To go home
$ ss cd

# To edit powershell profile script
$ ss ep

# To open a text/script file with Powershell ISE 
$ ss ise filename.ps1

# List programs which are available in app path that can be run
# with simply putting with ss i.e., ss notepad++ or ss chrome
$ ss list-programs

# run a program from apppath, app path in registry
# is a collection of paths when you run a command
# from run dialog box it looks for executable file paths
# there (correct me if I am wrong)
$ ss chrome
Or
$ ss devenv

ss is a command that will create the file if the provided file path doesn’t exist. Let’s go into the script. We have the godfather functionss which manages the commandline arguments in the proper way, gives a warning if no commandline is provided, and calls the ss.ps1 script with those arguments. I did this intentionally to keep the profile file smaller.

function ss() {
    if ($args.Count -lt 1) {
        return "Please provide correct commandline"
    }
    elseif ($args.Count -eq 1) {
        & "$env:homedir\ss.ps1" $args
    }
    else {
        $cmd = $args[0]
        # echo "cmd: `"$cmd`""
        $cargs = [string]$args
        # echo "cargs: `"$cargs`""
        $cargs = $cargs.TrimStart($cmd)
        $cargs = $cargs.TrimStart()
        # echo "cargs: `"$cargs`""
        & "$env:homedir\ss.ps1" $args[0] $cargs
    }
    
    return ""
}

ss cd or ss ep functionalities are easy to understand. Initially, code for ss ise was more simple. But ise seems to behave unstable sometimes. It’s why I corrected the commandline to specify the absolute file path instead of the relative one, i.e., .\filename.ext is relative where e:\folder\filename.ext is the absolute file path.

# ss ise: call powershell_ise editor
if ($cmd.ToLower().Equals("ise")) {
    $cargs = [string]$args[1]

    $cpath = $cargs
    # if the file 
    if ($cargs.IndexOf("\") -eq "-1") {
        $cpath =$(get-location).path+"\$cargs"
    }
    elseif ($cargs.StartsWith("..\")) {
        $cpath =$(get-location).path
        $cpath =$cpath.Substring(0, $cpath.LastIndexOf("\"))
        $cpath +=$cargs.TrimStart("..")
    } 
    elseif ($cargs.StartsWith(".\")) {
        $cpath =$(get-location).path+$cargs.TrimStart(".")
    }
    
    if (Test-Path $cpath) {
        # echo "1. Path: $cpath"
        & $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell_ise.exe $cpath
    }
    else {
        echo "Creating File $cpath as it does not exist."
        echo "# Date: $(get-date)"> $cpath
        echo "# Author: $env:USERNAME">> $cpath
        & $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell_ise.exe $cpath
    }
    break
}

To run programs from the app path, ss initially looks if the following Registry entry exists: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\$(cmdArgument).exe. If it finds it, it takes the default value of that key which is the file path for the executable. We remove the quotation signs from both ends.

if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\$cmd.exe") {
        echo "Starting program $origcmd"
    $regitem = Get-ItemProperty 
       "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\$cmd.exe"
    # Get-ItemProperty 
       "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\notepad++.exe"
    $regcmd = $regitem."(default)"
    # Modify the command so that arguments don't get splitted
    $regcmd = $regcmd.TrimStart("`"")
    $regcmd = $regcmd.TrimEnd("`"")
    & "$regcmd" $cargs
    break
}
elseif (!(Test-Path "$env:homedir\$cmd.ps1")) {
    echo "Please check your command"
    break
}

Hope these scripts help you automate your works. Thank you.

History

  • Initial release - July 11, 2011.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)