root/TaskScheduler/TaskScheduler/Tasks/ServiceUpTask.cs

User picture

Author: marisic.net

Revision: 112 («Previous)


File Size: 5.78 KB

(September 25, 2008 18:33 UTC) Over 3 years ago


  

 
Show/hide line numbers
#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")]
    [DebuggerDisplay("Name = {Name}, Id = {Id}, LastRan = {LastRan}")]
    public class ServiceUpTask : ITask
    {
        public string ServiceName { get; set; }
        public string UserName { get; set; }
        public string DomainName { get; set; }
        public string Password { get; set; }
        public string MachineName { get; set; }

        #region Overrides of Task

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

                try
                {
                    impersonationContext = AssumeIdentity(UserName, DomainName, Password);

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


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

                        service.Refresh();

                        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>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="ITask"/> is active.
        /// </summary>
        /// <value><c>true</c> if active; otherwise, <c>false</c>.</value>
        public bool Active { get; set; }

        /// <summary>
        /// Gets or sets the last ran.
        /// </summary>
        /// <value>The last ran.</value>
        public DateTime? LastRan { get; set; }

        /// <summary>
        /// Gets or sets the id.
        /// </summary>
        /// <value>The id.</value>
        public decimal? Id { get; set; }

        /// <summary>
        /// Builds the service.
        /// </summary>
        /// <param name="serviceName">Name of the service.</param>
        /// <param name="machineName">Name of the machine.</param>
        /// <returns></returns>
        private static ServiceController ServiceBuilder(string serviceName, string machineName)
        {
            ServiceController service = string.IsNullOrEmpty(machineName) ? new ServiceController(serviceName) : new ServiceController(serviceName, machineName);
            return service;
        }


        ///<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);
                    WindowsImpersonationContext 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);
    }
}