visual studio services open msc crear control windows-services

windows services - studio - ¿Cómo puedo detener/iniciar programáticamente un servicio de Windows en una caja remota?



windows services control panel (9)

Aquí hay una ServiceExtension que puede iniciar y detener servicios en las PC remotas.

Y puede establecer el tipo de inicio del servicio, incluso a "automático (retrasado)"

versión modificada de esta Answer para trabajar en máquinas remotas.

using System; using System.ComponentModel; using System.Runtime.InteropServices; using System.ServiceProcess; namespace Helpers { public enum ServiceStartModeEx { Automatic = 2, Manual = 3, Disabled = 4, DelayedAutomatic = 99 } /// <summary> /// Extensions to the ServiceController class. /// </summary> public static class ServiceControlerExtensions { /// <summary> /// Set the start mode for the service. /// </summary> /// <param name="serviceController">The service controller.</param> /// <param name="mode">The desired start mode.</param> public static void SetStartMode(this ServiceController serviceController, ServiceStartModeEx mode) { IntPtr serviceManagerHandle = OpenServiceManagerHandle(serviceController); IntPtr serviceHandle = OpenServiceHandle(serviceController, serviceManagerHandle); try { if (mode == ServiceStartModeEx.DelayedAutomatic) { ChangeServiceStartType(serviceHandle, ServiceStartModeEx.Automatic); ChangeDelayedAutoStart(serviceHandle, true); } else { // Delayed auto-start overrides other settings, so it must be set first. ChangeDelayedAutoStart(serviceHandle, false); ChangeServiceStartType(serviceHandle, mode); } } finally { if (serviceHandle != IntPtr.Zero) { CloseServiceHandle(serviceHandle); } if (serviceManagerHandle != IntPtr.Zero) { CloseServiceHandle(serviceManagerHandle); } } } private static IntPtr OpenServiceHandle(ServiceController serviceController, IntPtr serviceManagerHandle) { var serviceHandle = OpenService( serviceManagerHandle, serviceController.ServiceName, SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG); if (serviceHandle == IntPtr.Zero) { throw new ExternalException("Open Service Error"); } return serviceHandle; } private static IntPtr OpenServiceManagerHandle(ServiceController serviceController) { var machineName = string.IsNullOrWhiteSpace(serviceController.MachineName) ? null : serviceController.MachineName; IntPtr serviceManagerHandle = OpenSCManager(machineName, null, SC_MANAGER_ALL_ACCESS); if (serviceManagerHandle == IntPtr.Zero) { throw new ExternalException("Open Service Manager Error"); } return serviceManagerHandle; } private static void ChangeServiceStartType(IntPtr serviceHandle, ServiceStartModeEx mode) { bool result = ChangeServiceConfig( serviceHandle, SERVICE_NO_CHANGE, (uint)mode, SERVICE_NO_CHANGE, null, null, IntPtr.Zero, null, null, null, null); if (result == false) { ThrowLastWin32Error("Could not change service start type"); } } private static void ChangeDelayedAutoStart(IntPtr hService, bool delayed) { // Create structure that contains DelayedAutoStart property. SERVICE_DELAYED_AUTO_START_INFO info = new SERVICE_DELAYED_AUTO_START_INFO(); // Set the DelayedAutostart property in that structure. info.fDelayedAutostart = delayed; // Allocate necessary memory. IntPtr hInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SERVICE_DELAYED_AUTO_START_INFO))); // Convert structure to pointer. Marshal.StructureToPtr(info, hInfo, true); // Change the configuration. bool result = ChangeServiceConfig2(hService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, hInfo); // Release memory. Marshal.FreeHGlobal(hInfo); if (result == false) { ThrowLastWin32Error("Could not set service to delayed automatic"); } } private static void ThrowLastWin32Error(string messagePrefix) { int nError = Marshal.GetLastWin32Error(); var win32Exception = new Win32Exception(nError); string message = string.Format("{0}: {1}", messagePrefix, win32Exception.Message); throw new ExternalException(message); } [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern IntPtr OpenService( IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess); [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr OpenSCManager( string machineName, string databaseName, uint dwAccess); [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern Boolean ChangeServiceConfig( IntPtr hService, UInt32 nServiceType, UInt32 nStartType, UInt32 nErrorControl, String lpBinaryPathName, String lpLoadOrderGroup, IntPtr lpdwTagId, [In] char[] lpDependencies, String lpServiceStartName, String lpPassword, String lpDisplayName); [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool ChangeServiceConfig2( IntPtr hService, int dwInfoLevel, IntPtr lpInfo); [DllImport("advapi32.dll", EntryPoint = "CloseServiceHandle")] private static extern int CloseServiceHandle(IntPtr hSCObject); private const uint SERVICE_NO_CHANGE = 0xFFFFFFFF; private const uint SERVICE_QUERY_CONFIG = 0x00000001; private const uint SERVICE_CHANGE_CONFIG = 0x00000002; private const uint SC_MANAGER_ALL_ACCESS = 0x000F003F; private const int SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct SERVICE_DELAYED_AUTO_START_INFO { public bool fDelayedAutostart; } } }

Puedes comenzar un servicio como este

using System.ServiceProcess;

serviceName = "el nombre del servicio"

machineName = "el nombre del host remoto / local"

var service = new ServiceController(serviceName, machineName); try { service.SetStartMode(ServiceStartModeEx.DelayedAutomatic); service.Start(); } finally { service.Close(); }

Puede detener un servicio como este

var service = new ServiceController(serviceName, machineName); try { if (service.CanStop) { service.SetStartMode(ServiceStartModeEx.Disabled); service.Stop(); } } finally { service.Close(); }

Para otorgar derechos de usuario para iniciar y detener un servicio en una PC remota, debe establecer algunos derechos de servicio, puede buscar en google qué es subinacl.exe y dónde descargarlo.

C:/Program Files (x86)/Windows Resource Kits/Tools>subinacl.exe /service SERVICENAME /grant=MACHINENAME/USERNAME=F

Quiero escribir una consola o hacer clic en una aplicación WinForms que detendrá y / o iniciará un servicio de Windows en una caja remota.

Ambos cuadros ejecutan .NET 3.5. ¿Qué API .NET están disponibles para lograr esto?


Cª#:

var sc = new System.ServiceProcess.ServiceController("MyService", "MyRemoteMachine"); sc.Start(); sc.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Running); sc.Stop(); sc.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Stopped);


El fragmento de código de galets anterior es un gran comienzo. Sin embargo, tenga en cuenta que asume que el servicio ya ha comenzado o, lo que es más importante, que

sc.Status == System.ServiceProcess.ServiceControllerStatus.Running

Además, puede ser importante que, en algún momento durante la ejecución del código, llame

sc.Refresh();

porque los valores de las propiedades (como ServiceControllerStatus) pueden no reflejar las propiedades reales del servicio. Por ejemplo, puede llamar

sc.Start();

y espera indefinidamente cuando se ejecuta este comando

sc.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Running)

Aquí hay una versión de este código que codifiqué con esas consideraciones en mente.

//Restart Content Service on DEV. String svcName = "TheServiceName"; String machineName = "TheMachineName"; var sc = new System.ServiceProcess.ServiceController(svcName, machineName); Console.WriteLine("Stopping Service ''{0}'' on machine ''{1}", svcName, machineName); sc.Stop(); sc.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Stopped); //sc.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Running); do { try { sc.Refresh(); if (sc.Status == System.ServiceProcess.ServiceControllerStatus.Running) { Console.WriteLine("Code has detected that servive start is pending, waiting 5 seconds to see if status changes.."); System.Threading.Thread.Sleep(5000); } else { Console.WriteLine("waiting 5 seconds and retrying start.."); System.Threading.Thread.Sleep(5000); Console.WriteLine("Attempt Starting Service ''{0}'' on machine ''{1}", svcName, machineName); sc.Start(); } } catch(Exception ex) { //If it is already running, then abort do while if (ex.InnerException.Message == "An instance of the service is already running") { Console.WriteLine(ex.InnerException.Message); continue; } Console.WriteLine(ex.InnerException.ToString()); } } while (sc.Status != System.ServiceProcess.ServiceControllerStatus.Running);


He hecho lo siguiente:

Nota:

  1. Si no comenzó su servicio si está tratando de detenerlo, arrojará una excepción.
  2. Si configura estas cosas en su web.config, la excepción relacionada con la configuración no vendrá. No hay necesidad de hacer nada en IIS.

En Web.Config en <configuration>

<appSettings> <add key="ServiceName" value="YourServiceName" /> <add key="MachineName" value="YourMachineName" /> </appSettings> <system.web> <authentication mode="Windows"/> <identity impersonate="true" userName="YourUserName" password="YourPassword"/> </system.web>

En mi clase de servicio:

private void RestartService() { string serviceName = System.Configuration.ConfigurationSettings.AppSettings["ServiceName"]; string machineName = System.Configuration.ConfigurationSettings.AppSettings["MachineName"]; try { var service = new ServiceController(serviceName); if (service.Status != ServiceControllerStatus.Stopped) { service.Stop(); service.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Stopped); } service.Start(); service.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Running); } catch (Exception) { } }

Espero que esto ayude.,


Puede usar System.Management API (WMI) para controlar servicios de forma remota. WMI es la API genérica para realizar tareas administrativas.

Sin embargo, para este problema, le sugiero que use la clase System.ServiceProcess.ServiceController más fácil de usar.


Si no desea codificarlo usted mismo, PsService by Microsoft / Sysinternals es una herramienta de línea de comandos que hace lo que quiere.


También puede hacer esto desde una consola de comandos utilizando el comando sc :

sc <server> start [service name] sc <server> stop [service name]

Utilizar

sc <server> query | find "SERVICE_NAME"

para obtener una lista de nombres de servicios.

La opción <server> tiene la forma //ServerName

Ejemplo

sc //MyServer stop schedule detendrá el servicio del Programador.


si necesita obtener el nombre del Servicio:

ejecutar esto desde la línea de comando:

consulta sc

Verá, por ejemplo, que el nombre de servicio de SQL Server es ''MSSQL $ SQLEXPRESS''.

Entonces, para detener el servicio de SQL Server en C #:

ServiceController controller = new ServiceController(); controller.MachineName = "Machine1"; controller.ServiceName = "MSSQL$SQLEXPRESS"; if(controller.Status == ServiceControllerStatus.Running) controller.Stop(); controller.WaitForStatus(ServiceControllerStatus.Stopped);


ServiceController .

Debe tener permiso para administrar los servicios en el cuadro remoto.

Como dice Mehrdad, también puedes usar WMI. Ambos métodos funcionan para iniciar y detener, pero WMI requiere más codificación y le dará más acceso a otros recursos