Scheduled tasks and restarting services

I recently had the ‘pleasure’ to have some of my maintenance scripts that restart some ‘Windows Services‘ stopped working since ‘other’ people installed stuff that creates new dependencies. The problem is that the normal commands like ‘net stop’ or ‘sc start’ are not aware of dependent services and simply fail to perform their task if the dependent service is still running. Additionally, the built in task engine for Windows does not really have much in the line of useful logging and error reporting. Most of the time you have to ‘guess’ what went wrong 😉

.Net to the rescue

Fortunately I knew from past experience that the .Net framework’s ServiceController class has the Stop and Start methods that do take into account the dependencies and also try to stop or start them as needed. So all you need is to create what is essentially a wrapper class to call these methods. Additionally you have full access to errors and can log them in any way you like. As a side bonus it might be useful to have this tool also handle batches of requests since you usually want to stop and start a bunch of related services at the same time.

To keep things simple the tool simple accepts one parameter that – a file name for the file that contain a list of the action ‘service name’s. e.g.

stop .\Winmgmt
start .\Winmgmt

Then it is a simple matter of reading the file line for line using File.ReadAllLines() method and using the first part of the line to see if the service must be stopped or started. I like things that are simple and ‘just works’.

The code also makes provision that it can stop/start services on other machines – provided the account it runs under has the right privileges. The rest of the code are there just for error handling and logging.

The code

static void Main(string[] args)
{

…initial stuff

string[] lines = File.ReadAllLines(args[0]);
foreach (string line in lines)
{

ProcessLine(line);
System.Threading.Thread.Sleep(new TimeSpan(0,0, waitBetweenServiceChangeSec));

}

}

private static void ProcessLine(string line)
{

string action = “”;
string machineName = “.”;
string serviceName = “”;
if (line.Split(‘ ‘).Length > 1) //make sure there is an ‘action’ and service name
{

action = line.Split(‘ ‘)[0].Trim().ToLower();
serviceName = line.Substring(line.IndexOf(‘ ‘)).Trim();
if (serviceName.IndexOf(‘\\’) > -1)
{

machineName = serviceName.Substring(0, serviceName.IndexOf(‘\\’));
serviceName = serviceName.Substring(serviceName.IndexOf(‘\\’) + 1);

}

if (action == “start”)

StartService(serviceName, machineName);

else if (action == “stop”)

StopService(serviceName, machineName);

}

}

private static void StopService(string serviceName, string machineName)
{

ServiceController sc;
ServiceControllerStatus resultingStatus = ServiceControllerStatus.Stopped;
try
{

LogProgress(string.Format(“Stopping the service {0}\\{1}”, machineName, serviceName), EventLogEntryType.Information, 2);
if (machineName == “.”)

sc = new ServiceController(serviceName);

else

sc = new ServiceController(serviceName, machineName);

if (sc.CanStop && sc.Status != ServiceControllerStatus.Stopped)
{

sc.Stop();
sc.WaitForStatus(resultingStatus, new TimeSpan(0, 0, waitTimeSec));
sc.Refresh();
if (sc.Status != resultingStatus)
{

LogProgress(string.Format(“The service {0}\\{1} did not stop properly in the time allowed!”, machineName, serviceName), EventLogEntryType.Warning, 2);

}
#if DEBUG
LogProgress(string.Format(“The service {0}\\{1} stopped sucessfully”, machineName, serviceName), EventLogEntryType.Information, 2);
#endif

}

}
catch (Exception ex)
{

LogProgress(string.Format(“Error stopping service {0}\\{1}: {2}”, machineName, serviceName, ex.Message), EventLogEntryType.Error, 2);

}

}

private static void LogProgress(string message, EventLogEntryType elet, int eventId)
{

Console.WriteLine(message);
EventLog.WriteEntry(eventLogSource, message, elet, eventId);

}

I’m not showing the StartService method as it is basically the same as the StopService method (with one or two extra ‘if’s).

Alternatives

I considered powershell (for 0.834 seconds like Data would have said) but it is only really useful if you run them manually since you have to ‘sign’ them and jump through a million hoops to get it working in a scheduled ‘hands-off’ way. Yes I know this was done to make it more ‘secure’ and avoid malicious stuff but it also makes it useless to solve a simple problem. With the amount of trouble you have to go through to get it working you might as well create a proper app like I did here to solve the issue.

Find a copy here.

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>