PowerShell で設定した環境変数が別のウィンドウに反映されない
$Env:X = 'value' はプロセススコープの変更で、そのセッションを閉じると消える。
恒久化するには [Environment]::SetEnvironmentVariable() に User か Machine スコープを渡すか、プロファイルに書く。
公開: 更新:
要約
PowerShell で環境変数を設定したのに、新しいウィンドウを開くと消えている。
あるいはコントロールパネルで設定したのに、開きっぱなしのウィンドウでは古い値のままである。
どちらもスコープの理解で説明が付く。
$Env:API_TOKEN = 'abc123'
$Env:API_TOKEN # => abc123(このセッションでは見える)
# 新しいウィンドウを開いて
$Env:API_TOKEN # => 何も出ない公式ドキュメント(新しいタブで開く)のとおり、Windows の環境変数には Machine・User・Process の 3 つのスコープがあり、$Env: 構文で書き換わるのは Process スコープだけである。
Process スコープはセッションの起動時に Machine と User の値から組み立てられ、セッションを閉じれば破棄される。
恒久化したいなら [Environment]::SetEnvironmentVariable() に User か Machine を渡す。
実行例
mcr.microsoft.com/powershell(Linux)のコンテナで 1 行ごとに新しい pwsh を起動して試すと、$Env: で入れた値は同じセッションと子プロセスでは見えたものの新しいセッションでは空になり、第 3 引数を省いた SetEnvironmentVariable でも同じく残らず、$PROFILE に書いた値だけが新しいセッションに引き継がれた。$Env:PATH を代入で置き換えると uname が見つからなくなり、Linux の区切り文字 : で += 追記した場合は hello と uname の両方が動いている。
$ $Env:API_TOKEN = "abc123"; $Env:API_TOKEN; pwsh -NoLogo -Command { "子プロセス: $Env:API_TOKEN" }
abc123
子プロセス: abc123$ "新しいセッション: [$Env:API_TOKEN]"
新しいセッション: []$ [Environment]::SetEnvironmentVariable("API_TOKEN", "abc123"); $Env:API_TOKEN
abc123$ "新しいセッション: [$Env:API_TOKEN]"
新しいセッション: []$ $PROFILE
/root/.config/powershell/Microsoft.PowerShell_profile.ps1$ Get-Content $PROFILE
$Env:API_TOKEN = "abc123"$ "新しいセッション: [$Env:API_TOKEN]"
新しいセッション: [abc123]$ $Env:PATH = "/opt/tools"; hello; uname -s
hello from /opt/tools
uname: The term 'uname' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.$ $Env:PATH += ":/opt/tools"; hello; uname -s
hello from /opt/tools
Linux— 2026-09-26 時点の出力
検証環境
- 検証日
- 実行環境
mcr.microsoft.com/powershellUbuntu 22.04.4 LTS
この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。
よくある原因
$Env:はプロセススコープ: Windows コマンドシェルのsetや Unix のsetenvと同じ扱いで、現在のセッションにしか効かない。
子プロセスには引き継がれるので、そのセッションから起動したビルドツールでは見える。
この「見えるのに残らない」挙動が混乱の元になる。- 既存セッションには伝わらない: Process スコープは起動時に Machine と User から構成される。
したがってコントロールパネルや別のウィンドウで User スコープを変えても、すでに動いているセッションは古い値を持ち続ける。 - スコープ引数を省略した:
[Environment]::SetEnvironmentVariable('Foo','Bar')は第 3 引数が無いとプロセススコープへの書き込みになる。$Env:Foo = 'Bar'と結果は変わらない。 - Machine スコープに権限が足りない: Machine スコープの書き込みには権限が要る。
権限が無いとコマンドは失敗しエラーになる。 - PATH を上書きしている:
$Env:PATH = 'C:\Tools'と代入すると、それまでの PATH がすべて消える。
そのセッションでgitすら見つからなくなる。
解決策
1. User スコープに恒久化する
[Environment]::SetEnvironmentVariable('API_TOKEN', 'abc123', 'User')第 3 引数に 'User' か 'Machine' を渡すとレジストリに書かれ、以後に起動するセッションへ引き継がれる。
削除は空文字列を渡す。
[Environment]::SetEnvironmentVariable('API_TOKEN', '', 'User')書き込んだ値は現在のセッションには入らないので、確認は新しいウィンドウで行う。
同じセッションでも使いたいなら両方に書く。
[Environment]::SetEnvironmentVariable('API_TOKEN', 'abc123', 'User')
$Env:API_TOKEN = 'abc123'2. PowerShell だけで良いならプロファイルに書く
notepad $PROFILE# Microsoft.PowerShell_profile.ps1
$Env:API_TOKEN = 'abc123'
$Env:PATH += ';C:\Tools'プロファイルは PowerShell の起動ごとに読まれるので、どのバージョン・どのプラットフォームでも同じ方法が使える。
ただし cmd.exe やエクスプローラーから起動したアプリには効かない。
PowerShell 以外にも見せたい値なら方法 1 を選ぶ。
なおプロファイルが読み込まれるにはスクリプト実行が許可されている必要がある。
実行ポリシーが Restricted のままだとプロファイル自体が読まれない。
3. PATH は追記する
$Env:PATH += ';C:\Tools'恒久化する場合も、既存の値を読んでから足す。
$old = [Environment]::GetEnvironmentVariable('PATH', 'User')
[Environment]::SetEnvironmentVariable('PATH', "$old;C:\Tools", 'User')GetEnvironmentVariable にも同じスコープを渡すのが重要である。$Env:PATH は Machine と User が結合済みの値なので、それをそのまま User スコープへ書き戻すと Machine 側の内容が User にも複製され、PATH が二重になる。
4. 反映されているか確認する
[Environment]::GetEnvironmentVariable('API_TOKEN', 'User')スコープを指定して読むと、レジストリに入った値をセッションの状態と切り離して確認できる。Get-ChildItem Env: で見えるのは Process スコープの一覧なので、恒久化の確認には使えない。