2008 Winter Scripting Games

Solution to Sudden Death Challenge Event 5: WMI From A to Z -- er, A to Y

*

WMI From A to Z – er, A to Y

Like we said in the instructions, Event 5 was a little tougher than the other events in the Sudden Death Challenge. (But like we also said, it wouldn’t be much of a challenge if everyone got a perfect score, would it?) But while this event might have been difficult it wasn’t impossible.

No, really, it wasn’t.

That’s especially true if you took our hint and followed the link to the WMI section of the Script Repository. If you did, you should have stumbled upon a script titled List All the Properties and Methods of the Win32 Classes. That script provides the basic framework for crafting an answer to Event 5.

But instead of talking about this why don’t we just show you some code? Here’s a VBScript solution to Event 5; needless to say, we could also have solved this problem using Perl or Windows PowerShell:

strComputer = "."

Set objWMIService=GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
 
For i = 65 to 89
    strCharacter = Chr(i)
    x = 0
    For Each objClass in objWMIService.SubclassesOf()
        If Left(objClass.Path_.Class,5) = "Win32" Then
            Set strClass = objWMIService.Get(objClass.Path_.Class)
            For Each strItem in strClass.Properties_
                If Left(strItem.Name, 1) = strCharacter Then
                    Wscript.Echo strItem.Name & "     " & objClass.Path_.Class 
                    x = 1
                    Exit For
                End If
            Next
            If x = 1 Then
                Exit For
            End If
        End If
    Next
Next

So how does this script work? Well, it starts off by binding to the WMI service on the local computer; that part seems straightforward enough. After that, however, the script veers off into the unexpected:

For i = 65 to 89

Why a loop that runs from 65 to 89, and why here? Well, as those of you who tried Event 4 know, the uppercase letters have ASCII values that run from 65 (A) to 89 (Y). VBScript won’t let us set up a loop that runs from A to Y. Therefore, we’re doing the next best thing: we’re setting up a loop that runs from the ASCII value of A to the ASCII value of Y.

Note. Why don’t we loop from A to Z instead of from A to Y? That’s easy: on our copy of Windows (Windows XP) there aren’t any property names in the root\cimv2 namespace that begin with the letter Z, at least not in the Win32_ classes.

The first thing we do inside this loop is use the Chr function to convert the ASCII value of the loop variable i to an actual letter:

strCharacter = Chr(i)

Because i is equal to 65 (the first time through the loop anyway), that’s going to make strCharacter equal to A.

After setting the value of a counter variable named x to 0 we then use this line of code to loop through a collection of all the classes found in the root\cimv2 namespace:

For Each objClass in objWMIService.SubclassesOf()

As you can see, there’s nothing particularly hard about that; we simply reference the SubclassesOf() property, a property that contains information about each class in a given namespace. Inside this loop the first thing we do is check to see if we’re dealing with a Win32 class; that’s something we do by using the Left function to determine whether or not the first five characters in the class named are Win32:

If Left(objClass.Path_.Class,5) = "Win32" Then

Suppose the first five characters aren’t Win32? In that case, we’re not dealing with a Win32 class; instead we’re dealing with a class like, say, CIM_DataFile. Therefore, we go back to the beginning of our For Each loop and try again with the next class in the collection.

If it turns out that we are dealing with a Win32 class we then use this line of code to create an object reference to the class itself:

Set strClass = objWMIService.Get(objClass.Path_.Class)

Once we’ve done that we set up another For Each loop, this one designed to walk us through all the properties of the class:

For Each strItem in strClass.Properties_

So what do we do inside this loop? Well, now that we have the properties for a given class we want to see if any of these property names start with the letter A. We can do that by checking to see if the first character in the property Name equals the value of the variable strCharacter:

If Left(strItem.Name, 1) = strCharacter Then

If the two values don’t match then we simply try again with the next property in the class. But what do we do if the values do match?

In that case, the first thing we do is echo the name of the property, a few blank spaces, and the name of the class:

Wscript.Echo strItem.Name & "     " & objClass.Path_.Class

We set the value of the counter variable x to 1, then use the Exit For statement to exit our innermost For Each loop.

Why did we set the value of x to 1? Well, when we exit our inner For Each loop we need to know why we exited the loop. That is, did we exit the loop because we found a property name starting with the letter A, or did we exit the loop because we’ve looked through all the property names for this class and couldn’t find one that started with the letter A? If we set the value of x to 1 then the script knows that we exited the loop because we found the property we were looking for.

In fact, that’s the first thing we do when we exit the loop; we check to see if x = 1:

If x = 1 Then

If x is equal to 1 that means that we found a property name beginning with A. Therefore, we use the Exit For statement to exit the For Each loop that loops us through all the classes in the root\cimv2 namespace. In turn, that takes us back to our original For Next loop where we then repeat the entire process, this time with i equal to 66 (and strCharacter equal to B). If x is not equal to 1 then we simply grab the next class in the collection and check to see if it has any property names that begin with A. Etc. etc.

When all is said and done you should get back data similar to (but not necessarily exactly like) this:

AdditionalDescription   Win32_JobObjectStatus
BankLabel       Win32_PhysicalMemory
Caption Win32_OnBoardDevice
DriveName       Win32_VolumeChangeEvent
EventType       Win32_PowerManagementEvent
FileName        Win32_ModuleLoadTrace
GuaranteesDelivery      Win32_NetworkProtocol
HotSwappable    Win32_OnBoardDevice
ImageBase       Win32_ModuleLoadTrace
JobCountSinceLastReset  Win32_Printer
KernelModeTime  Win32_Process
LengthAllowed   Win32_SystemSlot
MachineName     Win32_ComputerSystemEvent
Name    Win32_OnBoardDevice
OEMEventCode    Win32_PowerManagementEvent
ProcessID       Win32_ModuleLoadTrace
QuotaNonPagedPoolUsage  Win32_Process
Removable       Win32_OnBoardDevice
SECURITY_DESCRIPTOR     Win32_ComputerSystemEvent
TIME_CREATED    Win32_ComputerSystemEvent
UserStackBase   Win32_ThreadStartTrace
Version Win32_OnBoardDevice
WaitMode        Win32_ThreadStartTrace
XOffCharacter   Win32_SerialPortConfiguration
Year            Win32_CurrentTime

Like we said, this one was hard. But definitely not impossible.


Top of pageTop of page