Analyze event logs on hundreds of computers
\[Editor's Note: This new column brings you solutions for automating common security-related tasks. If you have a security task you'd like to automate, email your idea to email@example.com, and you might just see a solution in this column!\]
When something goes wrong on a Windows 2000 or Windows NT system, the event logs are the place to start your investigation of the problem. But what if you need to query tens or even hundreds or thousands of computers' event logs? Luckily, you can use scripts to automate the task, and I have three types to show you:
- the Dumpel utility
- Perl and the Win32::EventLog module
- Windows Management Instrumentation (WMI) and VBScript
The Dumpel utility is available in various Windows resource kits (e.g., the Microsoft Windows 2000 Resource Kit) and lets you query a particular computer's event log to produce a tab-separated text file, which you can pipe into the Findstr or Find commands or save and then use any search tool to query. Listing 1 is a simple command line that I saved as a batch file, log.cmd, and shows how you can query for a specific string in a log file on several remote computers. Log.cmd queries two computers, mike-lap and cheryl-lap, and can open the Application, Security, or System logs (which you specify in the first argument, %1) to look for a specific string (which you specify in the second argument, %2). You can put as many machine names as you want in the parentheses. (A quick way to see the names of all the local machines in your domain is to use the Net View command.) To use the file, run it from a command prompt, but keep in mind that you must have Administrator privileges on all machines for this command to work. For example, to query the Application log for occurrences of the word crypt32, you would type
log.cmd application crypt32
at a command prompt.
This method works reasonably well but isn't a granular search. The system will display on screen any line that contains the text in the second argument, so you could end up with more output than you expected.
I love Perl and have used it for years to test many Internet-based applications. Perl has excellent socket-handling and string-handling support. In addition, you can use Perl modules to add functionality to the language. One such module is Win32::EventLog, which works on any Win2K or NT server and lets you parse and process event-log data on local and remote computers. (You can learn more about the event-log module at http://aspn.activestate.com/ASPN/Reference/Products/ActivePerl-5.6/site/lib/Win32/EventLog.html.)
I used ActiveState's Perl 5.6.0 to write the Perl script w32timeevents.pl, which Listing 2 shows. You can download Perl 5.6.0 or later at no charge from http://www.activestate.com. W32timeevents.pl queries four computers' event logs for Windows Time Service (i.e., W32Time) events (which can lead to Kerberos failures because of clock skew). To use w32timeevents.pl, edit the lines at callouts A, B, and C in Listing 2 to add the computers you want to query, the event log (i.e., System, Security, or Application), and the event source (e.g., W32Time), respectively. Then, type
at a command prompt.
Note that the TimeGenerated field, which you can see at callout D in Listing 2, has an output format that is in seconds elapsed since January 1, 1970. I use the gmctime() function to display the time and date as text. Figure 1 shows sample output from w32timeevents.pl.
The most granular way to query event-log data is to use WMI. WMI is the Windows implementation of the Web-Based Enterprise Management (WBEM) technology. WMI's aim is to make computer systems much more manageable and reduce the cost of managing distributed systems. WBEM is based on the Common Information Model (CIM) schema, an industry standard driven by the Distributed Management Task Force (DMTF). If you want to learn about WMI, I strongly recommend that you download the WMI software development kit (SDK) at http://msdn.microsoft.com/downloads/sdks/wmi.
The sample VBScript code in Listing 3, page 15, eventid528.vbs, uses WMI and queries three computers (i.e., the local machine, mike-lap, and cheryl-lap) to look for specific security-related events—in this case, event ID 528 (i.e., successful logon events)—by a person named MYDOMAIN\Haxor.
Be aware of two tricky code pieces in the script. First, notice at callout A in Listing 3 that the backslash between the domain name and the username is preceded by a C-style escape code (i.e., a backslash), resulting in a double backslash (\\). Second, notice the security options in the call to GetObject() at callout B in Listing 3. I've specified impersonate as the impersonation level. In other words, I want the call to act on my behalf. (The other three levels are anonymous, meaning that the client isn't identified; identify, meaning that you know who the user is but can't act on his or her behalf; and delegated, meaning that you can identify the users and act on their behalf when accessing other machines. Impersonate and delegate are different in that a process impersonating a user can't access another computer on that user's behalf. However, a process delegating a user can access other computers on that user's behalf.) After the impersonation level, I specified a privilege—Security. When you use WMI to perform certain tasks, such as examining the Security log or requesting that the OS shut down, you need to set the appropriate privilege (e.g., the Security privilege to examine the Security log, the Shutdown privilege to request a shutdown). For a complete list of the tasks that you can request and the privileges necessary, see the Win2K resource kit. If you don't specify a privilege, you'll receive an error message. Also note that GetObject will fail if the Security log contains no entries, and you need the Manage auditing and security log right, which only the Administrator account has by default, to read the Security log.
Another code piece that requires explanation is the TimeGenerated field. The TimeGenerated field (callout C in Listing 3) output format is yyyymmddhhmmss.mmmmmmsuuu, where
- yyyy is a four-digit year (0000-9999)
- mm is a two-digit month (01-12)
- dd is a two-digit date (01-31)
- hh is a two-digit hour (00-23)
- mm is a two-digit minute (00-59)
- ss is a two-digit second (00-59)
- mmmmmm is a six-digit microsecond
- s is a plus (+) or minus (), indicating positive or negative offset from Universal Time Coordinate (UTC)
- uuu is a three-digit offset from UTC in minutes