VBScript 结束由 .bat 文件启动的进程
我有一个场景设置,我需要测试 .bat 文件执行的结果是否返回结果。 .bat 文件调用另一个 .exe,并且 .bat 文件有一个 CMD DOS 窗口,该窗口将关键错误信息从 .exe 输出到该 DOS 框。 如果 .exe 未正确启动,我可以在 SQL DB 中检查结果。 我需要关闭当前的 .bat 文件并重新启动它。 这看起来相当简单,我可以使用 WMI 调用获取 ProcessID。 我可以使用 Terminate() 命令终止该进程。 这适用于我用于测试的任何 .exe:记事本、calc、iexplorer 等。当我运行 VBScript 来终止 .bat 文件时,它说它终止了 PID(它确实这样做了,因为我再也看不到 PID了)但是,DOS 框仍然打开,并且从 .bat 文件调用的 .exe 仍在运行。 如果我单击 DOS 框上的“X”或右键单击标题栏并选择“关闭”,DOS 框和 .exe 都会被杀死。 我怎样才能让这个脚本正常工作。 服务器运行 Windows Server 2003(有些是 x32,有些是 x64)。 有任何想法吗? 这是我的代码的一个版本,已经进行了多次修订:
If colFiles.Count = 0 Then
Wscript.Echo "The file does not exist on the remote computer."
Else
Wscript.Echo "The file exists on the remote computer."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process")
For Each objItem in colProcessList
If InStr(objItem.CommandLine, "r15_A.bat") Then
Wscript.Echo "Batch file: " & objItem.CommandLine & " Process ID: " & objItem.ProcessID & " Parent ID: " & objItem.ParentProcessID
Call TerminateProcess(objItem.ParentProcessID)
Call TerminateProcess(objItem.ProcessID)
End If
Next
dim shell
set shell=createobject("wscript.shell")
shell.run BATDIR & BATFILE
'set shell=nothing
End If
Function TerminateProcess(PID)
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
Set colProcesses = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Handle = '" & PID & "'")
For Each objProcess in colProcesses
On Error Resume Next
return = objProcess.Terminate()
Set colProcesses = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Handle = '" & PID & "'")
If Error Then
TerminateProcess = FALSE
Else
TerminateProcess = TRUE
msgBox colProcesses.Count
End If
Next
End Function
我什至尝试使用 SendKeys 发送 ALt-F4、X、C 等。AppActivate 确实将正确的 DOS 框带到前面。
Set WshShell = CreateObject("WScript.Shell")
WshShell.AppActivate "r15_A"
'WshShell.SendKeys("+{F10}")
WshShell.SendKeys("C")
提前致谢
编辑-------------- 是的,我必须终止该 .bat 文件调用的进程。 唯一的缺点是这个 DOS 框保持打开状态。 很烦人,但我可以忍受。 最后,我编写了一个与第一个脚本类似的脚本,但仅通过检查 CommandLine 参数来检查我想要杀死的实例:(带有“-FAIL.txt”的代码的第一位测试以查看是否存在 FAIL 文件,如果是,则执行其余的 scipts)
Set colFiles = objWMIService. _
ExecQuery("Select * From CIM_DataFile Where Name = 'S:\\servers\\Logs\\" & LOGFILE & "-FAIL.txt'")
If colFiles.Count = 0 Then
'Wscript.Echo "The file does not exist on the remote computer."
Else
'Wscript.Echo "The file exists on the remote computer."
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = 'AppStart.exe'")
For Each objProcess in colProcessList
IF instr(objProcess.CommandLine, "robo05-A") > 0 THEN
'msgBox "Found text"
objProcess.Terminate()
'This part restarts the failed .bat file.
wscript.sleep (200)
dim shell
set shell=createobject("wscript.shell")
shell.run BATDIR & BATFILE
'set shell=nothing
ELSE
'msgBox "Not found"
END IF
Next
End If
I have a scenario setup where I need to test to see if the results of a .bat file execution returned results. The .bat file calls up another .exe and the .bat file has a CMD DOS window that outputs critical error info to that DOS box from the .exe. If the .exe does not start correctly, I am able to check the results in our SQL DB. I need to close the current .bat file and re-launch it.
This seems fairly simple, I can get the ProcessID using the WMI call. I can terminate the process with a Terminate() command. This works for any .exe I use for testing: notepad, calc, iexplorer, etc. When I run the VBScript to kill the .bat file, it says it terminates the PID (which it does, since I cannot see the PID anymore), however, the DOS box is still open and the .exe called from the .bat file is still running. If I click on the "X" on the DOS box or right-click on the title bar and select "Close", the DOS box and the .exe are both killed. How do I get this script to work correctly. The server is running Windows Server 2003 (some are x32 and others are x64). Any ideas? Here is a version of my code, there have been several revs:
If colFiles.Count = 0 Then
Wscript.Echo "The file does not exist on the remote computer."
Else
Wscript.Echo "The file exists on the remote computer."
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process")
For Each objItem in colProcessList
If InStr(objItem.CommandLine, "r15_A.bat") Then
Wscript.Echo "Batch file: " & objItem.CommandLine & " Process ID: " & objItem.ProcessID & " Parent ID: " & objItem.ParentProcessID
Call TerminateProcess(objItem.ParentProcessID)
Call TerminateProcess(objItem.ProcessID)
End If
Next
dim shell
set shell=createobject("wscript.shell")
shell.run BATDIR & BATFILE
'set shell=nothing
End If
Function TerminateProcess(PID)
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
Set colProcesses = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Handle = '" & PID & "'")
For Each objProcess in colProcesses
On Error Resume Next
return = objProcess.Terminate()
Set colProcesses = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Handle = '" & PID & "'")
If Error Then
TerminateProcess = FALSE
Else
TerminateProcess = TRUE
msgBox colProcesses.Count
End If
Next
End Function
I have even tried to use the SendKeys to send ALt-F4, X, C, etc. AppActivate does bring the correct DOS box to the front.
Set WshShell = CreateObject("WScript.Shell")
WshShell.AppActivate "r15_A"
'WshShell.SendKeys("+{F10}")
WshShell.SendKeys("C")
Thanks in advance
EDIT--------------
Yes, I am going to have to kill the process that this .bat file calls. Only down side is this DOS box stays open. Annoying but I can live with it. In the end I wrote a script similar to my first one but only checks for the instance I want to kill by checking the CommandLine parameter: (The first bit of code with "-FAIL.txt" test to see if a FAIL file is present, if it is, then the rest of the scipts executes)
Set colFiles = objWMIService. _
ExecQuery("Select * From CIM_DataFile Where Name = 'S:\\servers\\Logs\\" & LOGFILE & "-FAIL.txt'")
If colFiles.Count = 0 Then
'Wscript.Echo "The file does not exist on the remote computer."
Else
'Wscript.Echo "The file exists on the remote computer."
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = 'AppStart.exe'")
For Each objProcess in colProcessList
IF instr(objProcess.CommandLine, "robo05-A") > 0 THEN
'msgBox "Found text"
objProcess.Terminate()
'This part restarts the failed .bat file.
wscript.sleep (200)
dim shell
set shell=createobject("wscript.shell")
shell.run BATDIR & BATFILE
'set shell=nothing
ELSE
'msgBox "Not found"
END IF
Next
End If
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您遇到的问题是从批处理文件中调用的可执行文件仍在运行。 我尝试用蝙蝠重新创建您的设置,只是执行了
ping -t %computername%
,果然 vbscript 杀死了 cmd.exe,但没有杀死 ping(请注意,父 PID 是 explorer.dll)。 exe,所以你可能不想尝试杀死它)。 现在我可以轻松地从任务管理器中杀死 ping.exe,然后关闭窗口......但我只知道这样做,因为我知道蝙蝠在做什么以及什么保持打开状态。 您可以对包含“ping.exe”的进程进行 WMI 搜索,获取 PID,然后关闭它,这基本上会做同样的事情。 当然,在您的情况下,“ping.exe”可能与我的可执行文件不同。 如果 exe 时不时地发生变化,那么您可以从进程中获取命令行,找到包含 r15_A.bat 文件的文件路径的参数,然后使用 filesystemobject 打开此 bat 文件,查找它调用的任何可执行文件可能仍在运行,然后杀死它们......但实际上,这对于您想要完成的任务来说可能有点过分了。The problem your having is the the executable that is being called from within your batch file is still running. I tried to recreated your setup with a bat the just did a
ping -t %computername%
, and sure enough the vbscript killed the cmd.exe but not the ping (Please note the Parent PID was explorer.exe, so you probably don't want to attempt killing that). Now I could easily kill ping.exe from task manager which then closed the window...but I only knew to do that because I knew what the bat was doing and what was left open. You could do a WMI search for the process that contains "ping.exe", grab the PID and then close that and that would basically be doing the same thing. Of course in your situation "ping.exe" is probably not the same executable as mine. If the exe changes every now and then then you could grab the commandline from your process find the parameter which contains the filepath to the r15_A.bat file, then use the filesystemobject to open this bat file, look for any executables which it calls which could possibly be still running and then kill those....but really that may be overkill for what your trying to accomplish.