Ask:
Hey, Scripting Guys! This is the task I want to accomplish: I want to start two executables with a script. After the first application shuts down, I want the script to close the second application and exit. How do I accomplish these tasks?
--MK
For:
Hello, MK. You know, that's the kind of question we like. Why? Because it sounds really complicated and tricky. If anyone wants to do something for us, we can say, "You know, I'm trying to write a script that can start two applications, wait until the first one closes, and then automatically close the second one." "Then they're going to say," Oh, I'm sorry. Obviously, you're busy, and then you're not looking for us.
Of course, they don't know, it just sounds very difficult. In fact, its difficulty is equivalent to the following script:
Copy Code code as follows:
StrComputer = "."
Set objWMIService = GetObject ("winmgmts:\\" & StrComputer & "\root\cimv2:win32_process")
Errresult = Objwmiservice.create ("calc.exe", NULL, NULL, INTCALCID)
Errresult = Objwmiservice.create ("notepad.exe", NULL, NULL, INTNOTEPADID)
Set objWMIService = GetObject ("winmgmts:\\" & StrComputer & "\root\cimv2")
Set Colprocesses = Objwmiservice.execnotificationquery _
("SELECT * FROM __InstanceDeletionEvent" _
& "Within 1 Where targetinstance ISA ' Win32_Process '")
Do Until i = 999
Set objprocess = colprocesses.nextevent
If ObjProcess.TargetInstance.ProcessID = intCalcID Then
Exit do
End If
Loop
Set Colprocesses = objWMIService.ExecQuery _
("SELECT * from Win32_Process Where ProcessID =" & Intnotepadid)
For each objprocess in colprocesses
Objprocess.terminate ()
Next
Really, believe us: After you've learned what the script has done, it's actually pretty straightforward. We first connect to the WMI service on the computer, specifically, bind to the Win32_Process class. And that's what we're going to do now:
Set objWMIService = GetObject ("winmgmts:\\" & StrComputer & "\root\cimv2:win32_process")
We then created two new processes using the Create method: Calc.exe and Notepad.exe. For each new process, we use code similar to the following line of code:
Errresult = Objwmiservice.create ("calc.exe", NULL, NULL, INTCALCID)
All we have left to do is invoke the Create method with the following content:
• The name of the executable file (you may need to specify the full path name of the application depending on your computer's settings).
• A pair of Null parameters. With these two parameters, we can specify different working folders for the application and configure some other startup options. In this example code, we don't need to think about these things, so we just set the parameter value to Null.
• A variable (named intCalcID) acting as an "output parameter". After these processes are created, the ProcessID number assigned to the process is also assigned to these output parameter variables.
The end result is that we start the calculator, and the variable intcalcid contains the process ID assigned to the calculator instance. Then, we start Notepad, and the variable Intnotepadid contains the ProcessID assigned to the Notepad instance. This is the way to start two applications and track them.
The next thing we're going to do is, well, basically nothing: we want this script to pause until we close the calculator. To complete this task, we reconnect to the WMI service and then use ExecNotificationQuery to monitor any deleted processes. We need to reconnect to the WMI service because we are simply connecting to the Win32_Process class at the beginning of the script, so the object reference (objWMIService) simply references this class. We need to connect to the "generic" WMI service, so we just reuse the object reference objWMIService and make a new connection:
Set Colprocesses = Objwmiservice.execnotificationquery _
("SELECT * FROM __InstanceDeletionEvent" _
& "Within 1 Where targetinstance ISA ' Win32_Process '")
What is the reason for this? Each time a process is deleted, a __InstanceDeletionEvent class instance is generated. We want to examine each instance to see if the process ID of these instances is the target ID, which is the ID assigned to INTCALCID. If the deleted process has a different ID, it is not a "calculator" instance, in which case the script resumes monitoring. If the deleted process has the same ID as INTCALCID, it must be a "calculator" instance (because the process ID must be unique). In this case, we want to stop monitoring and then close Notepad.
The following is the code that actually performs the monitoring:
Do Until i = 999
Set objprocess = colprocesses.nextevent
If ObjProcess.TargetInstance.ProcessID = intCalcID Then
Exit do
End If
Loop
What we do here is set up a loop that runs all the time to the variable i equals 999. Now, the fact is that the variable I will always be not equal to 999; it's just a trick to make sure the loop runs until the calculator closes. (How do we know that the variable I will always not equal 999?) So, we don't have a value for I; Therefore, it takes the default value of 0. Because we never make any changes to this value, I always 0, so it will never be equal to 999. )
In the loop, we use this line of code to wait for the next deleted process:
Set objprocess = colprocesses.nextevent
Each time we delete a process, we check to see if the ProcessID matches the process ID assigned to the calculator. If it matches, we use the Exit do command to disconnect the loop and continue with the script. If you don't have the same ID, then we just keep looping and wait for the next deleted process. (as we said above, I will never be equal to 999, but it doesn't matter: Use the Exit do command to get out of the loop.) )
Attention. We found that we sort of skimmed over the whole idea of event monitoring. If you're a little confused about things like __InstanceDeletionEvent and colprocesses.nextevent, see Scripting Guys webcasts in the bud: A brief introduction to WMI events (English).
Now we just need to terminate the "Notepad" instance we started. To complete this task, we use this WMI query to retrieve a collection of all processes that have the process ID assigned to Notepad:
Set Colprocesses = objWMIService.ExecQuery _
("SELECT * from Win32_Process Where ProcessID =" & Intnotepadid)
After we get this collection, we use this code block to loop through the entire set of processes (only one process) and then close the application using the Terminate method:
For each objprocess in colprocesses
Objprocess.terminate ()
Next
Incidentally, this method applies to both the remote computer and the local computer, and simply changes the value of the variable StrComputer to the name of the remote computer. However, remember that in Windows XP and Windows Server 2003, processes that are started on a remote computer are run in an invisible window, and they are not visible on the screen. This means that this approach is useful for applications that do not require any user interaction when working with remote computers, and this approach is far less useful than other methods (in fact, completely useless) for applications that do require user intervention.