GPOでWindows 10/11のHOSTSファイルを確実に書き換える方法|スタートアップスクリプトが効かない原因とACL対策

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ファイルを登録して権限を付与する手順

  1. 「ファイル システム」を右クリックし、[ファイルの追加]を選択します。
  2. パスに次を入力します:
    C:\Windows\System32\drivers\etc\hosts
  3. アクセス許可の設定画面で、スクリプトが実行される主体に対して書き込みを許可します。
  4. 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が期待通りかicaclsSYSTEM(または指定グループ)に書き込み/変更がある
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点を入れて、無音失敗に強い実装にしておくと安心です。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次