WMI Programming with Visual Basic.NET: Managing the OS, continued
In my previous article, part three of this series, we looked at some examples of accessing OS and hardware related information through WMI and VB.NET. In this article, we will look into managing the OS using WMI methods.
You can download the zip of the entire Visual Studio.NET solution (developed for this article) here.
The first part of my series gives you the details for creating a Visual Studio.NET solution for WMI, right from scratch. It will not be repeated anymore in any of the future articles in this series.
Can we operate (or manage) using WMI classes?
In all of the previous parts of this series, I mostly concentrated on retrieving information (locally or remotely). We didn’t operate (or manage) that information. We just fetched and displayed the information on the form.
Certain classes of WMI provide some methods for operating on WMI objects. I should admit that we will not be able to do each and every operation that WIN32 API does. But, mostly we can serve our needs just by using WMI (instead of complicating ourselves with WIN32 API).
Since we now understand that we can manage the Windows operating system using some WMI objects, we need to know a bit of theory about its implementation. All of my examples (in previous parts of this series) until now were working only with certain properties of the respective WMI class. But, some of the WMI classes were already designed with certain methods to operate on the respective objects. To invoke those methods programmatically, the class “ManagementObject” exposes a method called “InvokeMethod.” Using this method, we can call any method of any WMI class (which has methods to execute) programmatically.
Whenever a method gets executed dynamically (programmatically), we should certainly check (in general) for its result (whether executed successfully or not). When any WMI methods gets executed through “InvokeMethod”, it returns an object of type “ManagementBaseObject”, which contains all of the parameters sent out (in this case return values or returned properties). We can know the status of the WMI method execution through this object easily by fetching its properties (or return values).
I don’t want to discourage you with only theory. The following sections will show you the practical implementation of the theory stated above.
As I wanted to implement the theory stated in the previous section, I am considering an example for controlling the list of services through WMI. So, before going into “real” controlling of services, first of all, we need to display the list of services to the user so that he can select a service and control it. The following code fragment fetches all the services of OS and adds them to the list box.
Me.lstServices.Items.Clear()
DimsearcherAsNewManagementObjectSearcher("SELECT * FROM Win32_service ")
I don’t want to get into the details of the above fragment, as the same was very clearly explained in my previous part of this series (part three). But, make sure that we are trying to fetch all the services from the WMI class “Win32_Service”.
When you execute the above code, you should be able to see all the list services populated into the list box as follows (Fig 1):
Every service generally starts when the OS starts and stops automatically when the OS shuts down (unless the respective service is configured differently). But we can also pause, resume or stop the service manually (based on the user's credentials and type of service). Now the question is, how can you know the state of a service, whether running or stopped or paused or resumed or what?
There exists a property called “state” within the “Win32_Service” class. This holds the current state of the service object selected. The following code fragment show you how to fetch that property:
The first two lines will actually clear the previous message. If you carefully observe the above program, you'll see that I used the SELECT statement of WQL (explained in part two of my series) along with a WHERE clause based on the service name selected within the listbox. So, it is confirmed that we will get only one object of “Win32_service” (unless more services exist with the same name).
Since there exists only one service with that name (assumed), I created an array with only one element (zero yields to single location) and copying the service object to the array (only one gets copied). After that, I assign that array element to “oItem” of type “ManagementObject”, where we can get the state of the service. Consider my apologies, as I could not find a better solution than this method of retrieving a single object from “ManagementObjectCollection”. I would be very glad if anyone could investigate and give me a better solution.
And finally I am assigning the current status of “state” to the label. The following figure (Fig 2) shows you the status of “Indexing Service” (at the bottom of the window) selected within the listbox (on my system).
This section actually manipulates (manages) the state of the service selected from the listbox. The “Win32_service” class mainly has the following methods to change the state of the service:
StartService
StopService
PauseService
ResumeService
Of course, there exist a few more too, but we shall concentrate on only the first two methods. The implementations of the last two methods are very similar to those of the first two methods. Recalling from the first section, we need to work with “InvokeMethod” of the class “ManagementObject” and receive the results in the form of an object of type “ManagementBaseObject” class. The following is the code fragment which tries to “stop” the service selected from the listbox:
MessageBox.Show("Could not Stop, Returned code:" & obj.ToString)
EndIf
The above fragment stops the service. To start the service, just replace “StopService” in the above program with “StartService” and modify the messages being displayed using “MessageBox.Show” statements. You could see a message box showing “Succesfully stopped” as shown in the following figure (Fig 3).
The next section gives a detailed explanation about the previous code fragment.
I already explained (in previous sections) up until the initialization of object ‘oItem’ with ‘ar(0)’. Proceeding further, we have a comment ‘Execute the method’. From that comment we are actually working with the service to change its state. Let me explain each statement separately.
The above statement calls the method ‘StopService’ which exists in the ‘Win32_Service’ class of WMI (through ‘InvokeMethod’ routine) and returns the result into ‘outParams’ of type ‘ManagementBaseObject’. The first ‘Nothing’ informs that there exist no input parameters to the method ‘StopService’. The second ‘Nothing’ states that no other options (like time to execute, etc.) are necessary to execute it and considers all the defaults.
DimobjAsObject= outParams("ReturnValue")
The above statement retrieves the ‘ReturnValue’ of the operation. A zero results in success. A non zero results in failure.
Ifobj.ToString = "0"Then
MessageBox.Show("Succesfully stopped..")
lstServices_SelectedIndexChanged(Nothing,Nothing)
Else
MessageBox.Show("Could not Stop, Returned code:" & obj.ToString)
EndIf
This is very straightforward. It just displays the proper message based on the return value and finally updates the status using the following statement:
lstServices_SelectedIndexChanged(Nothing,Nothing)
The above statement gets the code fragment explained in the second section of this article, which actually fetches the latest status of the selected service.
In the previous program, when we “stop” the service, if it is successfully stopped, we receive zero as the returned value. I stated that a non-zero value gets returned if unsuccessful. Using this value, we can figure out why it failed to “stop” (or “start” as well). The following table gives the list of return values and descriptions for both methods “StopService” and “StartService”.
Return code
Description
0
Success
1
Not Supported
2
Access Denied
3
Dependent Services Running
4
Invalid Service Control
5
Service Cannot Accept Control
6
Service Not Active
7
Service Request Timeout
8
Unknown Failure
9
Path Not Found
10
Service Already Running
11
Service Database Locked
12
Service Dependency Deleted
13
Service Dependency Failure
14
Service Disabled
15
Service Logon Failure
16
Service Marked For Deletion
17
Service No Thread
18
Status Circular Dependency
19
Status Duplicate Name
20
Status Invalid Name
21
Status Invalid Parameter
22
Status Invalid Service Account
23
Status Service Exists
24
Service Already Paused
By using the “Select..Case” statement with the return code, we can display properly using the definitions from the above table. Even though I copied the above table from WMI SDK documentation, I thought it was worthwhile to include the table as part of this article to provide you with complete information.