Scheduled Task – Status, Start, Stop of Windows Service

So yesterday I created a task scheduler, today I wanted to be able to figure out the status of service and be able to start/stop it. I thought this would be a great time to just implement a new task in my project for task schedule and be on my way.

I found the code for accessing services using System.ServiceProcess quite easily and in my test project it worked great. Infact too great, I was even concerned at how easy it was to start/stop a service from visual studio further reflection on this I assumed since I was debugging a test project it was most likely running under my admin rights (proved true.) So I dropped it into actual ASP.NET and of course was issued security exceptions.

This led me down needing to figure out how to assume the identity of a user that can start/stop the service and then use their credientials to handle it. With a little bit of shameless stealing from MSDN and code clean up I was able to create my new task.

#region Using Statements

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Security.Principal;
using System.ServiceProcess;

#endregion

namespace Tasks
{
    [assembly: SecurityPermission(SecurityAction.RequestMinimum, UnmanagedCode = true)]
    [assembly: PermissionSet(SecurityAction.RequestMinimum, Name = "FullTrust")]
    public class ServiceUpTask : Task
    {
        public string ServiceName { get; set; }

        #region Overrides of Task

        public override void Run()
        {
            if (!string.IsNullOrEmpty(ServiceName))
            {
                WindowsImpersonationContext impersonationContext = null;

                try
                {
                    impersonationContext = AssumeIdentity("userName", "someDomain", "password");

                    using (var service = new ServiceController(ServiceName))
                    {
                        Debug.Print(string.Format("Service {0}, Status {1}", service.ServiceName, service.Status));

                        if (service.CanStop)
                        {
                            service.Stop();
                        }
                    }

                    using (var service = new ServiceController(ServiceName))
                    {
                        if (service.Status == ServiceControllerStatus.Stopped)
                        {
                            service.Start();
                        }
                    }
                }
                finally
                {
                    //Make sure we release the identity in case of an exception no matter what.
                    StopImpersonating(impersonationContext);
                }
            }
        }

        ///<summary>
        ///Assumes the identity. Steal shamelessly from MSDN.
        ///</summary>
        ///<returns></returns>
        private static WindowsImpersonationContext AssumeIdentity(string userName, string domain, string password)
        {
            const int LOGON32_PROVIDER_DEFAULT = 0;
            const int dwLogonProvider = LOGON32_PROVIDER_DEFAULT;

            //This parameter causes LogonUser to create a primary token.
            const int LOGON32_LOGON_INTERACTIVE = 2;
            const int dwLogonType = LOGON32_LOGON_INTERACTIVE;

            var phToken = new IntPtr();
            if (LogonUser(userName, domain, password, dwLogonType, dwLogonProvider, ref phToken))
            {
                if (phToken != IntPtr.Zero)
                {
                    var windowsIdentity = new WindowsIdentity(phToken);
                    var impersonationContext = windowsIdentity.Impersonate();
                    CloseHandle(phToken);
                    return impersonationContext;
                }
            }

            return null;
        }

        /// <summary>
        /// Stops the WindowsIdentity impersonating.
        /// </summary>
        /// <param name="impersonationContext">The impersonation context.</param>
        private static void StopImpersonating(WindowsImpersonationContext impersonationContext)
        {
            //Stop impersonating the user.
            if (impersonationContext != null) impersonationContext.Undo();

            //Check the identity name.
            //Name of the identity after performing an Undo on the impersonation:
            //Uncomment for debugging if to check identity if needed
            //var identity = WindowsIdentity.GetCurrent();
        }

        #endregion

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
                                            int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool DuplicateToken(IntPtr ExistingTokenHandle,
                                                 int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
    }
}

These changes are all checked into my SVN for access see the Assembla page or the post below.

BloggingContext.ApplicationInstance.CompleteRequest();

Advertisements

Assembla – Free Online SVN Source Control Hosting

So I signed up for an account over at Assembla and must say I’m pretty impressed. It’s a website that offers free hosting of user managed source control using SVN. The free accounts can store up to 250MB of source (that’s alot) and open source/volunteer projects can be eligible receive their commercial accounts for free.

Aside from hosting source code it allows many full featured areas of project management from bug and ticket tracking, contionous integration connectivity, project wiki, file hosting and so on. This website is quite amazingly actually for how much it offers.

I will be hosting the source I include with my blog (starting with TaskScheduler) on Assembla. I have set up my space with public view access so you should be able to grab my source with no problems. Should anyone wish to contribute back to the source contact me and I will gladly add you to edit access. I will be adding a page for Assembla along with all my links to it.

http://www.assembla.com/wiki/show/MarisicDotNet

BloggingContext.ApplicationInstance.CompleteRequest();