我有一个批处理脚本,它通过 AT 命令运行,并且可能运行多次。当它启动时,我需要它检测它是否已在运行,如果是,则立即退出(第二个)。
- 它必须是强大的,并且能够处理脚本意外退出的情况(即我不能在进入时设置标志并在退出时清除它)
- 它必须在远程桌面会话中运行
- 我只能在 XP 上使用 Powershell v2,但如果我无法在批处理/powershell 或 vbs 中执行此操作,我不介意编写一个小 exe
- 该脚本必须最小化运行,因此我使用 Start "NAME" /MIN %COMSPEC% /C "MyScript.bat" 启动它
- 其他 cmd 窗口可能已打开,因此我需要检查正在运行的脚本
- 批处理脚本以 SYSTEM 用户身份运行,但我无法使用任何 WMI
我使用 PowerShell Get-Process 查看 MainWindowTitle,但在远程连接到计算机时此方法不起作用,因为脚本可能正在运行,但未在此远程连接实例中显示。在这种情况下,Get-Process 可以看到 cmd 进程,但 MainWindowTitle 为空白。
我已经尝试了 Get-Process 并查看了扩展的 StartInfo.EnvironmentVariables 属性,但看不到如何创建环境变量以使其出现在属性中。
我考虑在启动命令中使用 /WAIT,这样 AT 将保持打开状态直到完成,但包含 AT 的脚本不会最小化
有任何想法吗?
答案1
我认为锁定文件是最简单可靠的解决方案。诀窍是确保正在运行的批处理进程在文件终止之前保持对文件的独占写入锁定。该系统的优点在于,无论批处理终止的原因是什么,Windows 都会释放锁定。
一旦你有了一个锁定文件,你需要一种方法来检测该文件当前是否被锁定。我描述了如何做到这一点如何在命令行中检查给定的文件或目录是否被锁定(被任何进程使用)?
我使用这种原始但有效的技术通过 Windows 批处理完成了一些相当复杂的任务:
您不清楚批处理文件位于何处 - 在远程计算机上还是在本地计算机上,或者您是否可能同时在多台计算机上运行脚本,但每台计算机只有一个活动进程。
如果批处理脚本位于远程计算机上,并且您的进程对该脚本具有写访问权限,那么您可以将批处理文件本身用作锁定文件!您只需在使用追加模式将未使用的文件句柄重定向到批处理脚本时调用 :subroutine。如果另一个进程已经拥有锁定,则 CALL 将失败。脚本终止时将自动释放锁定(无论它如何终止)。
脚本文件
@echo off
:: Note - this extra call is to avoid a bug with %~f0 when the script
:: is executed with quotes around the script name.
call :getLock
exit /b
:getLock
:: The CALL will fail if another process already has a write lock on the script
call :main 9>>"%~f0"
exit /b
:main
:: Body of your script goes here. Only one process can ever get here
:: at a time. The lock will be released upon return from this routine,
:: or when the script terminates for any reason
exit /b
如果您的脚本与进程位于不同的机器上,但您一次只在一台机器上运行进程,那么我认为上述操作仍然有效。
也许更好的选择是在每台远程机器上建立一个专用的锁定文件,与批处理脚本分开。然后,您可以在任意数量的远程机器上运行该过程。
答案2
谢谢您的帮助。我已实施以下操作:
Before starting my script (in a wrapper script), check whether the lockfile exists:
If it does, read the PID out of it.
If the PID is still a running cmd process, exit my script as another version of it is already running.
If the PID is not still a running cmd process, delete the lockfile
Start the script, and create a new lockfile, containing the PID of the started script
When exiting my script, delete the lockfile
这似乎工作正常,进一步的测试将会证明一切。
- 为了列出正在运行的进程,我使用 POWERSHELL Get-Process,因为 TASKLIST 使用 WMI,而正如我之前所说,我无法使用 WMI。
- 为了确定启动脚本的 PID,我列出所有当前 cmd PID,启动脚本,然后列出所有 cmd PID,查找之前不存在的 PID。
答案3
我创建了一个名为 CMDS 的自动化插件,您可以在这里使用:我如何查看某个批处理文件是否正在运行并获取 PID?然而我不确定这是否适用于 XP。
示例命令:CMDS /TS "Your Batch File Title"
它还具有可供其自身使用的 GUI 模式。
这是帮助文件: