2008-10-14 15 views
41

Actualmente estoy escribiendo un pequeño código de arranque para un servicio que se puede ejecutar en la consola. Básicamente se reduce a llamar al método OnStart() en lugar de usar el ServiceBase para iniciar y detener el servicio (porque no ejecuta la aplicación si no está instalada como un servicio y hace que la depuración sea una pesadilla).Estoy ejecutándose como un servicio

En este momento estoy usando Debugger.IsAttached para determinar si debo usar ServiceBase.Run o [service] .OnStart, pero sé que no es la mejor idea porque algunas veces los usuarios finales quieren ejecutar el servicio de una consola (para ver la salida, etc. en tiempo real).

¿Alguna idea sobre cómo podría determinar si el controlador de servicio de Windows comenzó 'yo', o si el usuario comenzó 'yo' en la consola? Aparentemente Environment.IsUserInteractive no es la respuesta. Pensé en usar argumentos de línea de comando, pero parece "sucio".

Siempre pude ver acerca de una declaración try-catch en ServiceBase.Run, pero parece sucio. Editar: prueba de captura no funciona.

tengo una solución: ponerlo aquí para todos los demás interesados ​​apiladores:

public void Run() 
    { 
     if (Debugger.IsAttached || Environment.GetCommandLineArgs().Contains<string>("-console")) 
     { 
      RunAllServices(); 
     } 
     else 
     { 
      try 
      { 
       string temp = Console.Title; 
       ServiceBase.Run((ServiceBase[])ComponentsToRun); 
      } 
      catch 
      { 
       RunAllServices(); 
      } 
     } 
    } // void Run 

    private void RunAllServices() 
    { 
     foreach (ConsoleService component in ComponentsToRun) 
     { 
      component.Start(); 
     } 
     WaitForCTRLC(); 
     foreach (ConsoleService component in ComponentsToRun) 
     { 
      component.Stop(); 
     } 
    } 

EDIT: No había otra pregunta en StackOverflow donde el chico tenía problemas con el Environment.CurrentDirectory ser "C: \ Windows \ System32 "parece que esa puede ser la respuesta. Voy a probar hoy.

+0

Gracias Dor adición de la solución, debe ser una referencia útil. – Ash

+2

No es que IsUserInteractive * no * devuelva falso para aplicaciones de consola, como se indicó en el enlace que proporcionó anteriormente, al menos no en general. Lo estoy usando para ese propósito y nunca tuve ningún problema con él. –

+0

[Aquí está la misma pregunta para C++] (https://stackoverflow.com/questions/1974828/) –

Respuesta

15

como la ceniza, escribo todo el código de procesamiento real en un ensamblado de biblioteca de clases separadas, que luego fue referenciado por el ejecutable del servicio de Windows, así como una aplicación de consola.

Sin embargo, hay ocasiones en las que es útil saber si la biblioteca de clases se está ejecutando en el contexto del ejecutable del servicio o la aplicación de la consola. La forma en que hago esto es reflexionar sobre la clase base de la aplicación de alojamiento. (Lo siento por la VB, pero me imagino que el siguiente podría ser C# -ified con bastante facilidad):

Public Class ExecutionContext 
    ''' <summary> 
    ''' Gets a value indicating whether the application is a windows service. 
    ''' </summary> 
    ''' <value> 
    ''' <c>true</c> if this instance is service; otherwise, <c>false</c>. 
    ''' </value> 
    Public Shared ReadOnly Property IsService() As Boolean 
     Get 
      ' Determining whether or not the host application is a service is 
      ' an expensive operation (it uses reflection), so we cache the 
      ' result of the first call to this method so that we don't have to 
      ' recalculate it every call. 

      ' If we have not already determined whether or not the application 
      ' is running as a service... 
      If IsNothing(_isService) Then 

       ' Get details of the host assembly. 
       Dim entryAssembly As Reflection.Assembly = Reflection.Assembly.GetEntryAssembly 

       ' Get the method that was called to enter the host assembly. 
       Dim entryPoint As System.Reflection.MethodInfo = entryAssembly.EntryPoint 

       ' If the base type of the host assembly inherits from the 
       ' "ServiceBase" class, it must be a windows service. We store 
       ' the result ready for the next caller of this method. 
       _isService = (entryPoint.ReflectedType.BaseType.FullName = "System.ServiceProcess.ServiceBase") 

      End If 

      ' Return the cached result. 
      Return CBool(_isService) 
     End Get 
    End Property 

    Private Shared _isService As Nullable(Of Boolean) = Nothing 
#End Region 
End Class 
+2

No veo cómo podría funcionar si el mismo ensamblado se pudiera ejecutar como una aplicación de consola o como un servicio de Windows ... Assembly.GetEntryAssembly() y Assembly.EntryPoint devuelven los mismos valores en ambos casos. Supongo que solo funciona si ejecuta diferentes ensamblados en los dos casos. –

+0

@DanPorts: nunca he intentado ejecutar el mismo * assembly * como una aplicación de consola y como un servicio de Windows. Sin embargo, a veces es útil compilar el mismo conjunto de clases en una aplicación de cada tipo, en cuyo caso la clase anterior puede ser útil para determinar en qué contexto se está usando. – Kramii

19

Normalmente señalo el servicio de Windows como una aplicación de consola que toma un parámetro de línea de comando de "-console" para ejecutarse como una consola, de lo contrario se ejecuta como un servicio. Para depurarlo, simplemente establezca los parámetros de la línea de comando en las opciones del proyecto en "-console" ¡y listo!

Esto hace que la depuración sea fácil y sencilla, y significa que la aplicación funciona como un servicio por defecto, que es lo que usted querrá.

+3

Así es exactamente como lo hago yo también. Funciona muy bien; el único problema con la depuración es la seguridad (qué cuenta) y la carpeta de trabajo, que son más fáciles de codificar. –

9

Jonathan, no es exactamente la respuesta a su pregunta, pero acabo de terminar de escribir un servicio de Windows y también me di cuenta de la dificultad de la depuración y las pruebas.

Lo resolvió simplemente escribiendo todo el código de procesamiento real en un conjunto de biblioteca de clases separado, que luego fue referenciado por el ejecutable del servicio de Windows, así como una aplicación de consola y un arnés de prueba.

Además de la lógica básica del temporizador, todos los procesos más complejos ocurrieron en el ensamble común y pudieron ser probados/ejecutados bajo demanda de manera increíblemente fácil.

+0

Esta es una información muy útil, supongo que es la forma "correcta" de hacerlo. Ojalá pudieras aceptar dos respuestas :). –

+0

Sin problemas Jonathan, me alegro de que haya sido útil. En estos días trato de seguir este enfoque (ensamblaje de lógica de aplicación por separado) para todas las aplicaciones. De esta forma, un servicio de Windows puede verse como otro tipo de vista en la aplicación. Supongo que este es el patrón de Model View Controller. – Ash

2

La única manera que he encontrado para lograr esto, es comprobar si una consola está conectada al proceso en primer lugar, accediendo a cualquier propiedad del objeto de consola (por ejemplo, Título) dentro de un bloque try/catch.

Si el SCM inicia el servicio, no hay consola, y al acceder a la propiedad lanzará un System.IO.IOError.

Sin embargo, ya que esto se parece demasiado a depender de un detalle específico de implementación (¿qué pasa si el SCM en algunas plataformas o algún día decide proporcionar una consola a los procesos?), Siempre uso una línea de comando switch (-console) en aplicaciones de producción ...

-1

Esto es un autoenchufe, pero tengo una pequeña aplicación que cargará tus tipos de servicio en tu aplicación a través de la reflexión y los ejecutará de esa manera . Incluí el código fuente, por lo que podría cambiarlo ligeramente para mostrar la salida estándar.

No hay cambios de código necesarios para utilizar esta solución. Tengo un depurador.El tipo de solución IsAttached también es lo suficientemente genérica como para ser utilizada con cualquier servicio. Link es en este artículo: .NET Windows Service Runner

+0

De hecho, escribí una clase base para ellos que tiene el método Start(), así no tengo que recurrir a la reflexión. Gracias por el consejo. –

+0

Esto está diseñado para ser una forma independiente de ejecutar cualquier servicio fuera del entorno de servicios de Windows sin cambiar ningún código. Simplemente haga doble clic en el corredor, seleccione su servicio .exe o .dll, y haga clic en Aceptar. Si ejecuta el corredor para la línea de comando, verá IO estándar. –

12

Lo que funciona para mí:

  • La clase haciendo el trabajo real del servicio se ejecuta en un hilo separado.
  • Este subproceso se inicia desde el método OnStart() y se detiene desde OnStop().
  • La decisión entre el servicio y el modo de consola depende de código Environment.UserInteractive

muestra:

class MyService : ServiceBase 
{ 
    private static void Main() 
    { 
     if (Environment.UserInteractive) 
     { 
      startWorkerThread(); 
      Console.WriteLine ("====== Press ENTER to stop threads ======"); 
      Console.ReadLine(); 
      stopWorkerThread() ; 
      Console.WriteLine ("====== Press ENTER to quit ======"); 
      Console.ReadLine(); 
     } 
     else 
     { 
      Run (this) ; 
     } 
    } 

    protected override void OnStart(string[] args) 
    { 
     startWorkerThread(); 
    } 

    protected override void OnStop() 
    { 
     stopWorkerThread() ; 
    } 
} 
+0

Gracias por la sugerencia gyrolf, pero desafortunadamente Environment.UserInteractive solo es cierto para las aplicaciones de Windows Forms :(. –

+6

Según tengo entendido la documentación y el código de muestra que contiene, no hay ninguna restricción para las aplicaciones de Windows Forms. Lo uso con éxito en condiciones normales aplicaciones de consola. – gyrolf

+4

Puedo confirmar que esto es correcto. 'Environment.UserInteractive' es True cuando se ejecuta una consola, y False si se está ejecutando como un servicio. – voithos

3

Tal comprobar si el padre proceso es C: \ Windows \ system32 \ services.exe.

+0

Gracias, intentaré ver si eso funciona. .. –

8

I han modificado el ProjectInstaller para anexar la línea de comandos argumento parámetro/servicio, cuando está siendo instalado como servicio:

static class Program 
{ 
    static void Main(string[] args) 
    { 
     if (Array.Exists(args, delegate(string arg) { return arg == "/install"; })) 
     { 
      System.Configuration.Install.TransactedInstaller ti = null; 
      ti = new System.Configuration.Install.TransactedInstaller(); 
      ti.Installers.Add(new ProjectInstaller()); 
      ti.Context = new System.Configuration.Install.InstallContext("", null); 
      string path = System.Reflection.Assembly.GetExecutingAssembly().Location; 
      ti.Context.Parameters["assemblypath"] = path; 
      ti.Install(new System.Collections.Hashtable()); 
      return; 
     } 

     if (Array.Exists(args, delegate(string arg) { return arg == "/uninstall"; })) 
     { 
      System.Configuration.Install.TransactedInstaller ti = null; 
      ti = new System.Configuration.Install.TransactedInstaller(); 
      ti.Installers.Add(new ProjectInstaller()); 
      ti.Context = new System.Configuration.Install.InstallContext("", null); 
      string path = System.Reflection.Assembly.GetExecutingAssembly().Location; 
      ti.Context.Parameters["assemblypath"] = path; 
      ti.Uninstall(null); 
      return; 
     } 

     if (Array.Exists(args, delegate(string arg) { return arg == "/service"; })) 
     { 
      ServiceBase[] ServicesToRun; 

      ServicesToRun = new ServiceBase[] { new MyService() }; 
      ServiceBase.Run(ServicesToRun); 
     } 
     else 
     { 
      Console.ReadKey(); 
     } 
    } 
} 

Los ProjectInstaller.cs se modifica entonces para anular un OnBeforeInstall() y OnBeforeUninstall()

[RunInstaller(true)] 
public partial class ProjectInstaller : Installer 
{ 
    public ProjectInstaller() 
    { 
     InitializeComponent(); 
    } 

    protected virtual string AppendPathParameter(string path, string parameter) 
    { 
     if (path.Length > 0 && path[0] != '"') 
     { 
      path = "\"" + path + "\""; 
     } 
     path += " " + parameter; 
     return path; 
    } 

    protected override void OnBeforeInstall(System.Collections.IDictionary savedState) 
    { 
     Context.Parameters["assemblypath"] = AppendPathParameter(Context.Parameters["assemblypath"], "/service"); 
     base.OnBeforeInstall(savedState); 
    } 

    protected override void OnBeforeUninstall(System.Collections.IDictionary savedState) 
    { 
     Context.Parameters["assemblypath"] = AppendPathParameter(Context.Parameters["assemblypath"], "/service"); 
     base.OnBeforeUninstall(savedState); 
    } 
} 
+1

El ejemplo anterior no trata las citas correctamente, revise esto para una mejor solución http://stackoverflow.com/questions/4862580/using-installutil-to-install-a-windows-service-with-startup-parameters – Palani

+0

Manejo mejorado de cotizaciones alrededor de la ruta –

24

Otra solución .. por lo que puede funcionar como WinForm o como servicio de windows

var backend = new Backend(); 

if (Environment.UserInteractive) 
{ 
    backend.OnStart(); 
    Application.EnableVisualStyles(); 
    Application.SetCompatibleTextRenderingDefault(false); 
    Application.Run(new Fronend(backend)); 
    backend.OnStop(); 
} 
else 
{ 
    var ServicesToRun = new ServiceBase[] {backend}; 
    ServiceBase.Run(ServicesToRun); 
} 
+5

Me gusta esta solución, parece que es para lo que se diseñó 'Environment.UserInteractive'. –

+1

Me pregunto qué pasaría si ha marcado "Permitir que el servicio interactúe con el escritorio" para ese servicio. Por lo que sé, eso le permitiría al servicio tener una GUI.¿No debería devolver la propiedad de UserInteractive true entonces? [MSDN: la propiedad UserInteractive informa falso para un proceso de Windows o un servicio como IIS que se ejecuta sin una interfaz de usuario.] –

+3

He probado: Cuando marca "Permitir que el servicio interactúe con el escritorio", UserInteractive es verdadero. – csname1910

4

Este hilo es muy antiguo, pero pensé que arrojaría mi solución. Simplemente, para manejar este tipo de situación, construí un "arnés de servicio" que se usa tanto en la consola como en los casos de servicio de Windows. Como se mencionó anteriormente, la mayor parte de la lógica está contenida en una biblioteca separada, pero esto es más para probar y "enlazar".

El código adjunto de ninguna manera representa la "mejor manera posible" de resolver esto, solo mi propio enfoque. Aquí, la aplicación de consola llama al arnés de servicio cuando se encuentra en "modo consola" y por la lógica de "inicio de servicio" de la misma aplicación cuando se ejecuta como un servicio. Al hacerlo de esta manera, ahora se puede llamar

ServiceHost.Instance.RunningAsAService (booleano)

desde cualquier parte del código para comprobar si la aplicación se ejecuta como un servicio o simplemente como una consola.

Aquí está el código:

public class ServiceHost 
{ 
    private static Logger log = LogManager.GetLogger(typeof(ServiceHost).Name); 

    private static ServiceHost mInstance = null; 
    private static object mSyncRoot = new object(); 

    #region Singleton and Static Properties 

    public static ServiceHost Instance 
    { 
     get 
     { 
      if (mInstance == null) 
      { 
       lock (mSyncRoot) 
       { 
        if (mInstance == null) 
        { 
         mInstance = new ServiceHost(); 
        } 
       } 
      } 

      return (mInstance); 
     } 
    } 

    public static Logger Log 
    { 
     get { return log; } 
    } 

    public static void Close() 
    { 
     lock (mSyncRoot) 
     { 
      if (mInstance.mEngine != null) 
       mInstance.mEngine.Dispose(); 
     } 
    } 

    #endregion 

    private ReconciliationEngine mEngine; 
    private ServiceBase windowsServiceHost; 
    private UnhandledExceptionEventHandler threadExceptionHanlder = new UnhandledExceptionEventHandler(ThreadExceptionHandler); 

    public bool HostHealthy { get; private set; } 
    public bool RunningAsService {get; private set;} 

    private ServiceHost() 
    { 
     HostHealthy = false; 
     RunningAsService = false; 
     AppDomain.CurrentDomain.UnhandledException += threadExceptionHandler; 

     try 
     { 
      mEngine = new ReconciliationEngine(); 
      HostHealthy = true; 
     } 
     catch (Exception ex) 
     { 
      log.FatalException("Could not initialize components.", ex); 
     } 
    } 

    public void StartService() 
    { 
     if (!HostHealthy) 
      throw new ApplicationException("Did not initialize components."); 

     try 
     { 
      mEngine.Start(); 
     } 
     catch (Exception ex) 
     { 
      log.FatalException("Could not start service components.", ex); 
      HostHealthy = false; 
     } 
    } 

    public void StartService(ServiceBase serviceHost) 
    { 
     if (!HostHealthy) 
      throw new ApplicationException("Did not initialize components."); 

     if (serviceHost == null) 
      throw new ArgumentNullException("serviceHost"); 

     windowsServiceHost = serviceHost; 
     RunningAsService = true; 

     try 
     { 
      mEngine.Start(); 
     } 
     catch (Exception ex) 
     { 
      log.FatalException("Could not start service components.", ex); 
      HostHealthy = false; 
     } 
    } 

    public void RestartService() 
    { 
     if (!HostHealthy) 
      throw new ApplicationException("Did not initialize components.");   

     try 
     { 
      log.Info("Stopping service components..."); 
      mEngine.Stop(); 
      mEngine.Dispose(); 

      log.Info("Starting service components..."); 
      mEngine = new ReconciliationEngine(); 
      mEngine.Start(); 
     } 
     catch (Exception ex) 
     { 
      log.FatalException("Could not restart components.", ex); 
      HostHealthy = false; 
     } 
    } 

    public void StopService() 
    { 
     try 
     { 
      if (mEngine != null) 
       mEngine.Stop(); 
     } 
     catch (Exception ex) 
     { 
      log.FatalException("Error stopping components.", ex); 
      HostHealthy = false; 
     } 
     finally 
     { 
      if (windowsServiceHost != null) 
       windowsServiceHost.Stop(); 

      if (RunningAsService) 
      { 
       AppDomain.CurrentDomain.UnhandledException -= threadExceptionHanlder; 
      } 
     } 
    } 

    private void HandleExceptionBasedOnExecution(object ex) 
    { 
     if (RunningAsService) 
     { 
      windowsServiceHost.Stop(); 
     } 
     else 
     { 
      throw (Exception)ex; 
     } 
    } 

    protected static void ThreadExceptionHandler(object sender, UnhandledExceptionEventArgs e) 
    { 
     log.FatalException("Unexpected error occurred. System is shutting down.", (Exception)e.ExceptionObject); 
     ServiceHost.Instance.HandleExceptionBasedOnExecution((Exception)e.ExceptionObject); 
    } 
} 

Todo lo que necesita hacer aquí es reemplazar esa siniestra buscando ReconcilationEngine de referencia con el método que se bootstrapping su lógica.Luego, en su aplicación, use los métodos ServiceHost.Instance.Start() y ServiceHost.Instance.Stop(), ya sea que esté ejecutando en modo consola o como servicio.

-1

Bueno, hay algo de código muy antiguo (unos 20 años más o menos, no de mí, pero encuentran en la naturaleza, web salvaje, y en no C C#) que te dará una idea de cómo hacer el trabajo:

enum enEnvironmentType 
    { 
    ENVTYPE_UNKNOWN, 
    ENVTYPE_STANDARD, 
    ENVTYPE_SERVICE_WITH_INTERACTION, 
    ENVTYPE_SERVICE_WITHOUT_INTERACTION, 
    ENVTYPE_IIS_ASP, 
    }; 

enEnvironmentType GetEnvironmentType(void) 
{ 
    HANDLE hProcessToken = NULL; 
    DWORD groupLength  = 300; 
    PTOKEN_GROUPS groupInfo = NULL; 

    SID_IDENTIFIER_AUTHORITY siaNt = SECURITY_NT_AUTHORITY; 
    PSID pInteractiveSid = NULL; 
    PSID pServiceSid = NULL; 

    DWORD dwRet = NO_ERROR; 
    DWORD ndx; 

    BOOL m_isInteractive = FALSE; 
    BOOL m_isService = FALSE; 

    // open the token 
    if (!::OpenProcessToken(::GetCurrentProcess(),TOKEN_QUERY,&hProcessToken)) 
     { 
     dwRet = ::GetLastError(); 
     goto closedown; 
     } 

    // allocate a buffer of default size 
    groupInfo = (PTOKEN_GROUPS)::LocalAlloc(0, groupLength); 
    if (groupInfo == NULL) 
     { 
     dwRet = ::GetLastError(); 
     goto closedown; 
     } 

    // try to get the info 
    if (!::GetTokenInformation(hProcessToken, TokenGroups, 
     groupInfo, groupLength, &groupLength)) 
     { 
     // if buffer was too small, allocate to proper size, otherwise error 
     if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) 
      { 
      dwRet = ::GetLastError(); 
      goto closedown; 
      } 

     ::LocalFree(groupInfo); 

     groupInfo = (PTOKEN_GROUPS)::LocalAlloc(0, groupLength); 
     if (groupInfo == NULL) 
      { 
      dwRet = ::GetLastError(); 
      goto closedown; 
      } 

     if (!GetTokenInformation(hProcessToken, TokenGroups, 
      groupInfo, groupLength, &groupLength)) 
      { 
      dwRet = ::GetLastError(); 
      goto closedown; 
      } 
     } 

    // 
    // We now know the groups associated with this token. We want 
    // to look to see if the interactive group is active in the 
    // token, and if so, we know that this is an interactive process. 
    // 
    // We also look for the "service" SID, and if it's present, 
    // we know we're a service. 
    // 
    // The service SID will be present iff the service is running in a 
    // user account (and was invoked by the service controller). 
    // 

    // create comparison sids 
    if (!AllocateAndInitializeSid(&siaNt, 
     1, 
     SECURITY_INTERACTIVE_RID, 
     0, 0, 0, 0, 0, 0, 0, 
     &pInteractiveSid)) 
     { 
     dwRet = ::GetLastError(); 
     goto closedown; 
     } 

    if (!AllocateAndInitializeSid(&siaNt, 
     1, 
     SECURITY_SERVICE_RID, 
     0, 0, 0, 0, 0, 0, 0, 
     &pServiceSid)) 
     { 
     dwRet = ::GetLastError(); 
     goto closedown; 
     } 

    // try to match sids 
    for (ndx = 0; ndx < groupInfo->GroupCount ; ndx += 1) 
     { 
     SID_AND_ATTRIBUTES sanda = groupInfo->Groups[ndx]; 
     PSID    pSid = sanda.Sid; 

     // 
     // Check to see if the group we're looking at is one of 
     // the two groups we're interested in. 
     // 

     if (::EqualSid(pSid, pInteractiveSid)) 
      { 
      // 
      // This process has the Interactive SID in its 
      // token. This means that the process is running as 
      // a console process 
      // 
      m_isInteractive = TRUE; 
      m_isService = FALSE; 
      break; 
      } 
     else if (::EqualSid(pSid, pServiceSid)) 
      { 
      // 
      // This process has the Service SID in its 
      // token. This means that the process is running as 
      // a service running in a user account (not local system). 
      // 
      m_isService = TRUE; 
      m_isInteractive = FALSE; 
      break; 
      } 
     } 

    if (!(m_isService || m_isInteractive)) 
     { 
     // 
     // Neither Interactive or Service was present in the current 
     // users token, This implies that the process is running as 
     // a service, most likely running as LocalSystem. 
     // 
     m_isService = TRUE; 
     } 


closedown: 
    if (pServiceSid) 
     ::FreeSid(pServiceSid); 

    if (pInteractiveSid) 
     ::FreeSid(pInteractiveSid); 

    if (groupInfo) 
     ::LocalFree(groupInfo); 

    if (hProcessToken) 
     ::CloseHandle(hProcessToken); 

    if (dwRet == NO_ERROR) 
     { 
     if (m_isService) 
      return(m_isInteractive ? ENVTYPE_SERVICE_WITH_INTERACTION : ENVTYPE_SERVICE_WITHOUT_INTERACTION); 
     return(ENVTYPE_STANDARD); 
     } 
     else 
     return(ENVTYPE_UNKNOWN); 
} 
+1

Esto no se ve como C#. – LarsTech

+1

Pero podría traducirse a C#, ¿no es así? – chksr

+2

No tan fácil. C# -ified – as9876

1

a continuación el texto de la respuesta de chksr a .NET, y evitar el error que no tiene en cuenta los servicios interactivos:

using System.Security.Principal; 

var wi = WindowsIdentity.GetCurrent(); 
var wp = new WindowsPrincipal(wi); 
var serviceSid = new SecurityIdentifier(WellKnownSidType.ServiceSid, null); 
var localSystemSid = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null); 
var interactiveSid = new SecurityIdentifier(WellKnownSidType.InteractiveSid, null); 
// maybe check LocalServiceSid, and NetworkServiceSid also 

bool isServiceRunningAsUser = wp.IsInRole(serviceSid); 
bool isSystem = wp.IsInRole(localSystemSid); 
bool isInteractive = wp.IsInRole(interactiveSid); 

bool isAnyService = isServiceRunningAsUser || isSystem || !isInteractive; 
Cuestiones relacionadas