Windows 的 VPN 连接不会把 DNS 服务器存进你在“设置”里编辑的配置文件。隧道建立时,客户端与网关协商 IP 配置,网关下发一份解析器列表,Windows 再把它应用到隧道适配器上。那个适配器与你的 Wi-Fi 或以太网是分开的接口,而列表属于接口,不属于配置文件。一旦弄清哪个对象持有该值,在 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 创建的全体用户连接一般需要提权的 shell。

cmdlet 本身只有一行,微软的 Set-DnsClientServerAddress 参考文档中有记载:

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

有两种失败方式值得一眼认出。别名写错会从 cmdlet 得到报错,那是好结果,因为沉默会更糟。cmdlet 正确却看不出效果,通常意味着你看错了适配器:另一个客户端残留的隧道适配器、描述相近的物理网卡,或沙箱网络工具创建的第二个虚拟适配器。

为什么重连会让改动失效

这次覆盖属于某一个接口实例。当客户端拆掉适配器并在下次连接时重建,下发的值会再次被应用,你的列表就没了。有些客户端每次连接都重建接口;另一些在整个会话期间复用。比较两次连接之间 Get-NetAdapter 里的接口索引,你就知道自己属于哪种行为。

有三种持久的答案,而把它们叠在一起会带来各自的缺陷。连接专属的 DNS 后缀加上 一条 NRPT 规则,只把内部命名空间送给内部解析器,公共名称不受影响。施加在 VPN 连接上的组策略或 MDM 设置在连接时设定 DNS,无需任何脚本。响应连接事件并重新运行 cmdlet 的计划任务是最笨的办法,但它有效,而且会留下日志。为 DNS 选定一个负责人,并写下是哪一个。

单标签的内部名称还需要后缀搜索列表。Set-DnsClientGlobalSetting -SuffixSearchList 是全机范围的,因此它会改变机器上每个适配器的解析,包括以太网。在它进入镜像之前,先在实验机上测试。

验证解析,而不仅是设置

适配器上列出解析器,只能证明某个值被写进去了。直接问目标服务器,再走正常路径问一次:

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

这种差异告诉你故障在哪。直接查询有应答、普通查询失败:适配器设置或后缀列表没有生效。两者都失败:通过隧道到不了解析器,所以在再次动 DNS 之前先看路由和防火墙规则。直接查询失败、普通查询却从别处应答:拆分 DNS 配置错了,内部名称正由公共解析器回答,这是策略问题,然后才是连通性问题。

把测试跑两遍,一次在刚连上之后,一次在断开重连之后,并比较两次运行中 Get-DnsClientServerAddress 的输出。如果下发的值在第二次连接时又回来了,说明这次覆盖与适配器同生共死,只有上一节的 NRPT 或策略路径才撑得住。把两份记录和连接的时戳都留着;它们比再来一轮编辑更快地了断“是否留得住”这个问题。

相关文章