Chapter 12. Logs

Record keeping is an important part of system administration. A record of the activities that have taken place on a computer can help you troubleshoot problems currently occurring on a computer; in addition, by searching for patterns and trends, you can often anticipate potential problems and take steps to ensure that those problems never arise. In the form of event logs and plain-text log files, Microsoft® Windows® 2000 operating systems perform much of this record keeping for you. As a system administrator, your job is to routinely manage and analyze these log files, tasks that can be greatly facilitated through the use of the scripting technologies in the Microsoft® Windows® 2000 family of operating systems.

In This Chapter

Logs Overview

Financial institutions typically keep detailed records of each transaction they undertake. This record keeping serves at least two purposes. First, it allows the institutions to know, without question, where the money has been and where it is going; if a problem occurs, troubleshooters can go through archived records and retrace every transaction that has taken place in the past few hours, the past few days, and even the past few months. Second, by routinely analyzing these records, institutions are often alerted to trouble before it occurs. Many instances of fraud or embezzlement have been prevented because auditors noticed patterns of activity that were out of the ordinary and were able to put a stop to abuses before it was too late.

The Windows operating system also keeps detailed records of the activity that takes place on a computer. These records, typically stored in the event logs, provide system administrators with the same capabilities financial records provide financial institutions: The event logs help you trace the activity that has taken place on a computer and help you identify potential problems before it is too late. Few activities are as useful to a system administrator as a regular audit and analysis of the event logs for a computer.

Despite the acknowledged value of event logs, however, few system administrators routinely audit and analyze these logs. This is largely because the primary tool provided for working with event logs — Event Viewer — limits you to working with a single event log from a single computer at a time. Although it is recommended that you periodically analyze all the event logs for all your domain controllers, in practice this is tedious and time-consuming using Event Viewer. As a result, administrators rarely undertake this kind of analysis except in organizations that have gone to the trouble and expense of purchasing and installing third-party tools for working with event logs.

Fortunately, scripting provides you with the same capabilities that these third-party tools have.

Managing Logs

Event logs provide a central repository for recording the activities that take place on a computer. Because many of the most meaningful of these events are recorded in one of the event logs, you can find a given event without having to search through a multitude of source-specific log files. On the other hand, because each event log contains events generated from many sources, it can be difficult to identify a set of related events. The advantages/disadvantages of the operating system’s use of event logs reflect the problems inherent in managing one large data source versus the problems inherent in managing many smaller data sources.

Another advantage/disadvantage is that event logs are written using a proprietary binary data format and are designed to prevent modification of the contents of the log. This design provides a high level of security but also makes it more difficult to analyze the contents of the event log. Historically, this could be done only by using the Event Viewer snap-in and on only one computer at a time.

Fortunately, Windows 2000 includes a number scripting tools that make it easy to manage event logs across the enterprise.

Plain-Text Log Files

In addition to the event logs, the operating system also writes other events to plain-text log files, most of which are located in the %windir%Debug folder. Plain-text log files are useful for operations that might generate thousands of events at a time. Because these operations generate so many events, it would be unwise to have them save events to an event log; the thousands of events generated by this single operation might completely fill the log, overwriting all the other events that have taken place on the computer.

For example, each time the File Replication service runs, the resulting log file might contain several thousand lines, depending on the amount of data replicated. Instead of each replication operation being written as an event log record, all the replicated data is recorded in a plain-text log file (%windir%DebugNtFrs.log).

One major advantage of these log files is that they are written as plain-text files, files that can be opened and viewed using any text editor. However, plain-text log files also have limitations:

  • Plain-text log files can be easily modified by any user who has read-write access to the folder in which the logs are stored. For example, an unscrupulous administrator might open a log file, modify it to remove evidence of any activity he or she would prefer to keep secret, and then save the file.

  • Plain-text log files are difficult to analyze by using automated analysis methods. This is due, in part, to the fact that plain-text log files in Windows can use any one of several formatting styles, including comma-separated values, fixed-width text, or free-form text. This makes it difficult to write a single script that can read and analyze multiple log files.

Managing Event Logs

The Event service is an integral part of Windows 2000. Each time a Windows 2000–based computer is started, the Event service automatically begins recording events in the appropriate event logs, even if no one is logged on to the computer. In fact, the first event in the System event log is always a record that the Event service has been started.

The Event service is so integral to the operating system that it cannot be stopped except by turning off the computer.

Note

Note

The fact that the Event service cannot be stopped is a security measure: This prevents someone from stopping the service, carrying out an action, and then restarting the service. An administrator could carry out an action and then clear the event log, thus deleting all traces of that action, but the act of clearing the event log would be recorded as the first record in the new log.

The Event service is fully automated; you cannot stop it or start it, and you should never attempt to reconfigure it. Although the Event service is self-managing, at least two important management tasks are related to the event logs themselves: managing the size of event logs and backing up event logs.

Managing the Size of Event Logs

By default, event logs are configured for a maximum file size of 512 KB and are set to overwrite events that are older than seven days. When the log reaches its maximum size, any events older than seven days are overwritten to allow room for new records unless you reconfigure the maximum size of the log or the overwrite policy.

These default settings are adequate for user workstations and for small servers that conduct relatively little activity. However, these values might not be appropriate for servers such as domain controllers. For example, 512 KB is likely to be too small a log size based on the number of events that are recorded each day on a domain controller.

Backing Up Event Logs

To help maintain a historical record of events, you should back up your event logs on a regular schedule. However, you cannot back up event logs by using a standard backup process; this creates archived event logs that cannot be opened. Instead, to back up event logs, you must use a special backup procedure. Fortunately, this procedure is available through Windows Management Instrumentation (WMI).

Retrieving Event Log Properties

Knowing the properties of your event logs can be useful in planning management activities such as backing up and clearing the logs. For example, knowing both the maximum allowable size and the current size of an event log tells you how much space is available in the log. In turn, this helps you decide whether the log needs to be backed up and cleared.

In addition, tracking the number of records in each log is a simple metric that can often trigger alarms regarding potential problems. For example, suppose routine checks of the number of records in an event log show that a specific computer typically records 100 events a day. Today, however, this routine check shows that the computer has recorded 500 events. This might indicate a serious problem that warrants further investigation.

The WMI class Win32_NTEventLogFile can be used to retrieve the properties of any event log on a computer. Some of the most important event log properties you can retrieve by using WMI are shown in Table 12.1.

Table 12.1. Event Log Properties Available Through WMI

Property

Description

FileSize

Current size of the event log, in bytes.

LogFileName

“Friendly” name for the event log (for example, System).

To return the actual path and file name of the event log (for example, C:WindowsSystem32ConfigSysevent.evt), use the Name property instead.

MaxfileSize

Maximum allowable size (in bytes) for the event log.

Although event logs can be sized as large as 4 gigabytes, in practice they should be limited to no more than 300 megabytes. Event logs larger than that can be difficult to analyze because of the number of events contained within the log and because event logs are not optimized for data retrieval.

Name

Full path and file name for the event log.

NumberOfRecords

Number of records in the event log.

OverwriteOutdated

Number of days after which a record can be overwritten should an event log reach its maximum size. Values are:

  • 0— Any record can be overwritten if necessary. If necessary, all existing events in the event log can be overwritten to make room for new events.

  • 1–365— Events older than the specified number of days can be overwritten as needed. If the event log does not contain any records older than the value specified, no new events will be recorded until the log has been cleared.

  • 4294967295— No records can be overwritten. If the log reaches its maximum size, no new events will be recorded until the log has been cleared.

OverwritePolicy

Current overwrite policy for the event log. Values are the following:

  • WhenNeeded— Any record can be overwritten to make room for new records.

  • OutDated— Records older than a specified number of days can be overwritten to make room for new records.

  • Never— Old records are never overwritten.

The Event Log properties and methods available through WMI map to the event log properties as seen in Event Viewer. This relationship is shown in Figure 12.1.

Win32_NTEventLogFile Properties and Methods

Figure 12.1. Win32_NTEventLogFile Properties and Methods

Scripting Steps

There are several ways to retrieve the properties of event logs. For example, you might want to:

  • Retrieve the properties of multiple event logs.

  • Retrieve the properties of a single event log.

  • Retrieve the properties of the Security event log.

Retrieving the properties of multiple event logs

Listing 12.1 contains a script that retrieves the properties of multiple event logs on a single computer. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2, and set the impersonation level to “impersonate.”

  3. Use the ExecQuery method to query the Win32_NTEventLogFile class.

    This returns a collection consisting of all the event logs on the computer, except the Security event log. The additional step required to return information from the Security event log is discussed later in this chapter.

  4. For each event log in the collection, echo the event log properties LogFileName, MaxFileSize, and OverWriteOutdated.

    If you configure an event log so that it never overwrites events, you actually set the OverWriteOutdated property to 4294967295. If the value 4294967295 is returned, the script displays the string “Overwrite Outdated Records: Never.” If the value 0 is returned, this means the log has been configured to overwrite records as needed. To make this clear, the script displays the message “Overwrite Outdated Records: As Needed.”

Example 12.1. Retrieving the Properties of Multiple Event Logs

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 4 Set objInstalledLogFiles = objWMIService.ExecQuery _
 5     ("SELECT * FROM Win32_NTEventLogFile")
 6 For Each objLogfile in objInstalledLogFiles
 7     Wscript.Echo "Name: " &  objLogfile.LogFileName
 8     Wscript.Echo "Maximum Size: " &  objLogfile.MaxFileSize
 9     If objLogfile.OverWriteOutdated > 365 Then
10         Wscript.Echo "Overwrite Outdated Records: Never." & VbCrLf
11     ElseIf objLogfile.OverWriteOutdated = 0 Then
12         Wscript.Echo "Overwrite Outdated Records: As needed." & VbCrLf
13     Else
14         Wscript.Echo "Overwrite Outdated Records After: " & _
15             objLogfile.OverWriteOutdated & " days" & VbCrLf
16     End If
17 Next

Retrieving a property of a single event log

Listing 12.2 contains a script that retrieves the number of records in the System event log. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2, and set the impersonation level to “impersonate.”

  3. Use the ExecQuery method to query the Win32_NTEventLogFile class.

    To limit the data returned to the System event log, include a Where clause specifying the LogFileName “System”. This returns a collection of event logs with a single item: the System event log.

  4. For the only event log in the collection, echo the value of the NumberOfRecords property.

Example 12.2. Retrieving a Property in a Single Event Log

1 strComputer = "."
2 Set objWMIService = GetObject("winmgmts:" _
3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
4 Set colLogFiles = objWMIService.ExecQuery _
5     ("SELECT * FROM Win32_NTEventLogFile WHERE LogFileName='System'")
6 For Each objLogFile in colLogFiles
7     Wscript.Echo objLogFile.NumberOfRecords
8 Next

Retrieving the properties of the Security event log

Scripts that retrieve information about the event logs on a computer do not retrieve information about the Security event log unless those scripts include the Security privilege. The ability to manipulate the Security event log is provided by the Manage auditing and security logs user right, which must be explicitly assigned. To manipulate the Security event log, you must include this privilege as part of the GetObject moniker, even if you are an administrator and have been assigned this right by default.

Note that the Security privilege does not grant you the ability to manage auditing and security logs. You must already possess this right (typically assigned through Group Policy), or the script will fail. To access information from or about the Security event log, you must possess the Manage auditing and security logs user right, and the script must include the Security privilege.

The results of querying event logs without including the Security privilege are shown in Table 12.2.

Table 12.2. Querying Event Logs Without Including the Security Privilege

If You Attempt to Access...

You Will Retrieve...

All the event logs on a computer

Data for all the event logs except the Security event log

Security event log plus a second event log

Data for only the second event log

Only the Security event log

No data

No special user rights are required to access any of the other event logs on a computer.

Listing 12.3 contains a script that retrieves the number of records in and the maximum file size of the Security event log. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2, and set the impersonation level to “impersonate.”

    Because special user rights are required to access the Security event log, the Security privilege must be included as part of the moniker.

  3. Use the ExecQuery method to query the Win32_NTEventLogFile class.

    To limit the data returned to the Security event log, include a Where clause specifying the LogFileName as “Security.” This returns a collection of event logs with a single item: the Security event log.

  4. For the only item in the collection, echo the values for NumberOfRecords and MaxFileSize.

Example 12.3. Retrieving the Properties of the Security Event Log

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate,(Security)}!\" & _
 4         strComputer & "
ootcimv2")
 5 Set colLogFiles = objWMIService.ExecQuery _
 6     ("SELECT * FROM Win32_NTEventLogFile WHERE LogFileName='Security'")
 7 For Each objLogFile in colLogFiles
 8     Wscript.Echo objLogFile.NumberOfRecords
 9     Wscript.Echo "Maximum Size: " &  objLogfile.MaxFileSize
10 Next

Configuring Event Log Properties

Depending on the role played by a computer, you might need to change the default event log settings for that computer. If the default settings remain unchanged for all the computers in an organization, a domain controller that records thousands of events each day will be configured exactly the same as a workstation that records only 15 or 20 events a day. As a result, the domain controller might fail to record a number of important events, either because its event logs fill up too quickly or because some events might be overwritten before they can be archived.

Event log properties have typically been configured by means of the Event Viewer, a graphical user utility that has two major limitations: Event Viewer can configure only one event log on a single computer at a time, and Event Viewer cannot automate the process of configuring event logs. Because manually configuring event logs on an individual basis can be very time-consuming, administrators often leave the default settings as-is, even if those settings are not optimal for the roles played by certain computers. In turn, this means important events might not be recorded, or might be overwritten before they can be archived.

WMI enables you to write scripts that can programmatically configure event log properties. Two of the most important properties are shown in Table 12.3.

Table 12.3. Event Log Properties Configurable with WMI

Property

Description

MaxfileSize

Maximum allowable size (in bytes) for the event log.

Log files must be sized in increments of 64 KB to prevent file fragmentation. Although you can specify any size for the log file, this will automatically be resized to the nearest multiple of 64 KB. For example, if you specify a file size of 2,200 KB, the actual size will turn out to be 2,240 KB (35 × 64 KB).

OverwriteOutdated

Number of days after which a record can be overwritten when an event log reaches its maximum size. Values are the following:

  • 0— any record can be overwritten if needed

  • 1–365— events older than the specified number of days can be overwritten as needed

  • 4294967295— no records can be overwritten

When you reconfigure an event log, the changes you make do not take effect until the event log has been cleared. If you want the reconfiguration to take effect immediately, create your script to first reconfigure and then to back up and clear the event log.

Scripting Steps

Listing 12.4 contains a script that configures the maximum size and the overwrite policy for all the event logs on a computer. To carry out this task, the script must perform the following steps:

  1. Create a constant named wbemFlagUseAmendedQualifiers and set the value to &h2000.

    This constant is required when using the Put_ method to apply changes to an event log.

  2. Create a variable to specify the computer name.

  3. Use a GetObject call to connect to the WMI namespace rootcimv2, and set the impersonation level to “impersonate.”

    The Security privilege is included in the moniker so that the script can access all the event logs, including the Security event log.

  4. Use the ExecQuery method to query the Win32_NTEventLogFile class. This returns a collection consisting of all the event logs on the computer.

  5. Retrieve the name of the first event log in the connection.

  6. Set the maximum file size to 400 megabytes (approximately 4194304).

  7. Set the overwrite policy so that all records older than 14 days are overwritten.

  8. Use the Put_ method to write the changes to the event log. You must include the wbemFlagUseAmendedQualifiers flag, or the script will fail.

  9. Repeat the process with the next event log in the collection.

Example 12.4. Configuring Event Log Properties

 1 Const wbemFlagUseAmendedQualifiers = &h20000
 2 strComputer = "."
 3 Set objWMIService = GetObject("winmgmts:" & _
 4     "{impersonationLevel=impersonate,(Security)}!\" & _
 5     strComputer & "
ootcimv2")
 6 Set colNTEventLogFiles = objWMIService.ExecQuery _
 7     ("SELECT * FROM Win32_NTEventLogFile")
 8 For each objNTEventLogFile in colNTEventLogFiles
 9     objNTEventLogFile.MaxFileSize = 4194304
10     objNTEventLogFile.OverwriteOutDated = 14
11     objNTEventLogFile.Put_ wbemFlagUseAmendedQualifiers
12 Next

Backing Up and Clearing Event Logs

Event logs maintain a historical record of important events that occur on a computer. These records should be archived, at least temporarily, to help you carry out tasks such as troubleshooting problems (when did the first instance of X occur?) or capacity planning (how does the number of Ys occurring this month compare with the number of Ys that occurred last month?).

The most efficient way to archive event log records is to routinely back up and then clear these logs. Backing up the logs before clearing them ensures that the records will be available if you ever need them; clearing the event logs keeps those logs to a manageable size. Clearing the event logs also ensures that all events will be recorded. If you do not clear the event log before it reaches its maximum size, it either stops recording any new events or starts overwriting older events, depending on how the log has been configured. As a result, events will either be overwritten, and thus lost, or never recorded in the first place.

Note

Note

When you clear an event log, the operating system does not delete the previous event log file. Instead, Windows creates a new 64 KB log file that replaces the old log file. (The new log file is placed on exactly the same sectors of the disk drive as the old log file.) Because the disk drive sectors are overwritten and filled with new information, you cannot retrieve records from a cleared event log using an undelete tool.

Before you clear an event log, it is a good idea to create a backup of that log. WMI provides a method for backing up event logs. However, this method comes with two important stipulations. For one, you must use the proprietary event log binary log format. To archive event logs in plain-text format, you need to create a query to extract the records and then write the extracted information to a text file.

In addition, you must make backups to the local computer; you cannot save a backup of the event logs on Computer A to Computer B. Backups are implemented by using the LocalSystem account, which does not have the network credentials necessary to access remote computers. If you want to save backups to a central repository, modify the script to first perform the backup, and then move the backup file to the central repository.

A technical note on backing up event logs

Event logs must be backed up separately from any other system files. Although a regular system backup can copy the event log files, the copied event log files will be unusable. If you attempt to open an event log file that has been copied or backed up by using any means other than the Event Log Backup Application Programming Interface (API), you receive an error message stating that the event log file is corrupt.

This error message is the result of a unique characteristic of event log files. When a computer starts, the Event service changes several bits in each event log file header. These changed bits indicate that the event log file is open, and they prevent applications, including backup programs, from accessing the event log file. If you copy an event log file by using the Copy command or a standard backup program, the copied event log file includes these changed bits. If you then try to open the copied file, you receive a message that the event log is corrupt.

Despite the changed bits, you can use Event Viewer to work with the event log files, but only because it does not try to open the event log file itself. Instead, Event Viewer uses the Event service and the Event Logging API to open the event log files.

However, this does not completely solve the problem. For better or worse, the Event service and Event Logging API can be used to open only actual event logs; they cannot open archived event log files. Instead, Event Viewer must directly access backup event log files. If the Event Log Backup API did not produce these backup event log files, these backup files will include the changed bits indicating that the file is open. In that case, any attempt to access the file will fail.

When you use the Event Log Backup method, these header bits are changed to indicate that the file is closed, giving Event Viewer access to the data.

Scripting Steps

There are multiple ways to back up and clear the event logs. For example, you might:

  1. Back up and clear an event log.

  2. Back up and clear an event log only if the log meets specific conditions.

Backing up and clearing an event log

Listing 12.5 contains a script that backs up and then clears the Application event log on a computer. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2, set the impersonation level to “impersonate,” and include the Backup privilege.

    To use the BackupEventLog method, you must include the Backup privilege as part of your connection string. Backup is a user right that must be explicitly assigned and included as part of the GetObject moniker.

  3. Use the ExecQuery method to query the Win32_NTEventLogFile class.

    To limit data retrieval to the Application event log, include a Where clause specifying Application as the LogFileName. This returns a collection with a single item: the Application event log.

  4. For the sole item in the collection, use the WMI BackupEventLog method to back up the event log, specifying the full path to the backup file when using this method. If the backup file does not exist, WMI will create a new backup file.

    However, if a backup file by that name already exists, the backup attempt will fail. The failure occurs because the BackupEventLog method does not allow you to overwrite an existing backup file or to append additional records to an existing backup file. This is another security measure, one that prevents anyone from modifying archived event logs. Without this provision, an unscrupulous administrator could back up and clear the event logs, open the backup files, and then remove any events he or she wanted to keep secret.

  5. Use the WMI ClearEventLog method to clear the event log.

    In the script, this method will run only if the backup succeeded; if the BackupEventLog method returns anything other than 0, this means the backup failed. As a result, the message “The application event log could not be backed up” is echoed to the screen, and the event log is not cleared.

Example 12.5. Backing Up and Clearing an Event Log

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate,(Backup)}!\" & _
 4         strComputer & "
ootcimv2")
 5 Set colLogFiles = objWMIService.ExecQuery _
 6     ("SELECT * FROM Win32_NTEventLogFile WHERE LogFileName='Application'")
 7 For Each objLogfile in colLogFiles
 8     errBackupLog = objLogFile.BackupEventLog("c:scriptsapplication.evt")
 9     If errBackupLog <> 0 Then
10         Wscript.Echo "The Application event log could not be backed up."
11     Else
12         objLogFile.ClearEventLog()
13     End If
14 Next

You might want to run the script shown in Listing 12.5 as a scheduled task and thus back up and clear your event log on a regular basis.

Backing up and clearing an event log if the log meets specific conditions

If you wanted to, you could schedule the script in Listing 12.5 to run as a scheduled task each morning. The script would thus start up each day and then back up and clear each event log. At the end of the year, you would have 365 archive files for each event log. Although the data would be safely archived, dealing with scores of small event log files can be more complicated than dealing with a single large event log file.

As an alternative approach, you can create a script that backs up and clears an event log only if the log meets specific conditions.

Listing 12.6 contains a script that backs up and clears an event log only if the log is larger than 20 megabytes (approximately 20,000,000 bytes). If the log is smaller than 20 megabytes, the script exits without performing the backup. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  3. Use the ExecQuery method to query the Win32_NTEventLogFile class.

    This returns a collection consisting of all the event logs on the computer, except the Security event log. To return the Security event log, you need to include the Security privilege as part of the WMI moniker. The Security event log is not included in this script simply because the Security event log is often managed separately from the other event logs (and often by a separate administrator).

  4. For each event log in the collection, check the FileSize property to see whether the event log size is larger than 20 megabytes.

    • If the FileSize property returns a value greater than 20 megabytes, the event log is backed up to a file, using the name of the event log as the file name, and the event log is then cleared.

    • If the FileSize property returns a value less than 20 megabytes, the event log is not backed up and then cleared.

Example 12.6. Backing Up and Clearing Event Logs If the Log Meets Specific Conditions

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate, (Backup, Security)}!\" _
 4         & strComputer & "
ootcimv2")
 5 Set colLogFiles = objWMIService.ExecQuery _
 6     ("SELECT * FROM Win32_NTEventLogFile")
 7 For Each objLogfile in colLogFiles
 8     If objLogFile.FileSize > 20000000 Then
 9        strBackupLog = objLogFile.BackupEventLog _
10            ("c:scripts" & objLogFile.LogFileName & ".evt")
11        objLogFile.ClearEventLog()
12     End If
13 Next

Creating Unique File Names When Backing Up Event Logs

Each time you back up an event log, you must create a new archive file; you cannot overwrite existing archive files nor can you append additional information to an existing file. Instead, you must either rename the existing archive file or ensure that the new file is given a different name.

For example, the first time you back up the System event log to C:ScriptsSystemBackup.evt, the new file is created and the procedure succeeds. The second time you attempt the backup, however, the file SystemBackup.evt will already exist and the procedure will fail. To do a second backup, you must first rename or remove SystemBackup.evt.

To help overcome this problem, you can create a script to generate unique file names for each of your event log archives.

Scripting Steps

Listing 12.7 contains a script that uses the log name, date, and time to create unique file names when backing up an event log. To carry out this task, the script must perform the following steps:

  1. Use the VBScript functions Day, Month, and Year to determine the day, month, and year of the current date.

  2. Create a variable to specify the computer name.

  3. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  4. Use the ExecQuery method to query the Win32_NTEventLogFile class.

    To limit data retrieval to a single event log, a Where clause is used specifying that only the Application event log should be returned. The resulting collection will have a single item: the Application event log.

  5. For the first (and only) item in the collection, use the LogFileName property to determine the name of the event log file being backed up.

  6. Create a unique file name for the backup file.

    This is done by combining the LogFileName with the year, month, and day, separating each portion of the file name with underscores. The net result will be a file name similar to this: System_2002_12_20.evt, where:

    • System = The LogFileName.

    • 2002 = The year.

    • 12 = The month.

    • 20 = The day.

    • .evt = The file extension.

  7. Use the Backup method to back up the event log, specifying the generated name as the file name.

  8. Use the Clear method to clear the event log.

Example 12.7. Creating Unique File Names When Backing Up Event Logs

 1 dtmThisDay = Day(Now)
 2 dtmThisMonth = Month(Now)
 3 dtmThisYear = Year(Now)
 4 strBackupName = dtmThisYear & "_" & dtmThisMonth & "_" & dtmThisDay
 5 strComputer = "."
 6 Set objWMIService = GetObject("winmgmts:" _
 7     & "{impersonationLevel=impersonate,(Backup)}!\" & _
 8         strComputer & "
ootcimv2")
 9 Set colLogFiles = objWMIService.ExecQuery _
10     ("SELECT * FROM Win32_NTEventLogFile WHERE LogFileName='Application'")
11 For Each objLogfile in colLogFiles
12     objLogFile.BackupEventLog("c:scripts" & strBackupName & _
13         "_application.evt")
14     objLogFile.ClearEventLog()
15 Next

Querying Event Logs

Although events are automatically recorded on a computer (except for security events, which must be enabled by using Group Policy), few administrators routinely analyze their event logs. This is due in part to the limitations inherent within Event Viewer and in part to the nature of how events are recorded throughout the enterprise. The impediments to routinely analyzing event logs include:

  • The large number of events typically stored in an event log. Many of the events that take place on a computer are recorded to the event logs. The thousands of events recorded in the event logs on a domain controller make analysis extremely difficult.

  • Inability to save filtered records to a separate file. Event Viewer allows you to filter a desired set of records but does not allow you to save just those records to a separate file. To analyze, graph, or otherwise work with a filtered set of records, you must export all the events from Event Viewer to a text file, open the file in another application, and then filter and save the events of interest.

  • Lack of printing capabilities. Event Viewer provides no printing capabilities; records must be imported into another application before they can be printed.

  • Inability to record events on remote computers or on multiple computers. Because events are recorded only on the computer where they occur, the only way to obtain enterprise-wide data has been to manually examine the event logs on every computer.

The WMI class Win32_NTLogEvent class can be used to extract records from an event log and either display the results of those queries or save them to a file. This enables you to automate the process of analyzing event logs by creating scripts that do such things as:

  • Periodically return any instances of a particular event (for example, a failed logon or failed service).

  • Run each morning and retrieve all the events that occurred on the previous day. These event records can then be copied into a database, where they can be easily sorted, filtered, analyzed, and printed.

Several key event properties that can be returned using WMI are shown in Table 12.4.

Table 12.4. Event Properties in WMI

Property

Description

Category

Classification of the event as determined by the source.

Although primarily used when recording Security events, this property is available in other event logs as well. Common Security categories include Logon/Logoff, Account Management, and System Event.

ComputerName

Name of the computer on which the event occurred.

EventCode

Identification number for a particular kind of event.

For example, a successful logoff is recorded in the Security log with the Event ID 538. However, Event IDs are not necessarily unique. It is possible that, when retrieving Event ID 538, you can get other kinds of events with ID 538. If this happens, you might need to filter by the source as well as ID.

Message

Event description.

RecordNumber

Record number for the event.

Record numbers are always unique; they are not reset to 1 when an event log is cleared. As a result, the highest record number also indicates the number of records that have been written to the event log since the operating system was installed.

SourceName

Application that generated the event.

TimeWritten

Time that the record was written to the event log in the Universal Time Coordinate (UTC) format yyyymmddHHMMSS.xxxxxx-UUU, where:

  • yyyy represents the year

  • mm represents the month

  • dd represents the day

  • HH represents the hour (in 24-hour format)

  • MM represents the minutes

  • SS represents the seconds

  • xxxxxx represents the milliseconds

  • UUU represents the number of minutes to be subtracted from the current time in order to calculate Greenwich mean time

For example, an event recorded on October 31, 2002, at 10:45:39 A.M. Pacific time looks like this: 20021031104539.000000-480

Type

Error type. Values are:

  • 1 = Error

  • 2 = Warning

  • 4 = Information

  • 8 = Audit success

  • 16 = Audit failure

User

User account under which the event occurred.

Rather than storing the user account name, the event log stores the user’s Security Identifier (SID). This means the user field will “disappear” if a user account is deleted and the SID is no longer valid. When you back up an event log, however, the actual user name (rather than the SID) is included in the backup file.

Designing Event Log Queries

The way an event log query is constructed can have a huge impact on how long it takes WMI to process the query and return the requested information. This is not necessarily true of other managed objects. For example, a query that returns all the properties for all the installed services on a typical Windows 2000–based computer takes about 2 seconds to complete. A filtered query that returns the properties of a single service takes about 1 second to complete, a difference of only 1 second.

However, query times for different types of event log queries can vary widely. The relative query times for several different types of event log queries run on a Windows 2000 Server–based test computer are listed in Table 12.5. The test computer had a total of 13,743 events recorded in its event logs, with 669 of these in the System event log. Retrieving all the events from all the event logs required over 2 hours to complete. When the query was modified so that it retrieved events from only the System event log, the process took just 4 minutes.

Table 12.5. Relative Event Log Query Times

Query Type

Query Time (hours:minutes:seconds)

Select all events from all event logs

2:06:15

Select events only from the System event log

0:04:03

Select events only from the System event log that have EventCode 1000

0:01:33

Select events only from the System event log that have EventCode 1000 and occurred on a specific day

0:00:17

Event log queries can also return a very large amount of information compared with queries for other WMI classes, such as Win32_Service. Retrieving the properties for all the services on the test computer and saving them to a text file resulted in a file that was less than 13 KB. Performing the same task with the event logs resulted in a text file of nearly 1 MB. Attempting to retrieve events from large event logs over the network could cause a script to take hours to run and might generate a huge amount of network traffic.

Because of the length of time it can take an event log query to run and the large amount of information that can be returned, it is important that you carefully design your queries for retrieving data from the event logs. Unless you need to return all the events from all the event logs on a computer, write your queries so that they do one or more of the following:

  • Specify a single event log. If events are recorded in only one event log, there is no need to search the other logs for these records. For example, computer startup and shutdown events are recorded only in the System event log. If you are querying for these records, there is no reason to search the Application or DNS event logs.

  • Return only a subset of events. When analyzing event logs, you rarely need to examine every event. The vast majority of records in a typical event log report the success of a particular operation. If you are interested only in operations that failed, there is no reason to examine hundreds of records that report operations that succeeded. Instead, you can focus on a subset of events: those records reporting an operation that failed.

  • Return only events that occurred on a particular day. For most computers, this kind of query returns only a few hundred records, compared with thousands of records stored in a large event log. If you need to view only the event records for last Tuesday, construct your query so that only the records from that day are returned.

  • Asynchronouly return event records. If a dataset is large, asynchronous queries will usually run faster than semi-synchronous queries.

  • Copy events to a database. Unlike databases, event logs are not optimized for data retrieval and analysis. If you need to perform a number of queries on your event logs, or if you need to combine events from multiple event logs, you should copy those events to a database and then use the database and its tools to analyze the records. In addition to the speed differential, databases typically provide more sophisticated tools for analyzing data and calculating statistics than do event logs.

Querying a Specific Event Log

You can greatly speed up data queries by limiting your searches to a specific event log. It is very rare for events of a certain type, or events generated by a specific application, to be written to multiple event logs. Instead, operating system events are invariably written to the System event log, events generated by an application such as Microsoft Office are written to the Application event log, and so forth.

For example, if you are interested in the activities of the DNS service, any such events will be written to the DNS server event log. There is no reason to search the other event logs. A nonoptimized query that searches all the event logs instead of limiting the search to the DNS service log might search tens of thousands of events in the Security event log, even though no DNS service events will be recorded there.

Scripting Steps

Listing 12.8 contains a script that queries a specific event log and echoes the properties of all the records in that log. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  3. Use the ExecQuery method to query the Win32_NTLogEvent class.

    To limit data retrieval to the records in the System event log, a Where clause is included specifying that the Logfile must be equal to System. The resulting collection will contain only the events in the System event log.

  4. For each event in the collection, echo the event properties.

Example 12.8. Querying a Specific Event Log

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 4 Set colLoggedEvents = objWMIService.ExecQuery _
 5     ("SELECT * FROM Win32_NTLogEvent WHERE Logfile = 'System'")
 6 For Each objEvent in colLoggedEvents
 7     Wscript.Echo "Category: " & objEvent.Category
 8     Wscript.Echo "Computer Name: " & objEvent.ComputerName
 9     Wscript.Echo "Event Code: " & objEvent.EventCode
10     Wscript.Echo "Message: " & objEvent.Message
11     Wscript.Echo "Record Number: " & objEvent.RecordNumber
12     Wscript.Echo "Source Name: " & objEvent.SourceName
13     Wscript.Echo "Time Written: " & objEvent.TimeWritten
14     Wscript.Echo "Event Type: " & objEvent.Type
15     Wscript.Echo "User: " & objEvent.User
16 Next

Querying an Event Log for a Subset of Events

Querying an event log for a specific set of events can greatly increase the speed and efficiency of your query. The following examples demonstrate two ways to construct a script for determining the number of improper shutdowns recorded in the System event log with Event ID 6008 one way that is fast and efficient, another way that is not:

  • Retrieve all the events from the System event log, check each one to see whether the Event ID is 6008, and then report the total number of improper shutdown events found.

    On a Windows 2000–based test computer with approximately 700 events in the System event log, this process took more than 10 minutes.

  • Retrieve only events from the System event log that have Event ID 6008, and report the number of records retrieved by this query.

    On the same test computer, this query took just 9 seconds. If you know exactly what you are looking for, you should create a targeted query that returns only this information. This reduces processing time and, when you are working with remote computers, limits the amount of data that must be transferred across the network.

Scripting Steps

Listing 12.9 contains a script that queries an event log and tallies all instances of a specific Event ID. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  3. Use the ExecQuery method to query the Win32_NTLogEvent class.

    To limit data retrieval to specific events, include a Where clause specifying the System event log and EventCode 6008. The resulting collection will include only records from the System event log that have EventCode 6008.

  4. Use the Count property to echo the number of records in the collection.

    Because a filter was applied as part of the GetObject call, the number of records in the collection equals the number of proper shutdowns recorded in the System event log.

Example 12.9. Querying an Event Log for a Specific Event ID

1 strComputer = "."
2 Set objWMIService = GetObject("winmgmts:" _
3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
4 Set colLoggedEvents = objWMIService.ExecQuery _
5         ("SELECT * FROM Win32_NTLogEvent WHERE Logfile = 'System' AND " _
6             & "EventCode = '6008'")
7 Wscript.Echo "Improper shutdowns: " & colLoggedEvents.Count

Retrieving Event Log Records from a Specified Day

When analyzing event logs, you will often want to review events that occurred only on a specific day or set of days. For example, if a computer had problems on August 15, 2002, you would want to review only the records from that date. At least for your initial investigation, you do not need records for the entire month of August.

The one complicating factor in retrieving events that occurred on a specific day is the fact that WMI stores dates using the Universal Time Coordinate (UTC) format. Because of this, you cannot use a standard date-time (such as 12/19/2002) in your queries. Instead, you have to use a UTC date-time format such as this:

20021219000000.000000-480

UTC dates and techniques for converting them to standard dates (and vice-versa) are discussed in detail in “WMI Scripting Primer” in this book.

Scripting Steps

Listing 12.10 contains a script that queries the event logs for all events that occurred on December 19, 2002. To perform this task, the script must carry out the following steps:

  1. Create a variable named dtmStartDate, and set the value to 20021219000000.000000-480. This is a UTC date corresponding to the beginning of the day (hour 0) on December 19, 2002.

  2. Create a variable named dtmEndDate, and set the value to 20021220000000.000000-480. This is a UTC date corresponding to the beginning of the day (hour 0) on December 20, 2002. Your query will search for all events that were recorded on or after dtmStartDate (the start of the day on December 19), but before dtmEndDate (the start of the day on December 20).

  3. Create a variable to specify the computer name.

  4. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  5. Use the ExecQuery method to query the Win32_NTLogEvent class.

    To limit data retrieval to events that were recorded on December 19, 2002, include a Where clause specifying that the Time Written is both:

    • Greater than or equal to dtmStartDate

    • Less than dtmEndDate.

    Because no log file name is specified in the query, events will be returned from all the event logs except the Security event log.

  6. For each event in the collection, echo the event properties.

Example 12.10. Querying an Event Log for All Events From a Specified Day

 1 dtmStartDate = "20021219000000.000000-480"
 2 dtmEndDate = "20021220000000.000000-480"
 3 strComputer = "."
 4 Set objWMIService = GetObject("winmgmts:" _
 5     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 6 Set colEvents = objWMIService.ExecQuery _
 7     ("Select * from Win32_NTLogEvent Where TimeWritten >= '" _
 8         & dtmStartDate & "' and TimeWritten < '" & dtmEndDate & "'")
 9 For each objEvent in colEvents
10     Wscript.Echo "Category: " & objEvent.Category
11     Wscript.Echo "Computer Name: " & objEvent.ComputerName
12     Wscript.Echo "Event Code: " & objEvent.EventCode
13     Wscript.Echo "Message: " & objEvent.Message
14     Wscript.Echo "Record Number: " & objEvent.RecordNumber
15     Wscript.Echo "Source Name: " & objEvent.SourceName
16     Wscript.Echo "Time Written: " & objEvent.TimeWritten
17     Wscript.Echo "Event Type: " & objEvent.Type
18     Wscript.Echo "User: " & objEvent.User
19     Wscript.Echo objEvent.LogFile
20 Next

Asynchronously Retrieving Event Log Statistics

WMI supports both asynchronous and semi-synchronous scripts. When retrieving events from the event logs, asynchronous scripts often retrieve this data much faster.

In an asynchronous script, a query is issued and control is immediately returned to the script. The query continues to process on a separate thread while the script begins to immediately act on the information that is returned. Asynchronous scripts are event driven: each time an event record is retrieved, the OnObjectReady event is fired. When the query has completed, the OnCompleted event will fire, and the script can continue based on the fact that all the available records have been returned.

In a semi-synchronous script, by contrast, a query is issued and the script then queues a large amount of retrieved information before acting upon it. For many objects, semi-synchronous processing is adequate; for example, when querying a disk drive for its properties, there might be only a split second between the time the query is issued and the time the information is returned and acted upon. This is due in large part to the fact that the amount of information returned is relatively small.

When querying an event log, however, the interval between the time the query is issued and the time that a semi-synchronous script can finish returning and acting on the information can take hours. On top of that, the script might run out of memory and fail on its own before completing.

For event logs with a large number of records, the difference in processing time can be considerable. On a Windows 2000–based test computer with 2,000 records in the event log, a semi-synchronous query that retrieved all the events and displayed them in a command window took 10 minutes 45 seconds. An asynchronous query that performed the same operation took one minute 54 seconds.

Scripting Steps

Listing 12.11 contains a script that asynchronously queries the event logs for all records. To perform this task, the script must apply the following steps:

  1. Define two constants used to create a message box.

    • POPUP_DURATION = 10 —Indicates that the message box will automatically dismiss itself after 10 seconds unless the user clicks the OK button.

    • OK_BUTTON = 0 —Indicates that only an OK button will be displayed as part of the message box.

  2. Create a variable to specify the computer name.

  3. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  4. Create an SWbemSink object named SINK_.

  5. Retrieve the records in the event logs by using an InstancesOfAsync query, specifying Win32_NTLogEvent as the source of the query.

  6. Display a Popup message box that dismisses itself after 10 seconds.

    Displaying the message box ensures that the query will have enough time to start before the last line of the script has been processed. Without this message box, the script might finish before the query starts; if the last line of the script is executed before the query can begin to return data, the script will terminate and no data will be returned. After the query begins to return data, however, the data retrieval will continue, even if the last line of the script has been executed.

  7. Use a SINK_OnCompleted subroutine to indicate the code that runs when the query is complete. In this case, a message will be echoed to the screen.

  8. Use a SINK_OnObjectReady subroutine to indicate the code that runs each time the query returns an object (in this case, an event record).

Example 12.11. Asynchronously Querying an Event Log

 1 Const POPUP_DURATION = 10
 2 Const OK_BUTTON = 0
 3 Set objWSHShell = Wscript.CreateObject("Wscript.Shell")
 4 strComputer = "."
 5 Set objWMIService = GetObject("winmgmts:" _
 6     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 7 Set objSink = WScript.CreateObject("WbemScripting.SWbemSink","SINK_")
 8 objWMIService.InstancesOfAsync objSink, "Win32_NTLogEvent"
 9 errReturn = objWshShell.Popup("Retrieving events", POPUP_DURATION, _
10     "Event Retrieval", OK_BUTTON)
11 Sub SINK_OnCompleted(iHResult, objErrorObject, objAsyncContext)
12     WScript.Echo "Asynchronous operation is done."
13 End Sub
14 Sub SINK_OnObjectReady(objEvent, objAsyncContext)
15     Wscript.Echo "Category: " & objEvent.Category
16     Wscript.Echo "Computer Name: " & objEvent.ComputerName
17     Wscript.Echo "Event Code: " & objEvent.EventCode
18     Wscript.Echo "Message: " & objEvent.Message
19     Wscript.Echo "Record Number: " & objEvent.RecordNumber
20     Wscript.Echo "Source Name: " & objEvent.SourceName
21     Wscript.Echo "Time Written: " & objEvent.TimeWritten
22     Wscript.Echo "Event Type: " & objEvent.Type
23     Wscript.Echo "User: " & objEvent.User
24 End Sub

Copying Events to a Database

WMI provides a way to programmatically access the records in an event log. Although this is an extremely useful capability, WMI does have at least two limitations when it comes to querying large data sources such as event logs:

  • The WMI Query Language (WQL) contains only a small subset of the keywords and commands in Structured Query Language (SQL).

    For example, you might want to tally frequency statistics for the events in an event log. (This would tell you that Event ID 1 has occurred X number of times, Event ID 2 has occurred Y number of times, and so forth.) This type of query can be constructed in SQL by using code similar to the following (assuming you have a database named EventLog):

    SELECT Count(EventID) AS CountOfEventID, EventID FROM EventLog GROUP BY
    CountOfEventID
    

    However, this kind of query cannot be constructed using WQL.

  • Unlike a database, event logs are not optimized to process queries and rapidly return information.

    A query against an event log with a large number of records can take a long time to complete. On a Windows 2000–based test computer with an event log containing 12,000 records, a query that returned events with a specific Event ID required 48 seconds to complete. The same query run against an SQL database holding the exact same information completed in less than 1 second.

To carry out a regular and detailed analysis of your event logs, you might want to periodically extract the records from the event log and copy them to a database. Copying the records to a database enables you to create more sophisticated queries and greatly decreases the time it takes to run these queries.

Copying records to a database also allows you to combine the event logs from multiple computers. For example, you might combine all the DNS event logs from all your DNS servers into a single database. Using that database, you can easily construct queries that compare the events that occur on one DNS server with the events that occur on your other DNS servers.

Scripting Steps

You can periodically copy all the events from an event log to a database, clear the event log, and allow events to accumulate until you copy the events and clear the log again.

Listing 12.12 contains a script that retrieves all the events from an event log and copies them to a database. Before you create this script, you need to create the following:

  • A database with the System Data Source Name (DSN) of EventLogs.

    For information about accessing databases by using scripts, see “Creating Enterprise Scripts” in this book.

  • A table in the database named EventTable with field names equivalent to the field names used in the script:

    • Category

    • ComputerName

    • EventCode

    • Message

    • RecordNumber

    • SourceName

    • TimeWritten

    • Type

    • User

To carry out this task, the script must perform the following steps:

  1. Create the following two objects:

    • ADODB.Connection, representing a connection to an Active Data Objects (ADO) database.

    • ADODB.Recordset, representing an ADO recordset.

  2. Open the database with the System DSN of EventLogs.

  3. Open the table EventTable, using the SQL query “Select * from EventTable.”

  4. Create a variable to specify the computer name.

  5. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  6. Use the ExecQuery method to query the Win32_NTLogEvent class.

    This query returns a collection consisting of all the events from all the event logs, except the Security event log.

  7. For each event in the collection, use the AddNew command to add a new record to the database.

    The appropriate fields in the new record are then populated using the properties of the event record.

  8. After the record has been populated, use the Update command to write the new data to the database.

  9. Close the database connection and the recordset.

Example 12.12. Copying Events to a Database

 1 Set objConn = CreateObject("ADODB.Connection")
 2 Set objRS = CreateObject("ADODB.Recordset")
 3 objConn.Open "DSN=EventLogs;"
 4 objRS.CursorLocation = 3
 5 objRS.Open "SELECT * FROM EventTable" , objConn, 3, 3
 6 strComputer = "."
 7 Set objWMIService = GetObject("winmgmts:" _
 8     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 9 Set colRetrievedEvents = objWMIService.ExecQuery _
10     ("SELECT * FROM Win32_NTLogEvent")
11 For Each objEvent in colRetrievedEvents
12     objRS.AddNew
13     objRS("Category") = objEvent.Category
14     objRS("ComputerName") = objEvent.ComputerName
15     objRS("EventCode") = objEvent.EventCode
16     objRS("Message") = objEvent.Message
17     objRS("RecordNumber") = objEvent.RecordNumber
18     objRS("SourceName") = objEvent.SourceName
19     objRS("TimeWritten") = objEvent.TimeWritten
20     objRS("Type") = objEvent.Type
21     objRS("User") = objEvent.User
22     objRS.Update
23 Next
24 objRS.Close
25 objConn.Close

Writing Events to Event Logs

Windows operating systems do not automatically record every event that takes place on a computer. Many events of interest, including logon scripts that failed, software that could not be installed, and drives that could not be mapped, are not recorded in the event logs and are therefore not automatically available to anyone analyzing the event logs.

If your scripts carry out activities that should be logged (either because they succeeded or because they failed), you can use the Windows Script Host (WSH) LogEvent method to record events in the Application event log.

Note

Note

WMI does not provide a method for writing events to the event logs.

Limitations of the LogEvent method

Before you begin using the LogEvent method in your scripts, it is important to understand the limitations inherent in this method:

  • The LogEvent method can record only events in the Application Log.

  • You cannot specify a unique event ID or a unique Event Source when using this method.

    Instead, all events are logged with an event ID that corresponds to the event type (for example, all successful events will have an event ID of 0) and the Event Source WSH. This makes it impossible to search for events derived from a particular script unless you include the script name as part of the Event Description.

Writing to Event Logs

The LogEvent method in WSH allows you to write events to the Application Log. When writing these events, you can specify the information shown in Table 12.6.

Table 12.6. LogEvent Method Parameters

Specification

Description

Event type

Event types include the following:

  • 0— Success

  • 1— Error

  • 2— Warning

  • 4— Information

  • 8— Audit success (generally not used in the Application Log)

  • 16— Audit failure (generally not used in the Application Log)

Event description

Any text message describing the event.

Name of the computer to which the event will be recorded

If not specified, the event will be recorded to the Application Log on the computer on which the script is being run. If you prefer to record the event in the Application Log on a remote computer, enclose the Universal Naming Convention (UNC) name of the computer in quotation marks (for example, “\PrimaryServer”).

Before you attempt to record events to a remote computer, make sure the user running the script has permission to write events to the remote event log.

Scripting Steps

There are multiple ways to write an event to an event log. You can do this by:

  1. Writing an event to an event log on the local computer.

  2. Writing an event to an event log on a remote computer.

Writing an event to an event log on the local computer

Listing 12.13 contains a script that writes a Success event (event type 0) to the Application event log on the local computer. To carry out this task, the script must perform the following steps:

  1. Create a constant EVENT_SUCCESS and set the value to 0.

  2. Create an instance of the WSH Shell object.

  3. Use the LogEvent method to write the record to the event log, specifying two parameters:

    • EVENT_SUCCESS —Constant that indicates the type of event.

    • “Payroll application successfully installed.” —The event description.

    Because this event will be written to the local computer, the computer name (an optional, third parameter) does not have to be specified.

Example 12.13. Writing an Event to the Application Log

1 Const EVENT_SUCCESS = 0
2 Set objShell = Wscript.CreateObject("Wscript.Shell")
3 objShell.LogEvent EVENT_SUCCESS, _
4     "Payroll application successfully installed."

Writing an event to an event log on a remote computer

To record the event to the Application Log on a remote computer, add the UNC computer name as an optional, third, parameter to the LogEvent method. Listing 12.14 contains a script that writes the same event to the Application Log on the remote computer \PrimaryServer.

Example 12.14. Writing an Event to the Application Log on a Remote Computer

1 Const EVENT_SUCCESS = 0
2 Set objShell = Wscript.CreateObject("Wscript.Shell")
3 objShell.LogEvent EVENT_SUCCESS, _
4     "Payroll application successfully installed." , "\PrimaryServer"

Creating Detailed Event Log Entry Descriptions

When your script writes an event to the event log, it can tap the capabilities of WMI to create more meaningful event descriptions, descriptions that can include information such as the amount of memory installed on a computer or the amount of available disk space on a computer.

For example, the event log might include an error event indicating that an application could not be installed on a computer. This particular application might require 15 MB of free disk space in order to be installed. If the event description includes the fact that the computer had only 10 MB of free disk space, you know at least one reason why the application could not be installed on that computer.

Scripting Steps

Listing 12.15 contains a script that adds WMI data to an event log entry. To carry out this task, the script must perform the following steps:

  1. Create a constant EVENT_FAILED and set the value to 2.

    This indicates that an error occurred.

  2. Create an instance of the WSH Shell object. This is required to use the LogEvent method.

  3. Create a WSH Network object.

    This object is used to return the name of the computer on which the installation was attempted, as well as the domain and user name of the person who attempted the installation.

  4. Create a variable to specify the computer name.

  5. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  6. Use the ExecQuery method to query the Win32_ LogicalDisk class.

    This query returns a collection consisting of all the logical disks installed on the computer.

  7. For each logical disk in the collection, retrieve the free disk space by using the FreeSpace property.

  8. Add the drive name, the amount of free space, and a carriage return (VbCrLf) to the variable strDrive Space.

    After the script loops through the entire collection, this variable will contain a list of drives and the available space on each. For example:

    A: 0
    C: 152611
    D: 5678322
    
  9. Set the value of the variable strEventDescription to a string consisting of:

    • The string “Payroll application could not be installed on ”.

    • The user domain, computer name, and user name.

    • The string “Free space on each drive is: ” and the variable strDriveSpace.

    The final value for strEventDescription might look similar to this:

    Payroll application could not be installed on FABRIKAMatl-xp-pro-001
    by user kmeyer. Free space on each drive is:
    A: 0
    C: 152611
    D: 5678322
    
  10. Use the LogEvent method to write the record to the event log, specifying the event type and the event description.

Example 12.15. Adding WMI Data to an Event Log Entry

 1 Const EVENT_FAILED = 2
 2 Set objShell = Wscript.CreateObject("Wscript.Shell")
 3 Set objNetwork = Wscript.CreateObject("Wscript.Network")
 4 strComputer = "."
 5 Set objWMIService = GetObject("winmgmts:" _
 6     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 7 Set colDiskDrives = objWMIService.ExecQuery _
 8     ("SELECT * FROM Win32_Logicaldisk")
 9 For Each objDisk in colDiskDrives
10    strDriveSpace = strDriveSpace & objDisk.Name & " " & _
11         objDisk.FreeSpace & VbCrLf
12 Next
13 strEventDescription = "Payroll application could not be installed on " _
14     & objNetwork.UserDomain & "" & objNetwork.ComputerName _
15         & " by user " & objNetwork.UserName & _
16             ". Free space on each drive is: " & VbCrLf & strDriveSpace
17 objShell.LogEvent EVENT_FAILED, strEventDescription

Creating Custom Event Logs

By default, Windows 2000–based computers have three event logs: System Log, Security Log, and Application Log. Depending on a computer’s role and on the services hosted by the computer, you can have additional event logs, such as Directory Service Log, DNS Server Log, and File Replication Service Log.

Custom event logs, which can be created by adding a subkey to the registry, can make it easier for you to monitor specific applications or types of events. For example, you might create a custom event log named ScriptingEventLog and use this as a repository for any events written by one of your scripts. After the custom log has been created, it can be programmatically monitored and managed by using WMI.

One minor limitation of a custom event log is that no event sources are registered for the log. As a result, your event descriptions are prefaced with a notice informing you that no event source could be found for the event. An event description, recorded as “Drive X could not be mapped” and similar to the following, appears in Event Viewer:

The description for Event ID ( 100 ) in Source ( SCRIPTINGEVENTLOG ) cannot
be found. The local computer may not have the necessary registry information
or message DLL files to display messages from a remote computer. You may be able
to use the /AUXSOURCE= flag to retrieve this description; see Help and Support
for details. The following information is part of the event: Drive X could not
be mapped.

Caution

Caution

Changing the registry with a script can easily propagate errors. The scripting tools bypass safeguards, allowing settings that can damage your system, or even require you to reinstall Windows. Before scripting changes to the registry, test your script thoroughly and back up the registry on every computer on which you will make changes. For more information about scripting changes to the registry, see the Registry Reference on the Microsoft Windows 2000 Server Resource Kit companion CD or at http://www.microsoft.com/reskit.

Scripting Steps

Listing 12.16 contains a script that creates a custom event log by adding a subkey to the registry. To carry out this task, the script must perform the following steps:

  1. Create a constant named NO_VALUE and set the value to Empty. This constant is used to create an empty value for the new registry subkey.

  2. Create an instance of the WSH Shell object.

  3. Use the RegWrite method to create a new registry subkey and set its value to NO_VALUE. The new subkey is named HKLMSystemCurrentControlSetServicesEventLogScriptingEventLog, which means that the new event log will be named ScriptingEventLog.

Example 12.16. Creating a Custom Event Log

1 Const NO_VALUE = Empty
2 Set WshShell = WScript.CreateObject("WScript.Shell")
3 WshShell.RegWrite _
4 "HKLMSystemCurrentControlSetServicesEventLogScriptingEventLog", _
5     NO_VALUE

Managing Plain-Text Logs

In addition to the event logs, various Windows 2000 services record event information in plain-text log files. Plain-text logs are often used to store a large quantity of information that does not need to be (or perhaps should not be) stored in the event logs. For example, if the thousands of events generated each day by a Web server on an intranet were all recorded in event logs, the event logs would be far more difficult to filter and analyze. Because of this, it makes sense to log Internet Information Services events in a plain-text log instead of an event log.

A typical Windows 2000 domain controller might have 200 or more of these logs that store event information for such things as File Replication service replication, DHCP server activities, and Internet Information Services sessions. A partial list of Windows 2000 Server plain-text logs is shown in Table 12.7.

Table 12.7. Plain-Text Logs Used in Windows 2000 Server

Log Name

Format

Description

DCPromoUI.log

Fixed-width

Contains a detailed report of the Active Directory® directory service installation and removal process, including the name of the source domain controller used for replication and the directory partitions and number of items that were replicated.

DCPromo.log

Fixed-width

Records settings used during the promotion or demotion of a domain controller, including site name, location of Active Directory log and database files, and configuration of services and security settings.

Netsetup.log

Fixed-width

Records events that occur when joining a computer to a domain.

Netlogon.log

Fixed-width

Records errors that occur when the Net Logon service attempts to dynamically create a DNS record. If this log is blank, that means no errors have occurred.

Ntfrs.log

Fixed-width

Records events that occur each time the File Replication Service runs.

Userenv.log

Text

Records events that occur when a computer processes user profiles and Group Policy.

DHCPSrvLog

Comma-separated

Records DHCP server events.

Managing plain-text logs has always been difficult because of the large number of logs used on a computer and the large amount of information stored in each log. In addition, Windows 2000 Server log files can use different text formats: comma-separated values, fixed-width text, or a unique formatting scheme. It is difficult to import these files into a single application where the events can be filtered, sorted, and analyzed.

Scripts can help manage plain-text log files. A script can automatically parse a set of log files to extract and reformat the data or to search for a particular event. Because scripts can handle different log-file formats, they can also take data from disparate sources and combine this data in a central database.

Parsing Comma-Separated-Values Logs

A comma-separated-values (CSV) log consists of two primary components:

  • A header line, which indicates the data fields used in the log.

  • Record lines, containing the data for each record written to the log.

In both header and record lines, commas separate individual fields. By contrast, in a tab-separated-values (TSV) log, tab characters separate fields.

For example, in DHCPSrvLog.log, the header line and the first two record lines look something like the following:

ID Date,Time,Description,IP Address,Host Name,MAC Address
10,04/02/01,15:16:00,Assign,192.168.1.10,workstation1.fabrikam.com,0000F8083446,
10,04/02/01,15:16:00,Assign,192.168.1.11,workstation2.fabrikam.com,0000F8083447,

To parse a CSV log, the script needs to read in each line and then extract each field within the line. This can be done using the VBScript Split function, which splits a line into constituent parts based on the field delimiter (the character used to separate the individual fields). For example, this line:

Part 1,Part 2,Part 3,Part 4

Would be split into a four-item array, with the array consisting of the following elements:

  • Part 1

  • Part 2

  • Part 3

  • Part 4

Scripting Steps

Listing 12.17 contains a script that parses a CSV file. To carry out this task, the script must perform the following steps:

  1. Create a constant (ForReading) to be used with the FileSystemObject.

  2. Create an instance of the FileSystemObject.

  3. Open the DHCP server Log for Monday (C:WindowsSystem32DHCPDhcpSrvLog-Mon.log).

  4. Use the SkipLine method to move through the first 25 lines in the file.

    The first 25 lines in a DHCP server log are always header information that is not required for this script. You must start at the beginning of the file and explicitly skip these lines, however, because the FileSystemObject always begins reading at the first line of the file. You cannot specify an alternative starting point, such as the 26th line of the file.

  5. Beginning with line 26, read each line by using the ReadLine method, and temporarily store the contents in the variable strNextLine.

  6. Use the VBScript Split function to split the line into 8 separate variables. (The comma is used as the split delimiter.)

    Each variable (representing a comma-delimited field in the log) is stored in the array arrDHCPRecord.

  7. Echo the contents of arrDHCPRecord to the screen.

    In a production script, you would probably either save selected variables to a database or take some action based on the value of one or more of those variables (for example, the Event ID).

Example 12.17. Parsing a Comma-Separated-Values Log

 1 Const ForReading = 1
 2 Set objFSO = CreateObject("Scripting.FileSystemObject")
 3 Set objTextFile = objFSO.OpenTextFile("C:WindowsSystem32DHCP" _
 4     & "DhcpSrvLog-Mon.log", ForReading)
 5 Do While objTextFile.AtEndOfStream <> True
 6     If inStr(objtextFile.Readline, ",") Then
 7         arrDHCPRecord = split(objTextFile.Readline, ",")
 8         Wscript.Echo "Event ID: " & arrDHCPRecord(0)
 9         Wscript.Echo "Date: " & arrDHCPRecord(1)
10         Wscript.Echo "Time: " & arrDHCPRecord(2)
11         Wscript.Echo "Description: " & arrDHCPRecord(3)
12         Wscript.Echo "IP Address: " & arrDHCPRecord(4)
13         Wscript.Echo "Host Name: " & arrDHCPRecord(5)
14         Wscript.Echo "MAC Address: " & arrDHCPRecord(6)
15     Else
16         objTextFile.Skipline
17     End If
18     i = i + 1
19 Loop
20 objTextFile.Close

Parsing Fixed-Width Logs

Fixed-width text log fields are parsed differently from CSV log fields. In a comma-separated-values log, an individual field can contain any number of characters; by definition, a field contains all the characters that precede a comma. For example, the following are valid comma-separated-values fields, even though the fields consist of different field lengths:

Computer,Domain
WebServer,fabrikam.com
FinancialAccountingServer,finance.accounting.fabrikam.com

In a fixed-width text log, fields are delimited by length rather than by a comma or other character. The fields in any given record must be exactly the same size as fields in all the records.

For example, in NetSetup.log, there are three fields: date, time, and description. As shown in the following log excerpt, date begins with the first character, time with the seventh character, and description with the sixteenth character (numbers have been added to help indicate character positions):

123456789012345678901234567890123456789012345678901234567890
08/16 11:50:49 NetpDoDomainJoin
08/16 11:50:49 NetpMachineValidToJoin: 'WINTEST'
08/16 11:50:49 NetpGetLsaPrimaryDomain: status: 0x0
08/16 11:50:49 NetpMachineValidToJoin: status: 0x0

When this log is parsed, the first record is split into these three fields:

  • 08/16

  • 11:50:49

  • NetpDoDomainJoin

Scripting Steps

Listing 12.18 contains a script that parses the fixed-width-column log Netsetup.log. To carry out this task, the script must perform the following steps:

  1. Create a constant (ForReading) to be used with the FileSystemObject.

  2. Create an instance of the FileSystemObject.

  3. Open the Netsetup log (C:WindowsDebugNetsetup.log).

  4. Create a loop for reading each line in the file.

  5. Read the first line, and temporarily store the contents in the variable strLineToParse.

  6. Use the Mid function to parse the Date, Time, and Description from the variable.

    • Date represents the first six characters in the string.

    • Time begins at character position 7 and is nine characters long.

    • Description begins at character position 16 and makes up the remainder of the line.

  7. Echo the values of the individual fields.

  8. Repeat the loop with the next line in the log file.

  9. Close the log file.

Example 12.18. Parsing a Fixed-Width-Column Log

 1 Const ForReading = 1
 2 Set objFSO = CreateObject("Scripting.FileSystemObject")
 3 Set objTextFile = objFSO.OpenTextFile("C:WindowsDebugNetsetup.log", _
 4     ForReading)
 5 Do While objTextFile.AtEndOfStream <> True
 6     strLinetoParse = objTextFile.ReadLine
 7     dtmEventDate = Mid(strLinetoParse, 1, 6)
 8     dtmEventTime = Mid(strLinetoParse, 7, 9)
 9     strEventDescription = Mid(strLinetoParse, 16)
10     Wscript.Echo "Date: " & dtmEventDate
11     Wscript.Echo "Time: " & dtmEventTime
12     Wscript.Echo "Description: " & strEventDescription & VbCrLf
13 Loop
14 objTextFile.Close
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset