Exemple #1
0
 internal static extern bool CreateProcess(string lpApplicationName,
    string lpCommandLine, IntPtr lpProcessAttributes,
    IntPtr lpThreadAttributes, bool bInheritHandles,
    uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
    [In] ref STARTUPINFO lpStartupInfo,
    out PROCESS_INFORMATION lpProcessInformation);
Exemple #2
0
        // ReSharper disable once InconsistentNaming
        public static void Run(string[] _args, ServiceDescriptor descriptor = null)
        {
            if (_args.Length > 0)
            {
                var d = descriptor ?? new ServiceDescriptor();
                var svc = new WmiRoot().GetCollection<Win32Services>();
                var s = svc.Select(d.Id);

                var args = new List<string>(Array.AsReadOnly(_args));
                if (args[0] == "/redirect")
                {
                    // Redirect output
                    // One might ask why we support this when the caller
                    // can redirect the output easily. The answer is for supporting UAC.
                    // On UAC-enabled Windows such as Vista, SCM operation requires
                    // elevated privileges, thus winsw.exe needs to be launched
                    // accordingly. This in turn limits what the caller can do,
                    // and among other things it makes it difficult for the caller
                    // to read stdout/stderr. Thus redirection becomes handy.
                    var f = new FileStream(args[1], FileMode.Create);
                    var w = new StreamWriter(f) {AutoFlush = true};
                    Console.SetOut(w);
                    Console.SetError(w);

                    var handle = f.Handle;
                    Kernel32.SetStdHandle(-11, handle); // set stdout
                    Kernel32.SetStdHandle(-12, handle); // set stder

                    args = args.GetRange(2, args.Count - 2);
                }

                args[0] = args[0].ToLower();
                if (args[0] == "install")
                {
                    // Check if the service exists
                    if (s != null)
                    {
                        Console.WriteLine("Service with id '" + d.Id + "' already exists");
                        Console.WriteLine(
                            "To install the service, delete the existing one or change service Id in the configuration file");
                        throw new Exception("Installation failure: Service with id '" + d.Id + "' already exists");
                    }

                    string username = null, password = null;
                    var setallowlogonasaserviceright = false;
                    if (args.Count > 1 && args[1] == "/p")
                    {
                        // we expected username/password on stdin
                        Console.Write("Username: "******"Password: "******"Set Account rights to allow log on as a service (y/n)?: ");
                        var keypressed = Console.ReadKey();
                        Console.WriteLine();
                        if (keypressed.Key == ConsoleKey.Y)
                        {
                            setallowlogonasaserviceright = true;
                        }
                    }
                    else
                    {
                        if (d.HasServiceAccount())
                        {
                            username = d.ServiceAccountUser;
                            password = d.ServiceAccountPassword;
                            setallowlogonasaserviceright = d.AllowServiceAcountLogonRight;
                        }
                    }

                    if (setallowlogonasaserviceright)
                    {
                        LogonAsAService.AddLogonAsAServiceRight(username);
                    }

                    svc.Create(
                        d.Id,
                        d.Caption,
                        "\"" + d.ExecutablePath + "\"",
                        ServiceType.OwnProcess,
                        ErrorControl.UserNotified,
                        d.StartMode,
                        d.Interactive,
                        username,
                        password,
                        d.ServiceDependencies);

                    // update the description
                    /* Somehow this doesn't work, even though it doesn't report an error
                    Win32Service s = svc.Select(d.Id);
                    s.Description = d.Description;
                    s.Commit();
                     */

                    // so using a classic method to set the description. Ugly.
                    Registry.LocalMachine.OpenSubKey("System").OpenSubKey("CurrentControlSet").OpenSubKey("Services")
                        .OpenSubKey(d.Id, true).SetValue("Description", d.Description);

                    var actions = d.FailureActions;
                    if (actions.Count > 0)
                    {
            // set the failure actions
                        using (var scm = new ServiceManager())
                        {
                            using (var sc = scm.Open(d.Id))
                            {
                                sc.ChangeConfig(d.ResetFailureAfter, actions);
                            }
                        }
                    }
                    return;
                }
                if (args[0] == "uninstall")
                {
                    if (s == null)
                    {
                        Console.WriteLine("Warning! The service with id '" + d.Id +
                                          "' does not exist. Nothing to uninstall");
                        return; // there's no such service, so consider it already uninstalled
                    }
                    try
                    {
                        s.Delete();
                    }
                    catch (WmiException e)
                    {
                        if (e.ErrorCode == ReturnValue.ServiceMarkedForDeletion)
                            return; // it's already uninstalled, so consider it a success
                        throw e;
                    }
                    return;
                }
                if (args[0] == "start")
                {
                    if (s == null) ThrowNoSuchService();
                    s.StartService();
                    return;
                }
                if (args[0] == "stop")
                {
                    if (s == null) ThrowNoSuchService();
                    s.StopService();
                    return;
                }
                if (args[0] == "restart")
                {
                    if (s == null)
                        ThrowNoSuchService();

                    if (s.Started)
                        s.StopService();

                    while (s.Started)
                    {
                        Thread.Sleep(1000);
                        s = svc.Select(d.Id);
                    }

                    s.StartService();
                    return;
                }
                if (args[0] == "restart!")
                {
                    // run restart from another process group. see README.md for why this is useful.

                    var si = new STARTUPINFO();
                    var pi = new PROCESS_INFORMATION();

                    var result = Kernel32.CreateProcess(null, d.ExecutablePath + " restart", IntPtr.Zero, IntPtr.Zero,
                        false, 0x200 /*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out pi);
                    if (!result)
                    {
                        throw new Exception("Failed to invoke restart: " + Marshal.GetLastWin32Error());
                    }
                    return;
                }
                if (args[0] == "status")
                {
                    if (s == null)
                        Console.WriteLine("NonExistent");
                    else if (s.Started)
                        Console.WriteLine("Started");
                    else
                        Console.WriteLine("Stopped");
                    return;
                }
                if (args[0] == "test")
                {
                    var wsvc = new WrapperService();
                    wsvc.OnStart(args.ToArray());
                    Thread.Sleep(1000);
                    wsvc.OnStop();
                    return;
                }
                if (args[0] == "help" || args[0] == "--help" || args[0] == "-h"
                    || args[0] == "-?" || args[0] == "/?")
                {
                    printHelp();
                    return;
                }
                if (args[0] == "version")
                {
                    printVersion();
                    return;
                }

                Console.WriteLine("Unknown command: " + args[0]);
                printAvailableCommandsInfo();
                throw new Exception("Unknown command: " + args[0]);
            }
            Run(new WrapperService());
        }
Exemple #3
0
 internal static extern bool CreateProcess(string lpApplicationName,
                                           string lpCommandLine, IntPtr lpProcessAttributes,
                                           IntPtr lpThreadAttributes, bool bInheritHandles,
                                           uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
                                           [In] ref STARTUPINFO lpStartupInfo,
                                           out PROCESS_INFORMATION lpProcessInformation);
Exemple #4
0
        // ReSharper disable once InconsistentNaming
        /// <summary>
        /// Runs the wrapper.
        /// </summary>
        /// <param name="_args">Arguments. If empty, WinSW will behave in the service mode. Otherwise - CLI mode</param>
        /// <param name="descriptor">Service descriptor. If null, it will be initialized within the method.
        ///                          In such case configs will be loaded from the XML Configuration File.</param>
        /// <exception cref="Exception">Any unhandled exception</exception>
        public static void Run(string[] _args, ServiceDescriptor descriptor = null)
        {
            bool isCLIMode = _args.Length > 0;


            // If descriptor is not specified, initialize the new one (and load configs from there)
            var d = descriptor ?? new ServiceDescriptor();

            // Configure the wrapper-internal logging.
            // STDIN and STDOUT of the child process will be handled independently.
            InitLoggers(d, isCLIMode);


            if (isCLIMode) // CLI mode, in-service mode otherwise
            {
                Log.Info("Starting ServiceWrapper in the CLI mode");

                // Get service info for the future use
                Win32Services svc = new WmiRoot().GetCollection <Win32Services>();
                Win32Service  s   = svc.Select(d.Id);

                var args = new List <string>(Array.AsReadOnly(_args));
                if (args[0] == "/redirect")
                {
                    // Redirect output
                    // One might ask why we support this when the caller
                    // can redirect the output easily. The answer is for supporting UAC.
                    // On UAC-enabled Windows such as Vista, SCM operation requires
                    // elevated privileges, thus winsw.exe needs to be launched
                    // accordingly. This in turn limits what the caller can do,
                    // and among other things it makes it difficult for the caller
                    // to read stdout/stderr. Thus redirection becomes handy.
                    var f = new FileStream(args[1], FileMode.Create);
                    var w = new StreamWriter(f)
                    {
                        AutoFlush = true
                    };
                    Console.SetOut(w);
                    Console.SetError(w);

                    var handle = f.Handle;
                    Kernel32.SetStdHandle(-11, handle); // set stdout
                    Kernel32.SetStdHandle(-12, handle); // set stder

                    args = args.GetRange(2, args.Count - 2);
                }

                args[0] = args[0].ToLower();
                if (args[0] == "install")
                {
                    // Check if the service exists
                    if (s != null)
                    {
                        Console.WriteLine("Service with id '" + d.Id + "' already exists");
                        Console.WriteLine("To install the service, delete the existing one or change service Id in the configuration file");
                        throw new Exception("Installation failure: Service with id '" + d.Id + "' already exists");
                    }

                    string username = null, password = null;
                    bool   setallowlogonasaserviceright = false;
                    if (args.Count > 1 && args[1] == "/p")
                    {
                        // we expected username/password on stdin
                        Console.Write("Username: "******"Password: "******"Set Account rights to allow log on as a service (y/n)?: ");
                        var keypressed = Console.ReadKey();
                        Console.WriteLine();
                        if (keypressed.Key == ConsoleKey.Y)
                        {
                            setallowlogonasaserviceright = true;
                        }
                    }
                    else
                    {
                        if (d.HasServiceAccount())
                        {
                            username = d.ServiceAccountUser;
                            password = d.ServiceAccountPassword;
                            setallowlogonasaserviceright = d.AllowServiceAcountLogonRight;
                        }
                    }

                    if (setallowlogonasaserviceright)
                    {
                        LogonAsAService.AddLogonAsAServiceRight(username);
                    }

                    svc.Create(
                        d.Id,
                        d.Caption,
                        "\"" + d.ExecutablePath + "\"",
                        ServiceType.OwnProcess,
                        ErrorControl.UserNotified,
                        d.StartMode,
                        d.Interactive,
                        username,
                        password,
                        d.ServiceDependencies);

                    // update the description

                    /* Somehow this doesn't work, even though it doesn't report an error
                     * Win32Service s = svc.Select(d.Id);
                     * s.Description = d.Description;
                     * s.Commit();
                     */

                    // so using a classic method to set the description. Ugly.
                    Registry.LocalMachine.OpenSubKey("System").OpenSubKey("CurrentControlSet").OpenSubKey("Services")
                    .OpenSubKey(d.Id, true).SetValue("Description", d.Description);

                    var actions = d.FailureActions;
                    if (actions.Count > 0)
                    {// set the failure actions
                        using (ServiceManager scm = new ServiceManager())
                        {
                            using (Service sc = scm.Open(d.Id))
                            {
                                sc.ChangeConfig(d.ResetFailureAfter, actions);
                            }
                        }
                    }
                    return;
                }
                if (args[0] == "uninstall")
                {
                    if (s == null)
                    {
                        Console.WriteLine("Warning! The service with id '" + d.Id + "' does not exist. Nothing to uninstall");
                        return; // there's no such service, so consider it already uninstalled
                    }
                    try
                    {
                        s.Delete();
                    }
                    catch (WmiException e)
                    {
                        if (e.ErrorCode == ReturnValue.ServiceMarkedForDeletion)
                        {
                            return; // it's already uninstalled, so consider it a success
                        }
                        throw e;
                    }
                    return;
                }
                if (args[0] == "start")
                {
                    if (s == null)
                    {
                        ThrowNoSuchService();
                    }
                    s.StartService();
                    return;
                }
                if (args[0] == "stop")
                {
                    if (s == null)
                    {
                        ThrowNoSuchService();
                    }
                    s.StopService();
                    return;
                }
                if (args[0] == "restart")
                {
                    if (s == null)
                    {
                        ThrowNoSuchService();
                    }

                    if (s.Started)
                    {
                        s.StopService();
                    }

                    while (s.Started)
                    {
                        Thread.Sleep(1000);
                        s = svc.Select(d.Id);
                    }

                    s.StartService();
                    return;
                }
                if (args[0] == "restart!")
                {
                    // run restart from another process group. see README.md for why this is useful.

                    STARTUPINFO         si = new STARTUPINFO();
                    PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

                    bool result = Kernel32.CreateProcess(null, d.ExecutablePath + " restart", IntPtr.Zero, IntPtr.Zero, false, 0x200 /*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out pi);
                    if (!result)
                    {
                        throw new Exception("Failed to invoke restart: " + Marshal.GetLastWin32Error());
                    }
                    return;
                }
                if (args[0] == "status")
                {
                    Log.Warn("User requested the status");
                    if (s == null)
                    {
                        Console.WriteLine("NonExistent");
                    }
                    else if (s.Started)
                    {
                        Console.WriteLine("Started");
                    }
                    else
                    {
                        Console.WriteLine("Stopped");
                    }
                    return;
                }
                if (args[0] == "test")
                {
                    WrapperService wsvc = new WrapperService();
                    wsvc.OnStart(args.ToArray());
                    Thread.Sleep(1000);
                    wsvc.OnStop();
                    return;
                }
                if (args[0] == "help" || args[0] == "--help" || args[0] == "-h" ||
                    args[0] == "-?" || args[0] == "/?")
                {
                    printHelp();
                    return;
                }
                if (args[0] == "version")
                {
                    printVersion();
                    return;
                }

                Console.WriteLine("Unknown command: " + args[0]);
                printAvailableCommandsInfo();
                throw new Exception("Unknown command: " + args[0]);
            }
            else
            {
                Log.Info("Starting ServiceWrapper in the service mode");
            }
            Run(new WrapperService());
        }
Exemple #5
0
        public static void Run(string[] _args)
        {
            if (_args.Length > 0)
            {
                var           d   = new ServiceDescriptor();
                Win32Services svc = new WmiRoot().GetCollection <Win32Services>();
                Win32Service  s   = svc.Select(d.Id);

                var args = new List <string>(Array.AsReadOnly(_args));
                if (args[0] == "/redirect")
                {
                    // Redirect output
                    // One might ask why we support this when the caller
                    // can redirect the output easily. The answer is for supporting UAC.
                    // On UAC-enabled Windows such as Vista, SCM operation requires
                    // elevated privileges, thus winsw.exe needs to be launched
                    // accordingly. This in turn limits what the caller can do,
                    // and among other things it makes it difficult for the caller
                    // to read stdout/stderr. Thus redirection becomes handy.
                    var f = new FileStream(args[1], FileMode.Create);
                    var w = new StreamWriter(f);
                    w.AutoFlush = true;
                    Console.SetOut(w);
                    Console.SetError(w);

                    var handle = f.Handle;
                    Kernel32.SetStdHandle(-11, handle); // set stdout
                    Kernel32.SetStdHandle(-12, handle); // set stder

                    args = args.GetRange(2, args.Count - 2);
                }

                args[0] = args[0].ToLower();
                if (args[0] == "install")
                {
                    string username = null, password = null;
                    if (args.Count > 1 && args[1] == "/p")
                    {
                        // we expected username/password on stdin
                        Console.Write("Username: "******"Password: "******"\"" + d.ExecutablePath + "\"",
                        WMI.ServiceType.OwnProcess,
                        ErrorControl.UserNotified,
                        StartMode.Automatic,
                        d.Interactive,
                        username,
                        password,
                        d.ServiceDependencies);

                    // update the description

                    /* Somehow this doesn't work, even though it doesn't report an error
                     * Win32Service s = svc.Select(d.Id);
                     * s.Description = d.Description;
                     * s.Commit();
                     */

                    // so using a classic method to set the description. Ugly.
                    Registry.LocalMachine.OpenSubKey("System").OpenSubKey("CurrentControlSet").OpenSubKey("Services")
                    .OpenSubKey(d.Id, true).SetValue("Description", d.Description);

                    var actions = d.FailureActions;
                    if (actions.Count > 0)
                    {// set the failure actions
                        using (ServiceManager scm = new ServiceManager())
                        {
                            using (Service sc = scm.Open(d.Id))
                            {
                                sc.ChangeConfig(d.ResetFailureAfter, actions);
                            }
                        }
                    }
                }
                if (args[0] == "uninstall")
                {
                    if (s == null)
                    {
                        return; // there's no such service, so consider it already uninstalled
                    }
                    try
                    {
                        s.Delete();
                    }
                    catch (WmiException e)
                    {
                        if (e.ErrorCode == ReturnValue.ServiceMarkedForDeletion)
                        {
                            return; // it's already uninstalled, so consider it a success
                        }
                        throw e;
                    }
                }
                if (args[0] == "start")
                {
                    if (s == null)
                    {
                        ThrowNoSuchService();
                    }
                    s.StartService();
                }
                if (args[0] == "stop")
                {
                    if (s == null)
                    {
                        ThrowNoSuchService();
                    }
                    s.StopService();
                }
                if (args[0] == "restart")
                {
                    if (s == null)
                    {
                        ThrowNoSuchService();
                    }

                    if (s.Started)
                    {
                        s.StopService();
                    }

                    while (s.Started)
                    {
                        Thread.Sleep(1000);
                        s = svc.Select(d.Id);
                    }

                    s.StartService();
                }
                if (args[0] == "restart!")
                {
                    // run restart from another process group. see README.md for why this is useful.

                    STARTUPINFO         si = new STARTUPINFO();
                    PROCESS_INFORMATION pi = new PROCESS_INFORMATION();

                    bool result = Kernel32.CreateProcess(null, d.ExecutablePath + " restart", IntPtr.Zero, IntPtr.Zero, false, 0x200 /*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out pi);
                    if (!result)
                    {
                        throw new Exception("Failed to invoke restart: " + Marshal.GetLastWin32Error());
                    }
                }
                if (args[0] == "status")
                {
                    if (s == null)
                    {
                        Console.WriteLine("NonExistent");
                    }
                    else if (s.Started)
                    {
                        Console.WriteLine("Started");
                    }
                    else
                    {
                        Console.WriteLine("Stopped");
                    }
                }
                if (args[0] == "test")
                {
                    WrapperService wsvc = new WrapperService();
                    wsvc.OnStart(args.ToArray());
                    Thread.Sleep(1000);
                    wsvc.OnStop();
                }
                return;
            }
            ServiceBase.Run(new WrapperService());
        }