5,427,813 members and growing! (17,656 online)
Email Password   helpLost your password?
Web Development » Web Services » General     Intermediate

Create a web service method to manage a NT service

By aleksisa

Create a web service method to manage a NT service
VB, C# 1.0, C# 2.0, C#, Windows, .NET, .NET 1.1, .NET 2.0VS.NET2003, VS2005, Visual Studio, Dev

Posted: 17 Nov 2006
Updated: 17 Nov 2006
Views: 13,836
Bookmarked: 12 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
17 votes for this Article.
Popularity: 5.46 Rating: 4.43 out of 5
0 votes, 0.0%
1
0 votes, 0.0%
2
1 vote, 5.9%
3
2 votes, 11.8%
4
14 votes, 82.4%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Recently, I created a mobile application-Siccolo that allows me to manage SQL Servers by using web services hosted on public domain (see more information here about how to develop a mobile management tool)
Among other problems, I had to be able to restart SQL Server service on machine(s) other than web service host from within web method. And I wanted not just to stop and start MSSQLSERVER service, but also restart all the services that are dependent on MSSQLSERVER service, e.g. SQL Server Agent, Crystal Reports Engine, CRM Security Service etc.

The code presented allows to restart (or just stop, or start) NT Service.

Background (optional, but needed)

My "managing" web service is hosted under SSL with "Integrated Windows" authenication being set. Therefore, mobile application required to pass network credentials. And this is needed to be able remote access SQL Server machine to control MSSQLSERVER service.

Using the code

    Components used :
  • serviceprocessor.asmx.cs - web service interface
  • NTServiceInfo.cs - a small "wrapper" to control NT Service
Let's see how to restart SQL Server service. .NET provides just the tool for this task - System.ServiceProcess.ServiceController class. To create an instance of System.ServiceProcess.ServiceController:
    // C# //
    ...
    System.ServiceProcess.ServiceController <CODE>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 authenication (Integrated Windows authenication 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 authenicated user. Normally, web service is running under ASP.NET user with minimum privileges and I needed to impersonate authenicated user with the web service.
On the server side, to retrieve authenicated 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 <CODE>impersonationContext;
            impersonationContext = 
                ((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
    ...    
To enumerate dependent services - System.ServiceProcess.ServiceController has DependentServices property:
    // C# //
    ...
    foreach (System.ServiceProcess.ServiceController <CODE>dependent_service 
                        in Service.DependentServices)
    {    
        ...
    }
    ...    
To handle reqursive stopping and starting, I added small "wrapper" NTServiceInfo class:
    // NTServiceInfo :
    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:
// NTServiceInfo :
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;
        }

    }
So, after all, web method looks like this:
[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;
        }
    }
    
Or, to make functionality more generic:
[WebMethod]
        public bool RestartNTService(string RemoteServerAddress , 
                                    string NTServiceName, 
                                    out string NewServiceStatus  , 
                                    out bool CanStop, 
                                    out bool CanPauseAndContinue,
                                    out string ErrorInfo )
        {
    
            try
            {
        
                string ToDebugSetting = System.Configuration.ConfigurationSettings.AppSettings.Get("DebugMode");
                bool ToDebug = (ToDebugSetting!="");

                ErrorInfo="";
                NewServiceStatus ="";
                CanStop = false;
                CanPauseAndContinue = false;

                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();
                CanStop = si.CanStop();
                CanPauseAndContinue = si.CanPauseAndContinue();

                impersonationContext.Undo();

                ErrorInfo = "";
                return true;
            }
            catch (Exception ex_get_service_info)
            {
                NewServiceStatus ="";
                CanStop = false;
                CanPauseAndContinue = false;
                ErrorInfo = ex_get_service_info.Message;
                return false;
            }

        }

Points of Interest

If you would like to read more on this store - please take a look at Siccolo - Free Mobile Management Tool For SQL Server and full article at How to Develop Mobile Management Tool

History

no improvements so far. nearly perfect.

License

About the Author

aleksisa



Location: United States United States

Other popular Web Services articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 7 of 7 (Total in Forum: 7) (Refresh)FirstPrevNext
Subject  Author Date 
GeneralAccessing by Another UsernamememberBurak Donbay1:25 13 Jun '07  
GeneralRe: Accessing by Another Usernamememberaleksisa3:09 28 Jun '07  
Generalsql 2005 help me pleasememberserhaneker0:48 14 Jan '07  
GeneralRe: sql 2005 help me pleasememberaleksisa3:50 16 Jan '07  
GeneralCompleted code example?memberDEWright_CA10:34 27 Dec '06  
GeneralRe: Completed code example?memberaleksisa6:01 9 Jan '07  
Generala little boo-boomemberaleksisa12:11 17 Nov '06  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 17 Nov 2006
Editor:
Copyright 2006 by aleksisa
Everything else Copyright © CodeProject, 1999-2008
Web16 | Advertise on the Code Project