Environment variables store system and user configuration values that Windows and applications use to locate resources, configure behavior, and pass information between processes.
Table of Contents#
- Overview
- Scope and Precedence
- Viewing Variables
- Setting and Modifying Variables
- PATH Management
- Common Variables Reference
- Using Variables in Scripts
- Troubleshooting
- See Also
- Sources
1. Overview#
Environment variables are name-value pairs maintained by the operating system and available to all running processes. They serve as a universal configuration mechanism, providing paths to system directories, user profile locations, processor information, and custom application settings.
Windows uses three scopes for environment variables:
- System - apply to all users and services; stored in the registry
- User - specific to the logged-in user; stored in the registry
- Process - temporary, exist only for the lifetime of the current process and its children
2. Scope and Precedence#
When a process starts, it inherits a merged set of environment variables. If the same variable name exists in multiple scopes, the effective value follows this precedence (highest to lowest):
- Process - set at runtime; overrides everything
- User - set per user account
- System - machine-wide defaults
Note: The
PATHvariable is special. System and User PATH values are concatenated (system first, then user), not overridden.
Registry Locations#
| Scope | Registry Path |
|---|---|
| System | HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment |
| User | HKCU:\Environment |
Changes to registry-based variables require a new process or a logoff/restart to take effect for existing processes. You can broadcast a WM_SETTINGCHANGE message to notify applications of the change.
3. Viewing Variables#
PowerShell#
# List all environment variables
Get-ChildItem Env:
# Get a specific variable
$env:APPDATA
$env:PATH
# Filter variables by pattern
Get-ChildItem Env: | Where-Object { $_.Name -like "*PROGRAM*" }
# View system vs user PATH separately
[Environment]::GetEnvironmentVariable("PATH", "Machine")
[Environment]::GetEnvironmentVariable("PATH", "User")Command Prompt (CMD)#
:: List all environment variables
set
:: Show a specific variable
echo %APPDATA%
:: Show PATH
echo %PATH%GUI#
- Press
Win + R, typesysdm.cpl, press Enter - Go to the Advanced tab
- Click Environment Variables
4. Setting and Modifying Variables#
PowerShell#
# Set a process-scoped variable (temporary, current session only)
$env:MY_VAR = "value"
# Set a user-scoped variable (persistent)
[Environment]::SetEnvironmentVariable("MY_VAR", "value", "User")
# Set a system-scoped variable (persistent, requires admin)
[Environment]::SetEnvironmentVariable("MY_VAR", "value", "Machine")
# Remove a variable (set to null)
[Environment]::SetEnvironmentVariable("MY_VAR", $null, "User")Command Prompt (CMD)#
:: Set a process-scoped variable (current session only)
set MY_VAR=value
:: Set a persistent user variable
setx MY_VAR "value"
:: Set a persistent system variable (requires admin)
setx MY_VAR "value" /M
:: Remove a variable
set MY_VAR=Note:
setxhas a 1024-character limit for variable values. For longer values (especially PATH), use PowerShell or the GUI.
Registry (Direct)#
# Set a system variable via registry
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" `
-Name "MY_VAR" -Value "value"
# Set a user variable via registry
Set-ItemProperty -Path "HKCU:\Environment" -Name "MY_VAR" -Value "value"Broadcast Change Notification#
After modifying registry-based variables, notify running applications:
# Send WM_SETTINGCHANGE to notify applications
Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition @"
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,
uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
"@
$result = [UIntPtr]::Zero
[Win32.NativeMethods]::SendMessageTimeout(
[IntPtr]0xFFFF, 0x001A, [UIntPtr]::Zero, "Environment",
0x0002, 5000, [ref]$result) | Out-Null5. PATH Management#
The PATH variable tells Windows where to find executable files. It is a semicolon-separated list of directory paths.
View PATH Entries#
# List PATH entries, one per line
$env:PATH -split ";"
# View system PATH only
([Environment]::GetEnvironmentVariable("PATH", "Machine")) -split ";"
# View user PATH only
([Environment]::GetEnvironmentVariable("PATH", "User")) -split ";"Add to PATH#
# Add to user PATH (persistent)
$currentPath = [Environment]::GetEnvironmentVariable("PATH", "User")
$newPath = "$currentPath;C:\MyTools"
[Environment]::SetEnvironmentVariable("PATH", $newPath, "User")
# Add to system PATH (persistent, requires admin)
$currentPath = [Environment]::GetEnvironmentVariable("PATH", "Machine")
$newPath = "$currentPath;C:\MyTools"
[Environment]::SetEnvironmentVariable("PATH", $newPath, "Machine")
# Add to current session only
$env:PATH += ";C:\MyTools"Remove from PATH#
# Remove a directory from user PATH
$currentPath = [Environment]::GetEnvironmentVariable("PATH", "User")
$newPath = ($currentPath -split ";" | Where-Object { $_ -ne "C:\MyTools" }) -join ";"
[Environment]::SetEnvironmentVariable("PATH", $newPath, "User")Clean Up Duplicate Entries#
$currentPath = [Environment]::GetEnvironmentVariable("PATH", "User")
$cleanPath = (($currentPath -split ";") | Select-Object -Unique | Where-Object { $_ -ne "" }) -join ";"
[Environment]::SetEnvironmentVariable("PATH", $cleanPath, "User")6. Common Variables Reference#
System Directories#
| Variable | Typical Value | Description |
|---|---|---|
%ALLUSERSPROFILE% | C:\ProgramData | Common application data for all users |
%PROGRAMDATA% | C:\ProgramData | Same as ALLUSERSPROFILE |
%PROGRAMFILES% | C:\Program Files | 64-bit program installation directory |
%PROGRAMFILES(X86)% | C:\Program Files (x86) | 32-bit program installation directory |
%ProgramW6432% | C:\Program Files | 64-bit program files (even from 32-bit process) |
%COMMONPROGRAMFILES% | C:\Program Files\Common Files | Shared program components |
%COMMONPROGRAMFILES(x86)% | C:\Program Files (x86)\Common Files | Shared 32-bit program components |
%SystemDrive% | C: | Drive containing the Windows directory |
%SystemRoot% | C:\Windows | Windows installation directory |
%WINDIR% | C:\Windows | Same as SystemRoot |
%COMSPEC% | C:\Windows\System32\cmd.exe | Path to the command interpreter |
%DriverData% | C:\Windows\System32\Drivers\DriverData | Driver data directory |
User Directories#
| Variable | Typical Value | Description |
|---|---|---|
%APPDATA% | C:\Users\<username>\AppData\Roaming | Roaming application data |
%LOCALAPPDATA% | C:\Users\<username>\AppData\Local | Local application data |
%USERPROFILE% | C:\Users\<username> | Current user's profile directory |
%HOMEDRIVE% | C: | Drive letter of user's home directory |
%HOMEPATH% | \Users\<username> | Path portion of user's home directory |
%TEMP% / %TMP% | C:\Users\<username>\AppData\Local\Temp | Temporary file directory |
%USERNAME% | <username> | Current user's login name |
%PUBLIC% | C:\Users\Public | Public user profile |
%OneDrive% | C:\Users\<username>\OneDrive | OneDrive sync folder |
System Information#
| Variable | Typical Value | Description |
|---|---|---|
%COMPUTERNAME% | <hostname> | Machine hostname |
%USERDOMAIN% | <domain> | Domain of the current user |
%USERDOMAIN_ROAMINGPROFILE% | <domain> | Domain associated with roaming profile |
%LOGONSERVER% | \\<server> | Domain controller that authenticated the user |
%OS% | Windows_NT | Operating system identifier |
%PROCESSOR_IDENTIFIER% | (varies) | Processor description string |
%PROCESSOR_LEVEL% | (varies) | Processor family level |
%PROCESSOR_REVISION% | (varies) | Processor revision number |
%NUMBER_OF_PROCESSORS% | (varies) | Count of logical processors |
Shell and Path#
| Variable | Typical Value | Description |
|---|---|---|
%PATH% | (semicolon-separated dirs) | Executable search path |
%PathExt% | .com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh;.msc | File extensions treated as executable |
%PROMPT% | $P$G | CMD prompt format string |
%PSModulePath% | (semicolon-separated dirs) | PowerShell module search path |
CMD-Only Dynamic Variables#
These variables are only available in Command Prompt sessions and are evaluated dynamically:
| Variable | Description |
|---|---|
%CD% | Current working directory |
%DATE% | Current date |
%TIME% | Current time |
%RANDOM% | Random number (0 through 32767) |
%ERRORLEVEL% | Exit code of the previous command |
%CMDCMDLINE% | Command line used to launch the CMD session |
%CMDEXTVERSION% | Command processor extensions version number |
7. Using Variables in Scripts#
In PowerShell#
# Access environment variables
$appData = $env:APPDATA
$home = $env:USERPROFILE
# Use in paths
$logFile = Join-Path $env:TEMP "myapp.log"
# Expand variables in strings (double quotes only)
Write-Host "User profile is at $env:USERPROFILE"
# Access via the Env: drive
Get-Item Env:COMPUTERNAME
Set-Item Env:MY_VAR -Value "test"
Remove-Item Env:MY_VARIn CMD Batch Files#
:: Access variables with percent signs
echo %USERNAME% on %COMPUTERNAME%
:: Set and use in the same script
set LOGDIR=%TEMP%\logs
mkdir %LOGDIR%
:: Delayed expansion (inside loops)
setlocal enabledelayedexpansion
for /L %%i in (1,1,5) do (
set COUNT=%%i
echo !COUNT!
)
endlocalIn Application Configuration#
Many applications and frameworks use environment variables for configuration:
# Set Java home
[Environment]::SetEnvironmentVariable("JAVA_HOME", "C:\Program Files\Java\jdk-21", "Machine")
# Set Node.js options
[Environment]::SetEnvironmentVariable("NODE_OPTIONS", "--max-old-space-size=4096", "User")
# Set proxy for development tools
[Environment]::SetEnvironmentVariable("HTTP_PROXY", "http://<proxy-host>:<port>", "User")
[Environment]::SetEnvironmentVariable("HTTPS_PROXY", "http://<proxy-host>:<port>", "User")Troubleshooting#
| Issue | Cause | Solution |
|---|---|---|
| Variable change not visible in open terminals | Existing processes have stale environment | Open a new terminal; or broadcast WM_SETTINGCHANGE |
setx truncates PATH | PATH exceeds 1024-character setx limit | Use PowerShell [Environment]::SetEnvironmentVariable() or the GUI instead |
| Application cannot find executable | Directory not in PATH | Add the directory to PATH and open a new terminal |
| User variable overrides system variable | Same name exists in both scopes | Rename or remove one; remember PATH is concatenated, not overridden |
%VARIABLE% prints literally in CMD | Variable does not exist | Verify spelling and scope; use set to list all variables |
$env:VAR is empty in PowerShell | Variable not set for current scope | Check with [Environment]::GetEnvironmentVariable("VAR", "Machine") and "User" separately |
| Changes lost after reboot | Variable was set with $env: or set (process-scoped only) | Use setx, [Environment]::SetEnvironmentVariable(), or the GUI for persistence |