PowerShellを用いてホストファイルを編集する詳細ガイドという問いには、管理者で原本を別名保存し、IPとホスト名を構文検証し、既存の有効行に同じ名前がない場合だけ追加するという方法で答えます。hostsはローカル名解決へ直接影響し、誤った行はブラウザーや業務アプリを別IPへ向ける。Add-Contentは重複や妥当性を自動検査しない。この記事ではhostsの絶対パス、バックアップSHA256、追加するIPアドレスと完全修飾ホスト名を作業単位にするを判断軸にし、実行前の確認、記事固有のコード、合否判定、戻し方を一続きで示します。
DNSサーバー設定ではなく、ローカル端末一台のhostsへ限定した例外設定を扱う。完了は「ファイル末尾に正確な一行があり、Get-Contentと名前解決テストが承認IPを示し、他行のハッシュ差分を説明できる」と定義します。対象が取れない場合は「対象ホスト名が既存コメントにしかなければ新規行として扱うが、有効な別IP行がある場合は競合として止める」として切り分け、推測で成功扱いにしません。
DNSよりhostsが優先される影響
管理者で原本を別名保存し、IPとホスト名を構文検証し、既存の有効行に同じ名前がない場合だけ追加する。hostsファイルの安全な編集ではこの進め方により、操作したという事実ではなく、期待する状態へ到達したかでタイトルの問いへ答えられます。DNSサーバー設定ではなく、ローカル端末一台のhostsへ限定した例外設定を扱う。
DNSよりhostsが優先される影響の合格条件は、ファイル末尾に正確な一行があり、Get-Contentと名前解決テストが承認IPを示し、他行のハッシュ差分を説明できることです。作業時刻、実行ユーザー、端末名を添え、判断に使った値が後から追える形にします。
現在ファイルをハッシュ付きで保存
現在ファイルをハッシュ付きで保存は変更前の基準点です。hostsの絶対パス、バックアップSHA256、追加するIPアドレスと完全修飾ホスト名を作業単位にするを出力に含め、取得時刻と一緒に保存します。値だけを切り取ると別対象との比較になるため、識別列を省きません。
$hostsPath = Join-Path $env:WINDIR 'System32\drivers\etc\hosts'
$backupPath = 'C:\ApprovedBackup\hosts.before'
function Get-IttripFileSha256([string]$Path) { (Get-FileHash -LiteralPath $Path -Algorithm SHA256 -ErrorAction Stop).Hash.ToUpperInvariant() }
$hostsItem = Get-Item -LiteralPath $hostsPath -Force -ErrorAction Stop
if ($hostsItem.PSIsContainer -or ($hostsItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) { throw 'hostsがregular non-reparse fileではありません。' }
if (-not (Test-Path -LiteralPath $backupPath -PathType Leaf)) {
Write-Host '変更前にエクスプローラーを管理者権限で使い、hostsを承認済みバックアップフォルダーへ手動コピーしてください。既存バックアップは上書きしません。'
throw '手動バックアップがありません。'
}
$backupItem = Get-Item -LiteralPath $backupPath -Force -ErrorAction Stop
if ($backupItem.Attributes -band [IO.FileAttributes]::ReparsePoint) { throw 'バックアップがreparse pointです。' }
$beforeHash = Get-IttripFileSha256 $hostsPath
$backupHash = Get-IttripFileSha256 $backupPath
if ($backupHash -ne $beforeHash) { throw '手動バックアップSHA256が現在hostsと一致しません。' }
$beforeBytes = [IO.File]::ReadAllBytes($hostsPath)
$beforeLines = @([IO.File]::ReadAllLines($hostsPath))
$hostsBaseline = [pscustomobject]@{ FullName=$hostsItem.FullName; Length=$hostsItem.Length; LastWriteTimeUtc=$hostsItem.LastWriteTimeUtc; Attributes=[string]$hostsItem.Attributes; Sha256=$beforeHash; Backup=$backupPath; BackupSha256=$backupHash }
$hostsBaseline | Format-List
hostsはローカル名解決へ直接影響し、誤った行はブラウザーや業務アプリを別IPへ向ける。Add-Contentは重複や妥当性を自動検査しない。出力が多い場合も最初から無理に一件へ絞らず、候補数と除外理由を残してから対象を決めます。
追加行のIPとホスト名を検証
追加行のIPとホスト名を検証では、管理者で原本を別名保存し、IPとホスト名を構文検証し、既存の有効行に同じ名前がない場合だけ追加する。hostsファイルの安全な編集の例中にある名前、パス、ID、時刻はサンプルなので、そのまま本番へ貼らず、直前の読み取り結果から承認値を入れます。
$ipText='192.0.2.25';$hostName='app01.contoso.example';$parsedIp=$null
if(-not[ipaddress]::TryParse($ipText,[ref]$parsedIp)){throw 'IPアドレスが不正です。'};if($hostName -notmatch '^(?=.{1,253}$)(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+[A-Za-z]{2,63}$'){throw 'ASCII FQDNを指定してください。'}
if($beforeBytes.Length -ge 2 -and (($beforeBytes[0]-eq 0xFF -and $beforeBytes[1]-eq 0xFE) -or ($beforeBytes[0]-eq 0xFE -and $beforeBytes[1]-eq 0xFF))){throw 'UTF-16 hostsはこのASCII exact-append例の対象外です。'}
$conflicts=@(foreach($line in $beforeLines){$e=($line -split '#',2)[0].Trim();if(-not$e){continue};$p=$e -split '\s+';if($p.Count-ge2 -and $p[1..($p.Count-1)] -contains $hostName){$line}});if($conflicts.Count){throw '同じhostnameの有効行があります。'}
$prefixBytes=if($beforeBytes.Length -eq 0 -or $beforeBytes[-1] -eq 10){[byte[]]@()}else{[Text.Encoding]::ASCII.GetBytes([Environment]::NewLine)};$approvedLine="$ipText$([char]9)$hostName$([Environment]::NewLine)";$lineBytes=[Text.Encoding]::ASCII.GetBytes($approvedLine)
$expectedPostBytes=[byte[]]::new($beforeBytes.Length+$prefixBytes.Length+$lineBytes.Length);[Array]::Copy($beforeBytes,0,$expectedPostBytes,0,$beforeBytes.Length);[Array]::Copy($prefixBytes,0,$expectedPostBytes,$beforeBytes.Length,$prefixBytes.Length);[Array]::Copy($lineBytes,0,$expectedPostBytes,$beforeBytes.Length+$prefixBytes.Length,$lineBytes.Length)
$sha=[Security.Cryptography.SHA256]::Create();try{$expectedPostHash=([BitConverter]::ToString($sha.ComputeHash($expectedPostBytes))).Replace('-','')}finally{$sha.Dispose()}
$token="OPEN-HOSTS-EDITOR $ipText $hostName BEFORE=$beforeHash EXPECTED=$expectedPostHash BACKUP=$backupHash";if((Read-Host "手動編集手順を表示する場合は $token を入力") -ne $token){throw '中止しました。'}
if((Get-IttripFileSha256 $hostsPath)-ne$beforeHash -or (Get-IttripFileSha256 $backupPath)-ne$backupHash){throw '編集直前のhosts/backup SHA256が変わりました。'}
[pscustomobject]@{Hosts=$hostsPath;Backup=$backupPath;ApprovedFinalLine=($approvedLine.TrimEnd([char[]]@(13,10)));BeforeSha256=$beforeHash;ExpectedPostSha256=$expectedPostHash;ExpectedByteLength=$expectedPostBytes.Length;ExecuteAutomatically=$false}
Write-Host '管理者メモ帳で末尾へ表示された1行だけを追加し、既存encoding/BOM/newlineを変えず1回保存します。保存後hashがexpected post-imageと違えば未完了です。'
hosts全体をSet-Contentで作り直したり、HTTPから取得した内容で置換したりしない。文字コードと改行も維持する。hostsファイルの安全な編集でプレビュー対応コマンドを使える場合はWhatIfを先に実行し、非対応の操作は対象一覧と引数を画面へ出して人が承認してから一度だけ実行します。
重複がないときだけ一行加える
重複がないときだけ一行加えるでは同じ対象を別経路でもう一度読みます。判定したいのは「コマンドが終了したか」ではなく、ファイル末尾に正確な一行があり、Get-Contentと名前解決テストが承認IPを示し、他行のハッシュ差分を説明できるかどうかです。
Read-Host '手動追加後、Enterでbyte-exact post-imageと名前解決を検証します'
$afterHash=Get-IttripFileSha256 $hostsPath;$byteExact=$afterHash -eq $expectedPostHash;$resolved=@();$resolutionExact=$false
if($byteExact){try{$resolved=@([Net.Dns]::GetHostAddresses($hostName)|ForEach-Object IPAddressToString);$resolutionExact=$resolved -contains $ipText}catch{$resolutionExact=$false}}
[pscustomobject]@{HostName=$hostName;ExpectedIP=$ipText;Resolved=($resolved-join ',');BeforeSha256=$beforeHash;ExpectedPostSha256=$expectedPostHash;ActualPostSha256=$afterHash;OriginalBytePrefixBomEncodingNewlinesPreserved=$byteExact;NameResolutionExact=$resolutionExact;Completion=if($byteExact-and$resolutionExact){'Verified'}else{'IncompleteRecoveryRequired'}}
if(-not($byteExact-and$resolutionExact)){throw 'byte-exact expected post-imageまたは承認IPへの名前解決が不一致です。次のstate-bound manual recovery blockを実行します。'}
対象ホスト名が既存コメントにしかなければ新規行として扱うが、有効な別IP行がある場合は競合として止める。hostsファイルの安全な編集の期待値と実測値が一致しないときは追加変更を重ねず、対象識別、権限、ポリシー、時間差の順で原因を分けます。
Resolve-DnsNameではなく名前解決全体を確認
hosts全体をSet-Contentで作り直したり、HTTPから取得した内容で置換したりしない。文字コードと改行も維持する。Resolve-DnsNameではなく名前解決全体を確認に該当したら、警告を消して継続するのではなく、どの条件で止まったかを記録します。
対象ホスト名が既存コメントにしかなければ新規行として扱うが、有効な別IP行がある場合は競合として止める。hostsファイルの安全な編集ではエラー本文、FullyQualifiedErrorId、対象ID、直前に成功した段階を残すと、別担当者が安全な地点から調査できます。
構文違反や権限拒否で中止
取得したバックアップを内容確認後に管理者権限で戻し、名前解決結果とファイルハッシュを再確認する。復旧操作にも同じ識別条件を使い、名前が似た別対象へ戻し処理を適用しません。
- hostsファイルの安全な編集の変更前値と取得時刻
- 復旧対象: hostsの絶対パス、バックアップSHA256、追加するIPアドレスと完全修飾ホスト名を作業単位にする
- 復旧後の判定: ファイル末尾に正確な一行があり、Get-Contentと名前解決テストが承認IPを示し、他行のハッシュ差分を説明できる
- 再実行を止める条件: hosts全体をSet-Contentで作り直したり、HTTPから取得した内容で置換したりしない。文字コードと改行も維持する
バックアップから内容を戻す
一時対応には期限と変更理由をコメントで添え、DNS修正後に削除するチケットを作る。hostsファイルの安全な編集を繰り返す場合は、正常、対象なし、要承認、失敗を異なる終了状態として記録し、前回値との比較だけで異常を決めません。
| バックアップから内容を戻すの識別軸 | hostsの絶対パス、バックアップSHA256、追加するIPアドレスと完全修飾ホスト名を作業単位にする |
| 採用する実測 | ファイル末尾に正確な一行があり、Get-Contentと名前解決テストが承認IPを示し、他行のハッシュ差分を説明できる |
| 0件時の扱い | 対象ホスト名が既存コメントにしかなければ新規行として扱うが、有効な別IP行がある場合は競合として止める |
| 保留にする兆候 | hosts全体をSet-Contentで作り直したり、HTTPから取得した内容で置換したりしない。文字コードと改行も維持する |
質問:キャッシュの扱い
Q. hostsファイルの安全な編集は管理者PowerShellなら必ず成功しますか。A. いいえ。hostsはローカル名解決へ直接影響し、誤った行はブラウザーや業務アプリを別IPへ向ける。Add-Contentは重複や妥当性を自動検査しない。管理者権限は対象や製品仕様の不一致を解消しません。
Q. 0件を正常終了にできますか。A. 対象ホスト名が既存コメントにしかなければ新規行として扱うが、有効な別IP行がある場合は競合として止める。要件上0件が許される場合だけ正常とし、検出できなかった状態とは分けて報告します。
hostsファイルの安全な編集の実行記録には、開始前の対象候補、採用した識別値、実行したコード、終了後の実測、除外した候補と理由を同じ作業番号で残します。特に「hostsの絶対パス、バックアップSHA256、追加するIPアドレスと完全修飾ホスト名を作業単位にする」を省くと、後日の再確認で別対象の値を比較するおそれがあります。画面コピーだけでなく、日時と端末名を含む構造化した出力も保存します。
PowerShellを用いてホストファイルを編集する詳細ガイドを定期手順へ組み込む場合も、初回は対話的に候補を確認します。正常時は「ファイル末尾に正確な一行があり、Get-Contentと名前解決テストが承認IPを示し、他行のハッシュ差分を説明できる」、判定不能時は「対象ホスト名が既存コメントにしかなければ新規行として扱うが、有効な別IP行がある場合は競合として止める」、中止時は「hosts全体をSet-Contentで作り直したり、HTTPから取得した内容で置換したりしない。文字コードと改行も維持する」をそれぞれ別の結果として扱います。これにより、0件や例外を都合よく成功へ丸めず、次の担当者が同じ対象と条件で追試できます。
修正後コードの合格条件:Copy-Itemの実行後にバックアップSHA256が原本と一致しなければ追記しません。有効行のホスト名を完全一致で調べ、IPとFQDNを含む承認トークンを入力した場合だけASCII一行を加え、名前解決が期待IPにならなければバックアップから戻せます。
バックアップへ戻す場合の明示承認
$recoveryMode=if($afterHash -eq $expectedPostHash){'RemoveApprovedFinalLine'}else{'RestoreExactBackup'}
$token="OPEN-HOSTS-RECOVERY MODE=$recoveryMode CURRENT=$afterHash BACKUP=$backupHash";if((Read-Host "手動復元手順を表示する場合は $token を入力") -ne $token){throw '復元は承認されませんでした。'}
if((Get-IttripFileSha256 $hostsPath)-ne$afterHash -or (Get-IttripFileSha256 $backupPath)-ne$beforeHash){throw 'recovery直前のcurrent post-imageまたはexact backupが変わりました。'}
if($recoveryMode -eq 'RemoveApprovedFinalLine'){Write-Host '管理者メモ帳で末尾の承認済み1行だけを削除し、既存bytesを変えず1回保存します。'}else{Write-Host 'editorが広範囲を書き換えたため、エクスプローラーでexact hash確認済みbackupをhostsへ一回手動コピーします。current observed post-image以外には上書きしません。'}
Read-Host '手動復元後、Enterで開始前SHA256を再読します';$restoredHash=Get-IttripFileSha256 $hostsPath;[pscustomobject]@{RecoveryMode=$recoveryMode;RestoredSha256=$restoredHash;ExpectedBeforeSha256=$beforeHash;Exact=($restoredHash-eq$beforeHash)};if($restoredHash-ne$beforeHash){throw '手動復元後hashが開始前と一致しません。'}
再修正後は承認後にhostsを排他ロックし、レビュー済みSHA256と同一であることを再確認してから一度だけ書きます。検証失敗時は、自分が作ったpost-imageのSHA256と一致する場合だけ自動復元し、他プロセスの変更を上書きしません。
安全版 r4a-takeover-20260719:PowerShellによるhosts自動書込・自動全体復元を廃止しました。手動バックアップのexact SHA256を確認し、管理者メモ帳で末尾へ一行だけ追加します。復元時はpost-imageとbackupを再照合し、同じ一行だけを手動削除して開始前hashを確認します。
独立監査追補 r4a-r6-20260719:開始前bytesをprefixとして一切変更せず、sanctioned line bytesだけを連結したexpected post-image hashを必須にします。名前解決不一致も未完了とし、観測post-imageに拘束した一行削除またはexact backup手動復元へ分岐します。
公式情報・参考資料
hostsファイルの安全な編集で使うコマンド名、引数、対応環境は次のMicrosoft一次資料で確認しました。記事の確認日は2026年7月17日です。OSやモジュール更新後は、実行端末のGet-Helpと併せて再確認してください。

コメント