Windows Management Instrumentation (WMI)

Windows management instrumentation(WMI) provides us with a way to access management information of the computers. WMI is of great use to the system administrators who want to automate administrative tasks by writing scripts or applications. Programming in WMI can be done in power shell, c++ applications or .net apps. Detailed info is available here : http://msdn.microsoft.com/enus/library/windows/desktop/aa393964(v=vs.85).aspx

By management information we mean, WMI can retreive information like services on the computer, logical disk information, information specific to a computer and so on. In this article, we are going to write a windows forms application that helps us to retrieve a list of services on a remote computer and operate on them(start/stop).

Open Visual Studio 2008 and create a new windows forms application project. We need to add a reference to System.Management to work with WMI.

WMI1.gif

Also, we are going to use impersonation to get access to a remote computer. Add the following references

using System.Management;
using System.Security.Principal;

We are going to access a remote computer and for that we would need credentials to impersonate. So here is the form design that takes the remote server name and the credentials as input

WMI2.gif

The WMI fetches data in the form of a query. These queries are very similar to what we write to fetch data from a SQL database. Once we have provided the server name and credentials we will fetch the services on that remote computer on the Get Services button click.

private void btnGetServices_Click(object sender, EventArgs e)
{
    ConnectionOptions conn = new ConnectionOptions();
    conn.Impersonation = ImpersonationLevel.Impersonate;
    conn.Username = txtUsername.Text;
    conn.Password = txtPassword.Text;
    ManagementScope theScope = new ManagementScope("\\\\"+txtServerName.Text+"\\root\\cimv2", conn);    
    ManagementObjectSearcher servSearcher = new ManagementObjectSearcher(theScope, new ObjectQuery("SELECT * FROM Win32_Service"));

    foreach (ManagementObject servObj in servSearcher.Get())
    {
         lstServices.Items.Add(servObj["Caption"]);
    }
}

The ManagementObjectSearcher lets us specify the query from where we need to fetch the management data. Here, as we are working with windows services, we would be fetching data from Win32_Service. (SELECT * FROM Win32_Service)

ManagementObjectSearcher.Get()method returns us a collection of management objects. We iterate through the collection and add the service names to the listbox on the form . servObj["Caption"] : why "caption" ? this you will find out at the end of the article.

So now we are done with fetching the services that are running on a remote server.

WMI3.gif

Now, we will select a service from the listbox and display its state (Started/Stopped) in a label. We will pass the string of the selected index to the "fetchServiceObject" method which will return us the management object of that particular service. With the help of that management object we can get the status of the service.

Selected Index Change Method :

private void lstServices_SelectedIndexChanged(object sender, EventArgs e)
{
    ManagementObjectCollection serviceobjs = fetchServiceObject(lstServices.SelectedItem.ToString());
    foreach (ManagementObject service in serviceobjs)
    {
        
if (service["started"].Equals(true))
        {
            lblServState.Text = "Started";
        }
        else
        {
            lblServState.Text = "Stopped";
        }
    }
}
public ManagementObjectCollection fetchServiceObject(string service)
{
    ConnectionOptions conn = new ConnectionOptions();
    conn.Impersonation = ImpersonationLevel.Impersonate;
    conn.Username = txtUsername.Text;
    conn.Password = txtPassword.Text;
    ManagementScope theScope = new ManagementScope("\\\\" + txtServerName.Text + "\\root\\cimv2", conn);
    ManagementObjectSearcher serviceSearcher = new ManagementObjectSearcher(theScope, new ObjectQuery("SELECT * FROM Win32_Service where Caption='" + service + "'"));

    return serviceSearcher.Get();     // Returns the service where caption == listbox  selected item     
}

As already discussed, the Get() method will return the collection of management objects so the return type of the method is ManagementObjectCollection.

WMI4.gif

We can also start and stop the service. Below is the code

Stop a service :

private void button1_Click(object sender, EventArgs e)
{
    ManagementObjectCollection serviceObjs = fetchServiceObject(lstServices.SelectedItem.ToString());
    foreach (ManagementObject service in serviceObjs)
    {
        if (service["Started"].Equals(true))
        {
            service.InvokeMethod("StopService", null);
        }
    }
}

Verify on the remote server and the service must have been stopped. This can be restared from the below code.

Start a service :

private void btnStartservice_Click(object sender, EventArgs e)
{
    ManagementObjectCollection serviceObjs = fetchServiceObject(lstServices.SelectedItem.ToString());
    foreach (ManagementObject service in serviceObjs)
    {
        if (service["Started"].Equals(false))
        {
            service.InvokeMethod("StartService", null);
        }
    }
}

We had used the ["Caption"] property to display the name of the service. Where did this come from? Here is the list of all the Win32 classes and the properties in each class. http://msdn.microsoft.com/en-us/library/windows/desktop/aa394084%28v=vs.85%29.aspx 

Similarly we can use the Win32_LogicalDisk to get the information related to the disks such as the names,total space, free space etc. This code works for the remote computers on the same domain. Sometimes you might face access issues because of the firewall. Details of the troubleshooting can be found here http://msdn.microsoft.com/en-us/library/windows/desktop/aa394603(v=vs.85).aspx

Cheers !