WindowsのPATHをregコマンドで変更する

会社のセキュリティが厳しくなった事で、ユーザアカウント制御による権限昇格が出来なくなり、
Windowsの「システム環境変数の編集」が出来なくなりました……。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128512/fd31c016-4961-b937-4f76-e8360cd1cf2c.png)

今のところ、管理者権限でコマンドプロンプトやPowerShellは利用できます[^3]。
それらを使ってPath等の設定変更をするために必要な設定等を行うための方法です。

[^3]: 色々書いてから気が付いたのですが、管理者権限でcmdプロンプトは上がるので、そこから `rundll32.exe sysdm.cpl,EditEnvironmentVariables`を叩けば UAC回避できますね……orz

`SETX /M`でも設定は出来るものの、色々気になるところもあって `REG`コマンドを使って設定しています。

## 環境変数の確認

```cmd:コントロールパネルを起動して確認
rundll32.exe sysdm.cpl,EditEnvironmentVariables
```

```cmd:ユーザ環境変数の確認
reg query "HKCU\Environment" /v Path
```

```cmd:システム環境変数の確認
reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path
```

`reg query`の結果は以下のようになります。

```console
PS C:\Users\user> reg query HKCU\Environment /v Path

HKEY_CURRENT_USER\Environment
    Path    REG_EXPAND_SZ    %USERPROFILE%\AppData\Local\Microsoft\WindowsApps;C:\Users\user\AppData\Local\Programs\Microsoft VS Code\bin;
```

蛇足ですが、PowerShellで Get-ItemPropertyで行うと、REG_EXPAND_SZのため、環境変数展開をされてしまいます。

```powershell
Get-ItemProperty -LiteralPath 'Registry::HKEY_CURRENT_USER\Environment' -Name 'Path'
```

```console
PS C:\Users\user> Get-ItemProperty -LiteralPath 'Registry::HKEY_CURRENT_USER\Environment' -Name 'Path'

Path         : C:\Users\user\AppData\Local\Microsoft\WindowsApps;C:\Users\user\AppData\Local\Programs\Microsoft VS Code\bin;
```

## 環境変数の設定

コマンド自体は以下になるのですが、**注意**が必要です。

```cmd:ユーザ環境変数Pathの設定
REG ADD HKCU\Environment /v Path /t REG_EXPAND_SZ /d "設定したいパス"
```

```cmd:システム環境変数Pathの設定
REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /d "設定したいパス"
```

なぜ `REG`コマンドなのかというと、`SETX` で設定すると、レジストリの型が REG_EXPAND_SZ から REG_SZ になってしまう事があります[^1]。
環境変数展開を前提としたPath設定を行う様な物があると不具合につながる可能性が怖い事などもあって、`REG`を使って行うようにしています。

ただし、`REG` コマンドで設定しただけでは `SETX` と違い、設定が新規プロセスの環境変数に反映しません。Registryを変更した後に WM_SETTINGCHANGE をブロードキャストする必要があります。標準のコマンドラインから、このメッセージをブロードキャストする事をストレートに実現する方法は無いので、これには `SETX` でなんでも良いのでユーザ環境変数を一つ設定する事で代替とします。

困るのは、コマンドプロンプト(cmd.exe)から手打ちで設定しようと思うと、コマンドラインのインタープリター自身で、`%SYSTEMROOT%`等は環境変数展開されてしまいます。
`^%SYSTEMROOT^%`の様に`^`を使って%をエスケープする方法もありますが、設定文字列をクォートした場合 `"^%SYSTEMROOT^%"` は `^`が残ってしまいます。[^2]

このため設定方法としては多分以下の二通りになると思います。

- 一時利用のバッチファイルを作って、`"%%SYSTEMROOT%%\..."` といった形で `%%` でエスケープする
- PowerShellのプロンプトから入力する

ここでは二つ目の方法、PowerShellから手打ちで設定すると以下の様になります。
最後の SETX はユーザ環境変数に適当に設定して設定変更を通知しているだけなので、なんでもかまいません。

```powershell:ユーザ環境変数の設定と設定変更の通知
PS C:\Users\user> REG ADD HKCU\Environment /v Path /t REG_EXPAND_SZ /d "%USERPROFILE%\AppData\Local\Microsoft\WindowsApps;C:\Users\user\AppData\Local\Programs\Microsoft VS Code\bin;%LOCALAPPDATA%\Programs\Python\Python310;"
値 Path は存在します。上書きしますか? (Yes/No) y
この操作を正しく終了しました。

PS C:\Users\user> REG QUERY HKCU\Environment /v Path
HKEY_CURRENT_USER\Environment
    Path    REG_EXPAND_SZ    %USERPROFILE%\AppData\Local\Microsoft\WindowsApps;C:\Users\user\AppData\Local\Programs\Microsoft VS Code\bin;%LOCALAPPDATA%\Programs\Python\Python310;

PS C:\Users\user> SETX _UPDATEENV_ 1
成功: 指定した値は保存されました。
```

この後にWindows Terminal等を立ち上げると新しい環境変数が有効になります。

[^1]: SETX でも設定する値に % の文字が含まれると REG_EXPAND_SZ になるようです。
[^2]: ここら辺、どうもすっきりしないので、何か良い方法あればご教示ください……🙇