Windows の VPN 接続は、設定で編集するプロファイルに DNS サーバーを保存しません。トンネルが確立すると、クライアントはゲートウェイと IP 構成を交渉し、ゲートウェイがリゾルバーの一覧を送り、Windows がそれをトンネル アダプターに適用します。そのアダプターは Wi-Fi や Ethernet とは別のインターフェイスであり、一覧はプロファイルではなくインターフェイスに属します。どのオブジェクトが値を持っているかが分かれば、PowerShell での上書きは一つのコマンドであり、上書きを再接続後も保たせることこそ判断が必要な部分です。

アドレスを所有するオブジェクトは何か

RAS は接続が成功したときにトンネル アダプターを作成し、接続が切れたときに削除します。ipconfig /all で表示される DNS サーバーは、その構成のやり取りの間に、IPv4 と IPv6 のアドレスやルートと並んで届きます。値はインターフェイスに紐づくため、Set-DnsClientServerAddress は接続が存在する間だけ存在するものに書き込みます。

この一つの事実が、VPN の DNS をめぐる混乱の大半を説明します。プロファイルは未接続でも調べられますが、指し示すインターフェイスが存在しないため、VPN エイリアスに対して cmdlet を呼ぶログオンスクリプトは、誰かが接続する前に失敗します。元に戻ったように見える変更も説明できます:何も戻っていないのであり、インターフェイスが破棄され、ゲートウェイが送った値で作り直されたのです。

DNS に触れる前にエイリアスを見つける

プロファイル名とインターフェイスのエイリアスは通常同じ文字列ですが、同じオブジェクトではありません。Get-VpnConnection はプロファイルを一覧し、Get-NetAdapter は Windows が実際に持つインターフェイスを一覧します。DNS の cmdlet が求めるのは後者で、この二つは人が思うより頻繁に食い違います、とくにクライアントがアダプター名に "(RAS)" のような記述子を付ける場合に顕著です。

プロファイルが存在しなければ、PowerShell でネイティブなエントリを作成できます。トンネルの種類と認証はゲートウェイが提供するものと一致していなければならず、不一致は作成時ではなく接続時に表面化します:

Add-VpnConnection -Name "Corporate" -ServerAddress vpn.example.net `
  -TunnelType Ikev2 -EncryptionLevel Required `
  -AuthenticationMethod Eap -AllUserConnection

一度接続し、DNS のコマンドを書く前に実際のエイリアスを読み取ります:

rasdial.exe "Corporate"
Get-NetAdapter | Where-Object InterfaceDescription -like "*VPN*"
Get-DnsClientServerAddress -InterfaceAlias "Corporate"

上書きは正しい順序で適用する

構文よりも順序が重要です。アダプターが起動していて、エイリアスが解決でき、アカウントにインターフェイス設定の変更が許可されている必要があります。ユーザーごとの接続は通常サインイン中のユーザーの変更を受け付けますが、-AllUserConnection で作成した全ユーザー接続は一般に昇格したシェルを必要とします。

cmdlet 自体は一行で、Microsoft の Set-DnsClientServerAddress のリファレンスに記載されています:

Set-DnsClientServerAddress -InterfaceAlias "Corporate" -ServerAddresses 10.20.0.53,10.20.0.54
Get-DnsClientServerAddress -InterfaceAlias "Corporate" -AddressFamily IPv4

失敗のしかたは二種類あり、見れば分かります。誤ったエイリアスは cmdlet からエラーを返しますが、沈黙よりはましなので、それは良い結果です。正しい cmdlet なのに目に見える効果がない場合は、たいてい別のアダプター——別のクライアントが残したトンネル アダプター、似た説明の物理 NIC、サンドボックスのネットワーク ツールが作った二つ目の仮想アダプター——を見ています。

再接続で変更が取り消される理由

上書きはインターフェイスの一つのインスタンスに属します。クライアントがアダプターを破棄し、次の接続で作り直すと、送られた値が再び適用され、一覧は消えます。接続のたびに作り直すクライアントもあれば、セッションの間ずっと使い回すクライアントもあります。Get-NetAdapter のインターフェイス インデックスを二回の接続で比べれば、どちらの挙動か分かります。

持続する答えは三つあり、重ねて使うとそれ自体が不具合を生みます。接続固有の DNS サフィックスと NRPT ルールを組み合わせれば、内部の名前空間だけを内部リゾルバーに送り、公開名には触れません。VPN 接続に適用するグループ ポリシーや MDM の設定は、スクリプトなしで接続時に DNS を設定します。接続イベントに反応して cmdlet を再実行するスケジュール タスクは乱暴な選択ですが、動作し、ログも残ります。DNS の所有者を一つに決め、どれにするかを書き留めてください。

一つのラベルだけの内部名にはサフィックス検索リストも必要です。Set-DnsClientGlobalSetting -SuffixSearchList はマシン全体に適用されるため、Ethernet を含むそのマシンのすべてのアダプターの解決を変えます。イメージに取り込む前にラボのマシンで試してください。

設定だけでなく解決を確認する

アダプターに一覧されたリゾルバーは、値が書き込まれたことしか証明しません。意図したサーバーに直接問い合わせ、次に通常の経路で問い合わせます:

Resolve-DnsName server01.corp.example -Server 10.20.0.53
Resolve-DnsName server01.corp.example

この分かれ方で、どこに不具合があるか分かります。直接の問い合わせが答え、通常の問い合わせが失敗するなら、アダプターの設定かサフィックス リストが効いていません。どちらも失敗するなら、トンネル経由でリゾルバーに到達できていないので、DNS に再び触る前にルートとファイアウォール規則を確認してください。直接の問い合わせが失敗し、通常の問い合わせが別の場所から答えるなら、分割 DNS が誤って構成され、内部名が公開リゾルバーに答えられており、これは接続性の問題である前にポリシーの問題です。

テストは二回、接続直後に一回、切断して再接続した後に一回実行し、両方の Get-DnsClientServerAddress の出力を比べます。二回目の接続で送られた値が戻っていれば、上書きはアダプターとともに生きて死んだのであり、前の節の NRPT かポリシーの経路だけが持ちこたえます。両方の記録と接続のタイムスタンプを保管してください;もう一回編集を重ねるより速く、残るかどうかの問いに決着がつきます。

関連記事