Click here to Skip to main content
15,860,861 members
Articles / Programming Languages / C#
Article

Extend ServiceController class to change the StartupType of Windows Services

Rate me:
Please Sign up or sign in to vote.
4.53/5 (22 votes)
7 Jul 20045 min read 121.9K   2.8K   41   20
How to control the windows service's StartupType and extend the functionality of the ServiceController class

Image 1

Introduction

In this article we will extend the functionality of the ServiceController class to control any windows service’s StartupType. In addition to obtaining more information about the service such as service Description. I'll use the WMI classes in Net Framework included in System.Management namespace.

Background

The Net Framework gave us a flexible advanced framework to do a lot of tasks that we needed to implement. One of these features included in the System.ServiceProcess namespace. This namespace contains classes that allow us to implement, control and install windows services. For more information refer to System.ServiceProcess Namespace in MSDN

Note: Windows Service is a long running executable that run without user interface (for example the application that receive string messages from other machine and display it as message box to the user called Messenger Service)

One of these classes is the ServiceController class which enables us to query windows service for its state and control it. You can use code like the following to connect to the telnet service, query for its status and if it's stopped, run it.

C#
ServiceController sc = new ServiceController("Telnet");
if (sc.Status.Equals(ServiceControllerStatus.Stopped))
{
sc.Start();
}
else
{
sc.Stop();
}
Note: To run the previous code, you should add a reference to System.ServiceProcess.dll and add the using keyword in the file that contains this snippet.

You can also search for the all Win32 services installed in the machine by using the ManagementObjectSearcher as following
C#
ManagementObjectSearcher objSearcher =
  new ManagementObjectSearcher("Select * from Win32_Service");
foreach(ManagementObject service in objSearcher.Get())
{
this.listBox1.Items.Add(service["name"]);
}

But I noticed that the ServiceController class missed two things:

  • Get the description of the service
  • Get or set the StartupType of the service (which is very important if you planning to use service that's may be disabled)
I faced this problem with the Messenger service which is disabled by default in Windows Server 2003 and windows XP SP2. And I found the solution for this situation in the WMI.

Windows Management Instrumentation (WMI)

WMI is the Microsoft implementation of the Web Based Enterprise Management (WBEM) which is an industry initiative to develop a standard technology for accessing management information in an enterprise environment. For more information see Windows Management Instrumentation in the MSDN.

.NET framework implements these components in the System.Management namespace (see System.Management namespace in MSDN).

WMI architecture

We can think of WMI architecture as the Hardware drivers. In WMI there are mainly three components

Managed ObjectsLike the Hardware device (i.e. sound card)
ProvidersLike the device driver that shipped with the hardware device
WMI infrastructureWindows service that mange the interaction between Managed Objects, Providers and Applications.
And there’s also the WMI management application which act as consumer to the providers (like what we will do now)


And the WMI service has a lot of Managed Objects and Providers shipped with it and one of these Managed Objects is the Win32_Service Managed Object which gives you the ability to monitor and control any Win32 Service.

Note: Please don’t mix with the WMI Managed Object and the Managed code. Managed Objects means the objects that con be managed by the WMI service

Using the code

What we want to do is to merge the features of the serviceController class with the System.Management namespace to produce ServiceControllerEx class which will take all the properties and methods of the ServiceController class beside two properties

  • Description {get}
  • StartupType {get/set}

The first step is to add references to the System.ServiceProcess and System.Management namespaces then use the appropriate using statement.

C#
using System;
using System.ServiceProcess;
using System.Management;

Inheritance and Constructors

Inherit the ServiceControllerEx class from the Microsoft's ServiceController class

C#
public class ServiceControllerEx:ServiceController
And because the inheritance doesn't inherit the class's constructors, we should do it ourselves
C#
public ServiceControllerEx():base()
{ }
public ServiceControllerEx(string name):base(name)
{ }
public ServiceControllerEx(string name,string machineName):base(name,machineName)
{ }
In the previous code we just initiate the base class's constructors and we didn't add any custom implementation.

Description property

Now come to the important part. Let's add the description property (note that it's Read only)
C#
public string Description
{
get
{
//construct the management path
string path="Win32_Service.Name='"+this.ServiceName+"'";
ManagementPath p=new ManagementPath(path);
//construct the management object
ManagementObject ManagementObj=new ManagementObject(p);
if(ManagementObj["Description"]!=null)
{
return ManagementObj["Description"].ToString();
}
else
{
return null;
}
}
}
We used the ManagementObject class which represents a WMI Management Object (see WMI architecture). But to use it we should pass the path of the object to the constructor. The path of service like Messenger service should be like this Win32_Service.Name='Messenger'. This path says that we need a Win32_Service where its name is Messenger

Because the ManagementObject class is not specific to the Windows services (we can use it to monitor the computer system hardware or even running processes) So there isn't a predefined properties regarding the Windows services but we use properties in the format of ManagementObject["property name"] So to get the Description of the service use the line
C#
return ManagementObj["Description"].ToString();

We used ToString() as this property returns object data Type. (For more information about the Win32_Service class and its properties and method please refer to WMI documentation)

Implementing StartupType property (get accessor)

C#
public string StartupType
{
get
{
if(this.ServiceName != null)
{
 //construct the management path
 string path="Win32_Service.Name='"+this.ServiceName+"'";
 ManagementPath p=new ManagementPath(path);
 //construct the management object
 ManagementObject ManagementObj=new ManagementObject(p);
 return ManagementObj["StartMode"].ToString();
}
else
{
return null;
}
}
In this peace of code we can use the same concept of the properties of the Win32_Service class.

StartupType property (set accessor)


For the set accessor the situation is different now because we will not query the management Object but we will change its state. See the following
C#
set
{
if(value!="Automatic" && value!="Manual" && value!="Disabled")
throw new Exception("The valid values are Automatic, Manual or Disabled");

if(this.ServiceName!=null)
{
//construct the management path
string path="Win32_Service.Name='"+this.ServiceName+"'";
ManagementPath p=new ManagementPath(path);
//construct the management object
ManagementObject ManagementObj=new ManagementObject(p);
//we will use the invokeMethod method of the ManagementObject class
object[] parameters=new object[1];
parameters[0]=value;
ManagementObj.InvokeMethod("ChangeStartMode",parameters); 
}
}
To change the StartupType of the Win32_Service WMI class (or managed object) we will use the changeStartupMode of the win32_Service WMI object. To accomplish this we are using the System.Management.ManagementObject class and as we agreed we will not find a method called ChangeStartupMode but instead we will use the generic method called InvokeMethod which takes the method name of the WMI object (ChangeStartupMode) and any parameters that will be passed.
C#
object[] parameters=new object[1];
parameters[0]=value;
ManagementObj.InvokeMethod("ChangeStartMode",parameters); 

That's all. In few simple steps we managed to extend the functionality of the ServiceController class to be more useful for us. I attached the source code and executable which contains the new class and a sample windows application as a client. Please send me your feedback or enhancements.

Points of Interest

  • I've checked in Framework v2.0 (Shipped with Visual Studio 2005 beta1) and I didn't find any changes in the behavior of the ServiceController class.
  • The StartupType property takes the strings Automatic, Manual or Disabled. And return back Auto, Manual or Disabled so keep in mind to fine tune the property to unify the input and output.
  • The testing application uses the ServiceController class to get the list of all services and add it to listBox then uses the modified ServiceConrollerEx to get and set the service's properties.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Ireland Ireland
Expert in Microsoft technologies.
MCP+Site Building, MCSD, MCAD, and MCSD.NET (Early achiever)
Worked as Web developer, Trainer and software developer
Currently working as Developer support engineer.
You can contact me also through my blog http://blogs.msdn.com/mohamed_sharafs_blog/

Comments and Discussions

 
QuestionDo we have to run application which include this extension of ServiceController as administrator in order to change the service StartupType? Pin
JJChen4023-Apr-21 9:39
JJChen4023-Apr-21 9:39 
GeneralMy vote of 5 Pin
Member 110219883-Sep-14 10:22
Member 110219883-Sep-14 10:22 
GeneralThanks Pin
jovan kates31-Aug-13 2:24
jovan kates31-Aug-13 2:24 
QuestionGreat Solution Pin
Georgi Karadjov23-Jan-13 22:53
Georgi Karadjov23-Jan-13 22:53 
QuestionThanks Mohamed for this great article, but I have a question Pin
s5g56h7h722-Aug-10 5:05
s5g56h7h722-Aug-10 5:05 
AnswerRe: Thanks Mohamed for this great article, but I have a question Pin
Carl P Daniel26-May-11 11:02
Carl P Daniel26-May-11 11:02 
GeneralRe: Thanks Mohamed for this great article, but I have a question Pin
Mohamed Sharaf27-May-11 5:00
Mohamed Sharaf27-May-11 5:00 
GeneralFantastic. Great article. Pin
Ben Dennis8-Jun-10 14:34
Ben Dennis8-Jun-10 14:34 
GeneralRe: Fantastic. Great article. Pin
Mohamed Sharaf8-Jun-10 14:53
Mohamed Sharaf8-Jun-10 14:53 
GeneralGreat article Pin
Tamal Saha16-Jul-09 6:58
Tamal Saha16-Jul-09 6:58 
GeneralQuestion Pin
PIEBALDconsult2-Feb-09 16:11
mvePIEBALDconsult2-Feb-09 16:11 
Questionmanager["StartMode"] returns "Unknown",why? Pin
RodionMrt23-May-08 8:02
RodionMrt23-May-08 8:02 
GeneralThanks for this article Pin
DarthVona23-Apr-08 6:33
DarthVona23-Apr-08 6:33 
GeneralRemote Service Controlling Pin
jeremykamper21-Jul-06 7:29
jeremykamper21-Jul-06 7:29 
GeneralRe: Remote Service Controlling Pin
Russell Thomas28-Oct-14 2:47
Russell Thomas28-Oct-14 2:47 
QuestionHow to get the name of the *.exe Pin
stefanpetri2-Aug-04 23:18
stefanpetri2-Aug-04 23:18 
AnswerRe: How to get the name of the *.exe Pin
Mohamed Sharaf3-Aug-04 0:10
Mohamed Sharaf3-Aug-04 0:10 
AnswerRe: How to get the name of the *.exe Pin
stefanpetri3-Aug-04 1:03
stefanpetri3-Aug-04 1:03 
GeneralBetter StartMode PinPopular
termi14-Jul-04 4:09
termi14-Jul-04 4:09 
First of all: great article, it was just what I needed, thanks.

But I was thinking: Why set the startmode by means of a string when .NET has an enum built in that describes every mode?

This is the resulting code:

/// <summary>
/// Gets or sets the start mode.
/// </summary>
public ServiceStartMode StartMode {
get {
ManagementPath path = new ManagementPath("Win32_Service.Name='"+this.ServiceName+"'");
ManagementObject manager = new ManagementObject(path);

string mode = manager["StartMode"].ToString();
switch(mode) {
case "Auto":
return ServiceStartMode.Automatic;
case "Manual":
return ServiceStartMode.Manual;
default:
case "Disabled":
return ServiceStartMode.Disabled;
}
}
set {
ManagementPath path = new ManagementPath("Win32_Service.Name='"+this.ServiceName+"'");
ManagementObject manager = new ManagementObject(path);

manager.InvokeMethod("ChangeStartMode", new object[] {value.ToString()});
}
}
GeneralRe: Better StartMode Pin
Mohamed Sharaf14-Jul-04 7:59
Mohamed Sharaf14-Jul-04 7:59 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.