Windows の プロキシ を 自動設定するタスクを作成

最近、利用するネットワーク環境が変えることが多くなり、プロキシ設定がめんどくさくなってきたのでスクリプトを作ってみました.

作業環境

  • Windows 10 64bit

プロキシ の 設定箇所

Windows で ブラウザなどを使う場合にプロキシを設定するのは [設定] - [ネットワークとインターネット] - [プロキシ] や、ブラウザのオプションから設定をします.
また、Node.js などは環境変数 HTTP_PROXYHTTPS_PROXY を 使うので、環境変数を設定します.
ブラウザだけではないので、ネットワークを切り替えプロキシの有無を変えたりするとなると、結構手間がかかります…

Windows の プロキシ設定を切り替えるためのツールはありそうだったのですが、環境変数の変更までとなると なかなか見つからず、簡単なスクリプトで済ませることにしました.

プロキシ の 自動設定スクリプト

今回は Windows 10 に 特別なものを入れないで動かしたいので、Windows PowerShell を 使うことにします.
ここでは configure-proxy.ps1 というファイル名で作成しました.

1
$PROXY_HOST="proxy.example.com"
2
$PROXY_PORT=8080
3
$LOCAL_ADDR="<local>"
4
5
$REG_KEY="HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings"
6
7
try {
8
    $ignore = [System.Net.Dns]::GetHostAddresses(${PROXY_HOST}) | ? { $_.AddressFamily -eq "InterNetwork" }
9
10
    Set-ItemProperty -path ${REG_KEY} ProxyEnable -value 1
11
    Set-ItemProperty -path ${REG_KEY} ProxyServer -value "${PROXY_HOST}:${PROXY_PORT}"
12
    Set-ItemProperty -path ${REG_KEY} ProxyOverride -value ${LOCAL_ADDR}
13
    Set-Item -path env:HTTP_PROXY -value "http://${PROXY_HOST}:${PROXY_PORT}"
14
    Set-Item -path env:HTTPS_PROXY -value ${env:HTTP_PROXY}
15
    [Environment]::SetEnvironmentVariable("HTTP_PROXY", ${env:HTTP_PROXY}, [EnvironmentVariableTarget]::User)
16
    [Environment]::SetEnvironmentVariable("HTTPS_PROXY", ${env:HTTP_PROXY}, [EnvironmentVariableTarget]::User)
17
} catch {
18
    Set-ItemProperty -path ${REG_KEY} ProxyEnable -value 0
19
    Remove-Item -path env:HTTP_PROXY
20
    Remove-Item -path env:HTTPS_PROXY
21
    [Environment]::SetEnvironmentVariable("HTTP_PROXY", "", [EnvironmentVariableTarget]::User)
22
    [Environment]::SetEnvironmentVariable("HTTPS_PROXY", "", [EnvironmentVariableTarget]::User)
23
}
24
25
$source=@"
26
[DllImport("wininet.dll")]
27
public static extern bool InternetSetOption(int hInternet, int dwOption, int lpBuffer, int dwBufferLength);
28
"@
29
$wininet = Add-Type -memberDefinition ${source} -passthru -name InternetSettings
30
${wininet}::InternetSetOption([IntPtr]::Zero, 95, [IntPtr]::Zero, 0)|out-null
31
${wininet}::InternetSetOption([IntPtr]::Zero, 37, [IntPtr]::Zero, 0)|out-null
32
33
exit 0

先頭の3行が設定部分になります.
$PROXY_HOST$PROXY_PORT に 利用する プロキシ・サーバ の ホスト名 と ポート番号を記述します.
$LOCAL_ADDR は “ローカル アドレスにはプロキシ サーバーを使用しない” に チェックする場合は <local> を いれます. また、”次で始まるアドレスにはプロキシを使用しない” に 値を入れる場合は、同じく $LOCAL_ADDR に セミコロン区切りで設定します. 例えば下記のようにします.
$LOCAL_ADDR="*.example.com;*.example.net;<local>"

8行目の GetHostAddresses(${PROXY_HOST}) で プロキシ・サーバ の IP アドレス を 引きます.
これは、現在のネットワークでプロキシ・サーバが引けるかを確認するためになります.
未使用変数 $ignore で 受けているのは、変数で受けないと DNS を 引いた情報が標準出力へ流れるのを防ぐためです.

IP アドレスが引けたら、後続の処理で以下を行いプロキシが利用できる設定をします.
コマンドラインからも呼べるように現在のセッションと永続化の両方の環境変数を設定しています.

  • レジストリ に プロキシの利用を有効化し、プロキシ・サーバの情報、ローカルや除外アドレスの設定
  • 現在のセッションにおける 環境変数 HTTP_PROXYHTTPS_PROXY を 設定
  • ユーザの環境変数 HTTP_PROXYHTTPS_PROXY を 設定

IP アドレスが引けなかった場合は catch ブロックへ処理が飛びます.
DNS で ルックアップできなかったので プロキシ・サーバ が 利用できないものとして、プロキシの設定を解除します.

  • レジストリ の プロキシ利用を無効化します (設定した値は残し、使わないものとしています)
  • 現在のセッションにおける 環境変数 HTTP_PROXYHTTPS_PROXY を クリア
  • ユーザの環境変数 HTTP_PROXYHTTPS_PROXY を クリア

最後にレジストリに設定したプロキシ情報をブラウザに反映するための処理を行います.
こちらの部分につきましては、下記の記事を参考にさせていただきました. ありがとうございます!

タスク スケジューラ から PowerShell を 実行する ラッパー・スクリプト

上記コマンドを必要に応じて実行することでプロキシ設定をだいぶ軽減できますが、やはり自動設定してくれるようにしたいところです.
そのために タスク スケジューラ を 使うのですが、タスク スケジューラ から PowerShell を 実行すると、コマンド プロンプト らしきものが 一瞬見えてしまいます. それを防ぐためにラッパーのスクリプトを作成します.
こちらは 「windows」で「PowerShell」を「一切画面表示せず」に「タスクスケジューラに登録」する方法を再確認 - Qiita さん の 情報を参考させていただきました. ありがとうございます!

ここでは ps-executer-for-task-scheduler.js というファイル名で作成しました.

1
shell = WScript.createObject("WScript.Shell");
2
ret = shell.Run("\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -NoProfile -ExecutionPolicy RemoteSigned -File \"" + WScript.Arguments.Item(0) + "\"", 0, true);
3
WScript.Quit(ret);

powershell.exe を このスクリプトの引数で渡されたファイルで実行するというものになります.
-NoProfile -ExecutionPolicy RemoteSigned は スクリプトの実行ポリシーを一時的に下げるものになります. 今回は自分のスクリプトを実行することがわかっていますが、そうでない場合はよく確認してから実行する必要があります.
(と、これを見てくださっている方には 自分の スクリプト ではない ですね. ご確認ください…)

タスク スケジューラ に 設定

スタートメニュー で “タスク” で 検索すると、タスク スケジューラ が でてきます.

タスク スケジューラ ウィンドウ 右 の 操作 から、[タスクの作成] を クリックします. (“基本タスクの作成”ではないこと、注意です)

タスクの作成 の [全般]タブ で、タスクの名前を設定します. ここでは Configure Proxy としました.

[条件]タブ を 表示し、[電源] に ついているチェックを外します.
チェックがついていると外出時などでネットワーク構成が変わっているときなど、肝心な時に動作してくれなくなるので大事です.

[操作]タブ を 表示し、[新規] ボタンをクリックします.

[プログラム/スクリプト] に 先ほど作成した ラッパー・スクリプト ps-executer-for-task-scheduler.js を 指定します.
[引数の追加] に PowerShell 本体 の configure-proxy.ps1 を ダブルクォートで囲って入力します.
最後に、[開始] に スクリプトがあるディレクトリを入力します.
ここでは、C:\Temp\windows-proxy-config-task ディレクトリにスクリプトがにあるものとして設定しています.

入力できたら [OK] ボタンをクリックして戻ります.

[トリガー] タブ を 表示し、[新規] ボタンをクリックします. (ここから先は操作が重くなったり、処理に時間がかかったりすることがあります)

[タスクの開始] で イベント時 を 選択します.

設定を以下のように選択します.

  • [ログ] は Microsoft-Windows-NetworkProfile/Operational
  • [ソース] は NetworkProfile
  • [イベント ID] は 10000

詳細設定で、[遅延時間を指定する] を 念のため 1 秒間 に しておきます.
ネットワークが切り替わった後に発動するので問題ないはずですが、ちょっとだけ待ってから動かします.

設定したら OK を クリックします.

※ 上記で設定した イベント ID の 10000 は ネットワークに接続された場合に通知される ID に なります. ネットワーク切断時 は 10001 です. ソフトウェア で ネットワーク接続を切り替え、切断して元のネットワークに戻った場合にもタスクを実行したい、といったケースがある場合は、再度 [新規] を クリックして ID 10001 で 同じものを登録しておきます.

タスク スケジューラ の ウィンドウに戻ります.
ウィンドウ 左 から [タスク スケジューラ ライブラリ] を クリックすると、今回登録したタスクが表示されます.

ウィンドウ 中央 下段 から [履歴] タブを選択するとタスクのログが見れます.
まずは登録されたログが表示されています.

ネットワークを切り替え、ログのテーブル表示部分から 右クリック [最新の情報に更新] を すると、登録したタスクが実行されていることが確認できます.

リポジトリ

とりあえず、スクリプトだけ GitHub https://github.com/azriton/windows-proxy-config-task に アップしました.
README などは 追々書いていきたいと思います.



これでネットワークを切り替えた場合に、プロキシ設定が切り替わるようになりました!
ネットワークが切り替わったというイベントと、1秒の遅延設定をしているので、切り替わったと思う瞬間より少し遅れがある場合もありますが、十分使える範囲かと思います.