C# windows service to monitor another windows service...

We have a third party windows service that runs after installation and we need to monitor that service.  So in the grand scheme of things under high volumes of using the service of the vendor it stops.

The issue is that we do not know when it stops and the business has to tell us that this or that isn't working and we then have to find the failing service (many boxes with the same service) and manually start it.

Writing a C# .NET app to "monitor" this service is what we are seeking but have no great examples of this.  There are articles on how to keep alive the service that you built but not another service.

We are trying to "query" what is there and get it from that angle without much success.

Any suggestions?  I know this isn't a windows service code below but it was easier to try and debug/output etc.

using System;
using System.Management;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RestartProcess
{
    class processes
    {
        public static void Main()
        {
            ManagementEventWatcher startWatch = new ManagementEventWatcher(
              new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
            startWatch.EventArrived += new EventArrivedEventHandler(startWatch_EventArrived);
            startWatch.Start();
            ManagementEventWatcher stopWatch = new ManagementEventWatcher(
              new WqlEventQuery("SELECT * FROM Win32_ProcessStopTrace"));
            stopWatch.EventArrived += new EventArrivedEventHandler(stopWatch_EventArrived);
            stopWatch.Start();
            Console.WriteLine("Press any key to exit");
            while (!Console.KeyAvailable) System.Threading.Thread.Sleep(50);
            startWatch.Stop();
            stopWatch.Stop();
        }

        static void stopWatch_EventArrived(object sender, EventArrivedEventArgs e)
        {
            Console.WriteLine("Process stopped: {0}", e.NewEvent.Properties["ProcessName"].Value);
        }

        static void startWatch_EventArrived(object sender, EventArrivedEventArgs e)
        {
            Console.WriteLine("Process started: {0}", e.NewEvent.Properties["ProcessName"].Value);
        }
    }
}

Is there a way to tell it "here is the service" to monitor and if it is down - restart it?

Any help would be greatly appreciated.
LVL 1
cyimxtckAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

it_saigeDeveloperCommented:
There are a couple of ways to do this, however, before you get into the programming aspect of it, why not just utilize the Recovery options available from the Services snap-in?Capture.JPG-saige-
0
cyimxtckAuthor Commented:
We have it set this way actually but it doesn't restart the service all the time. The failure can cause the service to be down for minutes while it crashes.  When it crashes we need to have it come back up after x attempts.

It seems illogical I agree....we went down this road first before trying to develop an app as a windows service.

My contention is if we wait x minutes and try then repeat until it starts back up we will be good to go.  Give it a "lag" if you will.

So the idea is to have a file with the name of the service and wait time to try a restart to be successful.

Great thought though.
0
it_saigeDeveloperCommented:
That was my fear.  Just to paraphrase to ensure that I am understanding you.  You have a service that will no longer process requests.  Sometimes when this happens the service process stops but at other times it does not.

Does this describe the issue?  If it does, then you are correct, simply enabling the service recovery will not work (unless the executable itself actually quits, if this is the case then you will want to ensure that you have checked the option to 'Enable actions for stops with errors.'

-saige-
0
Creating Active Directory Users from a Text File

If your organization has a need to mass-create AD user accounts, watch this video to see how its done without the need for scripting or other unnecessary complexities.

cyimxtckAuthor Commented:
Yes you have nailed it....that is what we are facing.  It is some real spaghetti code so we have no idea what "part" is failing so it could be anything really since there are so many things that can choke.

If we give it a cyclic approach I am thinking this would resolve it.  Like once the final "piece" has choked out it can be restarted.  We have to do it manually but by the time the business knows it is down, we RDP into the box (after finding which one it is out of the 9 total servers) we have the ability to manually start it again.

So I was thinking about something like this:

using System;
using System.Management;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.ServiceProcess;

namespace RestartProcess
{
    class processes
    {
        public static void Main()
        {
            ManagementEventWatcher startWatch = new ManagementEventWatcher(
              new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
            startWatch.EventArrived += new EventArrivedEventHandler(startWatch_EventArrived);
            startWatch.Start();
            Console.WriteLine(startWatch.ToString());
            ManagementEventWatcher stopWatch = new ManagementEventWatcher(
              new WqlEventQuery("SELECT * FROM Win32_ProcessStopTrace"));
            stopWatch.EventArrived += new EventArrivedEventHandler(stopWatch_EventArrived);
            Console.WriteLine(stopWatch.ToString());
            stopWatch.Start();
            Console.WriteLine("Press any key to exit");
            while (!Console.KeyAvailable) System.Threading.Thread.Sleep(1000); // 1000 ms variable
            startWatch.Stop();
            stopWatch.Stop();
        }

        static void stopWatch_EventArrived(object sender, EventArrivedEventArgs e)
        {
            Console.WriteLine("Process stopped: {0}", e.NewEvent.Properties["ProcessName"].Value);
        }

        static void startWatch_EventArrived(object sender, EventArrivedEventArgs e)
        {
            Console.WriteLine("Process started: {0}", e.NewEvent.Properties["ProcessName"].Value);
        }
         
        public static void StartService(String strSVCName)
        {

        ServiceController sc = new System.ServiceProcess.ServiceController(strSVCName);
        try
        {
            if (sc.Status.Equals(ServiceControllerStatus.Paused))
            {
                WriteLogEntry(DateTime.Now, "Paused");
                sc.Start();
                sc.WaitForStatus(ServiceControllerStatus.Running);
                WriteLogEntry(DateTime.Now, "Started Up!");
            }

            if (sc.Status.Equals(ServiceControllerStatus.PausePending))
            {
                WriteLogEntry(DateTime.Now, "Pause Pending");
            }

            if (sc.Status.Equals(ServiceControllerStatus.ContinuePending))
            {
                WriteLogEntry(DateTime.Now, "Continue Pending");
            }

            if (sc.Status.Equals(ServiceControllerStatus.StartPending))
            {
                WriteLogEntry(DateTime.Now, "Start Pending");
            }

            if (sc.Status.Equals(ServiceControllerStatus.StopPending))
            {
                WriteLogEntry(DateTime.Now, "Stop Pending");
            }

            if (sc.Status.Equals(ServiceControllerStatus.Stopped))
            {
                WriteLogEntry(DateTime.Now, "Stopped");
                sc.Start();
                sc.WaitForStatus(ServiceControllerStatus.Running);
                WriteLogEntry(DateTime.Now, "Started Up!");
            }
        }

        catch (Exception ex)
        {
            Console.WriteLine(ex.InnerException.ToString());
        }
        finally
        {
            sc.Close();
            sc.Dispose();
        }
        }

        public static void WriteLogEntry(DateTime When, String What)
        {
            StreamWriter WriteLog = new StreamWriter("ServiceUpkeep.log");
            WriteLog.Write(What + " " + When);
        }
    }
}


And then specify the strSVCName string to read from the flat file.  So it would cycle through everything and if it has a status of Running nothing happens.  Otherwise it writes to the log file and then restarts it and will wait until it is actually started.

Does that make sense?

I am just trying to determine the best way to get this into a windows service and "call it" to do the job since the console app can be closed, we could auto start the service, etc. for a better solution.

Which is of course the part that I am struggling with a bit here....lol
0
it_saigeDeveloperCommented:
First question then, when you remote into the servers, how do you make the determination that the service is no longer responding?

-saige-
0
cyimxtckAuthor Commented:
Usually by going to the Task Manager and seeing if the process is running.  The status is usually stopped or blank.
0
cyimxtckAuthor Commented:
Or the entry is missing all together (forgot that one).
0
it_saigeDeveloperCommented:
I use a NotifiableServiceController class to throw events when a service status changes.

class NotifiableServiceController : INotifyPropertyChanged
{
	#region INotifyPropertyChanged Memembers
	/// <summary>Occurs when a property value changes.</summary>
	[NonSerialized]
	private PropertyChangedEventHandler fPropertyChanged;
	/// <summary>Occurs when a property value changes.</summary>
	public event PropertyChangedEventHandler PropertyChanged
	{
		add { fPropertyChanged += value; }
		remove { fPropertyChanged -= value; }
	}

	/// <summary>Invoked whenever the effective value of any dependency property on this DependencyObject has been updated. The specific dependency property that changed is reported in the event data.</summary>
	/// <param name="sender">The source of the event data.</param>
	/// <param name="e">The event data that describes the property that changed, as well as old and new values.</param>
	protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
	{
		PropertyChangedEventHandler handler = fPropertyChanged;
		if (handler != null)
			handler(sender, e);
	}

	/// <summary>Invoked whenever the effective value of any dependency property on this DependencyObject has been updated. The specific dependency property that changed is reported in the event data.</summary>
	/// <param name="property">The event data that describes the property that changed.  <see cref="System.Linq.Expressions.Expression"/> type.</param>
	protected virtual void OnPropertyChanged<T>(Expression<Func<T>> property, T newValue)
	{
		if (property.Body.NodeType == ExpressionType.MemberAccess)
			OnPropertyChanged(this, new PropertyChangedEventArgs<T>((property.Body as MemberExpression).Member.Name, newValue));
	}
	#endregion

	#region Private Backing Fields
	private readonly Guid fId;
	private readonly System.Timers.Timer fRefreshTimer = new System.Timers.Timer();
	private readonly ServiceControllerEx fServiceController;
	private readonly List<ServiceControllerEx> fDependentServiceControllers = new List<ServiceControllerEx>();
	#endregion

	#region Public Properties
	/// <summary>Gets a value indicating whether this instance can stop.</summary>
	/// <value><c>true</c> if this instance can stop; otherwise, <c>false</c>.</value>
	public bool CanStop
	{
		get { return fServiceController.CanStop; }
	}

	/// <summary>Gets the display name.</summary>
	/// <value>The display name.</value>
	public string DisplayName
	{
		get { return fServiceController.DisplayName; }
	}

	/// <summary>Gets the identifier.</summary>
	/// <value>The identifier.</value>
	public Guid Id
	{
		get { return fId; }
	}

	/// <summary>Gets the name of the service.</summary>
	/// <value>The name of the service.</value>
	public string ServiceName
	{
		get { return fServiceController.ServiceName; }
	}

	/// <summary>Gets the status.</summary>
	/// <value>The status.</value>
	public ServiceControllerStatus Status
	{
		get { return fServiceController.Status; }
	}
	#endregion

	#region Constructors
	/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
	/// <param name="Service">The service.</param>
	public NotifiableServiceController(ServiceController Service) : this(Service, new Guid(), TimeSpan.FromSeconds(.5), null) { ;}

	/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
	/// <param name="Service">The service.</param>
	/// <param name="Id">The identifier.</param>
	public NotifiableServiceController(ServiceController Service, Guid Id) : this(Service, Id, TimeSpan.FromSeconds(.5), null) { ;}

	/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
	/// <param name="Service">The service.</param>
	/// <param name="Id">The identifier.</param>
	/// <param name="Interval">The interval.</param>
	public NotifiableServiceController(ServiceController Service, Guid Id, TimeSpan Interval) : this(Service, Id, Interval, null) { ;}

	/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
	/// <param name="Service">The service.</param>
	/// <param name="Id">The identifier.</param>
	/// <param name="DependentServices">The dependent services.</param>
	public NotifiableServiceController(ServiceController Service, Guid Id, IEnumerable<ServiceController> DependentServices) : this(Service, Id, TimeSpan.FromSeconds(.5), DependentServices) { ;}

	/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
	/// <param name="Service">The service.</param>
	/// <param name="Interval">The interval.</param>
	public NotifiableServiceController(ServiceController Service, TimeSpan Interval) : this(Service, new Guid(), Interval, null) { ;}

	/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
	/// <param name="Service">The service.</param>
	/// <param name="Interval">The interval.</param>
	/// <param name="DependentServices">The dependent services.</param>
	public NotifiableServiceController(ServiceController Service, TimeSpan Interval, IEnumerable<ServiceController> DependentServices) : this(Service, new Guid(), Interval, DependentServices) { ;}

	/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
	/// <param name="Service">The service.</param>
	/// <param name="DependentServices">The dependent services.</param>
	public NotifiableServiceController(ServiceController Service, IEnumerable<ServiceController> DependentServices) : this(Service, new Guid(), TimeSpan.FromSeconds(.5), DependentServices) { ;}

	/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
	/// <param name="Service">The service.</param>
	/// <param name="Id">The identifier.</param>
	/// <param name="Interval">The interval.</param>
	/// <param name="DependentServices">The dependent services.</param>
	/// <exception cref="System.ArgumentNullException">Service;Service cannot be a null value.</exception>
	public NotifiableServiceController(ServiceController Service, Guid Id, TimeSpan Interval, IEnumerable<ServiceController> DependentServices)
	{
		if (Service == null)
			throw new ArgumentNullException("Service", "Service cannot be a null value.");

		fId = Id;
		fServiceController = new ServiceControllerEx(Service.ServiceName);
		if (DependentServices != null)
		{
			foreach (var service in DependentServices)
				fDependentServiceControllers.Add(new ServiceControllerEx(service.ServiceName));
		}

		fRefreshTimer.Interval = Interval.TotalMilliseconds;
		fRefreshTimer.Elapsed += OnTimerElapsed;
		fRefreshTimer.Start();
	}
	#endregion

	#region Public Methods
	/// <summary>Gets the controllable services.</summary>
	/// <returns>IEnumerable&lt;NotifiableServiceController&gt;.</returns>
	public static IEnumerable<NotifiableServiceController> GetControllableServices()
	{
		var controllers = new List<NotifiableServiceController>();
		foreach (var controller in ServiceController.GetServices())
		{
			try
			{
				controllers.Add(new NotifiableServiceController(controller));
			}
			catch (Exception) { /* This service is cannot be controlled */;}
		}
	return controllers;
	}

	/// <summary>Restarts this instance.</summary>
	public void Restart()
	{
		try
		{
			if (fServiceController.CanStop && (fServiceController.Status == ServiceControllerStatus.Running || fServiceController.Status == ServiceControllerStatus.Paused))
			{
				Stop();
				fServiceController.WaitForStatus(ServiceControllerStatus.Stopped);
			}

			if (fServiceController.Status == ServiceControllerStatus.Stopped)
			{
				Start();
				fServiceController.WaitForStatus(ServiceControllerStatus.Running);
			}
		}
		catch (Exception)
		{
			throw;
		}
	}

	/// <summary>Starts this instance.</summary>
	public void Start()
	{
		try
		{
			if (fServiceController.Status == ServiceControllerStatus.Stopped)
			{
				fServiceController.Start();
				fServiceController.WaitForStatus(ServiceControllerStatus.Running);

				foreach (var dependent in fDependentServiceControllers)
				{
					if (dependent != null && dependent.StartupType != ServiceStartMode.Disabled && dependent.Status == ServiceControllerStatus.Stopped)
					{
						dependent.Start();
						dependent.WaitForStatus(ServiceControllerStatus.Running);
					}
				}

				OnPropertyChanged(() => Status, fServiceController.Status);
			}
		}
		catch (Exception)
		{
			throw;
		}
	}

	/// <summary>Stops this instance.</summary>
	public void Stop()
	{
		try
		{
			if (fServiceController.CanStop && (fServiceController.Status == ServiceControllerStatus.Running || fServiceController.Status == ServiceControllerStatus.Paused))
			{
				foreach (var dependent in fDependentServiceControllers)
				{
					if (dependent != null && dependent.StartupType != ServiceStartMode.Disabled && dependent.CanStop && (dependent.Status == ServiceControllerStatus.Running || dependent.Status == ServiceControllerStatus.Paused))
					{
						dependent.Stop();
						dependent.WaitForStatus(ServiceControllerStatus.Stopped);
					}
				}

				fServiceController.Stop();
				fServiceController.WaitForStatus(ServiceControllerStatus.Stopped);
				OnPropertyChanged(() => Status, fServiceController.Status);
			}
		}
		catch (Exception)
		{
			throw;
		}
	}
	#endregion

	#region Private Methods
	void OnTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
	{
		var status = fServiceController.Status;
		fServiceController.Refresh();
		if (status != fServiceController.Status)
			OnPropertyChanged(() => Status, fServiceController.Status);
	}
	#endregion

	#region Overriden Methods
	/// <summary>Returns a <see cref="System.String" /> that represents this instance.</summary>
	/// <returns>A <see cref="System.String" /> that represents this instance.</returns>
	public override string ToString()
	{
		return string.Format("{0} ({1})", DisplayName, Status);
	}
	#endregion
}

class ServiceControllerEx : ServiceController
{
	/// <summary>Gets the description.</summary>
	/// <value>The description.</value>
	public string Description
	{
		get
		{
			if (ServiceName != null)
			{
				// Construct the management path
				ManagementPath path = new ManagementPath(string.Format("\\\\{0}\\root\\cimv2:Win32_Service.Name='{1}'", MachineName, ServiceName));
				// Construct the management object
				ManagementObject obj = new ManagementObject(path);
				return obj["Description"] != null ? obj["Description"].ToString() : null;
			}
			else
				return null;
		}
	}

	/// <summary>Gets or sets the type of the startup.</summary>
	/// <value>The type of the startup.</value>
	public ServiceStartMode StartupType
	{
		get
		{
			if (ServiceName != null)
			{
				// Construct the management path
				ManagementPath path = new ManagementPath(string.Format("\\\\{0}\\root\\cimv2:Win32_Service.Name='{1}'", MachineName, ServiceName));
				// Construct the management object
				ManagementObject obj = new ManagementObject(path);
				string mode = obj["StartMode"].ToString();
				switch (mode)
				{
					case "Auto":
						return ServiceStartMode.Automatic;
					case "Manual":
						return ServiceStartMode.Manual;
					case "Disabled":
					default:
						return ServiceStartMode.Disabled;
				}
			}
			else
				return ServiceStartMode.Disabled;
		}
		set
		{
			if (ServiceName != null)
			{
				// Construct the management path
				ManagementPath path = new ManagementPath(string.Format("\\\\{0}\\root\\cimv2:Win32_Service.Name='{1}'", MachineName, ServiceName));
				// Construct the management object
				ManagementObject obj = new ManagementObject(path);
				obj.InvokeMethod("ChangeStartMode", new object[] { value.ToString() });
			}
		}
	}

	/// <summary>Initializes a new instance of the <see cref="ServiceControllerEx"/> class.</summary>
	public ServiceControllerEx() { ;}

	/// <summary>Initializes a new instance of the <see cref="T:System.ServiceProcess.ServiceController" /> class that is associated with an existing service on the local computer.</summary>
	/// <param name="name">The name that identifies the service to the system. This can also be the display name for the service.</param>
	public ServiceControllerEx(string name) : base(name) { ;}

	/// <summary>Initializes a new instance of the <see cref="T:System.ServiceProcess.ServiceController" /> class that is associated with an existing service on the specified computer.</summary>
	/// <param name="name">The name that identifies the service to the system. This can also be the display name for the service..</param>
	/// <param name="machineName">The computer on which the service resides.</param>
	public ServiceControllerEx(string name, string machineName) : base(name, machineName) { ;}
}

class PropertyChangedEventArgs<T> : PropertyChangedEventArgs
{
	/// <summary>Gets the new value of the <paramref name="PropertyName"/> parameter.</summary>
	public T NewValue { get; private set; }

	/// <summary>Initializes a new instance of the <see cref="PropertyChangedEventArgs{T}"/> class.</summary>
	/// <param name="PropertyName">Name of the property.</param>
	public PropertyChangedEventArgs(string PropertyName) : base(PropertyName)
	{
		NewValue = default(T);
	}

	/// <summary>Initializes a new instance of the <see cref="PropertyChangedEventArgs{T}"/> class.</summary>
	/// <param name="PropertyName">Name of the property.</param>
	/// <param name="NewValue">The new value.</param>
	public PropertyChangedEventArgs(string PropertyName, T NewValue) : base(PropertyName)
	{
		this.NewValue = NewValue;
	}
}

Open in new window

Example usage -
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Management;
using System.ServiceProcess;
using System.Threading;

namespace EE_Q28706883
{
	class Program
	{
		static NotifiableServiceController controller;
		static AutoResetEvent reset = new AutoResetEvent(true);

		static void Main(string[] args)
		{
			// I'm going to use the Adobe Acrobat Update Service as my test service.
			controller = new NotifiableServiceController(new ServiceController() { ServiceName = "AdobeARMservice" });
			controller.PropertyChanged += OnServiceModified;
			Console.WriteLine("Press 'Q' to quit.");
			while (Console.ReadKey().Key != ConsoleKey.Q)
				reset.WaitOne(5);
		}

		private static void OnServiceModified(object sender, PropertyChangedEventArgs e)
		{
			if (sender is NotifiableServiceController)
			{
				NotifiableServiceController controller = sender as NotifiableServiceController;
				Console.WriteLine("{0} has changed for {1}", e.PropertyName, controller);
				if (controller.Status == ServiceControllerStatus.Stopped)
					controller.Start();
			}
		}
	}

	class NotifiableServiceController : INotifyPropertyChanged
	{
		#region INotifyPropertyChanged Memembers
		/// <summary>Occurs when a property value changes.</summary>
		[NonSerialized]
		private PropertyChangedEventHandler fPropertyChanged;
		/// <summary>Occurs when a property value changes.</summary>
		public event PropertyChangedEventHandler PropertyChanged
		{
			add { fPropertyChanged += value; }
			remove { fPropertyChanged -= value; }
		}

		/// <summary>Invoked whenever the effective value of any dependency property on this DependencyObject has been updated. The specific dependency property that changed is reported in the event data.</summary>
		/// <param name="sender">The source of the event data.</param>
		/// <param name="e">The event data that describes the property that changed, as well as old and new values.</param>
		protected virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			PropertyChangedEventHandler handler = fPropertyChanged;
			if (handler != null)
				handler(sender, e);
		}

		/// <summary>Invoked whenever the effective value of any dependency property on this DependencyObject has been updated. The specific dependency property that changed is reported in the event data.</summary>
		/// <param name="property">The event data that describes the property that changed.  <see cref="System.Linq.Expressions.Expression"/> type.</param>
		protected virtual void OnPropertyChanged<T>(Expression<Func<T>> property, T newValue)
		{
			if (property.Body.NodeType == ExpressionType.MemberAccess)
				OnPropertyChanged(this, new PropertyChangedEventArgs<T>((property.Body as MemberExpression).Member.Name, newValue));
		}
		#endregion

		#region Private Backing Fields
		private readonly Guid fId;
		private readonly System.Timers.Timer fRefreshTimer = new System.Timers.Timer();
		private readonly ServiceControllerEx fServiceController;
		private readonly List<ServiceControllerEx> fDependentServiceControllers = new List<ServiceControllerEx>();
		#endregion

		#region Public Properties
		/// <summary>Gets a value indicating whether this instance can stop.</summary>
		/// <value><c>true</c> if this instance can stop; otherwise, <c>false</c>.</value>
		public bool CanStop
		{
			get { return fServiceController.CanStop; }
		}

		/// <summary>Gets the display name.</summary>
		/// <value>The display name.</value>
		public string DisplayName
		{
			get { return fServiceController.DisplayName; }
		}

		/// <summary>Gets the identifier.</summary>
		/// <value>The identifier.</value>
		public Guid Id
		{
			get { return fId; }
		}

		/// <summary>Gets the name of the service.</summary>
		/// <value>The name of the service.</value>
		public string ServiceName
		{
			get { return fServiceController.ServiceName; }
		}

		/// <summary>Gets the status.</summary>
		/// <value>The status.</value>
		public ServiceControllerStatus Status
		{
			get { return fServiceController.Status; }
		}
		#endregion

		#region Constructors
		/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
		/// <param name="Service">The service.</param>
		public NotifiableServiceController(ServiceController Service) : this(Service, new Guid(), TimeSpan.FromSeconds(.5), null) { ;}

		/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
		/// <param name="Service">The service.</param>
		/// <param name="Id">The identifier.</param>
		public NotifiableServiceController(ServiceController Service, Guid Id) : this(Service, Id, TimeSpan.FromSeconds(.5), null) { ;}

		/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
		/// <param name="Service">The service.</param>
		/// <param name="Id">The identifier.</param>
		/// <param name="Interval">The interval.</param>
		public NotifiableServiceController(ServiceController Service, Guid Id, TimeSpan Interval) : this(Service, Id, Interval, null) { ;}

		/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
		/// <param name="Service">The service.</param>
		/// <param name="Id">The identifier.</param>
		/// <param name="DependentServices">The dependent services.</param>
		public NotifiableServiceController(ServiceController Service, Guid Id, IEnumerable<ServiceController> DependentServices) : this(Service, Id, TimeSpan.FromSeconds(.5), DependentServices) { ;}

		/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
		/// <param name="Service">The service.</param>
		/// <param name="Interval">The interval.</param>
		public NotifiableServiceController(ServiceController Service, TimeSpan Interval) : this(Service, new Guid(), Interval, null) { ;}

		/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
		/// <param name="Service">The service.</param>
		/// <param name="Interval">The interval.</param>
		/// <param name="DependentServices">The dependent services.</param>
		public NotifiableServiceController(ServiceController Service, TimeSpan Interval, IEnumerable<ServiceController> DependentServices) : this(Service, new Guid(), Interval, DependentServices) { ;}

		/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
		/// <param name="Service">The service.</param>
		/// <param name="DependentServices">The dependent services.</param>
		public NotifiableServiceController(ServiceController Service, IEnumerable<ServiceController> DependentServices) : this(Service, new Guid(), TimeSpan.FromSeconds(.5), DependentServices) { ;}

		/// <summary>Initializes a new instance of the <see cref="NotifiableServiceController"/> class.</summary>
		/// <param name="Service">The service.</param>
		/// <param name="Id">The identifier.</param>
		/// <param name="Interval">The interval.</param>
		/// <param name="DependentServices">The dependent services.</param>
		/// <exception cref="System.ArgumentNullException">Service;Service cannot be a null value.</exception>
		public NotifiableServiceController(ServiceController Service, Guid Id, TimeSpan Interval, IEnumerable<ServiceController> DependentServices)
		{
			if (Service == null)
				throw new ArgumentNullException("Service", "Service cannot be a null value.");

			fId = Id;
			fServiceController = new ServiceControllerEx(Service.ServiceName);
			if (DependentServices != null)
			{
				foreach (var service in DependentServices)
					fDependentServiceControllers.Add(new ServiceControllerEx(service.ServiceName));
			}

			fRefreshTimer.Interval = Interval.TotalMilliseconds;
			fRefreshTimer.Elapsed += OnTimerElapsed;
			fRefreshTimer.Start();
		}
		#endregion

		#region Public Methods
		/// <summary>Gets the controllable services.</summary>
		/// <returns>IEnumerable&lt;NotifiableServiceController&gt;.</returns>
		public static IEnumerable<NotifiableServiceController> GetControllableServices()
		{
			var controllers = new List<NotifiableServiceController>();
			foreach (var controller in ServiceController.GetServices())
			{
				try
				{
					controllers.Add(new NotifiableServiceController(controller));
				}
				catch (Exception) { /* This service is unabled to be controlled */;}
			}
			return controllers;
		}

		/// <summary>Restarts this instance.</summary>
		public void Restart()
		{
			try
			{
				if (fServiceController.CanStop && (fServiceController.Status == ServiceControllerStatus.Running || fServiceController.Status == ServiceControllerStatus.Paused))
				{
					Stop();
					fServiceController.WaitForStatus(ServiceControllerStatus.Stopped);
				}

				if (fServiceController.Status == ServiceControllerStatus.Stopped)
				{
					Start();
					fServiceController.WaitForStatus(ServiceControllerStatus.Running);
				}
			}
			catch (Exception)
			{
				throw;
			}
		}

		/// <summary>Starts this instance.</summary>
		public void Start()
		{
			try
			{
				if (fServiceController.Status == ServiceControllerStatus.Stopped)
				{
					fServiceController.Start();
					fServiceController.WaitForStatus(ServiceControllerStatus.Running);

					foreach (var dependent in fDependentServiceControllers)
					{
						if (dependent != null && dependent.StartupType != ServiceStartMode.Disabled && dependent.Status == ServiceControllerStatus.Stopped)
						{
							dependent.Start();
							dependent.WaitForStatus(ServiceControllerStatus.Running);
						}
					}

					OnPropertyChanged(() => Status, fServiceController.Status);
				}
			}
			catch (Exception)
			{
				throw;
			}
		}

		/// <summary>Stops this instance.</summary>
		public void Stop()
		{
			try
			{
				if (fServiceController.CanStop && (fServiceController.Status == ServiceControllerStatus.Running || fServiceController.Status == ServiceControllerStatus.Paused))
				{
					foreach (var dependent in fDependentServiceControllers)
					{
						if (dependent != null && dependent.StartupType != ServiceStartMode.Disabled && dependent.CanStop && (dependent.Status == ServiceControllerStatus.Running || dependent.Status == ServiceControllerStatus.Paused))
						{
							dependent.Stop();
							dependent.WaitForStatus(ServiceControllerStatus.Stopped);
						}
					}

					fServiceController.Stop();
					fServiceController.WaitForStatus(ServiceControllerStatus.Stopped);
					OnPropertyChanged(() => Status, fServiceController.Status);
				}
			}
			catch (Exception)
			{
				throw;
			}
		}
		#endregion

		#region Private Methods
		void OnTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			var status = fServiceController.Status;
			fServiceController.Refresh();
			if (status != fServiceController.Status)
				OnPropertyChanged(() => Status, fServiceController.Status);
		}
		#endregion

		#region Overriden Methods
		/// <summary>Returns a <see cref="System.String" /> that represents this instance.</summary>
		/// <returns>A <see cref="System.String" /> that represents this instance.</returns>
		public override string ToString()
		{
			return string.Format("{0} ({1})", DisplayName, Status);
		}
		#endregion
	}

	class ServiceControllerEx : ServiceController
	{
		/// <summary>Gets the description.</summary>
		/// <value>The description.</value>
		public string Description
		{
			get
			{
				if (ServiceName != null)
				{
					// Construct the management path
					ManagementPath path = new ManagementPath(string.Format("\\\\{0}\\root\\cimv2:Win32_Service.Name='{1}'", MachineName, ServiceName));
					// Construct the management object
					ManagementObject obj = new ManagementObject(path);
					return obj["Description"] != null ? obj["Description"].ToString() : null;
				}
				else
					return null;
			}
		}

		/// <summary>Gets or sets the type of the startup.</summary>
		/// <value>The type of the startup.</value>
		public ServiceStartMode StartupType
		{
			get
			{
				if (ServiceName != null)
				{
					// Construct the management path
					ManagementPath path = new ManagementPath(string.Format("\\\\{0}\\root\\cimv2:Win32_Service.Name='{1}'", MachineName, ServiceName));
					// Construct the management object
					ManagementObject obj = new ManagementObject(path);
					string mode = obj["StartMode"].ToString();
					switch (mode)
					{
						case "Auto":
							return ServiceStartMode.Automatic;
						case "Manual":
							return ServiceStartMode.Manual;
						case "Disabled":
						default:
							return ServiceStartMode.Disabled;
					}
				}
				else
					return ServiceStartMode.Disabled;
			}
			set
			{
				if (ServiceName != null)
				{
					// Construct the management path
					ManagementPath path = new ManagementPath(string.Format("\\\\{0}\\root\\cimv2:Win32_Service.Name='{1}'", MachineName, ServiceName));
					// Construct the management object
					ManagementObject obj = new ManagementObject(path);
					obj.InvokeMethod("ChangeStartMode", new object[] { value.ToString() });
				}
			}
		}

		/// <summary>Initializes a new instance of the <see cref="ServiceControllerEx"/> class.</summary>
		public ServiceControllerEx() { ;}

		/// <summary>Initializes a new instance of the <see cref="T:System.ServiceProcess.ServiceController" /> class that is associated with an existing service on the local computer.</summary>
		/// <param name="name">The name that identifies the service to the system. This can also be the display name for the service.</param>
		public ServiceControllerEx(string name) : base(name) { ;}

		/// <summary>Initializes a new instance of the <see cref="T:System.ServiceProcess.ServiceController" /> class that is associated with an existing service on the specified computer.</summary>
		/// <param name="name">The name that identifies the service to the system. This can also be the display name for the service..</param>
		/// <param name="machineName">The computer on which the service resides.</param>
		public ServiceControllerEx(string name, string machineName) : base(name, machineName) { ;}
	}

	class PropertyChangedEventArgs<T> : PropertyChangedEventArgs
	{
		/// <summary>Gets the new value of the <paramref name="PropertyName"/> parameter.</summary>
		public T NewValue { get; private set; }

		/// <summary>Initializes a new instance of the <see cref="PropertyChangedEventArgs{T}"/> class.</summary>
		/// <param name="PropertyName">Name of the property.</param>
		public PropertyChangedEventArgs(string PropertyName) : base(PropertyName)
		{
			NewValue = default(T);
		}

		/// <summary>Initializes a new instance of the <see cref="PropertyChangedEventArgs{T}"/> class.</summary>
		/// <param name="PropertyName">Name of the property.</param>
		/// <param name="NewValue">The new value.</param>
		public PropertyChangedEventArgs(string PropertyName, T NewValue) : base(PropertyName)
		{
			this.NewValue = NewValue;
		}
	}
}

Open in new window

Produces the following output -Capture.JPGIn this case I stopped the service using the Services snap-in and by killing the process.  In both cases the service will restart so long as the above code is running.

A couple of things to note, obviously, this is not a service again this is like your method above, it is a console application.  In order for the code present to work in this way (at least on Windows Vista and above) the program (as is) needs to be ran as an administrator.

As it stands the above can easily be converted into a service and a service installer added that automatically starts the service upon successful installation.

-saige-
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
cyimxtckAuthor Commented:
Great work!  Everything works as expected and starts in the console.

Thanks so much!
0
cyimxtckAuthor Commented:
Perfect solution
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.