How do I set an env variable in PowerShell if it doesn’t 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:
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.
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.

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.

Leave a Comment