Windowsの起動時に、自宅LAN接続時だけhostsを自動切り替えする

(Geminiにより生成したイメージ画像)

自宅サーバーを運用していると、自宅LANに接続しているときだけ、特定のドメインを自宅サーバーのローカルIPアドレスへ向けたいことがあります。

今回は、Windowsのログオン時にPowerShellを実行し、自宅の有線LANに接続しているときだけhostsを有効化するようにしました。

自宅以外のネットワークでは、hostsファイルに記載している設定を自動的に削除します。

1.hostsに登録する内容

自宅サーバーのIPアドレスを、使用しているドメインに割り当てます。

192.168.X.XXX example.work
192.168.X.XXX cloud.example.work
192.168.X.XXX mono.example.work

ここで使用しているIPアドレスやドメインは、実際の環境では自分のサーバーに合わせて変更します。

2.PowerShellのスクリプトを作成する

以下の内容のファイルを、Cドライブの直下に作成してps1ファイルとして保存します。(C:\home-hosts.ps1)

# home-hosts.ps1
# 自宅の有線LAN接続時だけ、自宅サーバーへのhosts設定を有効にする

$HostsFile = "$env:SystemRoot\System32\drivers\etc\hosts"

# 自宅LAN
$HomeNetwork = "192.168.X."

# 自宅サーバー
$ServerIP = "192.168.X.XXX"

# hostsで管理するドメイン
$Domains = @(
    "example.work",
    "cloud.example.work",
    "mono.example.work"
)

# 管理する範囲を示す目印
$StartMarker = "# --- HOME HOSTS START ---"
$EndMarker   = "# --- HOME HOSTS END ---"

# 管理者権限チェック
$CurrentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
$Principal = New-Object Security.Principal.WindowsPrincipal($CurrentUser)

if (-not $Principal.IsInRole(
    [Security.Principal.WindowsBuiltInRole]::Administrator
)) {
    Write-Host "Run as Administrator."
    exit 1
}

# 有線LANを取得
$Ethernet = Get-NetAdapter -Physical |
    Where-Object {
        $_.Status -eq "Up" -and
        $_.MediaType -eq "802.3"
    }

# 自宅の有線LANか判定
$AtHome = $false

foreach ($Adapter in $Ethernet) {
    $Config = Get-NetIPConfiguration -InterfaceIndex $Adapter.ifIndex

    foreach ($IP in $Config.IPv4Address) {
        if ($IP.IPAddress.StartsWith($HomeNetwork)) {
            $AtHome = $true
        }
    }
}

# hostsを読み込む
# 元の内容はそのまま保持する
$Hosts = @(Get-Content $HostsFile)

# 以前の自動設定部分だけ削除
$NewHosts = @()
$InsideManagedBlock = $false

foreach ($Line in $Hosts) {

    if ($Line -eq $StartMarker) {
        $InsideManagedBlock = $true
        continue
    }

    if ($Line -eq $EndMarker) {
        $InsideManagedBlock = $false
        continue
    }

    if (-not $InsideManagedBlock) {
        $NewHosts += $Line
    }
}

$Hosts = $NewHosts

# 自宅なら末尾にhosts設定を追加
if ($AtHome) {

    Write-Host "Home wired LAN detected."
    Write-Host "Enabling hosts entries."

    $Hosts += ""
    $Hosts += $StartMarker

    foreach ($Domain in $Domains) {
        $Hosts += "$ServerIP $Domain"
        Write-Host "ON: $Domain"
    }

    $Hosts += $EndMarker
}
# 自宅以外なら追加しない
else {

    Write-Host "Home wired LAN not detected."
    Write-Host "Disabling hosts entries."

    foreach ($Domain in $Domains) {
        Write-Host "OFF: $Domain"
    }
}

# hostsを書き戻す
# Set-ContentではなくWriteAllLinesを使用
[System.IO.File]::WriteAllLines(
    $HostsFile,
    $Hosts,
    [System.Text.Encoding]::ASCII
)

# DNSキャッシュをクリア
Clear-DnsClientCache

Write-Host "Completed."

3.スクリプトのテスト

PowerShellから手動で実行して動作を確認します。

自宅以外のネットワークでは、次のように表示されます。

Home wired LAN not detected.
Disabling hosts entries.
OFF: example.work
OFF: cloud.example.work
OFF: mono.example.work
Completed.

この状態でhostsファイルを確認すると、以下の3行が削除されています。

192.168.X.XXX example.work
192.168.X.XXX cloud.example.work
192.168.X.XXX mono.example.work

4.タスクスケジューラに登録する

Windowsの「タスク スケジューラ」を起動します。

Win + R を押して taskschd.msc と入力すると起動できます。

「タスク スケジューラ ライブラリ」で「タスクの作成」を選択します。

5.全般タブの設定

タスク名を設定します。

家のLAN接続の時だけHosts切替

「ユーザーがログオンしているときのみ実行する」を選択し、「最上位の特権で実行する」にチェックを入れます。

6.トリガータブの設定

トリガーは「ログオン時」にします。

ユーザーは「任意のユーザー」にしておけば、Windowsのどのユーザーでログオンしても実行できます。

7.操作タブの設定

「操作」タブで「新規」を選択します。

プログラム/スクリプト:

powershell.exe

引数:

-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File "C:\home-hosts.ps1"

「-WindowStyle Hidden」を指定することで、Windowsへのログオン時にPowerShellの青いウインドウを表示しないようにしています。

8.保存してテスト

タスクを保存したら、「タスク スケジューラ ライブラリ」から作成したタスクを選択し、「実行」で手動テストできます。

自宅の有線LANに接続している場合はhostsに設定の3行が追加され、自宅以外のネットワークでは対象の設定の3行が削除されます。

これで、ネットワークを切り替えるたびにhostsファイルを手動で編集する必要がなくなりました。

さらに、、、

ネットワーク接続の変化、つまりLANケーブルを抜いて無線LANになった時や、再びLANケーブルに接続したときなどにも対応できたらいいんじゃないかと思い、ネットワーク接続の状態が変化したときにも、同じPowerShellスクリプトを実行するようにしました。

イベントトリガーを追加する

タスクスケジューラで、前回作成した「家のLAN接続の時だけHosts切替」を開きます。

「トリガー」タブから「新規」を選択し、「タスクの開始」を「イベント時」に変更します。

「設定」は「カスタム」を選択し、「新しいイベント フィルター」を開きます。

「XML」タブを選択し、「クエリを手動で編集する」にチェックを入れ、次のXMLを設定します。

<QueryList>
<Query Id="0" Path="Microsoft-Windows-NetworkProfile/Operational">
<Select Path="Microsoft-Windows-NetworkProfile/Operational">
*[System[(EventID=4004)]]
</Select>
</Query>
</QueryList>

イベントID 4004は、ネットワークの状態が変更されたときに記録されるイベントです。

これをトリガーにすることで、LANケーブルを抜いたときや接続したときにPowerShellスクリプトが実行されます。

バッテリー駆動でも実行できるようにする

もう一つ確認しておきたいのが、タスクの「条件」です。

初期状態では「コンピューターをAC電源で使用している場合のみタスクを開始する」が有効になっている場合があります。
ノートPCなどでは、LANを抜き差ししたときにバッテリー駆動になっていることもあります。
そのため、この項目のチェックを外しておきます。
これで、AC電源に接続していない状態でもネットワークの変化をきっかけにタスクが実行されます。

実際の動作

これで、次のように自動的に切り替わるようになりました。

自宅の有線LANに接続
↓
自宅LANを検出
↓
hostsに自宅サーバーへの設定を追加

LANケーブルを抜く
↓
自宅LANではないと判定
↓
hostsの管理ブロックを削除

Wi-Fiへ切り替えた場合も、自宅の有線LANではないため、hostsの設定は削除されます。

hostsファイルそのものを無条件に書き換えるのではなく、スクリプトが管理する範囲を

--- HOME HOSTS START ---

と

--- HOME HOSTS END ---

で囲んでおくことで、その部分だけを追加・削除するようにしています。

そのため、もともとhostsファイルに書かれているコメントや別の設定はそのまま残ります。

これで、Windowsへのログオン時だけでなく、ネットワーク接続が変わったタイミングでも、自宅LAN用のhosts設定が自動的に切り替わるようになりました。

🗂  Windows

↓

Getting Started

記事は右側のリストメニューから探せます。
初めての方は下のおすすめ記事からどうぞ。

Quote of the Day

CSSでできることはCSSで。

— ヨシオ
↑