{"id":65233,"date":"2007-03-27T02:50:00","date_gmt":"2007-03-27T02:50:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2007\/03\/27\/how-can-i-use-windows-powershell-to-be-notified-when-an-application-terminates\/"},"modified":"2007-03-27T02:50:00","modified_gmt":"2007-03-27T02:50:00","slug":"how-can-i-use-windows-powershell-to-be-notified-when-an-application-terminates","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/how-can-i-use-windows-powershell-to-be-notified-when-an-application-terminates\/","title":{"rendered":"How Can I Use Windows PowerShell to Be Notified When an Application Terminates?"},"content":{"rendered":"<p><H2><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\"> <\/H2>\n<P>Hey, Scripting Guy! We have an in-house application that, unfortunately, crashes a lot; when that happens we have to go through a lengthy procedure to restart the program. Using Windows PowerShell, is there any way I can be notified when this application crashes?<BR><BR>&#8212; OI<\/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, OI. You know, at first we thoughts to ourselves, we thought, \u201cHey, we ain\u2019t a-gonna answer none of them there questions today.\u201d And we really wuzn\u2019t a-gonna do it, no sir. But now we is. Ain\u2019t that a kick in the head?<\/P>\n<P>Sorry; we got a little carried away there. It\u2019s just that we\u2019re a bit giddy with excitement this morning. Remember that scene in <I>The Wizard of Oz<\/I> where everyone dances around singing, \u201cDing-dong the witch is dead\u201d? Well, we feel the same way: this week the Scripting Editor is down in San Diego attending the Microsoft Management Summit (MMS); that gives us at least a temporary reprieve from her red-pencil reign of terror. For years we\u2019ve been waiting for the chance to misspell words; now we can. For years we\u2019ve been waiting for the chance to use bad grammar; now we can. For years we\u2019ve been waiting for the chance to write entire paragraphs \u2013 no, make that entire <I>columns<\/I> \u2013 that don\u2019t make a bit a sense. And now we \u2013 well, OK, that we <I>have<\/I> been doing. But at least now we can write meaningless columns without having her interrupt us every two minutes and ask, \u201cWhat is <I>this<\/I> supposed to mean?\u201d<\/P>\n<P>Come on, everybody sing: ding-dong the witch is dead \u2026.<\/P>\n<P>Sorry. We\u2019re still a little giddy.<\/P>\n<P>Interestingly enough, another thing we\u2019ve wanted to do for years is show you how, using Windows PowerShell, you can be notified any time a particular process is terminated. For some reason, however, the Scripting Editor would never let us do that, either. But now there\u2019s no way that she can stop us.<\/P>\n<TABLE class=\"dataTable\" id=\"EMD\" 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>. Evil? Well, <I>evil<\/I> is a pretty strong word. But, yes, we\u2019d have to say that she\u2019s evil.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>As it turns out, working with event notifications in Windows PowerShell is a bit tricky; that\u2019s because PowerShell\u2019s Get-WMIObject Cmdlet doesn\u2019t support event notification queries. (What\u2019s an event notification query? See this <A href=\"http:\/\/msevents.microsoft.com\/cui\/eventdetail.aspx?EventID=1032268754&amp;culture=en-US\" target=\"_blank\"><B>Scripting Guys webcast<\/B><\/A> for more information.) So why <I>doesn\u2019t<\/I> Get-WMIObject support event notification queries? To be honest, we don\u2019t know: you-know-who would never let us look into that. For now, however, all that matters is that we can\u2019t use good old-fashioned WMI to receive a notification any time a process terminates. Instead, we have to take advantage of a couple other options available to us.<\/P>\n<P>One of those options involves the <B>Get-Process<\/B> Cmdlet. In the scenario OI described, we don\u2019t need notification <I>any<\/I> time a process is terminated; we only need notification when a particular process (for our purposes, Calculator) is terminated. Because of that we can create an event notification script with just three lines of code:<\/P><PRE class=\"codeSample\">$a = get-process calc\n$a.waitforexit()\n&#8220;Calculator has stopped running.&#8221;\n<\/PRE>\n<P>To begin with, we use the Get-Process Cmdlet to bind to the process with the name Calc. (The name, by the way, is the executable file name minus the file extension.) It\u2019s important to note that we\u2019re assuming we have only one process with the name Calc. What if we have multiple instances of Calculator running? Well, in that case this first line of code will work \u2013 we\u2019ll get back a collection consisting of all those instances of Calculator \u2013 but the script will fail on line 2. But don\u2019t fret: we\u2019ll show you a more generic process monitoring script in a few minutes.<\/P>\n<P>Once we\u2019ve gotten a handle to the Calc process we then call the <B>WaitForExit()<\/B> method:<\/P><PRE class=\"codeSample\">$a.waitforexit()\n<\/PRE>\n<P>What\u2019s that going to do? That\u2019s going to cause the script to \u201cblock;\u201d that means that the script will simply sit there and wait until the process in question has terminated. When that process <I>does<\/I> terminate we then use the third and final line of code to echo back the fact that Calculator has stopped running. <\/P>\n<P>Now, this script works just fine; try it and see for yourself. However, that doesn\u2019t mean that the script is perfect; for example, each time Calculator stops the script stops as well. That means you\u2019ll need to restart both Calculator and the monitoring script. <\/P>\n<P>And yes, that <I>is<\/I> the way the Scripting Editor would make you do things. But remember, the Scripting Editor isn\u2019t here; that means we can show you an alternate approach:<\/P><PRE class=\"codeSample\">$b = 1<\/p>\n<p>do \n    {\n        $a = get-process calc\n        $a.waitforexit()\n        Invoke-Item c:\\windows\\system32\\calc.exe<\/p>\n<p>    } \nwhile ($b -eq 1)\n<\/PRE>\n<P>What are we doing here? We\u2019re setting up a Do loop that runs as long as the variable $b is equal to 1. (And because $b will <I>always<\/I> be equal to 1 that means that the loop will run forever and ever.) Inside the loop we again bind to the Calc process and call the WaitForExit() method. But notice what we do if and when Calculator terminates. Instead of echoing a message to the screen we use the <B>Invoke-Item<\/B> Cmdlet to restart the application:<\/P><PRE class=\"codeSample\">Invoke-Item c:\\windows\\system32\\calc.exe\n<\/PRE>\n<P>And once Calculator restarts we loop around and resume monitoring. We don\u2019t know what OI means by \u201ca lengthy procedure\u201d to restart the in-house application, but if it\u2019s possible to do that programmatically then this might be a better way to go. Of course, in addition to restarting the application we can also report the fact that Calculator had to be restarted, maybe by echoing a message to the screen or writing a note to a log file or the event log or, well, whatever. That\u2019s entirely up to you.<\/P>\n<TABLE class=\"dataTable\" id=\"ELF\" 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>. Like we said, the preceding script is designed to run forever; the only way to stop it is to terminate that particular instance of Windows PowerShell. It\u2019s possible to modify the script so that it stops any time you, say, press the <B>Q<\/B> key on the keyboard, but that\u2019s a more involved procedure than we have time for today.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Like the first script we showed you, our fancy restart-the-process script works only if you have one instance of the target process running; if you have multiple instances of Calculator then you\u2019re going to run into trouble. In addition, this script works only with processes; that\u2019s because the Get-Process Cmdlet includes a WaitForExit() method. That\u2019s not necessarily going to be the case for other entities.<\/P>\n<P>With that in mind let\u2019s take a look at a more generic event monitoring script, one that uses the .NET Framework. First we\u2019ll show you the code, then we\u2019ll briefly describe how the script works: <\/P><PRE class=\"codeSample\">$a = 0<\/p>\n<p>$timespan = New-Object System.TimeSpan(0, 0, 1)\n$scope = New-Object System.Management.ManagementScope(&#8220;\\\\.\\root\\cimV2&#8221;)\n$query = New-Object System.Management.WQLEventQuery `\n    (&#8220;__InstanceDeletionEvent&#8221;,$timespan, &#8220;TargetInstance ISA &#8216;Win32_Process'&#8221; )\n$watcher = New-Object System.Management.ManagementEventWatcher($scope,$query)<\/p>\n<p>do \n    {\n        $b = $watcher.WaitForNextEvent()\n        $b.TargetInstance.Name\n    } \nwhile ($a -ne 1)\n<\/PRE>\n<P>With this script we\u2019re checking, every second, for deleted processes. How do we know we\u2019re going to check every second? Because of the way we configured our <B>System.Timespan<\/B> object:<\/P><PRE class=\"codeSample\">$timespan = New-Object System.TimeSpan(0, 0, 1)\n<\/PRE>\n<P>As you can see, we included three parameters \u2013 <B>0<\/B>, <B>0<\/B>, and <B>1<\/B> \u2013 when creating the new object. The first 0 represents hours, the second represents minutes, and the 1 represents seconds. What if we wanted to check for deleted processes every 15 minutes and 30 seconds? Then we\u2019d use this line of code:<\/P><PRE class=\"codeSample\">$timespan = New-Object System.TimeSpan(0, 15, 30)\n<\/PRE>\n<P>And how do we know we\u2019re looking for <I>processes<\/I> that have been deleted? Because that\u2019s what we asked for when we set up our <B>WQLEventQuery<\/B>:<\/P><PRE class=\"codeSample\">$query = New-Object System.Management.WQLEventQuery `\n    (&#8220;__InstanceDeletionEvent&#8221;,$timespan, &#8220;TargetInstance ISA &#8216;Win32_Process'&#8221; )\n<\/PRE>\n<P>See? We\u2019re looking for instances of the <B>__InstanceDeletionEvent<\/B> class, but only if those instances happen to be processes (that is, members of the <B>Win32_Process<\/B> class).<\/P>\n<TABLE class=\"dataTable\" id=\"E6G\" 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>. Yes, that\u2019s a cursory explanation, at best, of terms like <I>__InstanceDeletionEvent<\/I> and <I>TargetInstance<\/I>. But you can take a look at the <A href=\"http:\/\/msevents.microsoft.com\/cui\/eventdetail.aspx?EventID=1032268754&amp;culture=en-US\" target=\"_blank\"><B>aforementioned<\/B>&#8211;<B>webcast<\/B><\/A> for more details.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>After creating an instance of the <B>System.Management.ManagementEventWatcher<\/B> class we then go into another endless loop and wait for processes to be terminated. Each time a process ends we use this line of code to report back the process <B>Name<\/B>:<\/P><PRE class=\"codeSample\">$b.TargetInstance.Name\n<\/PRE>\n<P>Of course, we could get fancier here and issue an alert only if, say, the terminated process happened to be an instance of Calculator. But we\u2019ll let you do that sort of modification yourself.<\/P>\n<P>Oh, and thanks for asking: as a matter of fact, the Scripting Editor <I>is<\/I> planning to report back on her trip to MMS. Will that report be as interesting and entertaining as this column? Heavens no. But at least every word will be spelled correctly. <\/P>\n<TABLE class=\"dataTable\" id=\"EJAAC\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P><B>Ed<\/B><B>itor\u2019s Note:<\/B> The really amazing thing about the Scripting Editor is that she carries around a crystal ball (sometimes referred to as a laptop computer) that allows her to keep an eye on the other Scripting Guys from great distances. We won\u2019t discuss the consequences they\u2019ll suffer for their sad attempt to defy the powers of the Scripting Editor, but rest assured it will be\u2026unpleasant. Not that they\u2019ll ever learn their lesson\u2026.<\/P>\n<P>And keep an eye out on the Script Center for the Scripting Editor\u2019s <I>riveting<\/I> account of Microsoft Management Summit 2007 \u2013 or at least her riveting account of the weather in San Diego.<\/P><\/TD><\/TR><\/TBODY><\/TABLE><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! We have an in-house application that, unfortunately, crashes a lot; when that happens we have to go through a lengthy procedure to restart the program. Using Windows PowerShell, is there any way I can be notified when this application crashes?&#8212; OI Hey, OI. You know, at first we thoughts to ourselves, we [&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,45],"class_list":["post-65233","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-operating-system","tag-processes","tag-scripting-guy","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! We have an in-house application that, unfortunately, crashes a lot; when that happens we have to go through a lengthy procedure to restart the program. Using Windows PowerShell, is there any way I can be notified when this application crashes?&#8212; OI Hey, OI. You know, at first we thoughts to ourselves, we [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/65233","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=65233"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/65233\/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=65233"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=65233"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=65233"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}