Mobile Management For SQL Server(s!) - Siccolo - SQL Management Tool

Siccolo Development Articles - Microsoft CRM Customization and CRM Customization Tools, Windows Mobile Development and PocketPC Application, SQL Development, SQL Server scripts and SQL Reporting, .NET Software Development
Google
Main     
(V) - How To Develop SQL Mobile Management Tool (and How I created one) - Continued:
Engineered to help you extend your support from mobile devices for Microsoft SQL Servers.

Part VIII - Developing SQL Server related control management interfaces
(see also:
How to Build Simple Event Log Montior/Watcher (Using TCP in .NET)
How to Enumerate Services Using WMI with Win32_Service in .NET
System.ServiceProcess.ServiceController to get Service Information )
 
Here, we'll try to restart SQL Server service. And .NET provides just the tool for this task - System.ServiceProcess.ServiceController class.
To create an instance of System.ServiceProcess.ServiceController:
	// C# //
	...
	System.ServiceProcess.ServiceController Service;
	if (this.m_MachineName!="")
		{Service = new ServiceController(this.m_ServiceName, this.m_MachineName ) ;}
	else
	{Service = new ServiceController(this.m_ServiceName ) ;}
	...
	


And the fact that authentication (Integrated Windows authentication or Basic) is in place on IIS, actually helps here. In order to be able to access service(s) on the different machine than web service host, web service needs to "assume" an identity of authenticated user. Normally, web service is running under ASP.NET user with minimum privileges and I needed to impersonate authenticated user with the web service.
Remember NetCredential object I used previously (if not take a look -> Part III - Securing Mobile To Server Communication) On the server side, to retrieve authenticated user, we need to use System.Web.Services.WebService.User and then impersonate:
and code does just that - "Impersonates the user represented by the WindowsIdentity object."
	// C# //
	...
	
	System.Security.Principal.WindowsImpersonationContext impersonationContext;
			impersonationContext = 
				((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
	...	
	
So, now hopefully web service has enough credentials to remote access service on SQL Server machine.
System.ServiceProcess.ServiceController has two methods that are in need here - Start() and Stop().
But I wanted not just stop MSSQLSERVER service and start it, but also start all the services that are dependent on MSSQLSERVER service, e.g. SQL Server Agent, Crystal Reports Engine, CRM Security Service etc.
To enumerate dependent services - System.ServiceProcess.ServiceController has DependentServices property:
	// C# //
	...
	foreach (System.ServiceProcess.ServiceController dependent_service 
						in Service.DependentServices)
	{	
		...
	}
	...	
	
To handle reqursive stopping and starting, I added small "wrapper" NTServiceInfo class:
	[WebMethod]
	public bool RestartSQLServerService(string RemoteServerAddress,
					out string NewServiceStatus, 
					out string ErrorInfo )
	{
		try
		{
			string ToDebugSetting = 
					System.Configuration.ConfigurationSettings.AppSettings.Get("DebugMode");
			bool ToDebug = (ToDebugSetting!="");

			string NTServiceName = "MSSQLSERVER";

			ErrorInfo="";
			NewServiceStatus ="";

			System.Security.Principal.WindowsImpersonationContext impersonationContext;
				impersonationContext = 
					((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
			
			NTServiceInfo si = new NTServiceInfo(NTServiceName, RemoteServerAddress);

			if ( ! si.RestartServervice ((WindowsPrincipal) this.User,ToDebug,  out ErrorInfo))
			{return false;}

			NewServiceStatus =  si.ServiceStatus();

			impersonationContext.Undo();
				
			ErrorInfo = "";
			return true;
		}
		catch (Exception ex_get_service_info)
		{
			NewServiceStatus ="";
			ErrorInfo = ex_get_service_info.Message;
			return false;
		}
	}
	
In NTServiceInfo class:
(see also article on
Create a web service method to get NT service information)
	public bool RestartServervice(WindowsPrincipal User, 
				bool ToDebug, 
				out string ErrorInfo)
	{
		try
		{
			ErrorInfo ="";
		
			if (this.StopService(User, ToDebug, out ErrorInfo))
			{
				if (this.StartService(User, ToDebug, out ErrorInfo))
				{return true;}
				else{return false;}
			}
			else
			{return false;}

		}
		catch (Exception ex_restart_service)
		{
			ErrorInfo = "Restart Service [" + this.m_ServiceName + "] [" + ex_restart_service.Message + "]";
			return false;
		}
	}
	
Where StopService() and StartService() methods are:
(see also article on Create a web service method to start stop and restart a NT service)
	public bool StopService(WindowsPrincipal User, 
				bool ToDebug, 
				out string ErrorInfo)
	{
		try
		{
			System.Security.Principal.WindowsImpersonationContext impersonationContext;
				impersonationContext = 
					((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();

			System.ServiceProcess.ServiceController Service;
			if (this.m_MachineName!="")
			{Service = new ServiceController(this.m_ServiceName, this.m_MachineName ) ;}
			else
			{Service = new ServiceController(this.m_ServiceName ) ;}

			//stop all the Dependent services...
			foreach (System.ServiceProcess.ServiceController dependent_service 
							in Service.DependentServices)
			{					
				switch ( dependent_service.Status)
				{
					case ServiceControllerStatus.Stopped:
						//already stopped...nothing to do
						break;

					case ServiceControllerStatus.StopPending:
						dependent_service.WaitForStatus(ServiceControllerStatus.Stopped);
						break;

					default:
						Service.Stop();
						Service.WaitForStatus(ServiceControllerStatus.Stopped);
						break;
				}
			}

			//stop main service...
			switch ( Service.Status)
			{
				case ServiceControllerStatus.Stopped:
					//already stopped...nothing to do
					break;

				case ServiceControllerStatus.StopPending:
					Service.WaitForStatus(ServiceControllerStatus.Stopped);
					break;

				default:
					// *-*************************************************************************
					//check all dependent services?
					foreach (System.ServiceProcess.ServiceController dependent_service 
										in Service.DependentServices)
					{					
						switch ( dependent_service.Status)
						{
							case ServiceControllerStatus.Stopped:
								//already stopped...nothing to do
								break;

							case ServiceControllerStatus.StopPending:
							dependent_service.WaitForStatus(ServiceControllerStatus.Stopped);
								break;

							default:
								Service.Stop();
								Service.WaitForStatus(ServiceControllerStatus.Stopped);
								break;
						}
							

						}

						if ( !Service.CanStop )
						{
							throw new Exception ("Cannot stop service [" + 
							        this.m_ServiceName + "]");
						}
						Service.Stop();
						Service.WaitForStatus(ServiceControllerStatus.Stopped);
						break;
				}

				Service.Close();

				impersonationContext.Undo();

				ErrorInfo="";
				return true;
			}

		catch (Exception ex_stop_service)
		{
			ErrorInfo = ex_stop_service.Message;
			return false;
		}

	}


	public bool StartService(WindowsPrincipal User, 
				bool ToDebug, 
				out string ErrorInfo)
	{
		try
		{
			System.Security.Principal.WindowsImpersonationContext impersonationContext;
			impersonationContext = 
				((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();

			System.ServiceProcess.ServiceController Service;
			if (this.m_MachineName!="")
			{Service = new ServiceController(this.m_ServiceName, this.m_MachineName ) ;}
			else
			{Service = new ServiceController(this.m_ServiceName ) ;}
			
			switch ( Service.Status)
			{
				case ServiceControllerStatus.Stopped:
					Service.Start();
					Service.WaitForStatus(ServiceControllerStatus.Running);
					break;

				case ServiceControllerStatus.StopPending:
					//wait for it to stop
					Service.WaitForStatus(ServiceControllerStatus.Stopped);
					//... and then start
					Service.Start();
					Service.WaitForStatus(ServiceControllerStatus.Running);
					break;

				case ServiceControllerStatus.StartPending:
					//nothing to do...just wait
					Service.WaitForStatus(ServiceControllerStatus.Running);
					break;

				case ServiceControllerStatus.Running:
					//nothing to do.already running...
					break;
				
				default:
					Service.Start();
					Service.WaitForStatus(ServiceControllerStatus.Running);
					break;
			}

			//start all the Dependent services...
			foreach (System.ServiceProcess.ServiceController dependent_service 
							in Service.DependentServices)
			{
				
				switch (dependent_service.Status )
				{
					case ServiceControllerStatus.StartPending:
						//just wait for it to start
						dependent_service.WaitForStatus (ServiceControllerStatus.Running);
						break;

					case ServiceControllerStatus.Running:
						//already running.nothing to do
						break;

					default:
						NTServiceInfo si = 
						        new NTServiceInfo( dependent_service.ServiceName, 
										this.m_MachineName);
						if ( !si.StartService(User, ToDebug, out ErrorInfo))
						{
							throw new Exception ("Failed to start Dependent Service [" +  
							                dependent_service.ServiceName + 
								            "] - Error [" + ErrorInfo + "]") ;
						}
						break;
				}
			}
			
			Service.Close();

			impersonationContext.Undo();

			ErrorInfo="";
			return true;
		}
		catch (Exception ex_start_service)
		{
			ErrorInfo = ex_start_service.Message;
			return false;
		}

	}
	
  Back to (IV)      (I)

Article keywords: NT Service, Windows Service, Integrated Windows authentication, IIS authentication, System.ServiceProcess.ServiceController, System.Security.Principal.WindowsImpersonationContext, System.Security.Principal.WindowsIdentity, User.Identity.Impersonate(), impersonation context, impersonationContext.Undo(), ServiceName, PathToExecutable, CanStop, CanPauseAndContinue, ServicesDependedOn, Service.Status, ServiceControllerStatus.Stopped, ServiceControllerStatus.StopPending, Service.WaitForStatus(), Service.Start(), ServiceControllerStatus.Running, Service.DependentServices, Service.ServiceStatus


Back To Articles Page

Free Mobile Management For SQL Server(s!) - Siccolo - SQL Management ToolQuestions? Suggestions? Concerns? - email me to siccolo_mobile_management@yahoo.com    Greg Dubinovsky © 2006-2007
or share your thoughts at Siccolo Blog

Web being sponsor - Mid-Atlantic Processing. Well being sponsor - Clarity MediSpa. Hairless sponsor - Clarity MediSpa Laser Hair Removal.