解决windows服务器「计划任务」无法运行GUI脚本的问题

1,069 阅读9分钟

背景

之前写过一篇《如何在 windows 服务器上开机启动程序》,原理是用「计划任务」功能实现应用或服务的开机启动,或定时启动。

但是遇到了一个比较麻烦的问题,那就是一些需要 GUI 交互的脚本无法顺利执行,比如:运行一个 python 脚本,自动填写用户名、密码登录某个 APP。因为脚本要用到 pyautogui、pywinauto 这类操作 GUI(模拟鼠标键盘的操作)的库,所以在没有用远程桌面连接 win 服务器的时候,这些脚本是无法正常运行的。

最近又在研究这块,专门深度问了一下 ChatGPT,还真找到了一个解决方法——VNC Server

操作步骤

VNC Server 有很多应用,我随便选了一个 TightVNC。先把使用方法写在前面,后面再介绍原理。

  1. 官网 下载 TightVNC 的安装程序;

  2. 服务器安装 TightVNC,并 Run TightVNC Server,默认端口 5900,并设置访问密码;

  3. 重要)在服务器的安全组策略中,放开 5900 端口的入流量,否则无法连接到远程桌面,如下图: image.png

  4. 客户端,比如自己的 PC,也安装 TightVNC,运行 TightVNC Viewer,输入服务器的 IP,点击 connect,然后输入访问密码,即可登录远程桌面;

  5. (可选)为方便下次登录,直接保存成 .vnc 文件,下次双击即可,如下图: image.png

这样,通过 TightVNC 登录的远程桌面,再去「计划任务」里面启动需要操作 GUI 的脚本就没问题了。可以用下面这个简单的 vbs 脚本实验一下:

MsgBox "Hello, this is a message box!", 64, "Title"

注意:如果用 rdp 登录了远程桌面,那么要重新用 TightVNC 登录一遍,否则就失效了。

ChatGPT 讲原理

我直接把 ChatGPT 给我的答案贴上来吧,它回答的比我全面。

为什么计划任务不能顺利执行 pyautogui 的脚本

问:我在 win server 2012 的服务器上设置了一个计划任务。测试的时候没问题,但是第二天登陆上去一看,卡在了输入密码的一个步骤。pytyon 脚本里用了 pyautogui。请问是什么原因,要怎么解决 ChatGPT:

你提到在 Windows Server 2012 上运行的 Python 脚本使用了 pyautogui,并且任务卡在了输入密码的步骤。pyautogui 主要用于模拟键盘和鼠标操作,但它在无 GUI 环境(如锁屏、远程桌面断开、无用户登录等情况下)运行时可能会出现问题。

可能的原因

  1. 无用户会话:当你登出或者远程桌面断开连接时,Windows Server 2012 会进入锁屏状态或者没有活动的用户会话。pyautogui 依赖于图形用户界面(GUI)来进行鼠标和键盘操作,因此在没有图形界面或锁屏的情况下,pyautogui 将无法正常工作。
  2. 远程桌面断开:在通过远程桌面连接到服务器后,当你关闭远程桌面连接,系统可能会挂起 GUI 进程。此时,pyautogui 无法操作锁屏界面,因此任务会卡住。

解决方案

1. 使用“控制台会话”启动任务

当你使用任务计划程序创建任务时,确保该任务在有活动的桌面会话(“控制台会话”)下运行。可以按照以下步骤进行设置:

  • 勾选用户登录选项:在创建任务的“常规”选项卡中,确保选中了 “不论用户是否登录都要运行” ,但同时启用 “使用最高权限运行”

  • 强制使用控制台会话:你可以尝试通过命令行连接到服务器上的本地控制台会话:

    cmd
    Copy code
    mstsc /admin
    

    使用 /admin 选项可以连接到控制台会话,而不是创建新的远程桌面会话。控制台会话保持用户界面活动,pyautogui 可以在其中正常工作。

2. 使用虚拟显示(虚拟桌面环境)

如果你需要在服务器上运行 GUI 自动化脚本,可以考虑使用虚拟显示工具,如 VNC ServerRDP Wrapper,以保持虚拟桌面环境持续可用。这样即使远程桌面断开连接,图形环境仍然存在,pyautogui 可以继续操作。

  • VNC Server:安装并配置 VNC 服务器,保持持续的虚拟桌面连接,避免因为用户登出或远程桌面断开而导致的 GUI 丢失问题。
3. 避免使用 pyautogui 或 GUI 自动化工具

尽量避免在服务器环境中使用基于 GUI 的自动化工具。考虑是否能通过无 GUI 依赖的工具来实现任务。例如:

  • 使用 Selenium WebDriver(如果涉及网页自动化):Selenium 支持无头浏览器(Headless Chrome、Headless Firefox),可以在后台运行浏览器,无需 GUI 环境。
  • 通过 Python 内置模块或其他命令行工具来处理非图形界面任务:例如,可以使用 subprocessrequests 等库来模拟输入、提交表单等任务,而不是模拟键盘和鼠标操作。
4. 保持远程桌面连接(临时解决方案)

如果你只是想临时保持远程桌面连接持续运行以便测试,可以通过以下方式防止会话被锁定:

  • 使用 保持远程桌面活动的小工具(如 NoSleep 或类似工具)防止会话断开。

  • 修改组策略设置,避免在断开远程桌面连接时锁屏:

    1. 打开“组策略编辑器”(gpedit.msc)。
    2. 导航到 计算机配置 > 管理模板 > Windows 组件 > 远程桌面服务 > 远程桌面会话主机 > 会话时间限制
    3. 找到 “在指定时间后断开会话” ,并将其设置为“已禁用”。

总结

  • pyautogui 在无 GUI 环境下无法正常工作,因此任务会在锁屏时卡住。可以通过确保使用控制台会话、使用虚拟桌面工具、避免 GUI 自动化等方式解决。
  • 如果任务是基于 GUI 的操作,最好在保持用户登录和有活动会话的情况下运行。

为什么 VNC Service 能够保留 GUI

问:VNC Server 为什么能维持服务器的 GUI 环境?我本地电脑关机也没关系吗?

ChatGPT:

VNC Server 之所以能够维持服务器的 GUI 环境,且在你本地电脑关机或断开连接的情况下依然能保持运行,是因为 VNC(Virtual Network Computing) 的工作机制与远程桌面协议(如 RDP)不同。以下是 VNC Server 能保持服务器 GUI 环境运行的原因,以及你本地设备关机是否会影响其工作的详细解释:

1. VNC Server 的工作原理

  • VNC 是基于客户端-服务器架构的远程控制协议。它允许你通过网络在本地计算机(客户端)上查看和操作远程计算机(服务器)上的 GUI 环境。

  • VNC Server 是运行在远程计算机上的一个服务,它在服务器上维护一个独立的 GUI 会话。这个 GUI 环境由 VNC Server 管理,而不是依赖客户端设备。

    当你通过 VNC 客户端连接到服务器时,VNC Server 在后台继续运行并保持其管理的 GUI 环境,即使客户端断开或本地电脑关机,VNC Server 仍然维持远程计算机的图形界面。

2. 独立于本地计算机的 GUI 环境

  • 与 Microsoft 的远程桌面协议(RDP)不同,VNC 并不会接管或终止服务器上的图形界面。如果你断开 RDP 会话,通常服务器的 GUI 会话也会断开或退出。
  • 但是 VNC 不会这么做,VNC Server 保持服务器的 GUI 环境独立运行,即使没有任何客户端连接,它依然能够保持 GUI 的状态。除非你手动关闭 VNC Server 服务,服务器上的 GUI 环境会一直保持运行。

3. 本地电脑关机的影响

  • 你的本地电脑关机、断网或者断开 VNC 客户端连接,不会影响服务器上的 GUI 会话。VNC Server 会在服务器端继续运行,GUI 会话也不会被中断。
  • 当你重新打开本地电脑并再次使用 VNC 客户端连接时,你会重新恢复到之前的服务器 GUI 会话,而不是创建一个新的会话。

4. 为何 VNC 可以保持 GUI 环境

  • VNC 的设计独立于远程客户端:VNC Server 本质上只是向客户端传送图形界面信息,客户端仅仅作为一个“查看和控制器”。客户端断开连接时,VNC Server 依然在服务器上运行,并保持图形会话的状态。
  • 不会影响服务器的显示器状态:即使没有任何客户端连接,VNC Server 仍然会在后台管理服务器的显示输出和 GUI 操作。因此,它可以在无人连接时继续运行,直到你手动关闭 GUI 或 VNC 服务。

5. 与 RDP 的区别

  • RDP(远程桌面协议) :当你通过 RDP 连接服务器时,通常你接管了服务器的图形界面,而本地显示器上可能没有 GUI。断开 RDP 会话通常会结束图形界面。
  • VNC:与 RDP 不同,VNC 会保留服务器的图形界面,即使你断开连接,它也不会关闭服务器上的图形会话。

总结

  • VNC Server 可以维持服务器的 GUI 环境,因为它独立运行于服务器上,不依赖于本地客户端的连接。
  • 本地电脑关机、断网或者断开连接都不会影响 VNC Server 维护的服务器 GUI 会话。你可以随时通过客户端重新连接,并继续从上一次断开时的 GUI 状态工作。

结语

这下真的解决了一个大问题,之前因为无法在服务器上操作 GUI,好多设想的功能实现不了。包括但不限于:

  1. 微信自动发消息;
  2. 定时自动登录某些应用;
  3. 爬取应用里的一些数据;
  4. ……

这下好了,好多小工具都能搞起来了,希望对大家也有帮助。