{"id":64753,"date":"2007-05-31T23:25:00","date_gmt":"2007-05-31T23:25:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2007\/05\/31\/how-can-i-wait-until-one-application-has-quit-before-starting-a-second-application\/"},"modified":"2007-05-31T23:25:00","modified_gmt":"2007-05-31T23:25:00","slug":"how-can-i-wait-until-one-application-has-quit-before-starting-a-second-application","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/how-can-i-wait-until-one-application-has-quit-before-starting-a-second-application\/","title":{"rendered":"How Can I Wait Until One Application Has Quit Before Starting a Second Application?"},"content":{"rendered":"<p><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" height=\"34\" alt=\"Hey, Scripting Guy! Question\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"> \n<P>Hey, Scripting Guy! I have a script that starts two applications; however, the second application can <I>not<\/I> start until the first program has finished running. How can I ensure that my second program doesn\u2019t start until the first one ends?<BR><BR>&#8212; OR <\/P><IMG height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" height=\"34\" alt=\"Hey, Scripting Guy! Answer\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"><A href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><IMG class=\"farGraphic\" title=\"Script Center\" height=\"288\" alt=\"Script Center\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" align=\"right\" border=\"0\"><\/A> \n<P>Hey, OR. Not too long ago the Scripting Guy who writes this column read an article about Walter Mossberg, who happens to write a technology column for the <A href=\"http:\/\/online.wsj.com\/public\/us\" target=\"_blank\"><B>Wall Street Journal<\/B><\/A>. This article speculated that Mossberg, who writes a column twice a week and then performs a few other duties, makes around $1 million a year. If any of you read this same article it probably made you think: \u201cHmmm, Walter Mossberg writes two columns a week and performs a few other duties, and he makes $1 million a year. The Scripting Guy who writes that other column writes <I>5<\/I> columns a week and performs a few other duties. Does that mean he makes $2.5 milliona year?\u201d<\/P>\n<P>To tell you the truth, Microsoft doesn\u2019t like us to divulge salary information. However, we <I>can<\/I> tell you this: no, the Scripting Guy who writes this column does <I>not<\/I> make $2.5 million a year. Instead, Microsoft pays him exactly what he\u2019s worth.<\/P>\n<P>That\u2019s right: ouch!<\/P>\n<P>But that\u2019s OK. Sure, Walter Mossberg might get the big bucks, but he never gets the satisfaction of writing a script that runs an application and then waits until that program has finished before it runs a second application:<\/P><PRE class=\"codeSample\">strComputer = &#8220;.&#8221;<\/p>\n<p>Set objWMIService = GetObject(&#8220;winmgmts:\\\\&#8221; &amp; strComputer &amp; &#8220;\\root\\cimv2&#8221;)<\/p>\n<p>Set objProcess = GetObject(&#8220;winmgmts:root\\cimv2:Win32_Process&#8221;)<\/p>\n<p>errReturn = objProcess.Create(&#8220;Notepad.exe&#8221;, null, null, intProcessID)<\/p>\n<p>Set colMonitoredProcesses = objWMIService. _        \n    ExecNotificationQuery(&#8220;select * From __InstanceDeletionEvent &#8221; _ \n        &amp; &#8221; within 1 where TargetInstance isa &#8216;Win32_Process'&#8221;)<\/p>\n<p>Do While True\n    Set objLatestProcess = colMonitoredProcesses.NextEvent\n    If objLatestProcess.TargetInstance.ProcessID = intProcessID Then\n        Exit Do\n    End If\nLoop<\/p>\n<p>errReturn = objProcess.Create(&#8220;Calc.exe&#8221;, null, null, intProcessID)\n<\/PRE>\n<P>Now, some of you \u2013 maybe even Walter Mossberg \u2013 might take exception with this script. Why not use a far simpler script, one that looks like this:<\/P><PRE class=\"codeSample\">Set objShell = CreateObject(&#8220;Wscript.Shell&#8221;)<\/p>\n<p>objShell.Run &#8220;Notepad.exe&#8221;, ,True\nobjShell.Run &#8220;Calc.exe&#8221;\n<\/PRE>\n<P>We actually have two reasons for that. For one, OR told us that he <I>tried<\/I> a script exactly like the one above, but, for some reason, it didn\u2019t work: when the first process terminated the second process failed to start. We\u2019re not sure why that might be the case, so we decided to try a different, albeit somewhat more complicated, route.<\/P>\n<P>Second, and more important, our script can be used against a remote computer. You just need to do a couple things first. For one, assign the name of the remote computer to the variable strComputer. For another, get rid of the applications Notepad.exe and Calc.exe, and replace them with applications that: 1) don\u2019t require a visible window; and, 2) will run and then automatically terminate themselves. (Scripts are a good candidate for this; so are batch files.)<\/P>\n<P>Why those stipulations? That\u2019s easy: for security reasons you cannot create a visible process on a remote computer. We can start Notepad on a remote machine, but that instance of Notepad will run in a hidden window and the user will never see it. And if the user never sees it it\u2019s going to be awfully hard for him or her to use the application and then terminate it. <\/P>\n<P>Make sense? Well, sadly, that doesn\u2019t matter. Like it or not, that\u2019s just the way it works.<\/P>\n<TABLE class=\"dataTable\" id=\"E4D\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note<\/B>. What if you <I>do<\/I> need to start a GUI application on a remote machine, and what if you <I>do<\/I> need that application to run in a visible window? For one approach to that problem <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/resources\/qanda\/sept05\/hey0906.mspx\"><B>see this <\/B><B><I>Hey, Scripting Guy!<\/I><\/B><\/A> column.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>As for the script itself, we begin by connecting to the WMI service on the local computer. We then use this line of code to bind directly to the <B>Win32_Process<\/B> class:<\/P><PRE class=\"codeSample\">Set objProcess = GetObject(&#8220;winmgmts:root\\cimv2:Win32_Process&#8221;)\n<\/PRE>\n<P>Once we\u2019re bound to the Win32_Process class we can start an instance of Notepad by using this line of code:<\/P><PRE class=\"codeSample\">errReturn = objProcess.Create(&#8220;Notepad.exe&#8221;, null, null, intProcessID)\n<\/PRE>\n<P>As you can see, we simply call the <B>Create<\/B> method followed by four parameters:<\/P>\n<TABLE class=\"\" cellSpacing=\"0\" cellPadding=\"0\" border=\"0\">\n<TBODY>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>Notepad.exe<\/B>, the name of the executable file (or script) that we want to start. If this file or script is not in your Windows path then make sure you specify the full path name here.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>Null<\/B>, an optional parameter for specifying a working directory. Because the default directory for Notepad is fine for our purposes we pass a Null parameter, which is the same thing as saying \u201cuse the default value.\u201d<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>Null<\/B>, another optional parameter which enables us to specify startup options for the process. Again, the default values are fine for our purposes, so we pass a Null parameter here, too.<\/P><\/TD><\/TR>\n<TR>\n<TD class=\"listBullet\" vAlign=\"top\">\u2022<\/TD>\n<TD class=\"listItem\">\n<P><B>intProcessID<\/B>, an out parameter. When the script runs and Notepad starts up, the process ID will automatically be assigned to this out parameter. That\u2019s how we can keep track of our copy of Notepad, even if there are multiple copies of Notepad running on the computer.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<P>As soon as Notepad is up and running we set up an event subscription to monitor the <B>__InstanceDeletionEvent <\/B>class:<\/P><PRE class=\"codeSample\">Set colMonitoredProcesses = objWMIService. _        \n    ExecNotificationQuery(&#8220;Select * From __InstanceDeletionEvent &#8221; _ \n        &amp; &#8221; Within 1 Where TargetInstance ISA &#8216;Win32_Process'&#8221;)\n<\/PRE>\n<P>As the name implies, instances of this class are created any time an object is deleted. Of course, we\u2019re not interested in all objects; we\u2019re only interested in process objects. That\u2019s why we add the Where clause that limits our event subscription to objects (the <B>TargetInstance<\/B>) that are members of (<B>ISA<\/B>) the Win32_Process class.<\/P>\n<TABLE class=\"dataTable\" id=\"EHG\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note<\/B>. OK, so maybe that <I>is<\/I> a lot of information packed into a single paragraph. For a kindler, gentler introduction to WMI events, see our <A href=\"http:\/\/msevents.microsoft.com\/cui\/WebCastEventDetails.aspx?EventID=1032268754&amp;EventCategory=3&amp;culture=en-US&amp;CountryCode=US\" target=\"_blank\"><B>Scripting Week 2 webcast<\/B><\/A> on this very subject.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>That brings us to this block of code:<\/P><PRE class=\"codeSample\">Do While True\n    Set objLatestProcess = colMonitoredProcesses.NextEvent\n    If objLatestProcess.TargetInstance.ProcessID = intProcessID Then\n        Exit Do\n    End If\nLoop\n<\/PRE>\n<P>What we\u2019ve done here is set up an \u201cendless\u201d loop that will pause the script until a process is deleted; that\u2019s what the first two lines of code are for:<\/P><PRE class=\"codeSample\">Do While True\n    Set objLatestProcess = colMonitoredProcesses.NextEvent\n<\/PRE>\n<P>When line 2 executes, the script will \u201cblock\u201d (pause) until a process object gets deleted (that is, until a process is terminated). When a process <I>does<\/I> get deleted we then check to see if the process ID of the terminated process is equal to the process ID of the process <I>we<\/I> created:<\/P><PRE class=\"codeSample\">If objLatestProcess.TargetInstance.ProcessID = intProcessID Then\n<\/PRE>\n<P>Because process IDs must be unique at any given time, if the IDs match that can only mean one thing: the instance of Notepad we created has been terminated. In turn, we then call the <B>Exit Do<\/B> statement and exit the \u201cendless\u201d loop.<\/P>\n<P>And what if the process IDs <I>don\u2019t<\/I> match? In that case, that must mean our instance of Notepad is still running; it was some other process that was terminated. Thus we loop around and wait for the next event notification (the next process to be deleted).<\/P>\n<P>When we finally <I>do<\/I> exit the loop we simply call the Create method and start up our second application, in this case, Calc.exe:<\/P><PRE class=\"codeSample\">errReturn = objProcess.Create(&#8220;Calc.exe&#8221;, null, null, intProcessID)\n<\/PRE>\n<P>And then we\u2019re done.<\/P>\n<P>You know, that sounds like a column that\u2019s worth $2.5 million dollars, doesn\u2019t it? Especially when you consider how much other useful tasks the Scripting Guys perform. For example, next week the Scripting Guys will be manning a booth at <A href=\"http:\/\/www.microsoft.com\/events\/teched2007\/default.mspx\" target=\"_blank\"><B>TechEd 2007<\/B><\/A>. If you\u2019re attending TechEd (and you <I>are<\/I> attending TechEd, aren\u2019t you?) then swing by the Partners Expo Hall and look for the CMP Media Booth (booth 1301): the Scripting Guys will be there, handing out copies of <I>Dr. Scripto\u2019s Fun Book<\/I> and giving away <A href=\"http:\/\/www.microsoft.com\/technet\/scriptcenter\/funzone\/games\/games07\/bobble.mspx\"><B>Dr. Scripto bobblehead dolls<\/B><\/A>. In addition, the Scripting Guy who writes this column will be counting his money \u2026 which means he\u2019ll have plenty of time to chat with anyone who drops by.<\/P>\n<TABLE class=\"dataTable\" id=\"EOAAC\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note<\/B>. So will Walter Mossberg be manning a booth at TechEd 2007? Not as far as we know. $1 million a year and he can\u2019t even man a booth at TechEd. Interesting \u2026.<\/P><\/TD><\/TR><\/TBODY><\/TABLE><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! I have a script that starts two applications; however, the second application can not start until the first program has finished running. How can I ensure that my second program doesn\u2019t start until the first one ends?&#8212; OR Hey, OR. Not too long ago the Scripting Guy who writes this column read [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[31,87,3,4,5,6],"class_list":["post-64753","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-operating-system","tag-processes","tag-scripting-guy","tag-scripting-techniques","tag-vbscript","tag-wmi"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! I have a script that starts two applications; however, the second application can not start until the first program has finished running. How can I ensure that my second program doesn\u2019t start until the first one ends?&#8212; OR Hey, OR. Not too long ago the Scripting Guy who writes this column read [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/64753","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=64753"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/64753\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=64753"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=64753"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=64753"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}