批处理文件在继续之前等待另一个进程完成

Batch file wait for another processes to finish before continuing

我有一个批处理文件,每次启动我的工作 PC 时都会使用它。基本上,它会杀死 IT 部门放在 运行 作为我的用户帐户的 PC 上的所有英国媒体报道软件,我什至从未使用过 taskkill,安装一个小程序,然后加载我真正需要的所有程序立刻。问题是,我 运行 的一个程序,IT 部门最近认为安装一个 "helper" 程序来自动化程序中我已经知道如何做和可以做的一些事情会很有帮助手动相当快。问题是,辅助程序实际上有相反的效果,会减慢实际程序的速度。我们当然会就此向 IT 部门抱怨,但他们可能需要几个月的时间才能修复它,如果有的话。与此同时,我发现辅助程序 运行 在我的用户帐户下是它自己的进程,这意味着我可以杀死它,然后一切都会 运行 再次顺利进行。问题是,如何程序运行s。我正常启动程序,但发生了这种情况:

进程 A 加载。进程A加载进程B。进程A杀死自己。进程 B 加载进程 C。进程 C 加载进程 D、E 和 F(辅助程序)。进程B自杀,内存中留下C、D、E、F(此时程序已经满载)

如何让批处理文件等待进程 B 自行终止,然后再继续执行 taskkill 命令终止进程 D、E 和 F?由于命令行在直接调用 EXE 时只看到进程 A,因此它会在不到一秒的时间内恢复批处理文件,因为 A 会很快杀死自己。我不能只使用 timeout 或其他一些通用的时间浪费程序,因为程序的加载时间太不稳定,网络问题、程序更新等

几年前我构建了与此完全相同的东西,但不幸的是我没有代码,目前无法访问 Windows 机器。

但是,它应该相当简单,并且会遵循这些原则(只需调整代码使其工作,或者如果有任何问题请告诉我;我无法测试它但应该能够修复如果我知道它们是什么):

rem Usage: :killprocesswithwait [pid]
call :killprocesswithwait 1234

:killprocesswithwait
set pid=%1
taskkill /pid %pid%
:iloop
ping 127.0.0.1 -n 2 > nul
for /f "tokens=*" %%a in ('tasklist /fi "PID eq %pid%" ^| find /i %pid%') do (
    if /i "%%a"=="" (
        goto :eof
    ) else (
        goto :iloop
    )
)

这会等待所有程序退出并检查记事本是否存在,如果存在则重新启动它。

等三个程序启动肯定更好。将 Win32_ProcessStopTrace 更改为 Win32_ProcessStartTrace

Set WshShell = WScript.CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts:\.\root\CIMV2") 
Set objEvents = objWMIService.ExecNotificationQuery _
    ("SELECT * FROM Win32_ProcessStopTrace")

Do
    Set objReceivedEvent = objEvents.NextEvent
    msgbox objReceivedEvent.ProcessName
    If lcase(objReceivedEvent.ProcessName) = lcase("Notepad.exe") then 
        Msgbox "Process exited with exit code " & objReceivedEvent.ExitStatus
        WshShell.Run "c:\Windows\notepad.exe", 1, false
    End If
Loop

这会列出进程并终止任何调用的计算器。

Set objWMIService = GetObject("winmgmts:\.\root\cimv2")

Set colItems = objWMIService.ExecQuery("Select * From Win32_Process")

For Each objItem in colItems
    'msgbox objItem.ProcessID & " " & objItem.CommandLine
    If objItem.name = "Calculator.exe" then objItem.terminate
Next
@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q36241667.txt"
SET "filename2=%sourcedir%\q36241667_2.txt"

:dloop
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO (
 tasklist|FIND "%%a" >NUL
 IF ERRORLEVEL 1 timeout /t 1 >nul&GOTO dloop
)

FOR /f "usebackqdelims=" %%a IN ("%filename2%") DO ECHO(%%a

GOTO :EOF

您需要更改 sourcedir 的设置以适合您的情况。

我使用了名为 q36241667.txt & q36241667_2.txt 的文件,其中包含一些用于测试的虚拟数据。

假设filename1包含

processa.exe
processb.exe
processc.exe
processd.exe
processe.exe

然后 for 循环将等到所有进程都 运行 后再继续。

filename2 包含所需的终止命令(echo出于演示目的编辑)

如果此例程只是 start 在您的启动例程中编辑,那么它本身可能会触发 start 命令来终止任何不需要的进程。

我使用类似的例程在启动时将关键目录备份到 ramstick。

谢谢大家,我实际上接受了 Ruslan 的回答并对其进行了一些简化和更改。这很好用。等待 exe3 加载,因为它是最后一个加载,然后杀死所有 3 个。不需要设置变量,所以删除了那些并完全忘记了将它放入循环中。

:start
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq exe3.exe"') DO IF %%x == exe3.exe goto found
goto start
:found
taskkill /f /fi "blah1.exe"
taskkill /f /fi "blah2.exe"
taskkill /f /fi "blah3.exe"