概要
SETX と [Environment]::SetEnvironmentVariable の違いに躓いたので調査したことを共有します!
どちらもWindowsで環境変数を設定する手段ですが、細かいところで違いがありました。
知らずに使ってしまうと最悪Windows上でアプリが起動しなくなるかもしれないので、 よかったら参考にしてください。
以下の説明はすべてはPowerShellでの実行を想定
結論
説明が長くなったので、先に結論です。
- 展開(%...%)を使用するなら、
SETX使って、環境変数の末尾に/を入れない- x:
C:\Program Files\Git\bin;%SystemRoot%\System32\WindowsPowerShell\v1.0\ - o:
C:\Program Files\Git\bin;%SystemRoot%\System32\WindowsPowerShell\v1.0
- x:
- 展開(%...%)を使用しないなら、
[Environment]::SetEnvironmentVariableでも可
詳しくは以下
違い
設定時のレジストリキーの種類が異なる
試しに環境変数 Foo に %SystemRoot%\System32 を登録してみます。
SETX の場合は REG_SZ と REG_EXPAND_SZ から適した方
SETX Foo 'C:\Windows\System32'->REG_SZSETX Foo '%SystemRoot%\System32'->REG_EXPAND_SZ
つまり、SETX は%SystemRoot% のような環境変数を展開するような書式を検知したらREG_EXPAND_SZとして登録してくれます。
![]()
[Environment]::SetEnvironmentVariable は REG_SZ 固定
つまり%SystemRoot%があろうがなかろうが REG_SZ 固定になります。
以下は [Environment]::SetEnvironmentVariable('Foo', '%SystemRoot%', [System.EnvironmentVariableTarget]::User) の場合です。
![]()
REG_SZの場合、変数が展開されません!これは PATH を設定するときは非常にまずいです!
これに関しては dotnet のGitHubのIssueでずっと議論になっているようです。
変数が展開されていないことの確認
以下のコマンドを実施する場合は echo ([Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::Machine)) などで既存の変数を控えて最後に戻すようにしてください!
特に PATH は元に戻さないとアプリがおかしくなる可能性があります!
[Environment]::SetEnvironmentVariable('PATH', '%SystemRoot%\System32', [System.EnvironmentVariableTarget]::Machine) 実行して、PowerShellを再起動してPATHを確認すると、以下のように展開されていないことがわかります。
そして、もちろんパスも通らないので、PATHを使用しているアプリがおかしくなります!
> echo $Env:PATH %SystemRoot%\System32;...
SETX /M PATH '%SystemRoot%\System32' であれば REG_EXPAND_SZで登録されるので展開されたものがPATHとして登録されます。
> echo $Env:PATH C:\WINDOWS\System32;...
(バグ?) SETXの場合、 末尾にダブルクォーテーションが挿入されるパターンがある
条件は以下で発生することを確認しています
- 値の中にスペースが有る
- 値の最後が
/
例: C:\Program Files\Git\bin;C:\WINDOWS\System32\WindowsPowerShell\v1.0\
Program Filesにスペース、v1.0\で末尾がバックスラッシュみたいな場合におかしくなります。(実際に起こった事象を例にしています)。
> SETX /M PATH 'C:\Program Files\Git\bin;C:\WINDOWS\System32\WindowsPowerShell\v1.0\'
成功: 指定した値は保存されました。
> echo ([Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::Machine))
C:\Program Files\Git\bin;C:\WINDOWS\System32\WindowsPowerShell\v1.0"
最後に " がなぜが挿入されます。。。 (SETXのバグじゃないかと思っています)
ちなみに、PATHに登録する場合は " がついた方のパス(上記では C:\WINDOWS\System32\WindowsPowerShell\v1.0 )がPATHから除外されてしまいます。
;区切りのパスの末尾には / は不要なので、基本的には最後は / にしないほうが安全だと思います。
結論で述べた「環境変数の末尾に / を入れない」はこれが理由になります。
ご注意ください!
簡易解説
せっかくなのでSETXと[Environment]::SetEnvironmentVariableを少し解説します。
環境変数の設定方法
例えば Foo という環境変数に値 Bar;Baz を入れる場合は以下のようにコールします。
ユーザー環境変数の場合
SETX Foo 'Bar;Baz'
[Environment]::SetEnvironmentVariable('Foo', 'Bar;Baz', [System.EnvironmentVariableTarget]::User)
システム環境変数の場合
システム環境変数とは対象のマシンのユーザー全体で共通となる環境変数のことです。
実行には管理者権限が必要となります。
SETX /M Foo 'Bar;Baz'
[Environment]::SetEnvironmentVariable('Foo', 'Bar;Baz', [System.EnvironmentVariableTarget]::Machine)
環境変数の確認方法
コマンドライン (混合)
※環境変数設定後はPowerShellの再起動が必要
echo $Env:Foo
コマンドライン (個別)
# ユーザー環境変数の場合
echo ([Environment]::GetEnvironmentVariable('Foo', [System.EnvironmentVariableTarget]::User))
# システム環境変数の場合
> echo ([Environment]::GetEnvironmentVariable('Foo', [System.EnvironmentVariableTarget]::Machine))
レジストリ エディタ
- レジストリエディタを開く
- ユーザー環境変数の場合は
コンピューター\HKEY_CURRENT_USER\Environment - システム環境変数の場合は
コンピューター\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment

システムのプロパティ -> 環境変数
- Windowsキーを押す
- "env" と検索
システム環境変数の編集をクリック

環境変数をクリック


余談、PATHのREG_SZ登録をREG_EXPAND_SZに切り替える方法
途中までは「システムのプロパティ -> 環境変数」と同様
システム環境変数の編集をクリック環境変数をクリック- 変数
Pathを選択して、編集をクリック- ユーザー変数 と システム変数 どちらも同様
- "環境変数名の編集" の OK をクリック
- "環境変数" の OK をクリック
以上

どうやら、"環境変数名の編集" の OK を押したときに REG_EXPAND_SZ で登録される処理が発生するようです。
もし、PATHに %SystemRoot% を使用していて展開されていない場合は試してみてください。
環境変数の補足
Windows上では %SystemRoot% = C:\Windows です。
ちなみに %USERPROFILE%は現在のユーザーのホームフォルダを表します。
エクスプローラーで以下のように入力するとホームフォルダに移動することができます。

雑感
前回の記事で、Git for Windowsの設定するときのコマンドでSetEnvironmentVariable使ってたのですが、
%SystemRoot%が展開されないことに気づいて急遽記事を書きました。
もし、前回の記事を試してローカルがおかしくなった方がいたらごめんなさい。。。
「余談、PATHのREG_SZ登録をREG_EXPAND_SZに切り替える方法」を実施すれば解消すると思います 🙇♂️
「GetEnvironmentVariable使うなら、対のSetEnvironmentVariableでしょ!」って感じで使ってたらこんな罠があったとは。。。
ご参考になれば幸いです。
それでは~