【问题标题】:vbscript kill a process with a PID WMIServicevbscript 用 PID WMIService 杀死一个进程
【发布时间】:2015-07-23 08:16:57
【问题描述】:

我有一个文件夹,里面装满了几个 vbscript(比如 10 个),它们必须按顺序运行,而不是通过单击它们来运行每个我想自动化这个过程。下面是我的 master.vbs 脚本,它一个一个地运行该文件夹中的每个 vbscript。

strComputer = "."

Set objFSO = CreateObject("Scripting.FileSystemObject")
currentdirectory = objFSO.GetAbsolutePathName(".")

filedirectory = currentdirectory 

Set objFolder = objFSO.GetFolder(filedirectory)
Dim filestring

Set colFiles = objFolder.Files
For Each objFile in colFiles
    'Wscript.Echo objFile.Name
    filestring = filestring & objFile.Name & ","
Next

'filestring = filestring.Trim().Substring(0, filestring.Length - 1)
filestring = Left(filestring,Len(filestring)-1)


Dim files 
 files = Split(filestring,",")


For Each f In files
'WScript.Echo f

chk = Split(f,".")
If chk(UBound(chk)) = "vbs" then


pat = filedirectory & "\" & f
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process")
proc = "cmd.exe /c"& Chr(32) &"cscript.exe " & Chr(32) & chr(34) & pat & Chr(34) 
objWMIService.Create proc , null, null, intProcessID

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

Set colMonitoredProcesses = objWMIService.ExecNotificationQuery _
    ("Select * From __InstanceDeletionEvent Within 1 Where TargetInstance ISA 'Win32_Process'")

Do Until i = 1
    Set objLatestProcess = colMonitoredProcesses.NextEvent
    If objLatestProcess.TargetInstance.ProcessID = intProcessID Then
        i = 1
    End If
Loop

'Wscript.Echo "Process has been terminated."
End If
Next

我在这里遇到的问题是脚本运行得很好,因为所有脚本的进程名称都是相同的 (cscript) 它不会等待一个进程在启动另一个进程之前终止。

我知道我的代码只需要稍作调整,但我不知道该怎么做。 有人能指出我在这里做错了什么吗?..

【问题讨论】:

  • 愚蠢的问题,但是,你为什么要使用 wmi 来做呢?代码/问题中是否有任何原因未记录?
  • 而且,问题中的文字和标题之间存在不一致。您需要终止进程还是只是确保它们一个接一个地执行?
  • @MCND 我想确保它们一个接一个地被执行,我正在考虑终止进程,以便它们不会持续存在,因为 mastervbs 将通过 cmd 提示符执行?我可能错了。目标是从主 vbs 一个接一个地运行所有 vbs。
  • 我使用 wmi 的原因是为了跟踪进程,当且仅当它被终止时才启动一个新进程。

标签: vbscript wmi-service


【解决方案1】:
Option Explicit

' Styles for the window of the started process
Const SW_NORMAL = 1
Const SW_HIDE = 0

' Wait or not for the started process to end
Const RUN_WAIT = True 

' Access to the shell
Dim shell
    Set shell = WScript.CreateObject("WScript.Shell")

Dim oFile
    With WScript.CreateObject("Scripting.FileSystemObject")
        ' Enumerate files in current active directory
        For Each oFile In .GetFolder( shell.CurrentDirectory ).Files 
            ' If it is a VBS script
            If LCase(.GetExtensionName( oFile.Name )) = "vbs" Then 
                ' But not the current script
                If oFile.Path <> WScript.ScriptFullName Then 
                    ' Execute it and wait for the process to end
                    shell.Run "cscript.exe """ & oFile.Path & """", SW_NORMAL, RUN_WAIT
                End If 
            End If 
        Next 
    End With 

对于 WMI 解决方案,

Option Explicit

' Determine current directory for file retrieval
Dim currentDirectory 
    currentDirectory = WScript.CreateObject("WScript.Shell").CurrentDirectory

Dim oFile
    With WScript.CreateObject("Scripting.FileSystemObject")
        ' For each file in the current directory
        For Each oFile In .GetFolder( currentDirectory ).Files 
            ' If it is a VBS file
            If LCase(.GetExtensionName( oFile.Name )) = "vbs" Then 
                ' But not the current script
                If oFile.Path <> WScript.ScriptFullName Then 
                    ' Execute it via WMI
                    WMIExecute "cscript.exe """ & oFile.Path & """"
                End If 
            End If 
        Next 
    End With 

Sub WMIExecute( command )
    ' Styles for the window of the started process
    Const SW_NORMAL = 1
    Const SW_HIDE = 0

    ' Get a reference to WMI
    Dim wmi
        Set wmi = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")

    ' Configure how the process will be started 
    Dim processConfig    
        Set processConfig = wmi.Get("Win32_ProcessStartup").SpawnInstance_
        processConfig.ShowWindow = SW_NORMAL

    ' Prepare a monitor to wait for process termination
    Dim monitor
        Set monitor = wmi.ExecNotificationQuery ( _ 
            "Select * From __InstanceDeletionEvent Within 1 " & _ 
            " Where TargetInstance ISA 'Win32_Process'" _ 
        )

    ' Start the indicated process
    Dim processID, retCode
        retCode = wmi.Get("Win32_Process").Create( command, Null, processConfig, processID )

        ' The process is started if the return code is 0, else there is a error
        ' see https://msdn.microsoft.com/en-us/library/aa389388%28v=vs.85%29.aspx
        If Not retCode = 0 Then 
            WScript.Echo "ERROR code ["& Hex(retCode) &"] starting ["& command &"]"
            Exit Sub
        End If

    ' Wait for process termination, AND, every X seconds (10 in the code) also check
    ' if the process is still running just in case we miss the deletion event. 
    Dim oProcess, keepLooping, endTime, colProcesses
        endTime = Now
        keepLooping = True

        Do While keepLooping
            ' Wait for the next process deletion event
            Set oProcess = monitor.NextEvent

            ' If it is our event, no need to loop any more
            If oProcess.TargetInstance.ProcessID = processID Then
                keepLooping = False
            End If

            ' If we are still looping, and the timeout has been reached
            ' check if the process still exists
            If keepLooping And (Now >= endTime) Then 
                Set colProcesses = wmi.ExecQuery ( _ 
                    "Select ProcessID from Win32_Process Where ProcessID = " & processID _ 
                )
                ' If no process meets the condition, leave the loop, else repeat
                ' this check in X seconds
                If colProcesses.Count < 1 Then 
                    keepLooping = False 
                Else 
                    endTime = DateAdd("s", 10, Now )
                End If
            End If 
        Loop

End Sub

【讨论】:

  • 谢谢@MCND 正是我所需要的。而且我知道您没有使用 WMI,而只是一个想法,是否可以对 WMI 做同样的事情?.. 如果可以,我能理解如何做吗?
  • @Manikv,可以使用 wmi 来完成,但您的代码必须不断迭代等待进程结束。此外,有时,如果启动的进程很快结束,ExecNotificationQuery 可能会错过进程删除,并且永远不会达到循环中的退出条件。无论如何,WMI 代码已发布
猜你喜欢
  • 1970-01-01
  • 2014-02-18
  • 1970-01-01
  • 2014-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多