Hey, Scripting Guy! How Can I Be Notified When a Process Begins?

ScriptingGuy1

Hey, Scripting Guy! Question

Hey, Scripting Guy! I need to be notified when a process begins. I would like to use Windows PowerShell to do this, but it does not seem to work. While I could do this in VBScript, I prefer to use Windows PowerShell. Can this be done?

– NL

SpacerHey, Scripting Guy! Answer

Hi NL,

Because we have access to the .NET Framework in Windows PowerShell, it can most certainly be done. In Windows PowerShell 2.0, which just released as Community Technology Preview (CTP) 3, there is actually a cmdlet that you can use. But because a CTP is not supported, you can use the .NET Framework classes today. The advantage of this approach is that it will work with both Windows PowerShell 1.0 and Windows PowerShell 2.0, when it ships with Windows 7.

This week we will be talking about WMI eventing. For some VBScript examples of these kinds of scripts, you can refer to the eventing section of the Hey, Scripting Guy! archive. Additional information can be obtained from this Web page. The Microsoft book, Microsoft Windows Scripting with WMI: Self-Paced Learning Edition, has an entire chapter on WMI eventing.

Today’s script, MonitorForProcessStartUp.ps1, obtains diagnostic process information when any new process starts up. Here it is:

Clear-Host
$Start = get-date
Write-Host "Waiting for a new process to be created ...
You will be notified within 10 seconds of  process  creation
 start time was $Start"
$Query = "select * from __instanceCreationEvent within 10
          where targetInstance isa 'win32_Process'"
$Eventwatcher = New-Object management.managementEventWatcher $Query
$Event = $Eventwatcher.waitForNextEvent()
$Event.targetInstance |
Format-List -property [a-z]*

The first thing we want to do is to clear the screen. We do this so we can take a nice screen shot for today’s article, but it is also good for telling at a glance if your event has fired. As a best practice, you should actually prompt the user before clearing the screen. This is because someone could have data on the screen of their Windows PowerShell console, and become really enraged if you were to erase the screen. Personally, I have never seen that situation, but theoretically it could happen. To clear the screen you use the Clear-Host function as seen here:

Clear-Host

If you would like to prompt the user before clearing the screen, you could use this  technique:

$response = Read-Host -prompt "Would you like to clear the screen? <yes><no>"
if($response -eq "yes") { clear-host }

It is time to get the time, or the entire date as is our case here. To get a time stamp, we use the Get-Date cmdlet. The Get-Date cmdlet returns an entire System.DateTime object, which we store in the $Start variable. You may not be too excited about DateTime objects, but to me they are one of the strongest motivators for using Windows PowerShell instead of using VBScript. Why? Well, I hated date manipulation in VBScript—just a pet peeve perhaps. (Pet peeves are pretty cool. T hey do not make much noise, do not make messes, and eat very little. I have never had a pet peeve get me up in the middle of the night to take it outside either.) The members of the System.DateTime object are seen in Table 1.

Table 1 Members of the System.DateTime object

Name Member Type Definition

Add

Method

System.DateTime Add(TimeSpan value)

AddDays

Method

System.DateTime AddDays(Double value)

AddHours

Method

System.DateTime AddHours(Double value)

AddMilliseconds

Method

System.DateTime AddMilliseconds(Double value)

AddMinutes

Method

System.DateTime AddMinutes(Double value)

AddMonths

Method

System.DateTime AddMonths(Int32 months)

AddSeconds

Method

System.DateTime AddSeconds(Double value)

AddTicks

Method

System.DateTime AddTicks(Int64 value)

AddYears

Method

System.DateTime AddYears(Int32 value)

CompareTo

Method

System.Int32 CompareTo(Object value), System.Int32 CompareTo(DateTime value)

Equals

Method

System.Boolean Equals(Object value), System.Boolean Equals(DateTime value)

GetDateTimeFormats

Method

System.String[] GetDateTimeFormats(), System.String[] GetDateTimeFormats(IFormatProvider provider), System.String[] GetDateTimeFormats(Char format), System.String[] GetDateTimeFormats(Char format, IFormatProvider provider)

GetHashCode

Method

System.Int32 GetHashCode()

GetType

Method

System.Type GetType()

GetTypeCode

Method

System.TypeCode GetTypeCode()

IsDaylightSavingTime

Method

System.Boolean IsDaylightSavingTime()

Subtract

Method

System.TimeSpan Subtract(DateTime value), System.DateTime Subtract(TimeSpan value)

ToBinary

Method

System.Int64 ToBinary()

ToFileTime

Method

System.Int64 ToFileTime()

ToFileTimeUtc

Method

System.Int64 ToFileTimeUtc()

ToLocalTime

Method

System.DateTime ToLocalTime()

ToLongDateString

Method

System.String ToLongDateString()

ToLongTimeString

Method

System.String ToLongTimeString()

ToOADate

Method

System.Double ToOADate()

ToShortDateString

Method

System.String ToShortDateString()

ToShortTimeString

Method

System.String ToShortTimeString()

ToString

Method

System.String ToString(), System.String ToString(String format), System.String ToString(IFormatProvider provider), System.String ToString(String format, IFormatProvider provider)

ToUniversalTime

Method

System.DateTime ToUniversalTime()

DisplayHint

NoteProperty

Microsoft.PowerShell.Commands.DisplayHintType DisplayHint=DateTime

Date

Property

System.DateTime Date {get;}

Day

Property

System.Int32 Day {get;}

DayOfWeek

Property

System.DayOfWeek DayOfWeek {get;}

DayOfYear

Property

System.Int32 DayOfYear {get;}

Hour

Property

System.Int32 Hour {get;}

Kind

Property

System.DateTimeKind Kind {get;}

Millisecond

Property

System.Int32 Millisecond {get;}

Minute

Property

System.Int32 Minute {get;}

Month

Property

System.Int32 Month {get;}

Second

Property

System.Int32 Second {get;}

Ticks

Property

System.Int64 Ticks {get;}

TimeOfDay

Property

System.TimeSpan TimeOfDay {get;}

Year

Property

System.Int32 Year {get;}

DateTime

ScriptProperty

System.Object DateTime {get=if ($this.DisplayHint -ieq  Date) {
                        {0} -f $this.ToLongDateString()
                    }
                    elseif ($this.DisplayHint -ieq Time)
                    {
                        {0} -f  $this.ToLongTimeString()
                    }
                    else
                    {
                        {0} {1} -f $this.ToLongDateString(), $this.ToLongTimeString()
                    };}

To store the start date in the $Start variable, we use this code:

$Start = get-date

We now need to prompt the user to let them know that the script is actually working. We can use the Write-Host cmdlet to do this. We use an expanding string, which allows us to use the datetime value stored in the $Start variable directly. We do not need to fool with concatenation. Strings in Windows PowerShell are assumed to continue to the next line if they are not closed, and we can break our message up across three lines without needing to use line concatenation, or even embedding carriage returns and line feeds (a la vbcrlf from VBScript fame). This is seen here:

Write-Host "Waiting for a new process to be created ...
You will be notified within 10 seconds of  process  creation
 start time was $Start"

When the script is run, the message is printed on the screen along with the current starting time. This is shown here:

Image of the message printed on the screen when the script is run

 

After we have prompted our user, we can create our event query. This uses the same query syntax familiar from VBScript event scripts. This query string is seen here:

$Query = "select * from __instanceCreationEvent within 10
          where targetInstance isa 'win32_Process'"

Now we need to actually create the event watcher. To do this, we first need to create an instance of the System.Management.ManagementEventWatcher .NET Framework class. We use the New-Object cmdlet to do this. The class name is ManagementEventWatcher, and the namespace the class is found in is System.Management. Because we need to know the namespace the class resides in to be able to create an instance of the class, I make it a habit of always referring to the class by the full name. It is a bit cumbersome, but I have found it to be much more convenient than spending 15 minutes searching MSDN documentation to try to identify the namespace of a class. When we create the instance of the ManagementEventWatcher, we give it a constructor. The constructor is used to govern the way in which the class is actually created. In this example, we are giving ManagementEventWatcher the query stored in the $query parameter. This is my favorite constructor for this class. Other constructors are listed on MSDN. We store the newly minted System.Management.ManagementEventWatcher class in the $EventWatcher variable as seen here:

$Eventwatcher = New-Object system.management.managementEventWatcher $Query

Now all we need to do is to sit and wait. We are using the WaitForNextEvent method from the System.Management.ManagementEventWatcher class. When the event occurs, the returned ManagementBaseObject is stored in the $event variable as seen here:

$Event = $Eventwatcher.waitForNextEvent()

Next we use the targetInstance property to retrieve the properties of the Win32_Process class. We pipeline this to the Format-List cmdlet and print out all the properties that begin with the letters a-z and are followed by any other character. This removes the system properties that begin with the double underscore (such as __NameSpace). This is seen here:

$Event.targetInstance |
Format-List -property [a-z]*

The result is all the information normally associated with a query to the Win32_Process WMI class. This is shown here:

Image of the information in the notification

 

Well, NL, we hope you enjoyed today’s article about monitoring for process startup. We will continue working with WMI events tomorrow. Until then, do not pick up any stray pet peeves you see wandering along the side of the road. See you tomorrow.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

0 comments

Discussion is closed.

Feedback usabilla icon