26.3 Getting Started with WMI Scripting
Once you have a basic understanding of the WMI architecture,
scripting with WMI is easy. In fact, once you understand how to
reference, enumerate and query objects of a particular class with
WMI, it is straightforward to adapt the code to work with any managed
component.
26.3.1 Referencing an Object
To reference objects in WMI, you use a
UNC-style path name. An example of how to reference the C: drive on a
computer looks like the following:
\\dc1\root\CIMv2:Win32_LogicalDisk.DeviceID="C:"
The format should be easy to follow. The first part of the path
(\\dc1\) is a reference to the computer on which
the object resides. To reference the computer on which the script is
running, you can use a "." for the
computer name. The second part (root\CIMv2) is the
namespace the object resides in. The third part
(Win32_LogicalDisk) is the class of the object to
reference. The fourth part is the key/value pairs representing the
object. Generically, the path can be shown as follows:
\\ComputerName\NameSpace:ClassName.KeyName="KeyValue"[,KeyName2="KeyValue2"...]
Now that we know how to reference WMI objects, let's
go ahead and instantiate an object using VBScript's
GetObject function. For
GetObject to understand that we are referencing
WMI objects, we have to include one additional piece of information:
the moniker. Just as we've been using the LDAP: and
WinNT: progIDs to reference Active Directory and SAM-based objects in
ADSI, we need to use the winmgmts: moniker when we are dealing with
WMI objects:
Set objDisk = GetObject("winmgmts:\\dc1\root\CIMv2:Win32_LogicalDisk.DeviceID='C:'")
Note that if you want to reference the C: logical drive on the local computer, you
can leave off the computer name and namespace path. The
GetObject call would then look like this:
Set objDisk = GetObject("winmgmts:Win32_LogicalDisk.DeviceID='C:'")
|
You can leave out the namespace path because root\CIMv2 is the
default namespace. When accessing a provider that uses any other
namespace, you need to include the namespace path. Also, if you are
referencing a remote object, you need to include the namespace path
even if it is root\CIMv2.
|
|
26.3.2 Enumerating Objects of a Particular Class
Now let's look at an
example. We want to view all logical disks on a machine, not just a
particular disk. To do so, we need to use the
InstancesOf method on a WMI object pointing to the
namespace of the provider that contains the class. Perhaps an example
will make this clear:
strComputer = "."
Set objWMI = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objDisks = objWMI.InstancesOf("Win32_LogicalDisk")
for each objDisk in objDisks
Wscript.Echo "DeviceID: " & objDisk.DeviceID
Wscript.Echo "FileSystem: " & objDisk.FileSystem
Wscript.Echo "FreeSpace: " & objDisk.FreeSpace
Wscript.Echo "Name: " & objDisk.Name
Wscript.Echo "Size: " & objDisk.Size
WScript.Echo ""
next
Here we get a WMI object pointing to the root\CIMv2 namespace, after
which we call the InstancesOf method and pass the
Win32_LogicalDisk class. That method returns a
collection of Win32_LogicalDisk objects which we
then iterate over with a For Each loop.
As you can imagine, this is very powerful and allows you to easily
retrieve a list of all the logical disks, services, or processes on a
computer. The only issue with the last example is that we needed to
know which property methods of the
Win32_LogicalDisk class we wanted to see. We can
instead retrieve all properties of the
Win32_LogicalDisk class using the
Properties_ method on each object.
strComputer = "."
strWMIClass = "Win32_LogicalDisk"
Set objWMI = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objDisks = objWMI.InstancesOf(strWMIClass)
for each objDisk in objDisks
for each objProp in objDisk.Properties_
' Print out NULL if the property is blank
if IsNull(objProp.Value) then
Wscript.Echo " " & objProp.Name & " : NULL"
else
' If the value is an array, we need to iterate through each element
' of the array
if objProp.IsArray = TRUE then
For I = LBound(objProp.Value) to UBound(objProp.Value)
wscript.echo " " & objProp.Name & " : " & objProp.Value(I)
next
else
' If the property was not NULL or a an array, we will print it
wscript.echo " " & objProp.Name & " : " & objProp.Value
end if
end if
next
WScript.Echo ""
next
26.3.3 Searching with WQL
So far we've shown how to
instantiate specific objects, such as a logical drive, and also how
to enumerate all the objects of a particular class using the
InstancesOf method. Knowing how to do both of
these functions will take us a long way with WMI, but we are missing
one other important capability: the ability to find objects that meet
certain criteria.
The creators of WMI found an elegant way to handle this problem. They
implemented a subset of the Structured Query Language (SQL) known as
the WMI Query Language (WQL). WQL greatly increases the power of WMI
by giving the programmer ultimate control over locating objects.
With WQL, we can even perform the same function as the
InstancesOf method we used earlier. The following
query will retrieve all the Win32_LogicalDisk
objects on the system:
"select * from Win32_LogicalDisk"
We can use any property available on
Win32_LogicalDisk objects as criteria in our
search. As an example, let's say we wanted to find all NTFS logical
disks that have less than 100 MB of available space. The query would
look like the following:
select * from Win32_LogicalDisk
where FreeSpace < 104857600
and filesystem = 'NTFS'
Pretty easy, right? Now let's put WQL to use. We
first need to get a WMI object to the namespace we want to query.
After we've done that, we can call the
ExecQuery method on that object and pass the WQL
query to use. The next example uses the "less than
100 MB" query we just described to print out all
logical disks on the local computer that match that criterion:
strComputer = "."
Set objWMI = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objDisks = objWMI.ExecQuery _
("select * from Win32_LogicalDisk " & _
"where FreeSpace < 104857600 " & _
"and filesystem = 'NTFS' ")
For each objDisk in objDisks
Wscript.Echo "DeviceID: " & objDisk.DeviceID
Wscript.Echo "Description: " & objDisk.Description
Wscript.Echo "FileSystem: " & objDisk.FileSystem
Wscript.Echo "FreeSpace: " & objDisk.FreeSpace
Next
26.3.4 Authentication with WMI
So far, the examples we've shown
assume that the caller of the script has the necessary rights to
access the WMI information on the target machine. In most cases in
which you are trying to automate a task, that may not be the case.
Luckily, using alternate credentials in WMI is very straightforward.
Previously, to connect to a WMI namespace, we would have used the
following:
strComputer = "dc1"
Set objWMI = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
But let's say that the person calling the script
does not have any privileges on the dc1 computer. We must now use the following:
strComputer = "dc1.mycorp.com"
strUserName = "administrator"
strPassword = "password"
Set objLocator = CreateObject("WbemScripting.SWbemLocator")
Set objWMI = objLocator.ConnectServer(strComputer, "root\cimv2", _
strUserName, strPassword)
We've replaced the single call to
GetObject with a call to
CreateObject to instantiate a
WbemScripting.SWbemLocator object. The
SWbemLocator object has a method called
ConnectServer, which allows us to specify the
target machine, username, and password to authenticate with. You can
then use the object returned from ConnectServer to
get the instances of a class, perform a WQL search, or any other
function.
This was quick introduction to WMI scripting. We will be covering
additional tasks, such as invoking an action or modifying properties
of an object, as we walk through specific examples later in the
chapter.
|