Hey, Scripting Guy! How Can I Write an Event-Driven Script?

ScriptingGuy1

Bookmark and Share

 

Hey, Scripting Guy! Question

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 really a server—it is running Windows XP.

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?

— SC

Hey, Scripting Guy! AnswerHello SC,

Microsoft Scripting Guy Ed Wilson here. I am sipping a cup of gunpowder green tea with a cinnamon stick and a little lemon grass, listening to Mozart on my Zune, and nibbling on a Tim Tam 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.)

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.

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 VBScript book, or in my WMI book, the event-driven scripts were the most popular scripts.

A VBScript that will detect when a new process starts is discussed in the How Can I Monitor for the Creation of Different Processes? Hey, Scripting Guy! article. The MonitorForProcessCreation.vbs script is seen here.

MonitorForProcessCreation.vbs

arrProcesses = Array(“freecell.exe”,”sol.exe”,”spider.exe”,”winmine.exe”)

strComputer = “.”

Set objWMIService = GetObject(“winmgmts:\” & strComputer & “rootcimv2”)

i = 0

Set colMonitoredProcesses = objWMIService. ExecNotificationQuery _       
    (“Select * From __InstanceCreationEvent Within 5 Where TargetInstance ISA ‘Win32_Process'”)

Do While i = 0
    Set objLatestProcess = colMonitoredProcesses.NextEvent
    strProcess = LCase(objLatestProcess.TargetInstance.Name)

    For Each strName in arrProcesses
        If strName = strProcess Then
            Wscript.Echo strName & ” has started.”
        End If
    Next
Loop

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 Register-WmiEvent cmdlet is that the script is much easier to write and read. The MonitorForNotePadOrCalcGenerateEvent.ps1 script is seen here. 

MonitorForNotepadOrCalcGenerateEvent.ps1

#requires -version 2.0

$progs = “calc.exe, notepad.exe”

Register-WmiEvent -Class win32_ProcessStartTrace -SourceIdentifier processStarted

$newEvent = Wait-Event -SourceIdentifier processStarted

If ($progs -match $newEvent.SourceEventArgs.NewEvent.ProcessName)

   { write-host $newEvent.SourceEventArgs.NewEvent.ProcessName “detected” }

The first thing that is done in the MonitorForNotepadOrCalcGenerateEvent.ps1 script is the use of the #requires tag. I recommend using the #requires 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 #requires tag, you prevent the script from running on Windows PowerShell 1.0. The tag is shown here:

#requires -version 2.0

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 $progs holds the string assignment as seen here:

$progs = “calc.exe, notepad.exe”

The Register-WmiEvent cmdlet is used to register the event with WMI. The WMI class, Win32_ProcessStartTrace is an intrinsic event class, which means it automatically knows how to do events. When a new process starts, the Win32_ProcessStartTrace WMI class will trigger an event. The SourceIdentifier 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:

PS C:Usersadministrator.NWTRADERS> C:Usersadministrator.NWTRADERSDocumentsMonitorForNotepadOrCalcGenerateEvent.ps1

Register-WmiEvent : Cannot subscribe to event. A subscriber with source identifier ‘processStarted’ already exists.

At C:Usersadministrator.NWTRADERSDocumentsMonitorForNotepadOrCalcGenerateEvent.ps1:10 char:18

+ Register-WmiEvent <<<<  -Class win32_ProcessStartTrace -SourceIdentifier processStarted

    + CategoryInfo          : InvalidArgument: (System.Management.ManagementEventWatcher:ManagementEventWatcher) [Register-WmiEvent], 

   ArgumentException

    + FullyQualifiedErrorId : SUBSCRIBER_EXISTS,Microsoft.PowerShell.Commands.RegisterWmiEventCommand

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:

Get-Event | Remove-Event                                                                                                         

Get-EventSubscriber | Unregister-Event  

The code to register a WMI event is seen here:

Register-WmiEvent -Class win32_ProcessStartTrace -SourceIdentifier processStarted

The Wait-Event 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 $newEvent variable. By default the Wait-Event cmdlet will wait for any event, but by using the SourceIdentifier parameter, the Wait-Event cmdlet will respond to events from the specific source. You can also specify a timeout value that would cause the Wait-Event cmdlet to pause for a specific amount of time before returning control back to the script. This section of the script is seen here:

$newEvent = Wait-Event -SourceIdentifier processStarted

The if statement is used to determine if the processName that triggered the event matches one of the program names in the $progs variable. If the program name matches, the Write-Host cmdlet is used to display the name of the process that was detected. The code that does this is shown here:

If ($progs -match $newEvent.SourceEventArgs.NewEvent.ProcessName)

   { write-host $newEvent.SourceEventArgs.NewEvent.ProcessName “detected” }

Once an event has been triggered, the script will exit. When the script is run with the Windows PowerShell ISE, this output is seen:

Image of output seen when script is run with Windows PowerShell ISE


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.

If you want to know exactly what we will be looking at tomorrow, follow us on Twitter or Facebook. If you have any questions, send e-mail to us at scripter@microsoft.com or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

 

0 comments

Discussion is closed.

Feedback usabilla icon