2

I have a folder filled with few vbscripts (say 10) which has to be run sequentially, Instead of running each by clicking on them i want to automate this process. Below is my master.vbs script which runs each vbscript in that folder one by one.

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

The issue i have here is that the scripts are running perfectly by since the process name is going to be the same for all the scripts (cscript) It doesnt wait for a process to terminate before starting another .

I understand there is just minute tweaking required in my code but im not sure how to go about it. Can some one point out what im doing wrong here ?..

Mani kv
  • 153
  • 2
  • 19
  • Silly question, but, why are you using wmi to do it? Is there any reason not documented in the code/question? – MC ND Jul 23 '15 at 09:19
  • And, there is a incoherence between the text in the question and the title. Do you need to kill the processes or just to ensure they are executed one after the other? – MC ND Jul 23 '15 at 09:47
  • @MCND i want to ensure they get executed one after the other, I was thinking about killing the process so that they dont persist since the mastervbs is going to be executed via a cmd prompt? i might be wrong. The objective is to run all vbs one after the other from a master vbs. – Mani kv Jul 23 '15 at 10:02
  • the reason im using wmi is to keep a track of the process and if and only if it gets terminated start a new process. – Mani kv Jul 23 '15 at 10:03

1 Answers1

3
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 

For a WMI solution,

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
MC ND
  • 69,615
  • 8
  • 84
  • 126
  • Thanks @MCND Exactly what i required. and I understand you didnt use WMI but just a thought, Isnt it possible to do the same with WMI ?.. if so can i understand as to how to do it ? – Mani kv Jul 23 '15 at 10:46
  • @Manikv, It is possible to do it with wmi, but your code will have to keep iterating waiting for the process to end. Also, sometimes, if the started process ends really quick, the `ExecNotificationQuery` can miss the process deletion and the exit condition in the loop will never be reached. Anyway, WMI code posted – MC ND Jul 23 '15 at 11:17