EventMon: Stopping a Capture Based on an EventLog Event

Having worked in Product Support for many years, I’ve had many occasions where a specific Event Log error was showing up, and we wanted to understand how this event related to the problem we were t-shooting. And in some cases, the Event Log error was the problem we were t-shooting. So the task at hand was to get a network trace leading up to when the Event error was logged.

In the past, we had a tool called EventMon that would do the trick. This was simply a wrapper that would start the network trace, and monitor the event log for the specific event in question. So the quest of this blog will to create a similar utility using NMCap, VBS, and a CMD Batch wrapper.

Monitoring the Event Log

It turns out that WMI (Windows Management Interface) exposes methods that allow us to monitor the Event log. This means we can create a simple VBS script that will handle this part for us. The idea is to pass our script the Event Number and Event Log File (application, security, system, etc), and have the script run until the event occurs. For our example, the Event Log File parameter will be an optional parameter.

So our script is quite simple. We basically create an object for WMI which allows us to get to the object for the Event Log Notification. The notification event we look for is based on the parameters that were passed in to our script. By passing a simple SQL like query, we narrow down the type of notification we are looking for. Once this object is created, we call a method that waits until our event occurs. Once detected the object returned points to the specific event information.

So here’s the first part of the puzzle, EvtMon.VBS.

 '======================================================================
' Print out the help when something is not typed in correctly or when 
' nothing at all is typed in.

Public Sub PrintHelp
    Wscript.Echo "Usage:"
    Wscript.Echo "  EvtMon EventNumber [LogFileDisplayName]"
    Wscript.Echo "    LogFile is optional.  If used, the eventlog name"
    Wscript.Echo "    file ie, application, system, security, etc..."
End Sub

' Get the arguments.  Check for event nubmer and log file as arugments
Set objArgs = WScript.Arguments

' See how many arguments we have and colect them.
if objArgs.Count < 1 OR objArgs.Count > 2 Then
    PrintHelp
ElseIf objArgs.Count > 1 Then
    EventNumber = objArgs(0)
    LogFile = objArgs(1)
Else
    EventNumber = objArgs(0)
    LogFile = ""
End If

If EventNumber <> "" Then

    strComputer = "."

    ' Attatch to the WMI Service
    Set objWMIService = GetObject("winmgmts:{(Security)}\\" & _
            strComputer & "\root\cimv2")

    ' if the LogFile is populated add this to our query.  Create a
    ' Event Log monitoring object and send it a query.
    If LogFile = "" Then
        Set colMonitoredEvents = objWMIService.ExecNotificationQuery _    
            ("Select * from __InstanceCreationEvent Where " _
                & "TargetInstance ISA 'Win32_NTLogEvent' " _
                    & "and TargetInstance.EventCode = '" _
                    & EventNumber & "'")
    Else
        Set colMonitoredEvents = objWMIService.ExecNotificationQuery _    
            ("Select * from __InstanceCreationEvent Where " _
                & "TargetInstance ISA 'Win32_NTLogEvent' " _
                    & "and TargetInstance.EventCode = '" _
                    & EventNumber _
                    & "' and TargetInstance.LogFile = '" _
                    & LogFile & "'")
    End If

    ' Create an object which returns when the next event occurs.
    Set objLatestEvent = colMonitoredEvents.NextEvent
    
    ' Print some info based on the event log we encountered.
    Wscript.Echo objLatestEvent.TargetInstance.User
    Wscript.Echo objLatestEvent.TargetInstance.TimeWritten
    Wscript.Echo objLatestEvent.TargetInstance.Message
    WScript.Echo objLatestEvent.TargetInstance.Logfile
    Wscript.Echo
End If

Main CMD for Control: EventMon.CMD

The VBS Script simply detects the event log when it’s written. But we still need a way to start the trace, and then upon completion of the script stop the trace. We will do this with a CMD file that spawns NMCap, and upon completion of our script, signals NMCap to stop capturing. We also add in one more parameter before the Event Number and EventLog to allow you to enter the name of the capture file to create.

Since NMCap doesn’t have any way to signal it directly, we will generate some network traffic using a PING to tell NMCap to stop tracing.

So the CMD file looks as follows:

 @echo off
if "%1"=="" goto Usage
if "%2"=="" goto Usage

REM Following line is wrapped
start cmd.exe /c nmcap /network * /capture /file %1 /stopwhen /frame "ipv4.DestinationAddress==4.3.2.1" /DisableConversations

cscript //NoLogo EvtMon.vbs %2 %3
ping -n 1 4.3.2.1

goto :EOF

:Usage
echo Usage:
echo   %0 CaptureFile EventNumber [LogFile]
echo       Logfile is optional.  If used, the eventlog name
echo       file ie, applicaiton, system, security, etc...

Realize that since NMCap does take a while to load, you may want to put a sleep of some sort after you call NMCap. That way you can make sure it’s running before you start monitoring the EventLog.

This also assumes that NMCap is in the path, or that this CMD file is run from the NM3 install directory. You could always add the entire path for NMCap.

Finally since PING is used to stop the network trace, you must make sure that this isn’t being blocked by your firewall or NMCap will never see the traffic. I choose PING because this is usually left untouched by your fire wall, but you can always substitute some other traffic as a trigger. The trick, of course, is creating the filter that detects that traffic.

Stop That Capture: How does NMCap get stopped?

I guess it’s important to understand how NMCap works in this context. The first thing that happens, besides the parameter validation, is NMCap gets executed with a bunch of parameters. So let’s go over each of these explicitly.

The first one, “/network”, just says which network interface we are capturing on. In this case, we say “*” for all interfaces. You could just as easily narrow it down to one adapter if you need to.

The next parameters “/capture /file %1” tells NMCap what to filter out (nothing since no filter is supplied after the /capture command), and what to name the resulting capture file. The file name comes from the first parameter passed into the CMD batch file. The default capture size is a 20 Meg circular buffer. You can modify this to a larger size by adding a modifier after the file name. For instance, mystuff.cap:200M, would create a 200 meg circular buffer. Please see the NMcap help, “NMCap /?”, for more options and information.

The last part of NMCap, the “/stopwhen” directive, lets us determine when NMCap should stop capturing. So we pass it a “/frame” parameter which tells it to look for a filter which when satisfied will stop the capturing and exit NMCap. We pass it a filter that looks for a packet with an IPv4 destination address of 4.3.2.1. When the VBS script completes, the CMD file PINGs the address 4.3.2.1. So it’s this action that causes the trace to stop.

At the end, there is a “/DisableConversations” switch which tells NMCap to disregard conversation information. Since our filter does not rely on conversations to properly work, we can save memory for long running traces. With conversations enabled, we keep state information for ever, so this could adversely affect you capturing machine when running NMCAP for a long periods of time.

For more information on using NMCap please visit my blog on this subject.

https://blogs.technet.com/netmon/archive/2006/10/24/nmcap-the-easy-way-to-automate-capturing.aspx

Conclusion

With NMCap, this simple script and CMD batch file should allow you to capture network problems when related Event Log items are logged. This can be used to capture a host of problems from SQL error messages, to socket errors, to domain replication problems.