并不存在 Import-VpnProfile 这个 cmdlet,而看起来最接近的 Add-VpnConnection 从不读取 .ovpn 或 .conf 文件。它用你传入的参数拼装出 Windows 原生配置文件,所以这里的第一个检查点是文件格式,而不是命令行。如果网关支持 SSTP、IKEv2、L2TP/IPsec 或 PPTP,Windows 就能拥有该配置文件,列表其余部分同样适用。如果你拿到的是 OpenVPN 或 WireGuard 文件,请停在第一步:那些客户端有自己的导入器。

第 1 步:确认 Windows 真正能拥有的配置文件

先在这台机器上运行 Get-Command -Module VpnClient。Windows 10、Windows 11 和 Server 2016 或更高版本都自带该模块;如果缺失,任何抄来的脚本都无法让这台主机接受原生配置文件。真正重要的 cmdlet 是 Add-VpnConnection、Get-VpnConnection 和 Remove-VpnConnection,参数列表见 Add-VpnConnection 参考文档,值得完整读一遍。

原生意味着由 Windows VPN 协议栈终结隧道。它涵盖 IKEv2(通常配计算机证书)、SSTP(内部使用用户或证书身份验证的 TLS)以及带预共享密钥的 L2TP/IPsec。.ovpn 文件是 OpenVPN 脚本,不是 Windows 连接:它带有 remote、cipher 或 tls-auth 这类 Windows 协议栈完全不懂的指令。WireGuard 的 .conf 也是同一回事,里面有 PrivateKey 和 AllowedIPs;把一种转成另一种不是选参数,而是换一套隧道实现。

还有第三条路。如果管理员交给你一份 VPNv2 CSP XML 文档或 Intune 配置文件,那就是 MDM 路径,由预配协议栈应用,而不是 Add-VpnConnection。别把那些节点名翻译成 PowerShell 参数;应当去问是哪个机制在应用这份 XML。

第 2 步:把隧道类型与身份验证方式配对

-TunnelType 和 -AuthenticationMethod 是两个独立参数,网关只关心它们的组合。一个对一个错,得到的配置文件什么也连不上,或者隧道已建立却卡住不动。两者都要显式设置,不要相信为别的服务选定的默认值。

  • IKEv2 配 MachineCertificate:客户端出示计算机证书;同时设置 -EncryptionLevel Required。
  • SSTP 配 Eap:先建 TLS 隧道,再在 EAP 内部走 PEAP/MSCHAPv2 或证书。这需要第 3 步里的 XML。
  • SSTP、L2TP 或 PPTP 配 MSChapv2、Chap 或 Pap:普通用户名和密码,不用 EAP 数据块。
  • L2TP 配 MSChapv2 和 -Lt2pPsk:PSK 负责 IPsec 那一半,用户负责 PPP;两者都必须与服务器一致。

用 splat 把取值集中在一处:

$p = @{
  Name                 = "Corp IKEv2"
  ServerAddress        = "vpn.example.com"
  TunnelType           = "Ikev2"
  AuthenticationMethod = "MachineCertificate"
  EncryptionLevel      = "Required"
  SplitTunneling       = $false
  DnsSuffix            = "corp.example.com"
}
Add-VpnConnection @p -PassThru

-PassThru 返回 Windows 刚写入的对象,因此不必再调用一次就能检查。如果名称已存在,cmdlet 会拒绝执行;-Force 会覆盖它,这在生产笔记本上是错误反射,因为它会悄悄丢掉别人手工配置的内容。

第 3 步:正确交付凭据材料

密码、预共享密钥和 EAP 数据块正是这些脚本常翻车的地方。-EapConfigXmlStream 要的是 XmlDocument 而不是路径,所以先读取文件并强制转换。传字符串会产生一个读起来像架构问题的转换错误,让人去重写本来没问题的 XML。

$eap = [xml](Get-Content -Raw .\peap-mschapv2.xml)
Add-VpnConnection -Name "Corp SSTP" -ServerAddress "sstp.example.com" `
  -TunnelType Sstp -AuthenticationMethod Eap `
  -EapConfigXmlStream $eap -EncryptionLevel Required

那份 XML 不该照着博客片段自己编。它写明 EAP 方法类型和内部身份验证,网关会把两者与自己的策略比对。内部方法不匹配时,会在 TLS 握手完成之后才失败,看起来完全像密码错误,但其实不是。向负责网关的人索取 XML,或者从已经能用的配置文件导出。

对 IKEv2 来说,证书那一半是查存储。-MachineCertificateIssuerFilter 接受一个证书对象,Windows 用它到 LocalMachine\My 里找可用的客户端证书。证书需要私钥和服务器信任的链;缺任何一样,身份验证就会失败且不给出有用细节,所以先检查存储:

Get-ChildItem Cert:\LocalMachine\My |
  Where-Object { $_.HasPrivateKey -and $_.NotAfter -gt (Get-Date) } |
  Select-Object Subject, Issuer, Thumbprint, NotAfter

别把机密留在脚本文件里。在命令行上传入或写进 .ps1 的 PSK,最终会出现在终端记录、保存的会话和共享仓库中,而 -RememberCredential 会缓存用户凭据供以后使用,把一次临时测试变成长期授权。

第 4 步:首次运行前决定作用范围

同一个 cmdlet 会写入两本不同的电话簿。不带 -AllUserConnection 时,配置文件属于你,位于 %APPDATA%\Microsoft\Network\Connections\Pbk\rasphone.pbk。带上它并在提升权限的提示符下运行,所有账户都能看到该配置文件,包括登录屏幕,文件落在 %ProgramData%\Microsoft\Network\Connections\Pbk\rasphone.pbk。

作用范围不是装饰。全用户配置文件才能被服务账户、计划任务或登录前场景使用;每用户配置文件对这三者都不可见。读取对象的方式也不同:Get-VpnConnection 列出当前用户的条目,Get-VpnConnection -AllUserConnection 列出整机范围的条目。现在就选定一种,日后的变更应当当作删除重建,而不是编辑:

# elevated prompt
Remove-VpnConnection -Name "Corp IKEv2" -Force
Add-VpnConnection -Name "Corp IKEv2" -ServerAddress "vpn.example.com" `
  -TunnelType Ikev2 -AuthenticationMethod MachineCertificate `
  -EncryptionLevel Required -AllUserConnection

第 5 步:测试隧道究竟要交付什么

连着的小图标只证明隧道起来了,别的什么也证明不了。先从命令行连接,让失败以文字而不是对话框的形式出现,然后再读回 Windows 记录的内容:

rasdial "Corp IKEv2"
Get-VpnConnection -Name "Corp IKEv2" |
  Select-Object Name, ServerAddress, TunnelType, ConnectionStatus, SplitTunneling
Get-NetRoute -DestinationPrefix "0.0.0.0/0"

状态仍显示已连接时用户报告的两种故障是 DNS 和路由。解析一个内部名称,看看是哪个服务器应答;没有 -DnsSuffix 的配置文件可以隧道完全正常,却让每次内网查询都失败。然后 看看默认路由:关闭拆分隧道时,metric 最低的 0.0.0.0/0 路由应当指向 VPN 接口;开启时只有你预期的前缀才应当如此。如果两者看起来都对而流量仍然不通,问题就在配置文件之外,在策略或网关过滤器里。

连接彻底失败时,错误码会把要复查的步骤缩小到一处:

  • 691:网关拒绝了凭据。回到第 3 步,而不是查隧道。
  • 809:IKEv2 握手从未完成。检查 UDP 500 和 4500,以及证书信任。
  • 789:L2TP/IPsec 预共享密钥缺失或错误。
  • 868:服务器名称无法解析。先修 DNS,再改配置文件。

把可用的命令和它所编码的设置放在一起,下一个人就能重建,而不必从界面反推配置文件。如果确实必须重建,就删掉条目用同样的参数重新创建;给半配置好的配置文件打补丁会留下过期路由和身份验证状态。如果文件本来就不是原生的,回到拥有它的客户端去。把 .ovpn 打扮成 IKEv2 配置文件不叫导入,那叫工单。

相关文章