Use PowerShell to Modify Your Environmental Path

Summary: Learn how to use Windows PowerShell to work with your environmental path variable.

 

Weekend Scripter: Use Windows PowerShell to Modify Your Path


Microsoft Scripting Guy Ed Wilson here. Welcome back to the weekend and Guest Blogger Sean Kearney. Read more about Sean and his previous guest blog posts. Now without further ado (or RDO or CDO), here is Sean.

 

Back in the good old days, we had a command called path in MS-DOS. It was used and abused heavily because that’s how you had to make things work. Either dump the application into a common folder or take its folder and do something like this:

PATH %PATH%;C:THIS;

This would allow you to now just run the application that was located in the this folder by just typing its name rather than adding an explicit path every time.

This is still available to us of course, but it is isolated to the current session and is only temporary. However, in the Land of Windows PowerShell, there is still a need to modify PATH. You may have a common script folder or an added console application folder (such as C:Sysinternals)

For whatever reason, if you want to modify the path, accessing the data in the PATH variable is easy, but making a modification can be confusing. Windows PowerShell provides natively a one-way path to read the system environment variables using $ENV

$ENV:PATH

But try as you might, there is no built-in Set-Path cmdlet or even an Append-Path (of course Append is not an approved verb) or Find-Path-to-the-Yellow-Brick-Road.

Of course, I’m not sure that last one would have been useful for anybody other than Dorothy or Toto.

But there is no obvious way to do it. Even running CMD.EXE as an administrator only makes the change temporary. So how do we gain this capability?

We leverage the registry with Windows Powershell. The environment variables are all stored under:

HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerEnvironment

Therefore, it just becomes a matter of editing the key. Now keep in mind this is a permanent and global change. You will need to be running Windows PowerShell as an administrator.

First, to read the key with the content, you need to use the following command:

Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerEnvironment’ -Name PATH

The previous command will dump four separate properties on the screen—the PSPath, PSParentPath, PSChildname, PSProvider—and the actual ItemProperty path. We just want the path so that we can modify the previous command to look like the following:

(Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerEnvironment’ -Name PATH).Path

Now if we would like to add to that property, all we need to do is concatenate to the current value and set it back in the registry:

$oldPath=(Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerEnvironment’ -Name PATH).Path

$newPath=$oldPath+’;C:NewFolderToAddToTheList’

Set-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerEnvironment’ -Name PATH –Value $newPath

Now you’ll have to restart Windows PowerShell to see the change, but now all applications (including Windows) will have access to the updated path. But wouldn’t it make more sense to make these into cmdlets or advanced functions? I would think so. So we can just use $ENV:PATH to read it, so no sense rebuilding the wheel. I just need to easily add to the path. But we can get fancier than the old path command from DOS. We can add in some error checking, like validating if it’s already in the path or if the folder even exists.

Function global:ADD-PATH()
{
[Cmdletbinding()]
param
(
[parameter(Mandatory=$True,
ValueFromPipeline=$True,
Position=0)]
[String[]]$AddedFolder
)

# Get the current search path from the environment keys in the registry.

$OldPath=(Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerEnvironment’ -Name PATH).Path

# See if a new folder has been supplied.

IF (!$AddedFolder)
{ Return ‘No Folder Supplied. $ENV:PATH Unchanged’}

# See if the new folder exists on the file system.

IF (!(TEST-PATH $AddedFolder))
{ Return ‘Folder Does not Exist, Cannot be added to $ENV:PATH’ }

# See if the new Folder is already in the path.

IF ($ENV:PATH | Select-String -SimpleMatch $AddedFolder)
{ Return ‘Folder already within $ENV:PATH’ }

# Set the New Path

$NewPath=$OldPath+’;’+$AddedFolder

Set-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerEnvironment’ -Name PATH –Value $newPath

# Show our results back to the world

Return $NewPath
}

There you go: a nice new feature to add to your Windows PowerShell arsenal. If you want to get fancy and have a Get-Path, an alias should have done nicely for that, but it seems to hit the 260-character limit for some reason in the path. Therefore, we will cheat with this one-line function add-on:

FUNCTION GLOBAL:GET-PATH() { Return $ENV:PATH }

We can get even fancier now and have the ability to remove items from the path with a little magic from the –replace operator

Function global:REMOVE-PATH()
{
[Cmdletbinding()]
param
(
[parameter(Mandatory=$True,
ValueFromPipeline=$True,
Position=0)]
[String[]]$RemovedFolder
)

# Get the Current Search Path from the environment keys in the registry

$NewPath=(Get-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerEnvironment’ -Name PATH).Path

# Find the value to remove, replace it with $NULL. If it’s not found, nothing will change.

$NewPath=$NewPath –replace $RemovedFolder,$NULL

# Update the Environment Path

Set-ItemProperty -Path ‘Registry::HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerEnvironment’ -Name PATH –Value $newPath

# Show what we just did

Return $NewPath

}

Remember you will have to reload Windows PowerShell to get the new changes, and these changes are permanent. So be careful! To simplify getting the code, I put the functions into a module, and uploaded it to the Scripting Center Script Repository.

 

Thank you, Sean, for providing an great article and module. Please join us tomorrow for more Windows PowerShell goodies from Sean.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy