Windows任务计划程序非登录态下Excel查询自动刷新失败问题
当前需要在 MS Office Professional Plus 2016 中实现Query自动刷新功能。
已搭建执行链路:cmd脚本调用vbs脚本,再由vbs触发Excel macro执行。手动运行该链路时所有功能正常,但在Windows Task Scheduler(任务计划程序) 中选择 "run whether user is logged on or not(无论用户是否登录都运行)" 选项时,执行出现异常。
编写的宏会将查询结果日志写入文本文件用于定位代码断点。经排查,任务计划程序运行时Excel似乎弹出了提示类弹窗,但由于任务计划程序会隐藏所有交互弹窗,无法确认弹窗提示的具体内容;而手动运行cmd脚本、或任务计划程序选择"run only if user is logged on(仅当用户登录时运行)"选项时,全程无任何弹窗/提示出现。
经逐行注释排查,确认导致自动化流程中断的是RefreshQueries()子过程中With iTable.QueryTable块内的.Refresh行,完整代码如下:
Private Sub RefreshQueries() AddToLogFile ("Hello from subroutine RefreshQueries().") Dim iWorksheet As Excel.Worksheet Dim iTable As Excel.ListObject 'Check each worksheet. For Each iWorksheet In Excel.ActiveWorkbook.Worksheets AddToLogFile ("For-loop for iWorksheet " & iWorksheet.Name) 'Check all Objects if it is a query object. For Each iTable In iWorksheet.ListObjects If iTable.SourceType = Excel.XlListObjectSourceType.xlSrcQuery Then AddToLogFile ("Trying to refresh iTable: " & iTable.Name) QueryTimeStart = Timer On Error Resume Next With iTable.QueryTable 'Refresh the query data. .BackgroundQuery = False .EnableRefresh = True .Refresh End With If Err.Number <> 0 Then QueryRunTime = CalculateRunTime("QueryRunTime") 'Stop timer and get the duration. Call AddToHtmlErrorTable(iTable.Name, Err.Number, Err.Description, QueryRunTime) 'Add entry to error table. AddToLogFile ("Query in iTable " & iTable.Name & " failed. Description: " & Err.Description) NumberOfFailedQueries = NumberOfFailedQueries + 1 'IMPORTANT: increment must be after updating html error table! Err.Clear 'Clear errors between for loops. Else NumberOfSuccessfulQueries = NumberOfSuccessfulQueries + 1 AddToLogFile ("Query in iTable " & iTable.Name & " successfully refreshed.") End If End If Next iTable Next iWorksheet AddToLogFile ("Exiting subroutine RefreshQueries().") End Sub
- 是否有方法捕获后台运行时Excel弹出的提示内容(手动运行时无任何弹窗);
- 是否可以无需知晓弹窗内容,自动确认所有Excel弹出的提示框;
- 是否存在已知的Excel配置项,可以让数据连接刷新过程全程无确认提示执行。
1. 捕获非登录态下的Excel弹窗内容
Windows Vista及以上版本默认开启Session 0隔离,选择"无论用户是否登录都运行"的任务会在隔离的Session 0会话中执行,所有UI界面默认对登录用户不可见,可通过两种方式获取弹窗内容:
- 直接查看Session 0界面:以管理员身份启动命令提示符,先执行
query user确认当前登录用户的会话ID,再执行tscon 0 /dest:console即可切换到Session 0会话,直接看到Excel弹出的完整提示,操作完成后输入账号密码重新登录原桌面即可。 - VBA层自动记录弹窗内容:在模块开头声明Windows API
FindWindowEx、GetWindowText,在宏启动后开启100ms间隔的定时轮询,枚举进程ID匹配当前Excel进程、类名为#32770(Windows标准对话框类名)的顶层窗口,将窗口标题、提示文本全部写入现有日志文件,无需切换会话即可拿到弹窗内容。
2. 全局自动确认所有Excel弹窗
在启动Excel、打开工作簿的最早阶段配置屏蔽规则,可覆盖99%的弹窗场景:
- VBS启动层配置:创建Excel对象后第一时间关闭告警,再打开目标工作簿,避免打开文件阶段就弹出提示:
Set xlApp = CreateObject("Excel.Application") xlApp.Visible = False xlApp.DisplayAlerts = False xlApp.AskToUpdateLinks = False xlApp.AutomationSecurity = 3 ' msoAutomationSecurityForceDisable,强制禁用所有宏安全提示 ' 替换为你的文件绝对路径 Set xlBook = xlApp.Workbooks.Open("C:\path\to\your\file.xlsm", UpdateLinks:=0, ReadOnly:=False) ' 宏执行完成后记得退出Excel进程,避免后台残留 xlApp.Run "RefreshQueries" xlBook.Save xlBook.Close xlApp.Quit Set xlApp = Nothing
- VBA层补全配置:在
RefreshQueries()过程最开头加入以下配置,覆盖运行过程中的弹窗:
Application.DisplayAlerts = False Application.AskToUpdateLinks = False Application.AutomationSecurity = msoAutomationSecurityForceDisable ThisWorkbook.EnableAutoRecover = False
如果仍有漏网的非标准弹窗,可加入定时SendKeys "~"逻辑,每100ms发送一次回车键,自动点击弹窗的默认确认按钮,同会话下该方法对非登录态运行的Excel同样有效。
3. Query无提示刷新的配置项
现有代码缺少几个关键的QueryTable参数和全局配置,按以下调整即可实现全程无确认刷新:
补全QueryTable刷新参数
将原代码中的With iTable.QueryTable块修改为如下内容:
With iTable.QueryTable .BackgroundQuery = False .EnableRefresh = True ' 新增配置 .RefreshOnFileOpen = False ' 禁止打开文件时自动刷新触发提示 .SavePassword = True ' 保存数据源认证信息,避免弹出密码输入框 .SaveData = True .MaintainConnection = True .RefreshStyle = xlInsertDeleteCells ' 按实际业务需求选择行列调整规则,避免弹出结构变更确认 ' 刷新方法传入第二个参数,强制跳过刷新确认提示 .Refresh BackgroundQuery:=False, False End With
全局Excel配置
- 打开Excel,进入「文件-选项-信任中心-信任中心设置-外部内容」,将数据连接安全设置为「启用所有数据连接」,工作簿链接安全设置为「启用所有工作簿链接自动更新」。
- 将脚本、Excel文件、日志文件所在的根目录添加到信任中心「受信任位置」,勾选「同时信任此位置的子文件夹」,避免非受信任路径触发安全拦截提示。
- 确认脚本运行架构与Office架构一致:32位Office需调用
C:\Windows\SysWOW64\路径下的cmd.exe和wscript.exe执行脚本,64位Office调用C:\Windows\System32\路径下的对应程序,架构不匹配会在非登录态下触发COM调用失败弹窗。 - 任务计划程序中勾选「使用最高权限运行」,确认配置的运行账号对所有相关目录、数据源有完全控制权限,权限不足也会触发访问错误弹窗。
内容的提问来源于stack exchange,提问作者user19232952

