LotusScript中Shell命令执行异常 定时代理运行不稳定求助
问题排查:LotusScript定时执行BAT文件异常
问题描述
我编写了一段LotusScript代码,用于读取指定目录下的*.BAT文件,构建命令字符串后通过Shell执行。目前遇到以下问题:
Shell执行后返回值为33,但通过>生成TXT文件的操作未生效- 手动运行代理可正常工作,但作为定时代理时运行不稳定:仅当目录下只有1个
.bat文件时偶尔有效,存在多个.bat文件时完全失效 - 代理安全设置为
3. Allow restricted operations with full administration rights,未勾选run as web user,权限设置为All readers and above
原代码
On Error Goto ErrorHandler Dim session As New NotesSession Set db = session.CurrentDatabase server = db.server path = db.FilePath Dim result As Integer Dim CommandStr As String pathName$ = "C:\\Lotus\\apps\\curl\\Beyond\\*.bat" inboundPath$ = "C:\\Lotus\\apps\\curl\\Beyond\\" processPath$ = "C:\\Lotus\\apps\\curl\\Beyond\\processed\\" fileName$ = Dir$(pathName$, 0) Dim x As Integer x = 0 Do While fileName$ <> "" x = x + 1 If Lcase$(Right$(fileName$, 4)) = ".bat" Then txtFile$ = Left$(FileName$, Len(FileName$) - 4) & ".txt" pdfFile$ = Left$(FileName$, Len(FileName$) - 4) & ".pdf" CommandStr = inboundPath$ & FileName$ & " >" & inboundPath$ & txtFile$ result = Shell(CommandStr, 0) MsgBox "RESULT OF SHELL COMMAND FOR " & FileName$ & " - " & result Sleep(3) FileCopy inboundPath$ & txtFile$, processPath$ & txtFile$ Kill inboundPath$ & txtFile$ FileCopy inboundPath$ & pdfFile$, processPath$ & pdfFile$ Kill inboundPath$ & pdfFile$ FileCopy inboundPath$ & FileName$, processPath$ & FileName$ Kill inboundPath$ & FileName$ Call SendErrorMessage("Post BEYOND DOCUMENT for " & FileName$) End If fileName$ = Dir$() Loop OuttaHere: Exit Sub ErrorHandler: Print "Error in Auto Posting Beyond Docs: " & Error & " - " & Err Resume Next
排查与修复要点
1. Shell执行环境与重定向问题
定时运行时,代理以Domino服务账户身份执行,和手动运行的用户环境存在差异:
- 直接执行
.bat文件时,>重定向可能不生效,需要通过cmd.exe来解析重定向命令 - 路径中如果存在空格(当前代码路径无空格,但需提前规避),必须用引号包裹路径
修改Shell命令为:
CommandStr = "cmd /c """ & inboundPath$ & FileName$ & """ > """ & inboundPath$ & txtFile$ & """"
2. 返回值33的原因:文件占用
错误代码33表示"进程正在使用文件",定时运行时容易出现:
- 固定
Sleep(3)无法保证BAT文件执行完成,导致后续文件操作时文件被锁定 - 建议替换固定睡眠为等待进程结束(可通过Windows API实现),示例代码片段:
Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long Const INFINITE = &HFFFF Const PROCESS_ALL_ACCESS = &H1F0FFF ' 执行Shell后等待进程结束 result = Shell(CommandStr, 0) hProcess = OpenProcess(PROCESS_ALL_ACCESS, False, result) If hProcess <> 0 Then Call WaitForSingleObject(hProcess, INFINITE) Call CloseHandle(hProcess) End If
3. Dir$()遍历的潜在问题
在循环中执行Kill操作会干扰Dir$()的遍历上下文,导致后续文件无法被读取。建议先收集所有BAT文件名到数组,再遍历数组处理:
' 先收集所有BAT文件名到数组 Dim batFiles() As String Dim count As Integer count = 0 fileName$ = Dir$(pathName$, 0) Do While fileName$ <> "" If Lcase$(Right$(fileName$, 4)) = ".bat" Then count = count + 1 ReDim Preserve batFiles(1 To count) batFiles(count) = fileName$ End If fileName$ = Dir$() Loop ' 遍历数组处理文件 For i = 1 To count fileName$ = batFiles(i) ' 原有的BAT执行、文件操作代码 Next
4. 错误处理增强
当前Print错误信息在定时运行时无法查看,建议将错误信息写入Notes日志文档:
ErrorHandler: Dim logDoc As NotesDocument Set logDoc = db.CreateDocument logDoc.Form = "Log" logDoc.Subject = "Auto Posting Beyond Docs Error" logDoc.ErrorDetails = "Error: " & Error & " | Err Number: " & Err & " | Affected File: " & fileName$ logDoc.Created = Now() Call logDoc.Save(True, False) Resume Next
5. 文件操作的安全性
在执行FileCopy和Kill前,先检查文件是否存在,避免因文件缺失抛出异常:
' 检查TXT文件存在再操作 If Dir$(inboundPath$ & txtFile$) <> "" Then FileCopy inboundPath$ & txtFile$, processPath$ & txtFile$ Kill inboundPath$ & txtFile$ End If
内容的提问来源于stack exchange,提问作者Jason Johnston
相关产品推荐
相关产品推荐

