Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I set an env variable in PowerShell if it doesn't exist?

I'm surprised that I didn't get the answer for this common scenario after Googling for while...

How can an environment variable in be set in PowerShell if it does not exist?

like image 264
hackjutsu Avatar asked Aug 13 '16 01:08

hackjutsu


People also ask

How do I set an environment variable in PowerShell?

To set the environmental variable using PowerShell you need to use the assignment operator (=). If the variable already exists then you can use the += operator to append the value, otherwise, a new environment variable will be created.

Where are PowerShell environment variables stored?

In PowerShell, environment variables are stored in the Env: "drive", accessible through the PowerShell environment provider, a subsystem of PowerShell. This isn't a physical drive, but a virtual file system. Environment variables convey information about your login session to your computer.

How do you refresh an environment variable in PowerShell?

To refresh the environment variables in PowerShell, retrieves the environment variables and assign them $Env:Path to reload the environment variable path in the PowerShell. After reloading the path in PowerShell, you don't need to restart the PowerShell ISE or terminal.


2 Answers

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' }  # Alternatively: if (-not (Test-Path env:FOO)) { $env:FOO = '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.

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.


[*] 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.

like image 101
mklement0 Avatar answered Sep 27 '22 21:09

mklement0


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-PersistentEnvironmentVariable Set 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-LocalEnvironmentVariable Set 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

Windows 10 Windows

Ubuntu WSL Ubuntu - Linux


References

Check About Environment Variables
Shell initialization files
ZSH: .zprofile, .zshrc, .zlogin - What goes where?

like image 34
Joma Avatar answered Sep 27 '22 20:09

Joma