Created
December 23, 2016 15:44
-
-
Save CMCDragonkai/a02d77c2d7c0799dd42fd2aab26a3cd5 to your computer and use it in GitHub Desktop.
CLI: Adding paths to PATH environment variable in Windows
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env powershell | |
function Prepend-Idempotent { | |
# the delimiter is expected to be just 1 unique character | |
# otherwise there may be problems with trimming | |
param ( | |
[string]$InputString, | |
[string]$OriginalString, | |
[string]$Delimiter = '', | |
[bool]$CaseSensitive = $false | |
) | |
if ($CaseSensitive -and ("$OriginalString" -cnotlike "*${InputString}*")) { | |
"$InputString".TrimEnd("$Delimiter") + "$Delimiter" + "$OriginalString".TrimStart("$Delimiter") | |
} elseif (! $CaseSensitive -and ("$OriginalString" -inotlike "*${InputString}*")) { | |
"$InputString".TrimEnd("$Delimiter") + "$Delimiter" + "$OriginalString".TrimStart("$Delimiter") | |
} else { | |
"$OriginalString" | |
} | |
} | |
function Append-Idempotent { | |
# the delimiter is expected to be just 1 unique character | |
# otherwise there may be problems with trimming | |
param ( | |
[string]$InputString, | |
[string]$OriginalString, | |
[string]$Delimiter = '', | |
[bool]$CaseSensitive = $false | |
) | |
if ($CaseSensitive -and ("$OriginalString" -cnotlike "*${InputString}*")) { | |
"$OriginalString".TrimEnd("$Delimiter") + "$Delimiter" + "$InputString".TrimStart("$Delimiter") | |
} elseif (! $CaseSensitive -and ("$OriginalString" -inotlike "*${InputString}*")) { | |
"$OriginalString".TrimEnd("$Delimiter") + "$Delimiter" + "$InputString".TrimStart("$Delimiter") | |
} else { | |
"$OriginalString" | |
} | |
} | |
function Add-Path { | |
param ( | |
[string]$NewPath, | |
[ValidateSet('Prepend','Append')]$Style = 'Prepend', | |
[ValidateSet('User', 'System')]$Target = 'User' | |
) | |
try { | |
# we need to do this to make sure not to expand the environment variables already inside the PATH | |
if ($Target -eq 'User') { | |
$Key = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Environment', $true) | |
} elseif ($Target -eq 'System') { | |
$Key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SYSTEM\CurrentControlSet\Control\Session Manager\Environment', $true) | |
} | |
$Path = $Key.GetValue('Path', $null, 'DoNotExpandEnvironmentNames') | |
# note that system path can only expand system environment variables and vice versa for user environment variables | |
# in order to make sure this method is idempotent, we need to check if the new path already exists, this requires having a semicolon at the very end | |
if ($Style -eq 'Prepend') { | |
$key.SetValue('Path', (Prepend-Idempotent ("$NewPath".TrimEnd(';') + ';') ("$Path".TrimEnd(';') + ';') ';' $false), 'ExpandString') | |
} elseif ($Style -eq 'Append') { | |
$key.SetValue('Path', (Append-Idempotent ("$NewPath".TrimEnd(';') + ';') ("$Path".TrimEnd(';') + ';') ';' $false), 'ExpandString') | |
} | |
# update the path for the current process as well | |
$Env:Path = $key.GetValue('Path', $null) | |
} finally { | |
$key.Dispose() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for publishing this as most examples appear to ignore the fact that the tokens will be expanded and I wanted to leave them intact.
Can I just confirm though that the reason you're appending the
;
to$NewPath
is so that if$NewPath
is a substring of one of the existing paths it won't accidentally match? For example if I wanted to addC:\
, which is substring of most other paths inPATH
, it should still be added because the-notlike "*${InputString}*"
has to match the fullC:\;
and not simplyC:\
?I was originally thinking of using a comparison like this as it feels more readable (if less performant):
but I'm wondering if there is an edge case that this misses which your approach solves?
(I've seen a few other examples which get this wrong and I wasn't sure about your version until I read it a little closer.)