More Windows command line PATH goodness pathed.exe

Readers of this blog probably think I have an obsession with editing my system path. That belief is absolutely correct. I even added a tag on this blog for the articles about path manipulation. I am a command line junkie who is constantly trying out new tools so I have to add them to my path. I’ve written about doing this from powershell here and here, as well as doing it with setx. While these methods are good, I wanted something better. I got better with pathed.exe.

pathed.exe is a program that lets you edit both your user and the system path. It only manipulates the path, not other environmental variables. The reason for this extreme specialization is that pathed is specifically designed for appending to and removing from the path. It treats the path as a semicolon delimited array, which is of course what it is. For example, I just ran it now on my machine as I was writing this article (note: live coding is less embarrassing when you do it on a blog).

If you notice, their happen to be two copies of the path to mercurial on my path. Well lets fix it right now:

Wasn’t that easy?

Setx where have you been all my life?

For me, the reference implementation of mixed emotions is the combination of anger, relief, joy, and frustration when “Why isn’t there a way to do X?!” becomes “How come no one ever told me about Y?!” This past Friday, I got to experience that entire bag of emotion thanks to setx.exe.

Setx (technetss64) is a command line utility that sets environmental variables permanently on windows. This behavior is distinct from the set command (technetss64) which only affects the current cmd.exe session. To clarify, there are three levels of environment variables:

  • Machine level All users on a given machine see these
  • User Level Each individual user on a system has a set of these variables
  • Session Level When you actually spawn a cmd.exe process, it allows you to have a set of transient variables for the session

Now, until I knew about setx, I had two ways of setting environment variables permanently. The first was to go through several layers of the windows GUI. The second, preferable to me, method was to use PowerShell as I illustrate elsewhere on this blog. However, that method requires a lot of keystrokes or some aliasing. Setx however simplifies the syntax quite nicely.

One thing to note about setx, as per ss64, it is available on windows 7 and through the resource kits. If your windows installation does not have setx.exe, try installing a resource kit.

 

Cleaning up your path in PowerShell, and adding stuff to it.

A while back, I demonstrated some PowerShell one-liner-fu for path management. I also pointed out that my machine had duplicate entries in its path. Most people would not care about this at all. Most of the few people that do care would cleanup their path by hand. However, there are a mentally deranged few who realize the world needs a PowerShell script to clean up our paths for us. Luckily for you, I am that kind of crazy. However, I don’t stop there. I also show you how to search the registry to add items to your path.

Warning: I don’t know much about PowerShell and I’ve not tested this script nearly enough. This thing messes with your system path, and things can go really bad if you run it and it messes up your path. Be very careful running it. If you run it your the fool who follows a fool, which makes you Han Solo, not Ben Kenobi. However, your shooting your %PATH% not Greedo.

The script makes use of multi dimensional arrays and foreach loops. I’d be lying if i said that it was efficiently written or bug free. However, it works and does a few clever things with PowerShell.

So with that out of the way, the script is located in a github repository in our newly created github organization I mentioned before. The script is called Path-Fixer.ps1. It is available under the MIT license. I hope to improve it as time goes on. If you fork it and improve the script, please send us a pull request.

Notes about this script

Your path is a combination of two Environment variables. Those are the machine %PATH% and the user %PATH%. My script only concerns itself with the machine level path. Therefore I don’t use $ENV:PATH, like I do in my one-liner example to get the original path. Instead I use [Environment]::GetEnvironmentVariable(‘PATH’, ‘machine’).

Another thing I do is trim off trailing slashes at the end of the path. This means C:\windows\ becomes C:\windows. This may seem like excess, but it also allows me to remove duplicates that only differ because one has a trailing path, and one lacks it.

Two other caveats exist with regard to comparison. One is differences in case. Luckily, String.Replace() is case insensitive by default so my script handles it. The other is environment variable expansion. On windows if you stick %SYSTEMROOT%\system32 in your path, the OS will expand that to c:\windows\system32. My script does not handle this at the moment. Hopefully it will in the future.

I have some very simple registry detection to detect if a few programs are installed. This will probably remain a hard coded list of programs, and registry entries that determine the installation path. I’m hoping to also add detection through windows services. This would be good for something like mongodb that lacks an installer, but can self install as a windows service.

Finally, I’d like to point out that the script is UTF-16 encoded. This is simply because I wrote it script in PowerShell ISE, which decided to save it in UTF-16 format. Rather than change it to UTF-8 so git could easily diff it, I decided to fix git. This stackoverflow question provided the guidance I needed.

Conclusion

Once again, I’d like to reiterate that you must be careful when using this script. There might be some serious bugs, and messing with your path can lead to bad things happening. Also, while I will probably blog about updates to the script, the fastest way to keep track of its changes is to look at the github commit notes, and the source code itself. Finally, if you find a bug in my script or make and improvement, patches will be accepted, and due credit given.

Two Powershell One-Liners: Appending to my %PATH% and Whats in my %PATH%

To say I’ve fallen in love with PowerShell is an understatement. PowerShell is what perl would be; if perl was object based instead of stream based, and lacked all the “culture” of perl. I use PowerShell for a lot of things lately. Recently, I’ve been using it to manage my path, thanks to this PowerShell tip of the week. This has inspired me to share two one-liners related to path management.

The first allows you to add an item to your path. Few things annoy me more than windows programs that don’t include installers, and few installers annoy me more than those that install console programs and don’t offer to update your system path. Correcting this used to be a matter of going into nested levels of dialog windows. However, I can now do it from the PowerShell console. The command to append to your path is as follows:

[Environment]::SetEnvironmentVariable("PATH", [Environment]::GetEnvironmentVariable("PATH", 'Machine') + ';c:Program Filefoobin',"Machine")

A brief dissection:

  • [Environment]::SetEnvironmentVariable calls the static .NET method Environment.SetEnvironmentVariable()
  • “PATH” is the variable we are setting
  • $ENV: is a powershell drive for environment variables.
  • $ENV:PATH + ‘;c:Program Filefoobin’ concats your current path with a string.
  • “Machine” makes this environment variable apply to the entire machine, as opposed to the current user.

So there you have it, instead of digging three levels deep into menus to edit your path, you simply dig up this blog article and copy and paste that one line into PowerShell 🙂

The next one-liner is to determine what’s in your path. Simply typing $Env:PATH will print out your path in the same manner as the cmd.exe command path does. However, you probably want something more human readable. How about if each folder on your path was on a new line and the paths were sorted? Well thats quite easy:

$ENV:Path.Replace('"', '').Split(';') | Sort-Object -unique

On one of my machines this outputs:

%SystemRoot%system32WindowsPowerShellv1.0
C:\Program Files\Common Files\DivX Shared
C:\Program Files\Common Files\Microsoft Shared\Windows Live
C:\Program Files\Cppcheck
C:\Program Files\Gitcmd
C:\Program Files\GNU\GnuPG\pub
C:\Program Files\GnuWin\32\bin
C:\Program Files\Javajdk1.6.0_18bin
C:\Program Files\KDiff3
C:\Program Files\Microsoft SQL Server100\DTS\Binn
C:\Program Files\Microsoft SQL Server100\Tools\Binn
C:\Program Files\Microsoft SQL Server100\Tools\Binn\VSShellCommon7\IDE
C:\Program Files\Microsoft SQL Server80\Tools\Binn
C:\Program Files\Microsoft SQL Server90\DTS\Binn
C:\Program Files\Microsoft SQL Server90\Tools\binn
C:\Program Files\mongodb-win32-i386-1.6.1\bin
C:\Program Files\mtasc-1.14
C:\Program Files\Subversion\bin
C:\Program Files\TortoiseGit\bin
C:\Program Files\TortoiseHg
C:\Program Files\TortoiseSVN\bin
C:\Program Files\Vim\vim72
C:\Program Files\WinMerge
C:\Program Files\Zend\MySQL51\bin
C:\Program Files\Zend\ZendServer\bin
C:\Program Files\Zend\ZendServer\share\ZendFramework\bin
C:\Python26\Scripts
C:\Windows
C:\Windows\system32
C:\Windows\System32\Wbem
C:\Windows\System32\WindowsPowerShell\v1.0
D:\apps\apache-ant-1.8.0bin
D:\apps\jboss-4.2.2.GAbin

So lets break this down:

  • $ENV:Path is our path as before.
  • .Replace() is string.Replace(). Some of your path folders might be quoted, removing the quotes will cause them to be properly sorted.
  • .Split(‘;’) is String.Split(). We want to turn our path into an array of strings, one folder per string.
  • | Is a pipe. This works like cmd.exe and unix piping, excet its object based, not stream based.
  • Sort-Object -unique does exactly what you think it does. It sorts the folders in your path and removed duplicates. Sometimes paths contain a folder multiple times. Cleaning up the duplicates will be addressed in a future blog post.

This one liner is good to run when you inherit someone else’s workstation, or a server setup by someone else. One limitation it has is it does not expand environment variables. Ideally I’d like it to expand %SystemRoot% to C:Windows. However, Sort-Object is case insensitive by default, like the NTFS file system, so casing issues are not a problem.

Thats all for now folks. Happy scripting!