Cleaning the Path – A PowerShell One-liner

I’m not super crazy about writing one-liners in PowerShell, but I ran across a fun problem which was quick to write as a one-liner.  I’ll give that here with a little explanation, and follow up in a couple of days with a more polished advanced function solution.

Anyway, the problem was that I was working on a computer and happened to take a look at the PATH environment variable and saw a lot of directories in the path that were no longer valid. Apparently efforts to clean up the machine (e.g. removing old Visual Studio and SQL Server installs) didn’t include fixing the path.
To see if you have this problem, you can easily see your PATH with the following line of PowerShell (and no, this isn’t the one-liner)

$env:Path

When I saw the output (which included 48 different folders) I knew I needed to fix it.
Since Test-Path is an easy way to see if a folder exists, I quickly wrote the following to see which entries were bad:

$env:path -split ';' | where {!(Test-Path $_  )}

That listed 11 that were bad, but I also got an error because apparently there were some adjacent semicolons, meaning that $_ was set to an empty string which Test-Path didn’t like.
A quick addition made it not complain:

$env:path -split ';' | where {$_ -and !(Test-Path $_  )}

This gave me the list of directories that I needed to eliminate. Reversing the logic a bit to get the directories I want to retain looked like this:

$env:path -split ';' | where {$_ -and (Test-Path $_  )}

Looking better, but now I notice that some directories are listed more than once ($PSHOME, for example is listed 6 times).
Adding a quick uniqueness check:

$env:path -split ';' | where {$_ -and (Test-Path $_  )}| select-object -unique

That gives a much better list.
I then added -Join to paste these back together.

($env:path -split ';' | where {$_ -and (Test-Path $_  )}| select-object -unique) -join ';'

And that looks like a good value for $env:Path.
If I just needed to set it for the current session, I could do this:

$env:path=($env:path -split ';' | where {$_ -and (Test-Path $_  )}| select-object -unique) -join ';'

But that isn’t particularly useful. Before I do anything permanent, though, I should save the current PATH somewhere. We can use the System.Environment class to set environment variables for the machine and copy the existing PATH to a new environment variable.

[System.Environment]::SetEnvironmentVariable('Path_SAVED',($env:path),'Machine')

The final one-liner is this (and it’s not pretty):

[System.Environment]::SetEnvironmentVariable('Path',($env:path -split ';' | where {$_ -and (Test-Path $_  )}| select-object -unique) -join ';','Machine')

Ok…that was a fun exercise. PowerShell continually impresses me with how easy it is do to things.

Got any good ideas for ways to improve this?

Let me know in the comments, and watch for the follow-up article in a couple of days about rewriting this as a real advanced function.

-Mike