{"id":52113,"date":"2009-11-02T00:01:00","date_gmt":"2009-11-02T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2009\/11\/02\/hey-scripting-guy-how-can-i-write-an-event-driven-script\/"},"modified":"2009-11-02T00:01:00","modified_gmt":"2009-11-02T00:01:00","slug":"hey-scripting-guy-how-can-i-write-an-event-driven-script","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-how-can-i-write-an-event-driven-script\/","title":{"rendered":"Hey, Scripting Guy! How Can I Write an Event-Driven Script?"},"content":{"rendered":"<p><!-- AddThis Button BEGIN --><a class=\"addthis_button\" href=\"http:\/\/www.addthis.com\/bookmark.php?v=250&amp;pub=scriptingguys\"><img decoding=\"async\" alt=\"Bookmark and Share\" src=\"http:\/\/s7.addthis.com\/static\/btn\/v2\/lg-share-en.gif\" width=\"125\" height=\"16\"><\/a><!-- AddThis Button END --><\/p>\n<p class=\"MsoNormal\">&nbsp;<\/p>\n<p><span><\/p>\n<p><img decoding=\"async\" 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 class=\"MsoNormal\">\n<p><\/span><\/p>\n<p>Hey, Scripting Guy! I have a problem at work. It is not with the <a href=\"http:\/\/bit.ly\/2d4DJQ\"><font face=\"Segoe\">pointy-headed<\/font><\/a> boss, but I believe the problem is probably related to him anyway. There is this application that runs on a workstation in our computer room. It is not a client server application, and of course the workstation is not really a server&mdash;it is running Windows XP. <\/p>\n<p class=\"MsoNormal\">Anyway, here is the problem. When the workstation reboots, the application starts automatically (the shortcut to it is placed in the Startup folder). After the application has started, a reporting application needs to start. If the reporting application starts before the main application is completely initialized, the reporting application will hang forever. The only way to recover is to reboot the workstation. Unfortunately, the stupid main application does not shut down cleanly if it did not finish loading. At those times, the indexes have a tendency to become corrupt, and then we have to run this utility to clean up the index and that takes nearly 4 hours to complete. We do not shut down the workstation, but unfortunately with your security patches coming out the first Tuesday of every month, we have to reboot this machine at least once a month. It then becomes a crap shoot to see if we can get the computer up before everyone goes for lunch. I know you cannot fix the stupid application or fire the pointy headed boss who purchased this application, but is there anything I can do with a script to make it easier to get the application up and running?<\/p>\n<p class=\"MsoNormal\">&#8212; SC<\/p>\n<p class=\"MsoNormal\"><img decoding=\"async\" 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\">Hello SC, <\/p>\n<p class=\"MsoNormal\">Microsoft Scripting Guy Ed Wilson here. I am sipping a cup of <a href=\"http:\/\/bit.ly\/1sDVYv\"><font face=\"Segoe\">gunpowder green tea<\/font><\/a> with a cinnamon stick and a little lemon grass, listening to Mozart on my Zune, and nibbling on a <a href=\"http:\/\/bit.ly\/39Dieh\"><font face=\"Segoe\">Tim Tam<\/font><\/a> that my friend Brent sent me from Australia. The gunpowder green tea and the Mozart were planned. The Tim Tam was an accident. When I headed to the kitchen for my snack, I spotted the Scripting Wife with a freshly opened bag of Tim Tams and I prevailed upon her to share one with me. (You may recall that the Tim Tams belong to the Scripting Wife, and the Anzac biscuits are mine.) <\/p>\n<p class=\"MsoNormal\">Tim Tams are very sweet, and one does not need to eat more than one or two in a single sitting. They are perfect with coffee (which I seldom drink) or with the slightly sweet smoky taste of the gunpowder green tea. <\/p>\n<p class=\"MsoNormal\">SC, what you need to do is to write an event-driven script. In VBScript the technique to respond to an event from within a script was rather esoteric. In my <a href=\"http:\/\/bit.ly\/6lPWP\"><font face=\"Segoe\">VBScript book, or in my WMI book<\/font><\/a>, the event-driven scripts were the most popular scripts. <\/p>\n<p class=\"MsoNormal\">A VBScript that will detect when a new process starts is discussed in the <a href=\"http:\/\/bit.ly\/1Oxvz0\"><font face=\"Segoe\">How Can I Monitor for the Creation of Different Processes?<\/font><\/a> Hey, Scripting Guy! article. The MonitorForProcessCreation.vbs script is seen here. <\/p>\n<p class=\"CodeBlockScreenedHead\"><strong>MonitorForProcessCreation.vbs<\/strong><\/p>\n<p class=\"CodeBlockScreened\"><span><font><font face=\"Lucida Sans Typewriter\">arrProcesses = Array(&#8220;freecell.exe&#8221;,&#8221;sol.exe&#8221;,&#8221;spider.exe&#8221;,&#8221;winmine.exe&#8221;)<\/p>\n<p>strComputer = &#8220;.&#8221;<\/p>\n<p>Set objWMIService = GetObject(&#8220;winmgmts:\\&#8221; &amp; strComputer &amp; &#8220;rootcimv2&#8221;)<\/p>\n<p>i = 0<\/p>\n<p>Set colMonitoredProcesses = objWMIService. ExecNotificationQuery _&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; (&#8220;Select * From __InstanceCreationEvent Within 5 Where TargetInstance ISA &#8216;Win32_Process'&#8221;)<\/p>\n<p>Do While i = 0<br>&nbsp;&nbsp;&nbsp; Set objLatestProcess = colMonitoredProcesses.NextEvent<br>&nbsp;&nbsp;&nbsp; strProcess = LCase(objLatestProcess.TargetInstance.Name)<\/p>\n<p>&nbsp;&nbsp;&nbsp; For Each strName in arrProcesses<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; If strName = strProcess Then<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Wscript.Echo strName &amp; &#8221; has started.&#8221;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; End If<br>&nbsp;&nbsp;&nbsp; Next<br>Loop<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The MonitorForNotePadOrCalcGenerateEvent.ps1 script is very similar to the MonitorForProcessCreation.vbs script in functionality. Both scripts use WMI eventing, but the Windows PowerShell script uses a new cmdlet that was introduced in Windows PowerShell 2.0 (which officially was released on Thursday, October 22, with Windows 7). The advantage of using the <b>Register-WmiEvent<\/b> cmdlet is that the script is much easier to write and read. The MonitorForNotePadOrCalcGenerateEvent.ps1 script is seen here.<span>&nbsp; <\/span><\/p>\n<p class=\"CodeBlockScreenedHead\"><strong>MonitorForNotepadOrCalcGenerateEvent.ps1<\/strong><\/p>\n<p class=\"CodeBlockScreened\"><span><font><font face=\"Lucida Sans Typewriter\">#requires -version 2.0<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"CodeBlockScreened\"><span><font><font face=\"Lucida Sans Typewriter\">$progs = &#8220;calc.exe, notepad.exe&#8221;<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"CodeBlockScreened\"><span><font><font face=\"Lucida Sans Typewriter\">Register-WmiEvent -Class win32_ProcessStartTrace -SourceIdentifier processStarted<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"CodeBlockScreened\"><span><font><font face=\"Lucida Sans Typewriter\">$newEvent = Wait-Event -SourceIdentifier processStarted<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"CodeBlockScreened\"><span><font><font face=\"Lucida Sans Typewriter\">If ($progs -match $newEvent.SourceEventArgs.NewEvent.ProcessName) <\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"CodeBlockScreened\"><span><font><font face=\"Lucida Sans Typewriter\"><span>&nbsp;&nbsp; <\/span>{ write-host $newEvent.SourceEventArgs.NewEvent.ProcessName &#8220;detected&#8221; }<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The first thing that is done in the MonitorForNotepadOrCalcGenerateEvent.ps1 script is the use of the <b>#requires<\/b> tag. I recommend using the <b>#requires<\/b> tag anytime that you write a Windows PowerShell script that you know uses a feature from Windows PowerShell 2.0 that is not available in Windows PowerShell 1.0. By specifying the <b>#requires<\/b> tag, you prevent the script from running on Windows PowerShell 1.0. The tag is shown here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">#requires -version 2.0<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The program names, which are stored in a single string, are not an array of program names, but a single string. This is because later, a regular expression pattern will be used to determine if the program is listed in the allow list. The variable <b>$progs<\/b> holds the string assignment as seen here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">$progs = &#8220;calc.exe, notepad.exe&#8221;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The <b>Register-WmiEvent<\/b> cmdlet is used to register the event with WMI. The WMI class, <a href=\"http:\/\/bit.ly\/3XXxMW\"><font face=\"Segoe\">Win32_ProcessStartTrace<\/font><\/a> is an intrinsic event class, which means it automatically knows how to do events. When a new process starts, the <b>Win32_ProcessStartTrace<\/b> WMI class will trigger an event. The <b>SourceIdentifier<\/b> parameter is used to specify a name for the WMI event subscription. It must be unique for the Windows PowerShell session, or an error will be generated. This is seen here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">PS C:Usersadministrator.NWTRADERS&gt; C:Usersadministrator.NWTRADERSDocumentsMonitorForNotepadOrCalcGenerateEvent.ps1<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">Register-WmiEvent : Cannot subscribe to event. A subscriber with source identifier &#8216;processStarted&#8217; already exists.<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">At C:Usersadministrator.NWTRADERSDocumentsMonitorForNotepadOrCalcGenerateEvent.ps1:10 char:18<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">+ Register-WmiEvent &lt;&lt;&lt;&lt;<span>&nbsp; <\/span>-Class win32_ProcessStartTrace -SourceIdentifier processStarted<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\"><span>&nbsp;&nbsp;&nbsp; <\/span>+ CategoryInfo<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>: InvalidArgument: (System.Management.ManagementEventWatcher:ManagementEventWatcher) [Register-WmiEvent],<span>&nbsp; <\/span><\/p>\n<p><\/font><\/span><\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\"><span>&nbsp;&nbsp; <\/span>ArgumentException<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\"><span>&nbsp;&nbsp;&nbsp; <\/span>+ FullyQualifiedErrorId : SUBSCRIBER_EXISTS,Microsoft.PowerShell.Commands.RegisterWmiEventCommand<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">An easy way to avoid errors when attempting to create a new event subscription is to collect the events and remove the events, and then do the same thing for the registered event subscriptions. The code to do this is seen here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">Get-Event | Remove-Event<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/p>\n<p><\/font><\/span><\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">Get-EventSubscriber | Unregister-Event<span>&nbsp;&nbsp; <\/span><\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The code to register a WMI event is seen here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">Register-WmiEvent -Class win32_ProcessStartTrace -SourceIdentifier processStarted<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The <b>Wait-Event<\/b> cmdlet is used to cause the script to halt execution while it waits for an event to occur. When the event is raised, the resulting object is stored in the <b>$newEvent<\/b> variable. By default the <b>Wait-Event<\/b> cmdlet will wait for any event, but by using the <b>SourceIdentifier<\/b> parameter, the <b>Wait-Event<\/b> cmdlet will respond to events from the specific source. You can also specify a timeout value that would cause the <b>Wait-Event<\/b> cmdlet to pause for a specific amount of time before returning control back to the script. This section of the script is seen here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">$newEvent = Wait-Event -SourceIdentifier processStarted<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The <b>if<\/b> statement is used to determine if the <b>processName<\/b> that triggered the event matches one of the program names in the <b>$progs<\/b> variable. If the program name matches, the <b>Write-Host<\/b> cmdlet is used to display the name of the process that was detected. The code that does this is shown here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">If ($progs -match $newEvent.SourceEventArgs.NewEvent.ProcessName) <\/p>\n<p><\/font><\/span><\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\"><span>&nbsp;&nbsp; <\/span>{ write-host $newEvent.SourceEventArgs.NewEvent.ProcessName &#8220;detected&#8221; }<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">Once an event has been triggered, the script will exit. When the script is run with the Windows PowerShell ISE, this output is seen:<\/p>\n<p class=\"Fig-Graphic\"><img decoding=\"async\" title=\"Image of output seen when script is run with Windows PowerShell ISE\" alt=\"Image of output seen when script is run with Windows PowerShell ISE\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/october\/hey1026\/hsg-10-26-09-01.jpg\" width=\"600\" height=\"471\"><\/p>\n<p class=\"MsoNormal\"><br>Well, SC, as you can see, using events in Windows PowerShell scripts is considerably easier that it was when using VBScript. Join us tomorrow as WMI Event Week continues. <\/p>\n<p class=\"MsoNormal\">If you want to know exactly what we will be looking at tomorrow, follow us on <a href=\"http:\/\/www.twitter.com\/scriptingguys\/\" target=\"_blank\"><font face=\"Segoe\">Twitter<\/font><\/a> or <a href=\"http:\/\/www.facebook.com\/home.php?#\/group.php?gid=5901799452\" target=\"_blank\"><font face=\"Segoe\">Facebook<\/font><\/a>. If you have any questions, send e-mail to us at <a href=\"http:\/\/blogs.technet.commailto:scripter@microsoft.com\" target=\"_blank\"><font face=\"Segoe\">scripter@microsoft.com<\/font><\/a> or post your questions on the <a href=\"http:\/\/social.technet.microsoft.com\/Forums\/en\/ITCG\/threads\/\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p class=\"MsoNormal\">&nbsp;<\/p>\n<p><b><span>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/p>\n<p><\/span><\/b><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Hey, Scripting Guy! I have a problem at work. It is not with the pointy-headed boss, but I believe the problem is probably related to him anyway. There is this application that runs on a workstation in our computer room. It is not a client server application, and of course the workstation is not [&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,3,4,45],"class_list":["post-52113","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-events-and-monitoring","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>&nbsp; Hey, Scripting Guy! I have a problem at work. It is not with the pointy-headed boss, but I believe the problem is probably related to him anyway. There is this application that runs on a workstation in our computer room. It is not a client server application, and of course the workstation is not [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/52113","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=52113"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/52113\/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=52113"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=52113"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=52113"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}