Creating Faster Queries by Using a Forward-only Enumerator

Microsoft® Windows® 2000 Scripting Guide

In some cases, you can speed up a query by using a forward-only enumerator. For example, on a Windows 2000based test computer, a script that returned 10,000 events from the event logs required 47 seconds to complete. A script using a forward-only enumerator required just 28 seconds to complete. Admittedly, the time differential (19 seconds) might not appear that large. However, suppose the script had to perform the same task on all 50 of your domain controllers. In a situation like that, 19 seconds times 50 domain controllers results in a large difference between the two scripts.

A forward-only enumerator requires you to provide three parameters to ExecQuery. The first parameter is the WQL query. The second parameter represents the query language; this should either be left blank or set to "WQL". (At this point in time, WQL is the only query language that can be used with WMI.) The third parameter is the value 48. This value represents the combination of two "flags," numbers that can be combined to act as a single parameter to a method. These flags are:

  • wbemFlagReturnImmediately (decimal value 16). This is the default setting that causes ExecQuery to run semisynchronously. As explained earlier in this chapter, in semisynchronous mode, the script starts the query and can immediately begin working with the SWbemObjectSet that is returned while instances are still being retrieved. This is the default behavior for most WMI queries (in other words, although you do not have to specify it in the script, wbemFlagReturnImmediately is enabled on most queries).

  • wbemFlagForwardOnly (decimal value 32). This flag causes the script to use a forward-only enumerator.

Forward-only enumerators typically run faster than other queries and use less memory. However, with a forward-only enumerator, as soon as an object is enumerated it is released from memory. This frees memory and enables the query to run faster, but the objects can be enumerated only once; after that, they are no longer available. This means that you can use a forward-only enumerator to return instances and echo their values to the screen only once. As soon as the enumeration is finished (that is, as soon as the For Each loop completes), no instances remain in memory. As a result, an error occurs if you try to enumerate the instances a second time.

The following script uses a forward-only enumerator to return events from the event logs. Notice that the parameter following the SELECT query is left blank.

Const wbemFlagReturnImmediately = 16
Const wbemFlagForwardOnly = 32
strComputer = "."
Set objSWbemServices = _
    GetObject("winmgmts:{(Security)}\\" & strComputer & "\root\cimv2")
Set colNTLogEvents = objSWbemServices.ExecQuery _
    ("SELECT * FROM Win32_NTLogEvent", , _
     wbemFlagReturnImmediately + wbemFlagForwardOnly)
For Each objNTLogEvent In colNTLogEvents
    Wscript.Echo "Log File:        " & objNTLogEvent.LogFile        & vbCrLf & _
"Record Number:   " & objNTLogEvent.RecordNumber   & vbCrLf & _
"Type:            " & objNTLogEvent.Type           & vbCrLf & _
"Time Generated:  " & objNTLogEvent.TimeGenerated  & vbCrLf & _
"Source:          " & objNTLogEvent.SourceName     & vbCrLf & _
"Category:        " & objNTLogEvent.Category       & vbCrLf & _
"Category String: " & objNTLogEvent.CategoryString & vbCrLf & _
"Event:           " & objNTLogEvent.EventCode      & vbCrLf & _
"User:            " & objNTLogEvent.User           & vbCrLf & _
"Computer:        " & objNTLogEvent.ComputerName   & vbCrLf & _
"Message:         " & objNTLogEvent.Message        & vbCrLf
Next

You cannot use the SWbemObjectSet Count property when using a forward-only enumerator. For example, suppose you inserted the following statement after the ExecQuery call in the previous script.

Wscript.Echo colNTLogEvents.Count

If you try to run the revised script, the following error message will appear in the command window:

SWbemObjectSet: Unspecified error

Why? The answer lies in the way Count works. Because Count performs an enumeration to determine the number of items in the collection, reading the Count property would exhaust your one-time enumeration of the forward-only enumerator. As such, Count is not a supported property for any SWbemObjectSet that is returned using the forward only flag.