How do I set an env variable in PowerShell if it doesn't exist?
The following code defines environment variable FOO
, if it doesn't exist yet.
if (-not (Test-Path env:FOO)) { $env:FOO = 'bar' }
Note: This newly defined environment variable will only exist for the current process and any child processes it creates (e.g., when you start a new PowerShell session from the ISE). Thanks, PetSerAl.
The following was mostly contributed by Ansgar Wiechers, with a supplement by Mathias R. Jessen:
On Windows[*], if you want to define an environment variable persistently, you need to use the static SetEnvironmentVariable()
method of the [System.Environment]
class:
# user environment[Environment]::SetEnvironmentVariable('FOO', 'bar', 'User')# system environment (requires admin privileges)[Environment]::SetEnvironmentVariable('FOO', 'bar', 'Machine')
Note that these definitions take effect in future sessions (processes), so in order to define the variable for the current process as well, run $env:FOO = 'bar'
in addition, which is effectively the same as [Environment]::SetEnvironmentVariable('FOO', 'bar', 'Process')
.
When using [Environment]::SetEnvironmentVariable()
with User
or Machine
, a WM_SETTINGCHANGE
message is sent to other applications to notify them of the change (though few applications react to such notifications).
This doesn't apply when targeting Process
(or when assigning to $env:FOO
), because no other applications (processes) can see the variable anyway.
[*] On Unix-like platforms, attempts to target persistent scopes User
or Machine
are quietly ignored, as of .NET (Core) 5, and this non-support for defining persistent environment variables is unlikely to change, given the lack of a unified mechanism across Unix platforms.
Code
function Set-LocalEnvironmentVariable { param ( [Parameter()] [System.String] $Name, [Parameter()] [System.String] $Value, [Parameter()] [Switch] $Append ) if($Append.IsPresent) { if(Test-Path "env:$Name") { $Value = (Get-Item "env:$Name").Value + $Value } } Set-Item env:$Name -Value "$value" | Out-Null}function Set-PersistentEnvironmentVariable { param ( [Parameter()] [System.String] $Name, [Parameter()] [System.String] $Value, [Parameter()] [Switch] $Append ) Set-LocalEnvironmentVariable -Name $Name -Value $Value -Append:$Append if ($Append.IsPresent) { $value = (Get-Item "env:$Name").Value } if ($IsWindows) { setx "$Name" "$Value" | Out-Null return } $pattern = "\s*export[ \t]+$Name=[\w]*[ \t]*>[ \t]*\/dev\/null[ \t]*;[ \t]*#[ \t]*$Name\s*" if ($IsLinux) { $file = "~/.bash_profile" $content = (Get-Content "$file" -ErrorAction Ignore -Raw) + [System.String]::Empty $content = [System.Text.RegularExpressions.Regex]::Replace($content, $pattern, [String]::Empty); $content += [System.Environment]::NewLine + [System.Environment]::NewLine + "export $Name=$Value > /dev/null ; # $Name" Set-Content "$file" -Value $content -Force return } if ($IsMacOS) { $file = "~/.zprofile" $content = (Get-Content "$file" -ErrorAction Ignore -Raw) + [System.String]::Empty $content = [System.Text.RegularExpressions.Regex]::Replace($content, $pattern, [String]::Empty); $content += [System.Environment]::NewLine + [System.Environment]::NewLine + "export $Name=$Value > /dev/null ; # $Name" Set-Content "$file" -Value $content -Force return } throw "Invalid platform."}
- function Set-PersistentEnvironmentVariableSet a variable/value in actual process and system. This function calls Set-LocalEnvironmentVariable function to set process scope variables and perform task for set variables in machine scope.
On Windows you can use:
- [Environment]::SetEnvironmentVariable with machine scope, user or machine don't work on Linux or MacOS
- setx command
On Linux we can add export VARIABLE_NAME=Variable value to file ~/.bash_profile. For a new bash terminal the process execute these instructions located in ~/.bash_profile.
On MacOS similiar to Linux but if you have zsh terminal the file is .zprofile, if the default terminal is bash, the file is .bash_profile. In my function code we need to add detection of default terminal if you wish. I assume that default terminal is zsh.
- function Set-LocalEnvironmentVariableSet a variable/value in actual process. Using Drive env:.
Examples
#Set "Jo" value to variable "NameX", this value is accesible in current process and subprocesses, this value is accessible in new opened terminal.Set-PersistentEnvironmentVariable -Name "NameX" -Value "Jo"; Write-Host $env:NameX#Append value "ma" to current value of variable "NameX", this value is accesible in current process and subprocesses, this value is accessible in new opened terminal.Set-PersistentEnvironmentVariable -Name "NameX" -Value "ma" -Append; Write-Host $env:NameX#Set ".JomaProfile" value to variable "ProfileX", this value is accesible in current process/subprocess.Set-LocalEnvironmentVariable "ProfileX" ".JomaProfile"; Write-Host $env:ProfileX
Output
References
Check About Environment Variables
Shell initialization files
ZSH: .zprofile, .zshrc, .zlogin - What goes where?