Cómo verificar si un servicio de Windows está instalado en C #

79

Escribí un servicio de Windows que expone un servicio WCF a una GUI instalada en la misma máquina. Cuando ejecuto la GUI, si no puedo conectarme al servicio, necesito saber si es porque la aplicación del servicio aún no se ha instalado o si el servicio no se está ejecutando. Si es el primero, querré instalarlo (como se describe aquí ); si es lo último, querré ponerlo en marcha.

La pregunta es: ¿cómo detecta si el servicio está instalado, y luego de haber detectado que está instalado, cómo lo inicia?

Shaul Behr
fuente

Respuestas:

147

Utilizar:

// add a reference to System.ServiceProcess.dll
using System.ServiceProcess;

// ...
ServiceController ctl = ServiceController.GetServices()
    .FirstOrDefault(s => s.ServiceName == "myservice");
if(ctl==null)
    Console.WriteLine("Not installed");
else    
    Console.WriteLine(ctl.Status);
Aliostad
fuente
Gracias, ¡justo lo que necesitaba!
Shaul Behr
1
usando (var sc = ServiceController.GetServices (). FirstOrDefault (s => s.ServiceName == "myservice")) - Creo que este es un mejor enfoque.
Alexandru Dicu
4
@alexandrudicu: ¿Cómo es ese un mejor enfoque? Si .GetServices()devuelve 100 ServiceControllerobjetos y ha eliminado uno de los cien ignorando el resto, ¿es realmente sensiblemente mejor? Yo mismo no diría eso.
Allon Guralnek
37

También podría utilizar lo siguiente ...

using System.ServiceProcess; 
... 
var serviceExists = ServiceController.GetServices().Any(s => s.ServiceName == serviceName);
Simon Oliver Hurley
fuente
3
En mi opinión, esta es la forma más elegante de comprobar si su servicio existe. Solo una línea de código, aprovechando el poder de Linq. Y, por cierto, .Any () devuelve un bool que es exactamente lo que quieres cuando haces una pregunta de sí / no :-)
Alex X.
3
Si necesita verificar los servicios en una máquina remota, useGetServices(string)
ShooShoSha
7

Realmente haciendo un bucle así:

foreach (ServiceController SC in ServiceController.GetServices())

puede lanzar la excepción Acceso denegado si la cuenta bajo la cual se ejecuta su aplicación no tiene derechos para ver las propiedades del servicio. Por otro lado, puede hacer esto de manera segura incluso si no existe ningún servicio con ese nombre:

ServiceController SC = new ServiceController("AnyServiceName");

Pero acceder a sus propiedades si el servicio no existe resultará en InvalidOperationException. Entonces, aquí hay una forma segura de verificar si un servicio está instalado:

ServiceController SC = new ServiceController("MyServiceName");
bool ServiceIsInstalled = false;
try
{
    // actually we need to try access ANY of service properties
    // at least once to trigger an exception
    // not neccessarily its name
    string ServiceName = SC.DisplayName;
    ServiceIsInstalled = true;
}
catch (InvalidOperationException) { }
finally
{
    SC.Close();
}
ttaaoossuu
fuente
¡Gracias! y querría terminar con: finalmente {SC.Close (); }
Cel
6
¿Por qué no envolver todo en el uso? Eso eliminará la necesidad de finalmente {SC.Close ()} ya que una instrucción using se eliminará automáticamente. usando (ServiceController SC = new ServiceController ("MyServiceName"))
factura el
2

Para no linq, puede iterar a través de la matriz de esta manera:

using System.ServiceProcess;

bool serviceExists = false
foreach (ServiceController sc in ServiceController.GetServices())
{
    if (sc.ServiceName == "myServiceName")
    {
         //service is found
         serviceExists = true;
         break;
    }
}
ZTAN
fuente
1

Creo que esta es la mejor respuesta para esta pregunta. No es necesario agregar procesamiento adicional para verificar si el servicio existe, ya que lanzará una excepción si no lo hace. Solo necesitas atraparlo. Tampoco es necesario cerrar () la conexión si envuelve todo el método en using ().

using (ServiceController sc = new ServiceController(ServiceName))
{
 try
 {
  if (sc.Status != ServiceControllerStatus.Running)
  {
    sc.Start();
    sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 10));
    //service is now Started        
  }      
  else
    //Service was already started
 }
 catch (System.ServiceProcess.TimeoutException)
 {
  //Service was stopped but could not restart (10 second timeout)
 }
 catch (InvalidOperationException)
 {
   //This Service does not exist       
 }     
}
cuenta
fuente
2
No es una muy buena respuesta en absoluto. (1) La gestión del código mediante excepciones es una práctica muy mala: ineficaz y lenta, y (2) la respuesta aceptada es clara, concisa y responde perfectamente a los requisitos. ¿Lo miró antes de sumergirse en su propia respuesta?
Shaul Behr
Aparentemente, no sabe cómo leer la respuesta aceptada, ya que también preguntó claramente cómo iniciar el servicio, que no estaba incluido en la respuesta original.
factura el
Aparentemente, no sabe cómo escribir código correctamente. Como ya dijo @Shaul Behr, su enfoque es una mala práctica, ya que es ineficiente y lento. Es probable que decir tu propia respuesta sea lo mejor, lo empeora aún más: el autoelogio nunca se considera un buen comportamiento aquí en SO (y probablemente en todo el mundo también).
Yoda
1
Al parecer, no sé qué es peor ... Tu incapacidad para usar la gramática adecuada en tu intento de parecer que sabes lo que estás diciendo, o tu incapacidad para darte cuenta de que acabas de comentar en un hilo de 2014 ... Lol.
factura
Esta es la única respuesta que explica lo que sucede si alguien elimina el servicio entre verificar su existencia e interactuar con él
Mike Caron
1
 private bool ServiceExists(string serviceName)
    {
        ServiceController[] services = ServiceController.GetServices();
        var service = services.FirstOrDefault(s => string.Equals(s.ServiceName, serviceName, StringComparison.OrdinalIgnoreCase));
        return service != null;
    }
Ajaya Nayak
fuente