I'm surprised that I didn't get the answer for this common scenario after searching the internet for a while.
How can I set an environment variable in PowerShell if it does not already exist?
The following code defines environment variable FOO
for the current process, if it doesn't exist yet.
if ($null -eq $env:FOO) { $env:FOO = 'bar' }
# If you want to treat a *nonexistent* variable the same as
# an existent one whose value is the *empty string*, you can simplify to:
if (-not $env:FOO) { $env:FOO = 'bar' }
# Alternatively, via the Env: *drive*:
if (-not (Test-Path env:FOO)) { $env:FOO = 'bar' }
# Or even (quietly fails if the variable already exists):
New-Item -ErrorAction Ignore env:FOO -Value bar
In PowerShell (Core) 7.1+, which has null-coalescing operators, you can simplify to:
$env:FOO ??= 'bar'
Note:
Environment variables are strings by definition. If a given environment variable is defined, but has no value, its value is the empty string (''
) rather than $null
. Thus, comparing to $null
can be used to distinguish between an undefined environment variable and one that is defined, but has no value. However, note that assigning to environment variables in PowerShell / .NET makes no distinction between $null
and ''
, and either value results in undefining (removing) the target environment variable; similarly, in cmd.exe
set FOO=
results in removal/non-definition of variable FOO
, and the GUI dialog (accessible via sysdm.cpl
) doesn't allow you to define a variable with an empty string either. However, the Windows API (SetEnvironmentVariable
) does permit creating environment variables that contain the empty string, albeit in-process only.
On Unix-like platforms, empty-string values are allowed too, and the native, POSIX-compatible shells (e.g, bash
and /bin/sh
) - unlike PowerShell - also allow you to create them (e.g, export FOO=
). Note that environment variable definitions and lookups are case-sensitive on Unix, unlike on Windows.
This design limitation of the .NET APIs - as of .NET 8 - has been reported in GitHub issue #95559
Note: If the environment variable is created on demand by the assignment above ($env:FOO = ...
), it will exist for the current process and any child processes it creates only 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.
See also: Creating and Modifying Environment Variables (TechNet article).
[*] On Unix-like platforms, attempts to target the persistent scopes - User
or Machine
- are quietly ignored, as of .NET (Core) 7, and this non-support for defining persistent environment variables is unlikely to change, given the lack of a unified mechanism across Unix platforms.