{"id":65883,"date":"2006-12-08T13:39:00","date_gmt":"2006-12-08T13:39:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2006\/12\/08\/how-can-i-start-a-process-and-then-wait-for-the-process-to-end-before-terminating-the-script\/"},"modified":"2006-12-08T13:39:00","modified_gmt":"2006-12-08T13:39:00","slug":"how-can-i-start-a-process-and-then-wait-for-the-process-to-end-before-terminating-the-script","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/how-can-i-start-a-process-and-then-wait-for-the-process-to-end-before-terminating-the-script\/","title":{"rendered":"How Can I Start a Process and Then Wait For the Process to End Before Terminating the Script?"},"content":{"rendered":"<p><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\"><\/p>\n<p>Hey, Scripting Guy! How can I start a process and then wait until that process quits before terminating the script?<\/p>\n<p>&#8212; FG<\/p>\n<p><img decoding=\"async\" border=\"0\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" height=\"5\"><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\"><a href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><img decoding=\"async\" class=\"farGraphic\" title=\"Script Center\" border=\"0\" alt=\"Script Center\" align=\"right\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" height=\"288\"><\/a><\/p>\n<p>Hey, FG. Before we answer your question, the Scripting Guy who writes this column has a confession to make: he\u2019s the one who ruined Christmas for everyone. Not that he meant to, mind you, but that doesn\u2019t matter; all that matters is that he ruined Christmas. Last night this Scripting Guy was watching TV when he noticed a commercial featuring a delicatessen where orders were filled like clockwork: you came in, ordered, got your food, paid for your purchase, and then went on your merry way, all in a matter of seconds. And all done to snappy music to boot.<\/p>\n<p>Well, at least until some idiot had the audacity to \u2013 believe it or not \u2013 pay for his purchase using <i>money<\/i> instead of a debit card! Not only did the finely-tuned delicatessen machine come to a screeching halt, but the looks of disgust on the faces of both the cashier and the other deli patrons made everyone\u2019s feelings very clear: \u201cThanks a lot, buddy. You not only ruined Christmas for yourself, but you ruined it for everyone else in the world, too. We hope you\u2019re happy.\u201d<\/p>\n<p>As you probably guessed, the Scripting Guy who writes this column is that idiot. It\u2019s true: although he <i>has<\/i> a debit card he only uses it at the ATM machine. When it comes to actually buying stuff he always pays cash. Always. And when it comes time to pay the bills he always writes a check, puts the check in an envelope, puts a stamp on the envelope, and mails the thing. (You better sit down; you look a little faint.) No automatic deductions from his checking account, no Internet bill-paying; he still pays his bills the very same way Neanderthals paid <i>their<\/i> bills. <\/p>\n<table id=\"EID\" class=\"dataTable\" cellSpacing=\"0\" cellPadding=\"0\">\n<thead><\/thead>\n<tbody>\n<tr class=\"record\" vAlign=\"top\">\n<td>\n<p class=\"lastInCell\"><b>Note<\/b>. OK, you got us there: even Neanderthals used pay-by-phone whenever possible.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"dataTableBottomMargin\"><\/div>\n<p>Needless to say, the Scripting Guy who writes this column humbly apologizes for his boorish and unthinking behavior, and deeply regrets having ruined Christmas for everyone else.<\/p>\n<p>So does this mean that the Scripting Guy who writes this column is going to come to his senses and finally join the modern world? Oh, heavens no; he <i>likes<\/i> being an anachronism. However, he will at least show you how to write a script that starts a process and then waits around until that process has finished before terminating:<\/p>\n<pre class=\"codeSample\">strComputer = \".\"\nSet objWMIService = GetObject(\"winmgmts:\\\\\" &amp; strComputer &amp; \"\\root\\cimv2:Win32_Process\")\nobjWMIService.Create \"notepad.exe\", null, null, intProcessID\nSet objWMIService = GetObject(\"winmgmts:\\\\\" &amp; strComputer &amp; \"\\root\\cimv2\")\nSet colMonitoredProcesses = objWMIService.ExecNotificationQuery _\n    (\"Select * From __InstanceDeletionEvent Within 1 Where TargetInstance ISA 'Win32_Process'\")\nDo Until i = 1\n    Set objLatestProcess = colMonitoredProcesses.NextEvent\n    If objLatestProcess.TargetInstance.ProcessID = intProcessID Then\n        i = 1\n    End If\nLoop\nWscript.Echo \"Notepad has been terminated.\"\n<\/pre>\n<p>As you can see, we start off by connecting to the WMI service on the local computer. Could we also run this script against a remote computer? Sure we could; however, keep in mind that any process you start on a remote computer will, for security reasons, run in an invisible window and will not appear onscreen. That means you could use this script to run command-line tools that do their thing and then automatically terminate themselves upon finishing; those would work just fine. When it comes to GUI applications, which typically don\u2019t terminate themselves, this script is less useful, at least when run against remote computers. That\u2019s because the GUI application will run in an invisible window, making it far more difficult for someone to terminate that application.<\/p>\n<p>But don\u2019t let that deter you: for command-line tools or for any application started on the local computer this approach works great. <\/p>\n<p>Speaking of the WMI service, we should point out that, when making the connection to this service, we need to bind directly to the <b>Win32_Process<\/b> class:<\/p>\n<pre class=\"codeSample\">Set objWMIService = GetObject(\"winmgmts:\\\\\" &amp; strComputer &amp; \"\\root\\cimv2:Win32_Process\")\n<\/pre>\n<p>Why? Because in order to call the <b>Create<\/b> method and create a new process, we need to be connected to the class itself. The typical WMI approach \u2013 using ExecQuery to return a collection of all instances of the class \u2013 doesn\u2019t do us any good here.<\/p>\n<p>After making the connection we use the following line of code to create an instance of Notepad.exe (a GUI application, but that\u2019s OK: in this example we\u2019re running it locally anyway). With this line of code we call the <b>Create<\/b> method followed by the executable file we want to run (Notepad.exe). The executable file name is then followed by two Null parameters (startup parameters not used in this script), then followed by an \u201cout parameter\u201d named intProcessID:<\/p>\n<pre class=\"codeSample\">objWMIService.Create \"notepad.exe\", null, null, intProcessID\n<\/pre>\n<p>What was that again: an <i>out<\/i> parameter? Yes. Typically when you call methods you supply information (<i>in<\/i> parameters) to the method; for example, the executable file name (Notepad.exe) is an in parameter. With an out parameter, the method supplies information to <i>you<\/i>; in this case, that will be the process ID (PID) of the new process. All we have to do is provide the name of the variable where we want that information stored and the Create method will take care of the rest.<\/p>\n<p>At this point we want the script to simply sit around and wait until Notepad is done doing whatever it is Notepad does. To do <i>that<\/i> we create a second WMI object reference (reusing the variable named objWMIService) and then use the following query to monitor process deletion:<\/p>\n<pre class=\"codeSample\">Set colMonitoredProcesses = objWMIService.ExecNotificationQuery _\n    (\"Select * From __InstanceDeletionEvent Within 1 Where TargetInstance ISA 'Win32_Process'\")\n<\/pre>\n<p>We won\u2019t discuss monitoring scripts in any detail today; for more information, see the webcast <a href=\"http:\/\/msevents.microsoft.com\/cui\/eventdetail.aspx?EventID=1032268754&amp;culture=en-US\" target=\"_blank\"><b>An Ounce of Prevention: An Introduction to WMI Events<\/b><\/a>. Suffice to say that we\u2019re simply asking WMI to notify us any time a process is deleted (terminated). And we\u2019d like WMI to check for any new deletions every second, which is what the <b>Within 1<\/b> is for.<\/p>\n<p>After we issue the query we set up the following Do loop, a loop designed to run until a variable named i is equal to 1 (because i has not been initialized, it begins life equal to 0):<\/p>\n<pre class=\"codeSample\">Do Until i = 1\n    Set objLatestProcess = colMonitoredProcesses.NextEvent\n    If objLatestProcess.TargetInstance.ProcessID = intProcessID Then\n        i = 1\n    End If\nLoop\n<\/pre>\n<p>Inside this loop we use the following line of code to wait until WMI notifies us that a process has been deleted:<\/p>\n<pre class=\"codeSample\">Set objLatestProcess = colMonitoredProcesses.NextEvent\n<\/pre>\n<p>So what happens if a process <i>does<\/i> get deleted? Well, in that case we check to see if the <b>ProcessID<\/b> of the deleted process (objLatestProcess.TargetInstance.ProcessID) is equal to the ProcessID of the process we created:<\/p>\n<pre class=\"codeSample\">If objLatestProcess.TargetInstance.ProcessID = intProcessID Then\n<\/pre>\n<p>If the ProcessIDs differ we loop around and wait for notification of the next deleted process. If the ProcessIDs match that can only mean one thing: the process we started has been terminated. In that case we set the value of i to 1, something which, in turn, causes us to exit the loop.<\/p>\n<p>At that point we simply echo back a message stating that Notepad has been terminated. Needless to say, though, you can do anything you want at this point; after all, it\u2019s your script. (Or don\u2019t do anything at all; if you prefer, you can just exit the loop and the script will automatically terminate right then and there.)<\/p>\n<p>So will the Scripting Guy who writes this column even <i>consider<\/i> using a debit card to pay for purchases from now on? Well, to tell you the truth, that <i>did<\/i> look a lot faster and a lot easier than paying by cash. Of course, the people on this commercial simply swiped their card and then moved on: they didn\u2019t have to enter a PIN number, they didn\u2019t have to wait for authorization, and they didn\u2019t have to sign anything. And none of them ever asked if they could get cash back, either. But maybe none of that happens anymore. After all, the makers of a commercial would <i>never<\/i> fudge the truth a little just to make their product look better. Heaven forbid!<\/p>\n<p>Tell you what: Christmas is already ruined, but we\u2019ll see if we can avoid ruining Valentine\u2019s Day for you. We can\u2019t promise anything, but we\u2019ll see.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! How can I start a process and then wait until that process quits before terminating the script? &#8212; FG Hey, FG. Before we answer your question, the Scripting Guy who writes this column has a confession to make: he\u2019s the one who ruined Christmas for everyone. Not that he meant to, mind [&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":[42,31,87,3,4,5],"class_list":["post-65883","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-events-and-monitoring","tag-operating-system","tag-processes","tag-scripting-guy","tag-scripting-techniques","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! How can I start a process and then wait until that process quits before terminating the script? &#8212; FG Hey, FG. Before we answer your question, the Scripting Guy who writes this column has a confession to make: he\u2019s the one who ruined Christmas for everyone. Not that he meant to, mind [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/65883","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=65883"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/65883\/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=65883"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=65883"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=65883"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}