Kirk Evans Blog

.NET From a Markup Perspective

Control Your Windows Services with System.ServiceProcess.ServiceController

@kaevans

Control Your Windows Services with System.ServiceProcess.ServiceController

  • Comments 1

I was trying to do some work in a VirualPC image today, and each time I tried to load the VPC image, I got a "there is not enough memory" message.  This happens on a pretty frequent basis.  Instead of lowering the memory required for the VPC, I wanted to stop any services that are running and consuming memory. 

It would have been nice to enumerate through the processes and stop them all:

foreach(ServiceController sc1 in ServiceController.GetServices())
{
 if(sc1.CanStop && sc1.Status == ServiceControllerStatus.Running)
 {
  sc1.Stop();
 }
}

However, that would be a bad thing as there are many services running that I need.  Instead, I decided to use a configuration file to hold the specific names of the services that I wanted to stop.  But wait... when I close the VPC image, I will likely need those services again...

The result utility is here, I threw it together pretty quickly.  I am using recursion to make sure all the services we depend on are started when we want to start, and all of the services that depend on us are stopped before we stop.

using System;
using System.ServiceProcess;
using System.Configuration;
using System.Collections.Specialized;

namespace ServiceControl
{
 class ServiceUtil
 {
  [STAThread]
  static void Main(string[] args)
  {
   //Get the keys from the section in the config file.   
   NameValueCollection nv = (NameValueCollection)ConfigurationSettings.GetConfig("ServiceStopper");
   foreach(string key in nv.AllKeys)
   {
    //Each key name is the name of the service in SCM
    ServiceProcessor s = new ServiceProcessor(key);
    if(args[0].ToUpper() == "START")
     s.Process(ServiceProcessor.ServiceControlCommand.Start);
    else
     s.Process(ServiceProcessor.ServiceControlCommand.Stop);
   }
  }
 }

 internal class ServiceProcessor
 {
  #region nested types
  public enum ServiceControlCommand
  {
   Start,
   Stop
  }
  #endregion

  private string _serviceName;  
 
  #region ctors
  public ServiceProcessor(string serviceName)
  {
   _serviceName = serviceName;   
  }
  #endregion

  #region methods
  public void Process(ServiceControlCommand cmd)
  {
   ServiceController sc = new ServiceController(_serviceName);   
   ProcessServiceController(sc,cmd, 1);   
  }

  private void ProcessServiceController(ServiceController sc, ServiceControlCommand cmd, int indent)
  {       
   if(cmd == ServiceControlCommand.Start)
   {
    //Start all the services we depend on
    foreach(ServiceController child in sc.ServicesDependedOn)
    {
     ProcessServiceController(child, cmd, indent + 1);
    }    
   }
   else
   {
    //Process all the services that depend on us
    foreach(ServiceController child in sc.DependentServices)
    {
     ProcessServiceController(child, cmd, indent + 1);
    }
   }
           
   string pad = new string(' ',indent);
   Console.Write(pad);
   Console.Write(sc.ServiceName + ": ");

   //Process the current service
   if(cmd == ServiceControlCommand.Start )
   {
    StartService(sc);
   }
   else
   {
    StopService(sc);
   }
  }
        
  private void StopService(ServiceController sc)
  {
   //If it is running and we can stop it...
   if (sc.CanStop && sc.Status == ServiceControllerStatus.Running)
   {    
    Console.Write("Stopping... ");    
    try
    {
     sc.Stop();
     //Wait until status is Stopped, or time out after
     //10 seconds have elapsed
     TimeSpan t = new TimeSpan(0,0,0,20);
     sc.WaitForStatus(ServiceControllerStatus.Stopped,t);     
    }
    catch  (Exception oops)
    {
     Console.WriteLine(   oops.Message );
    }
   }
   Console.WriteLine(sc.Status);
  }

  private void StartService(ServiceController sc)
  {
   //We only want to start those services that are stopped
   if (sc.Status == ServiceControllerStatus.Stopped )
   {    
    Console.Write("Starting... ");    
    try
    {
     sc.Start();
     //Wait until status is Running, or time out after
     //10 seconds have elapsed
     TimeSpan t = new TimeSpan(0,0,0,20);
     sc.WaitForStatus(ServiceControllerStatus.Running ,t);     
    }
    catch  (Exception oops)
    {
     Console.Write(sc.Status + ":   ");
     Console.Write(   oops.Message);
    }
   }  
   Console.WriteLine(sc.Status);
  }
  #endregion
 }
}

The configuration file for the console application:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <configSections>
  <section name="ServiceStopper" type="System.Configuration.NameValueSectionHandler"/>
 </configSections>
 <ServiceStopper>
  <add key="MSMQ" value="Microsoft Message Queueing" />
  <add key="SMTPSVC" value="SMTP Service" />
  <add key="W3SVC" value="World Wide Web Publishing Service" />
  <add key="Irmon" value="Infrared Monitor" />
  <add key="IISADMIN" value="IIS Admin" />
  <add key="helpsvc" value="Help and Support" />
  <add key="ERsvc" value="Error Reporting Service" />  
 </ServiceStopper>
</configuration>

  • I was at a customer the other day, presenting on .NET 3.0, and the desktop background image on my computer...
Page 1 of 1 (1 items)
Leave a Comment
  • Please add 5 and 8 and type the answer here:
  • Post
Translate This Page
Search
Archive
Archives