用户在家登录,连上 VPN,等着以前在办公室会自动出现的驱动器映射。隧道起来了,域也响应了,却什么都没映射。并没有什么东西坏掉:登录脚本是在登录时运行的,而会话开始二十分钟后才打开的隧道并不是登录。把这两件事读成同一件事,人们就会去找一个并不存在的 VPN 故障。

四个决定能把这份意外变成行为正确的流程,第一个只是弄清楚脚本究竟挂在哪些事件上。

脚本挂在你无法重放的生命周期事件上

计算机侧的策略在机器启动时应用,用户侧的策略在有人登录时应用,而后台刷新会循环处理同样的设置,却不重启任何东西。那次刷新会处理脚本扩展,但不会重新运行各个脚本,脚本只在启动、关机、登录或注销时触发。因此 gpupdate /force 可能报告成功,而映射依然缺失;一次干净的刷新并不能证明脚本做过什么。

微软关于策略处理 的参考文档 正好划出了处理扩展与运行其内容之间的这条界线,当有人坚称刷新本应重放脚本时,该引用的就是这一页。

也不是每个脚本在离线时都会失败。只读取本地或缓存材料的脚本可能部分成功,而访问共享资源的脚本会悄无声息地失败,不留下明显痕迹。在归咎网络之前,先检查脚本的实际路径和它能到达的地方。把「脚本不在登录时运行」当作结论时也需要同样的审视,因为计划任务或客户端操作可能正在没人注意的地方完成这项工作。

把工作绑到连接上,而不是登录上

「登录脚本」这个说法背后藏着三件不同的事:用户连上之后映射驱动器、任何人登录之前应用机器配置,以及拉取更新后的策略。它们有各自的时限,只有第二件真正需要在登录前连通。把需求写成带时限的句子,例如:这个映射必须在隧道起来后一分钟内存在。

对于必须发生在连接之后的工作,使用由连接触发的任务,或客户端支持的连接操作。要确认客户端实际发出的是哪个事件,因为 Windows 原生 VPN 客户端引发的事件,第三方客户端并不会引发。对于必须先于登录的机器配置,受支持的答案是设备隧道或另一种登录前方案,而不是桌面出现后才运行的任务。 在真正需要它的身份和会话里运行这项工作,因为以 SYSTEM 创建的映射会落在用户永远看不到的会话里。

行动前先测试就绪状态,并且让失败发出声音

连接事件可能在 DNS 或文件服务器可用之前就到达,所以任务应当测试自己需要什么,而不是假定。解析具体名称,尝试具体连接,并用上限和延迟重试:短循环里的 Resolve-DnsName files.corp.example 能把「还没好」和「永远不行」分开。最后一次尝试之后要报告具体的失败,把名称和错误写进去。

没有日志的无限循环与从未开始的任务无法区分,它还掩盖了过期凭据和防火墙规则之间的差别。

验证四件事,然后让它可重复

试点期间记录四项观察而不是一项:连接事件触发了、任务启动了、资源响应了、请求的变更真的落地了。如果日志停在「任务已启动」,那么无论等多久,真正的失败都看不见。接着运行 gpresult /scope user /v,看会话认为自己持有什么策略,并与你期望的设置比较。列出 GPO 已应用的报告,对映射依然什么也没说。

在扩大范围之前,先让工作可以安全重复,因为客户端会重新连接,任务会再次触发。创建之前检查映射或配置是否已经存在,并记录你发现了什么。每次短暂重连之后都重复一遍工作,正是一个有用的任务变成事故的方式。

自动触发器不适用时,由用户批准、运行同一份已签名脚本的操作是合理的设计。它把时机讲清楚,而不是假装发生过一次登录事件。

相关文章