In Windows, the operating system and various apps use environment variables to store system information, such as paths to system folders, configuration settings, and information about the system environment. Users can use the Control Panel graphical interface (SystemPropertiesAdvanced.exe > Environment Variables) or the PowerShell console to add, edit, or delete environment variables and their values.

PowerShell version. The examples in our article work in both Windows PowerShell 5.1 and PowerShell 7.x. For new automation, PowerShell 7.6 LTS is recommended where module and app compatibility allows.
Add, edit, or delete environment variables and their values with PowerShell
In PowerShell, system environment variables can be accessed through a virtual drive called “Env:”.
Get-PSDrive -PSProvider "Environment"

PowerShell also provides standard cmdlets for managing environment variables through the Env: provider. For example:
Get-Item Env:windir
Get-ChildItem Env:
You can use these cmdlets to read, create, modify, and remove environment variables.
To list all Windows environment variables, simply display the contents of this drive using the dir command:
dir Env:
or
Get-ChildItem ENV:
Environment variables are stored in a flat namespace, where each entry is represented as a [variable]:[value] pair.
To get the value of a specific variable, specify its name after a colon:
$Env:windir
Or:
Get-ChildItem -Path Env:windir

PowerShell 7.5+. An environment variable can have an empty string as its value. This is different from removing the variable:
$Env:MyVariable = ''In order to remove a variable from the current process environment, use the command below:
Remove-Item Env:MyVariable
The most commonly used environment variables in PowerShell scripts are PATH, TEMP, USERPROFILE, COMPUTERNAME, OS, and HOMEPATH.
Some environment variables, such as PATH, contain multiple entries in a single string. On Windows, these entries are separated by semicolons (;). The following command displays a list of values in a convenient format:
($Env:Path) -split ';'

Note that $Env:Path shows the effective PATH variable for the current process. To view the User and Machine PATH values separately, use:
[Environment]::GetEnvironmentVariable("Path","Machine")
[Environment]::GetEnvironmentVariable("Path","User")
For variables in the current process, the Env: provider provides native PowerShell cmdlets:
New-Item -Path Env:SITE -Value 'CA'
Set-Item -Path Env:SITE -Value 'US'
Remove-Item -Path Env:SITE
These operations affect the environment of the current PowerShell process. Note that they do not create/modify persistent User or Machine environment variables.
With PowerShell, you can change the values of environment variables. For example, to add a new value to the PATH environment variable, run the command:
$Env:Path += ";C:\Git\"
Note that the command mentioned above modifies only the PATH variable of the current PowerShell process.
However, the new value of the environment variable will only be available within the current PowerShell session. The new value will reset once you close the PowerShell console or reboot the computer.
Environment variables scopes
The point is that environment variables have three scopes:
- Process scope โ environment variables available only to the current PowerShell process. For example:
$Env:MyVariable = “Test”
The variable will be available only in the current session and will disappear when the process exits. - Machine scope (system-wide environment variables) โ computer environment variables (stored in the registry under HKEY_LOCAL_MACHINE\ SYSTEM\ CurrentControlSet\ Control\ Session Manager\ Environment)
- User scope โ current user environment variables (registry key HKEY_CURRENT_USER\Environment).
Make environment variable’s value permanent
Only environment variables set at the user or machine level are persistent. In order to make an environment variable persistent, you must update it in the User or Machine scope. This can be done by modifying the corresponding registry values/using the .NET SetEnvironmentVariable() method. Note that modifying a Machine-level environment variable requires admin privileges. You can normally modify user-level environment variables without elevation.
Although environment variables can be modified directly in the registry, we recommend using the .NET Environment class as it’s generally a safer and more portable method. It also notifies Windows about the environment variable change, allowing newly launched apps to pick up the updated values more reliably than direct registry edits.
You can add a new value to the machine-level PATH variable using the following example:
# Requires administrator privileges
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator
)) {
throw 'Run PowerShell as Administrator to modify the Machine PATH.'
}
$machinePath = [Environment]::GetEnvironmentVariable('Path', 'Machine')
$entries = @()
if ($machinePath) {
$entries = @(
$machinePath -split ';' |
ForEach-Object { $_.Trim() } |
Where-Object { $_ }
)
}
# Add C:\Git only if it is not already present
if (-not ($entries | Where-Object { $_.TrimEnd('\') -ieq 'C:\Git' })) {
$entries += 'C:\Git'
try {
[Environment]::SetEnvironmentVariable(
'Path',
($entries -join ';'),
'Machine'
)
$updatedPath = [Environment]::GetEnvironmentVariable('Path', 'Machine')
if (-not ($updatedPath -split ';' | ForEach-Object { $_.Trim() } |
Where-Object { $_.TrimEnd('\') -ieq 'C:\Git' })) {
throw 'C:\Git was not found in the Machine PATH after the update.'
}
Write-Host 'C:\Git successfully added to the Machine PATH.'
}
catch {
Write-Error "Failed to update the Machine PATH: $($_.Exception.Message)"
throw
}
}
else {
Write-Host 'C:\Git is already present in the Machine PATH.'
}
Our example above checks for an existing entry before modifying the Machine PATH, preventing duplicate entries when the script is run multiple times.
Although the .NET Environment class is the recommended method, you can also modify the PATH variable directly in the registry:
Important. Directly modifying the Windows Registry requires extra care when changing PATH. The existing value may contain expandable references such as %SystemRoot% and may be stored as REG_EXPAND_SZ. Rewriting the value incorrectly can change its registry type or alter expandable references. Our example below is intended for demonstration; for production automation, prefer [Environment]::SetEnvironmentVariable() instead of modifying the registry directly.
When environment variables are changed directly in the registry, Windows does not automatically notify apps about the change. Production code should broadcast WM_SETTINGCHANGE with the Environment parameter after updating the registry so apps can detect the change. Already running processes still keep their existing environment block and may need to be restarted to use the new value.
$envpath = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
try {
$curValue = Get-ItemPropertyValue -Path $envpath -Name 'Path' -ErrorAction Stop
$entries = @(
$curValue -split ';' |
ForEach-Object { $_.Trim() } |
Where-Object { $_ }
)
if (-not ($entries | Where-Object { $_.TrimEnd('\') -ieq 'C:\Git' })) {
$entries += 'C:\Git'
Set-ItemProperty `
-Path $envpath `
-Name 'Path' `
-Value ($entries -join ';') `
-ErrorAction Stop
$updatedValue = Get-ItemPropertyValue `
-Path $envpath `
-Name 'Path' `
-ErrorAction Stop
if (-not ($updatedValue -split ';' |
ForEach-Object { $_.Trim() } |
Where-Object { $_.TrimEnd('\') -ieq 'C:\Git' })) {
throw 'C:\Git was not found in the registry PATH after the update.'
}
Write-Host 'C:\Git successfully added to the Machine PATH.'
}
else {
Write-Host 'C:\Git is already present in the Machine PATH.'
}
}
catch {
Write-Error "Failed to update the registry PATH: $($_.Exception.Message)"
throw
}
After changing the PATH, verify the persistent value with the command:
[Environment]::GetEnvironmentVariable('Path', 'Machine') 
Create a New Environment Variable Using the .NET Environment Class
You can create a new environment variable by using the built-in System.Environment class in .NET. This command adds a new global system environment variable named SITE:
$var_name = 'SITE'
$var_value = 'CA'
try {
[System.Environment]::SetEnvironmentVariable(
$var_name,
$var_value,
[System.EnvironmentVariableTarget]::Machine
)
$updatedValue = [System.Environment]::GetEnvironmentVariable(
$var_name,
[System.EnvironmentVariableTarget]::Machine
)
if ($updatedValue -ne $var_value) {
throw "Environment variable '$var_name' was not set to the expected value."
}
Write-Host "Environment variable '$var_name' was successfully created."
}
catch {
Write-Error "Failed to create environment variable '$var_name': $($_.Exception.Message)"
throw
}

To add an environment variable to the user scope, replace Machine with User:
try {
[System.Environment]::SetEnvironmentVariable(
$var_name,
$var_value,
[System.EnvironmentVariableTarget]::User
)
$updatedValue = [System.Environment]::GetEnvironmentVariable(
$var_name,
[System.EnvironmentVariableTarget]::User
)
if ($updatedValue -ne $var_value) {
throw "Environment variable '$var_name' was not set to the expected value."
}
Write-Host "Environment variable '$var_name' was successfully created for the current user."
}
catch {
Write-Error "Failed to create user environment variable '$var_name': $($_.Exception.Message)"
throw
} Remove an Environment Variable
In order to remove an environment variable from the current PowerShell process, use the command below:
Remove-Item Env:SITE
In case you want to remove a persistent User or Machine environment variable, use the .NET Environment class and verify the result afterward.
For example, for the Machine scope:
[Environment]::SetEnvironmentVariable('SITE', '', 'Machine')
$remaining = [Environment]::GetEnvironmentVariable('SITE', 'Machine')
if ($null -ne $remaining) {
throw "Environment variable 'SITE' was not removed."
} For the User scope:
PowerShell 7.5+ note. A regression in PowerShell 7.5 and some PowerShell 7.6 releases can cause the .NET SetEnvironmentVariable() method to leave a User environment variable with an empty value instead of completely removing the corresponding registry entry. For production automation, you should verify that the variable name no longer exists after removal.
[Environment]::SetEnvironmentVariable('SITE', '', 'User')
$variables = [Environment]::GetEnvironmentVariables('User')
if ($variables.Contains('SITE')) {
throw "Environment variable 'SITE' still exists in the User scope."
} Important. In PowerShell 7.5 and later, an environment variable in the current Process scope can have an explicit empty-string value. An empty string is therefore different from removing the variable when using the Env: provider. For persistent User and Machine environment variables on Windows, you should use [Environment]::SetEnvironmentVariable() with an empty string to remove the variable. Do not use $null for this purpose in PowerShell 7.5+ because it can leave an empty User environment variable instead of fully removing it.
What is the difference between Process, User, and Machine environment variables?
Windows supports three environment variable scopes:
- Process โ available only to the current process or PowerShell session.
- User โ available only to the current user account.
- Machine โ available system-wide for all users.
User and Machine variables are persistent, while Process variables are temporary.
Does modifying $Env:Path permanently change the PATH variable?
No. Changes made through $Env:Path affect only the current PowerShell session. The original value is restored when the session ends or the computer restarts.
What is the recommended way to make an environment variable change permanent?
Use the .NET Environment.SetEnvironmentVariable() method. It is generally safer than directly editing the registry and automatically notifies Windows about the change so newly launched applications can pick up updated values.
Why is editing the PATH variable directly in the registry not recommended?
Direct registry edits can change how expandable variables such as %SystemRoot% are stored. This may convert expandable values into plain text and alter the registry value type. The .NET method preserves environment variable semantics and avoids these issues.
Do running applications automatically receive updated environment variables?
No. Existing processes continue using the environment variables they received at startup. You may need to restart applications, open a new PowerShell session, or sign out and back in to see changes.
