Windows 10/11でHOSTSファイルに1行追加したいのに、GPOのスタートアップ/ログオンスクリプト経由だと反映されない――。原因はスクリプトではなく「実行ユーザー(セキュリティコンテキスト)とACL」のズレであることが多いです。確実に書き換える手順と、運用でハマりやすい罠をまとめます。
現象:管理者として実行すると書けるのに、GPOからだと書けない
HOSTSファイル(C:\Windows\System32\drivers\etc\hosts)は、名前解決に直結する重要ファイルです。そのため多くの環境でアクセス権(ACL)が厳しめに設定されており、「どのアカウントとしてスクリプトが実行されるか」で結果が変わります。
同じBATでも、ローカルで「管理者として実行」したときは成功するのに、GPO(コンピュータのスタートアップスクリプト、ユーザーのログオンスクリプトなど)から実行すると、エラーが出ないまま反映されない――この症状は、ほぼ例外なく実行コンテキストと権限の差で説明できます。
結論:GPO経由で確実にHOSTSを編集するための考え方
ポイントは次の2つです。
- スクリプトを「書き込み可能な権限」で実行する(例:コンピュータのスタートアップ=SYSTEM、または「最上位の特権」で動くタスク)
- HOSTSファイルのACLを、実行アカウントに合わせて明示的に整備する(GPOの「ファイル システム」で権限付与)
BATのロジック自体が正しいのに反映されない場合、スクリプトをいじるよりも先に、「誰が実行しているか」と「HOSTSに書けるか」を揃えるのが近道です。
なぜ差が出るのか:ローカル実行とGPO実行のセキュリティコンテキスト
Windowsでは同じコマンドでも、実行主体が違えばアクセスできる範囲が変わります。特にUAC(ユーザーアカウント制御)環境では、管理者グループのユーザーであっても、「昇格(管理者として実行)」したときだけ強い権限になります。
| 実行方法 | 主な実行ユーザー | HOSTSへの書き込み | ハマりやすい点 |
|---|---|---|---|
| ローカルで「管理者として実行」 | 昇格した管理者トークン | できることが多い | 成功しても、GPO経由の実行条件とは一致しない |
| GPO(ユーザーのログオンスクリプト) | ログオンユーザー(通常は標準ユーザー) | できないことが多い | 「管理者権限が必要な操作」は無音で失敗しやすい |
| GPO(コンピュータのスタートアップスクリプト) | ローカルSYSTEM | 本来は可能(ただし環境次第) | 起動直後でネットワーク未接続、スクリプト/ログ出力先の権限などで失敗することがある |
| GPPのスケジュールタスク(最上位の特権) | SYSTEMまたは指定サービスアカウント | 可能にしやすい | 運用設計(いつ実行するか・繰り返し・失敗時の再実行)が必要 |
今回のように「ローカル管理者実行では成功」「GPO実行では反映されない」という差が出たら、BATの中身よりも、実行ユーザーとHOSTSのACLを疑うのが定石です。
最短で切り分ける:スクリプトが“誰として”動いているかをログに出す
「エラーが出ない」のが厄介な点です。まずは、GPO経由で実行したときにどのユーザーコンテキストで動いているかを確実に把握しましょう。ログ出力先は、SYSTEMでも書き込めるパス(例:%SystemRoot%\Temp)が安全です。
@echo off
set LOG=%SystemRoot%\Temp\hosts_gpo_debug.log
echo ==== %date% %time% ==== >> "%LOG%"
whoami >> "%LOG%"
whoami /groups >> "%LOG%"
echo HOSTS=%SystemRoot%\System32\drivers\etc\hosts >> "%LOG%"
このログで、例えばSYSTEMで動いているのか、あるいはドメインユーザーで動いているのかが判別できます。次にHOSTSのACLを確認します。
icacls "%SystemRoot%\System32\drivers\etc\hosts" >> "%LOG%"
ここで、実行ユーザー(SYSTEMや、ログオンユーザー)に「書き込み(W)」や「変更(M)」相当が無ければ、BATがいくら正しくても追記できません。
本命の解決策:GPOの「ファイル システム」でHOSTSのACLを明示的に付与する
GPOには、特定ファイル/フォルダーのアクセス権をクライアントへ配布できる機能があります。HOSTSのように保護されたパスは、スクリプト側で無理やり“管理者化”しようとするより、先にACLを整える方が安定します。
設定する場所
グループポリシー管理エディターで、対象GPOを編集し、次のパスを開きます。
- コンピュータの構成
- ポリシー
- Windows の設定
- セキュリティの設定
- ファイル システム
HOSTSファイルを登録して権限を付与する手順
- 「ファイル システム」を右クリックし、[ファイルの追加]を選択します。
- パスに次を入力します:
C:\Windows\System32\drivers\etc\hosts - アクセス許可の設定画面で、スクリプトが実行される主体に対して書き込みを許可します。
- GPOを保存し、対象クライアントに適用します(
gpupdate /force、必要に応じて再起動)。
誰に権限を付けるべきか(推奨)
HOSTSは改ざんされると通信先を誘導できてしまうため、広い対象(Users、Everyone、Domain Users、Domain Computersなど)に書き込み権限を付与するのは避けるのが基本です。おすすめは「SYSTEMで実行する設計」に寄せ、SYSTEMに必要最小限の権限を持たせることです。
| スクリプトの実行設計 | 権限付与先(例) | 付与する権限の目安 | セキュリティ面のコメント |
|---|---|---|---|
| コンピュータのスタートアップスクリプト | SYSTEM | 変更(Modify)相当(書き込み含む) | 最も安全・シンプル。ユーザーへ書き込み権限を広げない |
| GPPのスケジュールタスク(SYSTEM実行) | SYSTEM | 変更(Modify)相当 | 実行タイミングを制御しやすい。端末起動中に反映も可能 |
| どうしてもログオンユーザーで実行 | 専用セキュリティグループ(最小の対象) | 変更(Modify)相当 | 対象を厳選。広い権限付与はリスクが高い |
「ファイル システム」の設定は、意図せず既存ACLを上書きしてしまうと運用に影響が出ます。特にセキュリティベースラインを適用している環境では、既存の権限設計があることも多いので、必ず検証用OU/検証PCで動作確認してから本番へ展開してください。
BATでの追記処理:重複防止・バックアップ・ログを最低限入れる
HOSTSは1行追記でも事故が起き得ます。運用で安定させるため、次の3点は入れておくと安心です。
- 重複追加しない(すでに存在する行を再度追記しない)
- バックアップを作る(hosts.bakなど)
- ログを残す(GPO経由の失敗が目視しづらいため)
例として、指定した1行が無い場合だけ追記するBATのサンプルです(GPO配布を想定)。
@echo off
setlocal EnableExtensions
set HOSTS=%SystemRoot%\System32\drivers\etc\hosts
set LINE=192.0.2.10 example.internal
set LOG=%SystemRoot%\Temp\hosts_update.log
echo ==== %date% %time% ==== >> "%LOG%"
echo TARGET=%HOSTS% >> "%LOG%"
rem 既に同じ行があるなら何もしない
findstr /i /c:"%LINE%" "%HOSTS%" >nul
if %errorlevel%==0 (
echo Already exists: %LINE% >> "%LOG%"
exit /b 0
)
rem 事前バックアップ(上書き)
copy /y "%HOSTS%" "%HOSTS%.bak" >nul
rem 末尾に追記(改行を保証したい場合は echo. を併用)
echo %LINE%>>"%HOSTS%"
rem 追記できたか最終確認
findstr /i /c:"%LINE%" "%HOSTS%" >nul
if not %errorlevel%==0 (
echo FAILED to write hosts. Check ACL and security software. >> "%LOG%"
exit /b 1
)
echo Added: %LINE% >> "%LOG%"
exit /b 0
このサンプルは「追記後にfindstrで再確認」することで、無音失敗を検知しやすくしています。環境によってはセキュリティ製品がHOSTSへの変更をブロック/巻き戻しすることもあるため、追記後確認は有効です。
PowerShellで書くとさらに堅牢
BATのリダイレクトはシンプルですが、文字コードや改行、エラーハンドリングの面で限界があります。企業環境で「確実に」「読みやすく」運用したいなら、PowerShellに寄せると保守が楽になります。
$hosts = Join-Path $env:SystemRoot "System32\drivers\etc\hosts"
$line = "192.0.2.10 example.internal"
$log = Join-Path $env:SystemRoot "Temp\hosts_update.log"
"==== $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') ====" | Add-Content -Path $log
"TARGET=$hosts" | Add-Content -Path $log
if (-not (Test-Path $hosts)) {
"HOSTS not found." | Add-Content -Path $log
exit 1
}
$exists = Select-String -Path $hosts -SimpleMatch -Quiet -Pattern $line
if ($exists) {
"Already exists: $line" | Add-Content -Path $log
exit 0
}
Copy-Item -Path $hosts -Destination ($hosts + ".bak") -Force
Add-Content -Path $hosts -Value $line -Encoding ASCII
$existsAfter = Select-String -Path $hosts -SimpleMatch -Quiet -Pattern $line
if (-not $existsAfter) {
"FAILED to write hosts. Check ACL and security software." | Add-Content -Path $log
exit 1
}
"Added: $line" | Add-Content -Path $log
exit 0
GPOからPowerShellを呼ぶ場合は、実行ポリシーや32/64bitの違いが影響することがあります。社内標準に合わせて、起動パラメータ(例:-ExecutionPolicy Bypass)や、GPO側の「PowerShellスクリプトの実行」設定も合わせて設計してください。
適用と検証:反映されないときに見るべきポイント
「GPOを作った」「gpupdateした」だけでは見落としが出ます。特にスタートアップスクリプトは再起動が絡むため、検証手順を固定化しておくとトラブルが減ります。
| 確認したいこと | 確認手段 | 見えるべき結果 |
|---|---|---|
| GPOが対象PCに適用されているか | gpresult /r(コンピュータ) | 対象GPOが適用一覧に出る |
| スクリプト自体が実行されたか | ログファイル(%SystemRoot%\Temp) | 実行日時とwhoamiが記録される |
| HOSTSのACLが期待通りか | icacls | SYSTEM(または指定グループ)に書き込み/変更がある |
| HOSTSに行が追加されたか | findstr またはファイル確認 | 追加した行が1回だけ存在する |
また、イベントビューアーの「Microsoft-Windows-GroupPolicy/Operational」には、GPOの処理状況が記録されます。スクリプトが走っていない/途中で止まっている場合は、ここを起点に追うと原因に辿り着きやすいです。
よくある落とし穴
スクリプトの保存場所がネットワークで、起動時に読めていない
スタートアップスクリプトは「ユーザーがログオンする前」に動きます。スクリプト本体が共有フォルダー上にある場合、ネットワーク初期化のタイミング次第で読み込めないことがあります。GPO配布なら、基本はSYSVOL配下に配置するか、先にローカルへコピーしてから実行するのが安全です。
ログオンスクリプトで走らせていて、UACにより非昇格のまま実行されている
「ドメインユーザーがローカル管理者グループに入っている」構成でも、ログオンスクリプトは通常昇格していないトークンで実行されます。結果としてHOSTSへの追記が拒否されます。対策は、スタートアップスクリプト(SYSTEM)へ寄せる、またはGPPのスケジュールタスクで最上位の特権にすることです。
32bit/64bitの違いで、意図しないパスを触っている
環境によっては、32bitプロセス経由でcmdが呼ばれ、ファイルシステムリダイレクトの影響を受けることがあります。HOSTSは通常System32配下ですが、実行経路に不安がある場合は、ログに%SystemRoot%やターゲットパスを必ず出して、どのパスを触っているかを固定してください。
セキュリティ製品がHOSTS改変をブロック/復元している
EDRやウイルス対策ソフトのポリシーで、HOSTSへの変更が禁止されていたり、変更を検知して元に戻す設定になっていることがあります。BAT側では「成功したように見える」のに、数秒後に元へ戻るケースもあります。追記後に再確認する処理(サンプルの最後のfindstr)と、製品側ログ/イベントログの確認が有効です。
改行や文字コードが崩れて、意図しない行になっている
追記したつもりでも、ファイル末尾に改行が無いと最終行に連結してしまい、結果的に名前解決が効かないことがあります。また、全角スペースやタブ、文字コードの混在でトラブルになることもあります。運用では、追加する行を半角スペース区切りで統一し、コメントを付けるなら短く一定の形式にするのがおすすめです。
運用で事故を防ぐコツ
- 追加行には識別子(コメント)を付ける:例
192.0.2.10 example.internal # managed-by-gpoのようにして、後から検索・削除・棚卸しをしやすくする。 - バックアップの世代を持つ:直近1つだけでなく、日付付きで残す運用も検討する(端末台数が多いほど復旧が重要)。
- 対象端末を絞る:OUやセキュリティフィルタリングで、必要な端末だけに適用する。HOSTSは影響範囲が大きいため、全社一括より段階展開が安全。
- 「本当にHOSTSが最適か」を一度考える:恒久対応ならDNS、短期回避ならHOSTSなど、目的に合った手段を選ぶ。HOSTSは簡単な反面、端末ごとの状態差が出やすい。
まとめ:GPOでHOSTSを確実に書き換えるには、ACLを整えて実行主体を揃える
ローカルで管理者実行すると成功するのに、GPO経由だと反映されない場合、原因の多くは実行ユーザー(セキュリティコンテキスト)の違いと、HOSTSに対するアクセス権(ACL)の不足です。
GPOの「ファイル システム」でHOSTSファイルのACLを明示的に整え、スクリプトをSYSTEM(スタートアップスクリプトや最上位特権タスク)で実行する設計に寄せると、端末差が出にくく、運用も安定します。あわせて、バックアップ・重複防止・ログの3点を入れて、無音失敗に強い実装にしておくと安心です。

コメント