Wie kann ein Windows Dienst programmgesteuert sich selber neu starten?

Wenn man sich mit Windows Diensten beschäftigt und diese auch selber programmiert und installiert, stößt man irgendwann auf die Frage “Ist es möglich, das ein Windows Dienst sich selber neu startet?“.

Wie sich herausstellt, bedeutet Neustart, dass der Dienst zunächst beendet werden muss um anschließend diesen neu zu starten. Das der Dienst sich selber beendet, ist dabei kein Problem. Wenn aber der Dienst beendet ist, wie soll dieser sich dann wieder neu starten können. Letztendlich ist das Programm beendet und wird nicht mehr abgearbeitet.

Meine Recherche hat dabei im wesentlichen zwei Möglichkeiten ergeben:

  1. Verwendung eines externen Programms, das aus dem Dienst heraus getriggert wird, den Dienst stoppt und anschließend wieder neu startet.
  2. Der Dienst beendet sich selber und übergibt dabei einen Code an das Betriebssystem, das dann den Neustart des Dienstes übernimmt. Hierfür muss der Dienst bei der Installation entsprechend konfiguriert werden.

Verwendung von CMD.exe (Windows-Eingabeaufforderung) um den Windows Dienst neu zu starten

Der folgende C# Code zeigt, wie das Programm CMD.exe verwendet werden kann, um den Dienst neu zu starten.

var serviceName = "MyService";
string strCmdText = string.Format("/C net stop {0} && net start {0}", serviceName);
Process.Start(fileName: "CMD.exe", arguments: strCmdText);

Dabei bedeutet && im übergebenen Kommando an CMD.exe, das der Startbefehl nur ausgeführt werden soll, wenn zuvor der Stoppbefehl erfolgreich beendet wurden ist.

Im EventLog des Betriebssytems werden die folgenden Meldungen eingetragen:

The MyService service entered the stopped state.
The MyService service entered the running state.

Neustart des Dienstes durch das Betriebsystem

Der folgende C# Code zeigt, wie der Dienst sich selber beenden kann und dabei einen Code an das Betriebssystem übergibt.

Environment.Exit(1);

Wurde der Dienst entsprechend konfiguriert, führt das Betriebssystem einen Neustart durch. Dabei muss der Exitcode ungleich 0 sein. Das Betriebssystem führt nur dann einen Neustart aus, wenn der Dienst einen Fehlercode ungleich 0 zurück gibt. Dabei bedeutet 0, das der Prozess erfolgreich beendet wurde. Jeder andere Code bedeutet, das ein Fehler aufgetreten ist. Ein Neustart des Dienstes für den fehlerfreien Fall ist nicht vorgesehen.

Im EventLog des Betriebssytems werden die folgenden Meldungen eingetragen:

The MyService service terminated unexpectedly.  It has done this 1 time(s).  The following corrective action will be taken in 500 milliseconds: Restart the service.
The MyService service entered the running state.

Der Eintrag im Eventlog ist ein Nachteil dieser Methode. Insbesondere dann, wenn der Neustart nicht aus Gründen eines Fehlers erfolgen soll.

Vorausgesetzt, der Dienst wurde bereits installiert, kann mit dem Programm SC.exe und dem Befehl failure der Dienst für einen Neustart durch das Betriebssystem konfiguriert werden. Im folgenden Beispiel wurde der Dienst unter dem Namen MyService installiert.

sc failure MyService reset=0 actions=restart/500

Hilfe zum Programm SC.exe erhält man nach dem Öffnen der Windows-Eingabeaufforderung mit der Eingabe von SC und Enter. Hilfe zu einem speziellen Befehl wird ausgegeben, wenn man SC gefolgt von dem Befehl eingibt und anschließend Enter drückt.

Der Befehl failure hat dabei den folgenden Aufbau:

Abb. 1: Hilfetext für den Befehl failure anzeigen

Alternativ kann der Dienst auch mittels der Management Console konfiguriert werden:

Windows Service Configuration
Abb. 2: Windows Service Recovery Configuration

Der Vollständigkeit halber hier die Ausgabe des Hilfetextes nach der Eingabe von SC und Enter:

Microsoft Windows [Version 10.0.14393]
(c) 2016 Microsoft Corporation. All rights reserved.

C:\Windows\system32>sc
DESCRIPTION:
        SC is a command line program used for communicating with the
        Service Control Manager and services.
USAGE:
        sc <server> [command] [service name] <option1> <option2>...


        The option <server> has the form "\\ServerName"
        Further help on commands can be obtained by typing: "sc [command]"
        Commands:
          query-----------Queries the status for a service, or
                          enumerates the status for types of services.
          queryex---------Queries the extended status for a service, or
                          enumerates the status for types of services.
          start-----------Starts a service.
          pause-----------Sends a PAUSE control request to a service.
          interrogate-----Sends an INTERROGATE control request to a service.
          continue--------Sends a CONTINUE control request to a service.
          stop------------Sends a STOP request to a service.
          config----------Changes the configuration of a service (persistent).
          description-----Changes the description of a service.
          failure---------Changes the actions taken by a service upon failure.
          failureflag-----Changes the failure actions flag of a service.
          sidtype---------Changes the service SID type of a service.
          privs-----------Changes the required privileges of a service.
          managedaccount--Changes the service to mark the service account
                          password as managed by LSA.
          qc--------------Queries the configuration information for a service.
          qdescription----Queries the description for a service.
          qfailure--------Queries the actions taken by a service upon failure.
          qfailureflag----Queries the failure actions flag of a service.
          qsidtype--------Queries the service SID type of a service.
          qprivs----------Queries the required privileges of a service.
          qtriggerinfo----Queries the trigger parameters of a service.
          qpreferrednode--Queries the preferred NUMA node of a service.
          qmanagedaccount-Queries whether a services uses an account with a
                          password managed by LSA.
          qprotection-----Queries the process protection level of a service.
          quserservice----Queries for a local instance of a user service template.
          delete----------Deletes a service (from the registry).
          create----------Creates a service. (adds it to the registry).
          control---------Sends a control to a service.
          sdshow----------Displays a service's security descriptor.
          sdset-----------Sets a service's security descriptor.
          showsid---------Displays the service SID string corresponding to an arbitrary name.
          triggerinfo-----Configures the trigger parameters of a service.
          preferrednode---Sets the preferred NUMA node of a service.
          GetDisplayName--Gets the DisplayName for a service.
          GetKeyName------Gets the ServiceKeyName for a service.
          EnumDepend------Enumerates Service Dependencies.

        The following commands don't require a service name:
        sc <server> <command> <option>
          boot------------(ok | bad) Indicates whether the last boot should
                          be saved as the last-known-good boot configuration
          Lock------------Locks the Service Database
          QueryLock-------Queries the LockStatus for the SCManager Database
EXAMPLE:
        sc start MyService


QUERY and QUERYEX OPTIONS:
        If the query command is followed by a service name, the status
        for that service is returned.  Further options do not apply in
        this case.  If the query command is followed by nothing or one of
        the options listed below, the services are enumerated.
    type=    Type of services to enumerate (driver, service, userservice, all)
             (default = service)
    state=   State of services to enumerate (inactive, all)
             (default = active)
    bufsize= The size (in bytes) of the enumeration buffer
             (default = 4096)
    ri=      The resume index number at which to begin the enumeration
             (default = 0)
    group=   Service group to enumerate
             (default = all groups)

SYNTAX EXAMPLES
sc query                - Enumerates status for active services & drivers
sc query eventlog       - Displays status for the eventlog service
sc queryex eventlog     - Displays extended status for the eventlog service
sc query type= driver   - Enumerates only active drivers
sc query type= service  - Enumerates only Win32 services
sc query state= all     - Enumerates all services & drivers
sc query bufsize= 50    - Enumerates with a 50 byte buffer
sc query ri= 14         - Enumerates with resume index = 14
sc queryex group= ""    - Enumerates active services not in a group
sc query type= interact - Enumerates all interactive services
sc query type= driver group= NDIS     - Enumerates all NDIS drivers