Saturday, April 17, 2004

Yesterday I delivered a talk at the Bangalore .Net User Group.

 

I gave a small introduction to the concept of the Windows Scripting Host and how the scripting host allows for multiple language interpreters to be plugged in and run via the same scripting interface. I also talked a little about the object model that is exposed to scripts under windows. Most of the time I was comparing this to the general notion of shell script in Unix, and how in the windows culture the need for small discrete utilities strung together by shell-script is replaced by having a language agnostic object model and API in windows scripting world.

 

The talk then went on to introduce WMI or Windows Management Instrumentation API. I went on to talk about how the API works, the class and namespace architecture and how to do reflecting in the WMI API. The sheer power of this API and how little understood and appreciated it is in Windows has always bothered me. Probably I will blog about WMI itself another day.

 

The talk finally wrapped by showing of some basic C# code that can use WMI. Since there were several queries about the samples and presentation I thought I will put them up here.

 

Here is the presentation for the talk.

Windows Scripting Host.ppt

 

Code snippets:

To run these on your machine, copy and  them and save them as the corresponding file names. The go to the command line and type:
cscript 

 

wshbasic.vbs

This displays all the running processes on your machine

 

set serv = GetObject("winmgmts://./root/cimv2")

set objs = serv.InstancesOf("Win32_Process")

for each obj in objs

      wscript.echo obj.name

next

 

 

wshprocess.vbs

This shows more information about each process by accessing some more properties of the process object

 

set serv = GetObject("winmgmts://./root/cimv2")

set objs = serv.InstancesOf("Win32_Process")

for each obj in objs

      wscript.echo obj.name &" "& obj.ProcessId &" "& _

            obj.ThreadCount &" "& obj.KernelModeTime

next

 

wshproperties.vbs

This shows how you can find out what all properties the process has. This is generally applicable to any class not just to Win32_Process

 

set obj = GetObject("winmgmts://./root/cimv2:Win32_Process")

wscript.echo "------------- Properties ----------------"

for each prop in obj.Properties_

      wscript.echo prop.name

next

 

wshmethods.vbs

And this shows you how you can access the methods of a object. You could easily put these two scripts together that will show you more or less complete information about an object.

 

set obj = GetObject("winmgmts://./root/cimv2:Win32_Process")

wscript.echo "------------- Methods ----------------"

for each prop in obj.Methods_

      wscript.echo prop.name

next

 

killprocess.vbs

This shows you how to call a method on a object. This example will close all the IE browser instances on your computer. The earlier script, wshmethods.vbs, would show you that a terminate() method existed for the Win32_Process class.

 

set serv = GetObject("winmgmts://./root/cimv2")

set objs = serv.InstancesOf("Win32_Process")

for each obj in objs

        if obj.name = "IEXPLORE.EXE" then

            obj.Terminate()

      end if

next

 

wqlkillprocess.vbs

This shows off the usage of WQL or the Windows Query Language in interacting with WMI. It does the same task as the above script.

 

set serv = GetObject("winmgmts://./root/cimv2")

set objs = serv.ExecQuery("select * from Win32_Process where name = 'IEXPLORE.EXE'")

for each obj in objs

      obj.terminate()

next

 

classes.vbs

This shows you how to know what other classes exist. Notice all the above examples used only the Win32_Process class. WMI provides hundreds of classes that you can use for various tasks. It is a fairly broad API. This shows you the classes that exist. You can then find out more about each class by examining its methods and properties using the scripts I have given earlier.

 

set serv = GetObject("winmgmts://./root/cimv2")

set results = serv.SubClassesOf()

for each result in results

      wscript.echo result.Path_

next

 

recclasses.vbs

In the WMI API, classes are organized into namespaces and the above script shows only the scripts available in the root/cimv2 namespace. This script will recursively traverse the namespace hierarchy and list all the classes available under each namespace. Neat ?

 

dispNS ""

 

sub dispCLS(ns)

      Set serv = GetObject("winmgmts:\\.\root\" & ns)

      Set classes = serv.SubclassesOf()

      For Each classobj In classes

            wscript.echo vbTab & classobj.Path_.Path

      Next

end sub

 

sub dispNS(ns)

      Set serv = GetObject("winmgmts:\\.\root" & ns)

      Set namespaces= serv.InstancesOf("__NAMESPACE")

      For Each namespace In namespaces

            wscript.echo "Classes in Namespace = " & ns & namespace.name

            dispCLS ns & namespace.name

      Next

end sub

 

That’s it with the script samples. Try running them, you might be surprised. You can look at MSDN for further documentation of the WMI classes, not all are documented. A couple more of tips:

 

If you want to connect to a another computer, not the local one, then change the GetObject() call in the above scripts to GetObject(“winmgmts:\\”). By specifying “.” the script will establish a connection to local computer.

 

To run a WMI script, the script needs to be run under admin privileges. Understandable considering the powerful things that these scripts can do. If you are not running as admin on your machine (which you shouldn’t be), you can use impersonation as shown in the code below.

 

I got this from:

http://www.activexperts.com/activmonitor/windowsmanagement/wmi/samples/wmiremote/

 

Sub ListShares( strComputer, strUser, strPassword )

    Dim strObject

    Dim objLocator, objWMIService, objShare

    Dim colShares

 

    Set objLocator = CreateObject( "WbemScripting.SWbemLocator" )

    Set objWMIService = objLocator.ConnectServer ( strComputer, "root/cimv2", strUser, strPassword )

    objWMIService.Security_.impersonationlevel = 3

    Set colShares = objWMIService.ExecQuery( "Select * from Win32_Share" )

        For Each objShare In colShares

            Wscript.Echo objShare.Name & " [" & objShare.Path & "]"

    Next

End Sub

 

Now finally the C# source, its easy to guess what this does:

 

using System.Management;

using System;

 

class CMain

{

        static void Main()

        {

                string qs = "select * from Win32_process";

                ObjectQuery q = new ObjectQuery(qs);

                ManagementObjectSearcher sr = new ManagementObjectSearcher(q);

                foreach(ManagementObject obj in sr.Get())

                {

                        Console.WriteLine(obj["Name"]);

                }

               

        }

}

 

I also have a do-all, end-all killer Perl script that does almost everything that you can think of with WMI. I will however make a post about that another day. I have an entry about this here

Comments are closed.