Working with WMI Classes
In addition to working with namespaces, the inquisitive network administrator will also want to explore the concept of classes. In WMI parlance, you have core classes, common classes, and dynamic classes. Core classes represent managed objects that apply to all areas of management. These classes provide a basic vocabulary for analyzing and describing managed systems. Two examples of core classes are parameters and the systemSecurity class. Common classes are extensions of the core classes and represent managed objects that apply to specific management areas. However, common classes are independent from a particular implementation or technology. The CIM_UnitaryComputerSystem is an example of a common class. Core and common classes are not used as much by network administrators because they serve as templates from which other classes are derived.
Therefore, many of the classes stored in root\cimv2 are abstract classes and are used as templates, and their properties and methods are inherited by classes that are derived from them. Abstract classes are not to be queried directly. However, a few classes in root\cimv2 are dynamic classes used to hold actual information. The important aspect to remember about dynamic classes is that instances of a dynamic class are generated by a provider and are therefore more likely to retrieve "live" data from the system.
The following script, ListWMIClasses.vbs, returns a list of classes found in the root\cimv2 namespace. There are more than 900 classes listed in the root\cimv2 namespace of most computers. A listing of the WMI classes in each of the namespaces is listed in the spreadsheets in the \My Documents\Microsoft Press\VBScriptSBS\Supplemental folder.
ListWMIClasses.vbs
Option Explicit
Dim strComputer 'target computer
Dim wmiNS 'wmi namespace
Dim objwmiService 'SwbemServices object. The connection into WMI
Dim colClasses 'sWbemObject set object. A collection of items
Dim objClass 'sWbemObject. An item in colClasses
Dim strOUT 'output of all items
strComputer = "."
wmiNS = "\root\cimv2" 'must precede namespace with \
Set objwmiService = _
GetObject("winmgmts:\\" & strComputer & wmiNS)
Set colClasses = objwmiService.SubclassesOf()
For Each objClass In colClasses
strOUT = strOUT & objClass.Path_.class & vbcrlf
Next
WScript.Echo funLine("There are " & colClasses.count & " classes" &_
" in the " & wmiNS & " namespace")
WScript.Echo strOUT
' *** function below ***
Function funLine(strIn)
funLine = Len(strIn)+1
funLine = strIN & VbCrLf & String(funLine,"=")
End Function
Search for specific WMI classes
1. | Open the \My Documents\Microsoft Press\VBScriptSBS\ch08\ListWMIClasses.vbs script in Microsoft Notepad or the script editor of your choosing. Save the file as YourNameListWMIClassesDictionary.vbs.
| 2. | Delete the line declaring the variable strOUT, because it will not be needed in this script.
| 3. | Add a variable to hold the dictionary object that will be created. Call it objDictionary, as seen below:
| 4. | Add a variable to hold an individual key in the dictionary. Call it strKey, as seen below:
| 5. | Add one more variable. This variable will be used to hold the search string. Call it strSearch, as seen below.
| 6. | In the Reference section of your script, assign a string value to the strSearch variable. This will be used to locate class names. I used "process" for my initial search.
| 7. | Now it is time to create the dictionary object. Place the code just before you create the connection into WMI. This will be the first line in your Worker section. Assign the dictionary to the variable objDictionary, as seen below:
Set objDictionary = CreateObject("Scripting.Dictionary")
| 8. | Inside the For...Each...Next loop that walks through the colClasses collection, delete strOUT = strOUT but do not delete the entire line. Instead, prefix the line with the command to add the class name to the dictionary. Because each class name is unique in the WMI namespace, and because we must have both a key and an item in the dictionary, we will use the class name twice, as seen in the code below:
objDictionary.Add objClass.Path_.class, objClass.Path_.class
| 9. | Delete the Output section of the script, as well as the function. The code to be removed is seen below:
WScript.Echo funLine("There are " & colClasses.count & " classes" &_
" in the " & wmiNS & " namespace")
WScript.Echo strOUT
' *** function below ***
Function funLine(strIn)
funLine = Len(strIN)+1
funLine = strIN & VbCrLf & String(funLine,"=")
End Function
| 10. | Use For...Each...Next to walk through the collection of keys in the dictionary. We can use the Keys method to get a collection of dictionary keys. Use the strKey variable to singularize an individual dictionary key. Make sure you close out the For...Each...Next block with the word Next. This is seen below:
For Each strKey In objDictionary.Keys
Next
| 11. | Use the InStr function to look inside the dictionary key represented by the variable strKey to see if there is a pattern match with the word specified in the variable strSearch. Begin the search at the first position in the word, and make the search case insensitive. Make sure you close out the If...Then...End If construction. Echo out the results. This code goes inside the loop and looks like the following:
If InStr(1,strKey, strSearch,vbTextCompare) Then
WScript.Echo strKey
End If
| 12. | Save and run your script. It should produce a listing something like the following when run from CScript. If it does not, then compare your script with the \My Documents\Microsoft Press\VBScriptSBS\ch08\ListWMIClassesDictionary.vbs script.
Win32_ProcessTrace
Win32_ProcessStartTrace
Win32_ProcessStopTrace
CIM_Process
Win32_Process
CIM_Processor
Win32_Processor
Win32_PerfRawData_PerfProc_Process
Win32_PerfRawData_PerfOS_Processor
Win32_PerfRawData_PerfProc_ProcessAddressSpace_Costly
Win32_PerfFormattedData_PerfOS_Processor
Win32_PerfFormattedData_PerfProc_Process
Win32_PerfFormattedData_PerfProc_ProcessAddressSpace_Costly
CIM_OSProcess
Win32_SystemProcesses
Win32_ComputerSystemProcessor
CIM_ProcessThread
Win32_SessionProcess
CIM_AssociatedProcessorMemory
Win32_AssociatedProcessorMemory
CIM_ProcessExecutable
Win32_NamedJobObjectProcess
Win32_ProcessStartup
| 13. | EXTRA CREDIT: Modify your script to write the results out to a text file. Compare your results to \My Documents\Microsoft Press\VBScriptSBS\ch08\ListWMIClassesTextSearch.vbs.
|
Adding an inputbox search
1. | Open the \My Documents\Microsoft Press\VBScriptSBS\ch08\ListWMIClassesDictionary.vbs script and save it as YourNameListWMIClassesDictionarySearch.vbs.
| 2. | Add three variables in the Header section of the script. These variables will be used for the title, prompt, and default value of the inputbox function. Call them strTitle, strPrompt, and strDefault, as seen below:
Dim strTitle 'title for the inputbox
Dim strPrompt 'prompt for the inputbox
Dim strDefault 'default value for the inputbox
| 3. | In the Reference section of the script, assign a string value to indicate the purpose of the script to the strTitle variable. My code looks like the following:
strTitle = "Search for WMI classes"
| 4. | On the next line, assign a prompt to the strPrompt variable that tells the user how to use the script. My code looks like the following:
strPrompt = "Enter class to search for" &_
vbNewLine & "No quotes required"
| 5. | On the next line in the Reference section, assign the string "Process" to the strDefault variable. This is seen below:
| 6. | Edit the strSearch variable assignment in the Reference section, so it does not have a string literal assigned to it. Instead of " hardcoding" our search string, we will use the inputbox function to allow the value to be supplied at runtime. This is seen below:
strSearch = InputBox(strPrompt,strTitle,strDefault)
| 7. | Save and run your script. You should see a dialog box that allows you to change the search string. It should have the value Process as the default value.
|
Viewing Properties
A property in WMI is a value that is used to indicate a characteristic (something describable) about a class. A property has a name and a domain that is used to indicate the class that actually owns the property. Properties can be viewed in terms of a pair of functions: one to set the property value and another to retrieve the property value. The ListClassProperties.vbs script lists all the properties of the WIN32_Service class.
ListClassProperties.vbs
Option Explicit
'On Error Resume Next
Dim strComputer 'name of target computer
Dim wmiNS 'WMI namespace that contains class
Dim wmiQuery 'simply the name of the class
Dim objWMIService 'connection to WMI namespace AND Class
Dim objItem 'item in the collection of properties
strComputer = "."
wmiNS = "\root\cimv2"
wmiQuery = ":win32_service"
Set objWMIService = GetObject("winmgmts:\\" & strComputer & _
wmiNS & wmiQuery)
WScript.Echo wmiQuery & vbTab & " has " & _
objWMIService.Properties_.count & " Properties"
For Each objItem in objWMIService.Properties_
WScript.Echo "Property: " & objItem.name
Next
Detailing service information
1. | Open the \My Documents\Microsoft Press\VBScriptSBS\Templates\wmiTemplate.vbs script in Notepad or your favorite script editor. Save the file as YourName ServiceInfo.vbs.
| 2. | Add the word service to the end of the wmiQuery line, making sure there is no space between the underscore and the word service. This will be the WMI class we will query. The completed line looks like the following:
wmiQuery = "Select * from win32_Service"
| 3. | We are going to report on only two properties: Name and Started. Delete all but two of the WScript.Echo commands. On the two remaining echo commands, add the properties Name and Started after the echo. This section of code now looks like the following:
WScript.Echo ": " & objItem.Name
WScript.Echo ": " & objItem.Started
| 4. | Save and run your script. The output is not very user friendly, as seen in the snipped output below:
: Alerter
: False
: ALG
: True
: AppMgmt
: False
: aspnet_state
: False
| 5. | To improve readability, add the words Name and Started in front of the colons, as seen below:
WScript.Echo "Name: " & objItem.Name
WScript.Echo "Started: " & objItem.Started
| 6. | Save and run your script. The output is better but still hard to read, as seen in the snipped output below:
Name: Alerter
Started: False
Name: ALG
Started: True
Name: AppMgmt
Started: False
Name: aspnet_state
Started: False
| 7. | There are two choices for improving the output. The first is to space over the second line, as seen below:
For Each objItem in colItems
WScript.Echo "Name: " & objItem.Name
WScript.Echo Space(6) & "Started: " & objItem.Started
Next
The second choice is to put the output on the same line:
For Each objItem in colItems
WScript.Echo "Name: " & objItem.Name, _
"Started: " & objItem.Started
Next
| 8. | Choose a method for improving the script output. Save and run the script. If there are problems with the output, compare your script with \My Documents\Microsoft Press\VBScriptSBS\ch08\ServiceINFO.vbs.
|
Working with WMI Methods
As you've learned in earlier chapters, a method answers the question "What does this thing do?" In many cases, the answer is "Well, it does nothing." However, the good thing about WMI is that it's constantly evolvingand in Windows Server 2003, more methods have been added than ever before. Like a property, a method also has a name and a domain. And just like a property, the method's domain refers back to the owning class. To determine if a class has any methods, you can use the ListClassMethods.vbs script. When run in CScript, the ListClassMethods.vbs script produces the following output:
:win32_service has 10 Methods
Method: StartService
Method: StopService
Method: PauseService
Method: ResumeService
Method: InterrogateService
Method: UserControlService
Method: Create
Method: Change
Method: ChangeStartMode
Method: Delete
The 10 methods from the WIN32_Service class can solve a number of problems for the network administrator. Suppose you want to stop the alerter service on all the computers on the network, then you could use the StopService method. If you need to change a service account password, then you use the Change method.
ListClassMethods.vbs
Option Explicit
'On Error Resume Next
dim strComputer 'name of target computer
dim wmiNS 'WMI namespace that contains class
dim wmiQuery 'simply the name of the class
dim objWMIService 'connection to WMI Namespace AND Class
dim objItem 'item in the collection of properties
strComputer = "."
wmiNS = "\root\cimv2"
wmiQuery = ":win32_Service"
Set objWMIService = GetObject("winmgmts:\\" & strComputer & _
wmiNS & wmiQuery)
WScript.Echo wmiQuery & vbTab & " has " & _
objWMIService.Methods_.count & " Methods"
For Each objItem in objWMIService.Methods_
WScript.Echo "Method: " & objItem.name
Next
Note  | Just because a class has a method does not guarantee that the method is implemented. You must verify that the implemented qualifier is attached to the method to ensure the method actually works. This is because methods could be inherited from a parent class and then not implemented in the child class. As an example, WIN32_Processor has a SetPowerState method. You cannot use this method because it is not implemented. (The SetPowerState method is inheritted from CIM_LogicalDevice, which is an abstract class used to create other WMI classes.) You can do this by looking the method up in the Platform SDK. It will simply say "implemented." Looking up the method is the only way you can ensure that the implementation of the method you wish to use is actually available for the class. I will admit that I have actually wasted several hours trying to make a particular method work, only to find out it was not even implemented. |
 |