只断开一个 OpenVPN GUI 配置,而不是所有隧道
由 GUI 管理的隧道要用 GUI 命令,由服务管理的隧道要用服务控制。动手写脚本之前,先弄清这个配置归哪个程序所有。
用脚本断开连接通常只因为一个原因失败:脚本找错了所有者。由社区版 OpenVPN GUI 管理的隧道属于该 GUI 的会话,由 Windows 服务启动的隧道属于该服务,而 OpenVPN Connect 两者都不属于。请按顺序完成这些检查,一旦所有者不明确就停下来。因为所有者含糊就发出 kill 命令,正是把一个配置的断线变成整站中断的方式。
对于由 GUI 管理的连接,有用的命令是发给 GUI 的消息,而不是发给 openvpn.exe 的信号。
先确认所有者
在写任何东西之前,先看看到底是哪个程序在显示已连接状态。托盘图标意味着归 GUI 会话所有。服务条目意味着归服务所有。带独立配置列表的单独应用窗口意味着两者都不是,此时适用它自己的、与版本相关的接口。
也要检查账号和桌面会话。以其他用户身份、或在非交互式会话中运行的计划任务,不应被假定为控制着登录用户所看到的那个 GUI。这种错配会产生一条干净退出却什么都不改变的命令,而在日志里排查这种故障代价最高。
然后发送所有者自己的断开命令
如果 GUI 安装在示例路径下,并且存在一个名为 office 的配置,整条命令只有一行:
"C:\Program Files\OpenVPN\bin\openvpn-gui.exe" --command disconnect office把它换成你真实的安装路径,以及 GUI 所显示的、大小写完全一致的配置名。项目的命令文档列出了受支持的 GUI 控制项,而这个示例只属于 OpenVPN GUI —— 它不是给每个名字里带 OpenVPN 的应用都能用的命令。
对于归服务所有的隧道,正确的控制对象是服务,而不是 GUI 的可执行文件。在停止任何东西之前,先检查已安装的服务以及它管理的配置,因为一次停止可能同时让多条隧道掉线,而且你拿不到按配置分列的结果。
确认没有别的东西掉线
GUI 还记录了一条 disconnect_all 命令,而它的作用范围正是它不适合只停 office 这类脚本的原因。如果你图省事想用它,先问问那台机器上还连着别的什么,用户又会怎样察觉。
taskkill /F /IM openvpn.exe 在两个层面更糟。它按可执行文件名挑选进程,并且强制终止,所以既没有表达配置名,也没有走所有者正常的断开流程。把这种做法叫作优雅关闭,等于把两个问题一起藏在一个退出状态后面。
无论走哪条路,都要在变更之前核实影响范围:列出已连接的配置,记下哪些必须存活,之后再复查一遍。
看状态,而不是看退出码
请求断开之后,要通过所有者去读取那条指定连接的状态,而不是相信命令的返回值。如果下一步需要在拆除之后使用网络,就用明确的超时去等这个状态变化,而不是假定进程一返回清理就已完成。与拆除抢跑的脚本会间歇性失败,而且背锅的会是 VPN。
如果状态始终不变,那所有者多半不是你找的那个人。在升级到更强硬的手段之前,先重新核对会话和账号。
日志里该写什么
记录配置名、你所针对的所有者、启动上下文,以及最终得到的状态。不要把完整配置或凭据倒进任务日志;如果命令行里含有指向机密文件的路径,也不要记录命令行。
一条点名配置和上下文的错误信息,就足以让下一个人复现问题。只记下通用退出码的日志会把人送回起点,而猜测正是从那里重新开始的。