Wie kann ich überprüfen, ob ein Dienst über eine Batchdatei ausgeführt wird, und ihn starten, wenn er nicht ausgeführt wird?

90

Ich möchte eine Batchdatei schreiben, die die folgenden Vorgänge ausführt:

  • Überprüfen Sie, ob ein Dienst ausgeführt wird
    • Wenn es ausgeführt wird, beenden Sie den Stapel
    • Wenn es nicht ausgeführt wird, starten Sie den Dienst

Die Codebeispiele, die ich bisher gegoogelt habe, haben sich als nicht funktionierend erwiesen, daher habe ich beschlossen, sie nicht zu veröffentlichen.

Das Starten eines Dienstes erfolgt durch:

net start "SERVICENAME"
  1. Wie kann ich überprüfen, ob ein Dienst ausgeführt wird, und wie kann ich eine if-Anweisung in einer Batchdatei erstellen?
  2. Ich bin ein bisschen verwirrt. Was ist das Argument, das ich an den Netzstart weitergeben muss? Der Dienstname oder sein Anzeigename?
Citronas
quelle
3
Schmutzige Programmierung: Wenn Sie den Dienst nur starten möchten, wenn er nicht ausgeführt wird, geben Sie einfach den Befehl start aus. Wenn es nicht ausgeführt wird, wird der Dienst gestartet. Wenn es ausgeführt wird, wird eine Fehlermeldung angezeigt, aber der Dienst wird ausgeführt (und wird nicht beendet). Schmutzig, aber es funktioniert. Wenn Sie jedoch andere Kommentare nur ausführen möchten, wenn Sie den Dienst starten mussten, wählen Sie auf jeden Fall die Cleaner-Version von lc.
Peter Schuetze
@Peter Schuetze: Ja, Ihr Einwand ist richtig, wenn der Start des Dienstes der einzige Zweck ist. Ich habe auch Protokollierungsstarts usw. aufgenommen, also habe ich mich an die Lösung von lc gehalten.
Citronas

Antworten:

163

Verwenden Sie, um den Status eines Dienstes zu überprüfen sc query <SERVICE_NAME>. Überprüfen Sie die Dokumentation auf Blockierungen in Batchdateien .

Der folgende Code überprüft den Status des Dienstes MyServiceNameund startet ihn, wenn er nicht ausgeführt wird (der if-Block wird ausgeführt, wenn der Dienst nicht ausgeführt wird):

for /F "tokens=3 delims=: " %%H in ('sc query "MyServiceName" ^| findstr "        STATE"') do (
  if /I "%%H" NEQ "RUNNING" (
   REM Put your code you want to execute here
   REM For example, the following line
   net start "MyServiceName"
  )
)

Erklärung dessen, was es tut:

  1. Fragt die Eigenschaften des Dienstes ab.
  2. Sucht nach der Zeile mit dem Text "STATE"
  3. Tokenisiert diese Zeile und zieht das dritte Token heraus, das den Status des Dienstes enthält.
  4. Testet den resultierenden Status anhand der Zeichenfolge "RUNNING".

Bei Ihrer zweiten Frage ist das Argument, an das Sie übergeben möchten, net startder Dienstname und nicht der Anzeigename.

lc.
quelle
Genial. Danke für deinen Einsatz. Geht leider nicht? Vielleicht bin ich dafür zu dumm. Ich habe "MyServiceName" als Test durch "SCardSvr" (Escape) ersetzt, alles in eine Batchdatei eingefügt, ausgeführt, aber der Dienst wird nicht gestartet. Selbst wenn ich net start durch etwas anderes ersetze, wie das Drucken in eine Datei, wird es nicht ausgeführt. Würde es Ihnen etwas ausmachen, einen zweiten Blick darauf zu werfen? =)
Citronas
Hoppla, ich hatte ein paar zusätzliche Sachen in der ersten Zeile ... Versuchen Sie das. Und wenn es nicht funktioniert, was passiert, wenn Sie sc query "SCardSvr"über eine Befehlszeile ausgeführt werden?
lc.
1
Haben Sie "SCardSvr" in Anführungszeichen? Ich glaube nicht, dass es sein sollte,
LittleBobbyTables - Au Revoir
@ LittleBobbyTables: Du hast recht. Ohne Anführungszeichen hat es funktioniert. Ich bin so dumm: - | Vielen Dank für Ihre Hilfe
Citronas
@ Mark Gut zu beachten. Ich denke, Sie müssen diese Zeichenfolge durch die Zeichenfolge ersetzen, die für die Zielsprache des Betriebssystems erforderlich ist. Ich gehe auch von "RUNNING" aus.
lc.
34

Verwenden Sie Folgendes, um einen Dienst umzuschalten:

NET START "Distributed Transaction Coordinator" || NET STOP "Distributed Transaction Coordinator"

Coops
quelle
1
Es funktioniert aufgrund des Exit-Codes von Anfang an. Wenn der Startbefehl fehlschlägt, liegt dies wahrscheinlich daran, dass er bereits ausgeführt wird (und das anschließende Beenden in beiden Fällen nicht schadet). Versuchen Sie also, ihn anzuhalten.
lc.
3
Der Befehl ist so strukturiert, dass wenn der Netzstart fehlschlägt, er ihn stoppt (aufgrund des ||, was sonst bedeutet). Wenn jedoch der Netzstart ausgeführt wird, wird der Netzstopp nicht ausgeführt. brillant!
Doktor DOS
1
Dies ist meiner Meinung nach die beste Antwort, und vielleicht sollte @citronas in Betracht ziehen, sie als akzeptierte Antwort zu markieren: einfach, intelligent und elegant und passt zu einer Site wie StackOverflow. Mach es einfach!
Sopalajo de Arrierez
2
Nicht pingelig zu sein (OK, vielleicht nur ein bisschen), aber das ||ist eigentlich ein OROperator, obwohl es in diesem Fall funktional eine ELSEAussage ist. Dies ist ein subtiler, aber wichtiger Unterschied. Ich habe immer noch meine +1 - ich mache das die ganze Zeit in Unix / Linux-Shell-Skripten. Ich weiß nicht, warum ich nie daran gedacht habe, dies im Windows-Batch zu tun.
Doug R.
Dies scheint gefährlich stark vereinfacht. Ich würde es niemals für etwas verwenden wollen, das ich für die Stapelverarbeitung automatisiert oder jemand anderem zur Verwendung gegeben habe ... aber es ist genau das, was der Arzt für ein schnelles Symbol bestellt hat, das ich für einen Dienst, den ich benötige, auf meinen eigenen Desktop stellen kann ab und zu schnell umschalten.
Joel Coehoorn
19

Mit dem folgenden Befehl können Sie feststellen, ob ein Dienst ausgeführt wird oder nicht:

sc query [ServiceName] | findstr /i "STATE"

Wenn ich es für mein NOD32-Antivirus ausführe, erhalte ich:

STATE                       : 4 RUNNING

Wenn es gestoppt würde, würde ich bekommen:

STATE                       : 1 STOPPED

Sie können dies in einer Variablen verwenden, um dann zu bestimmen, ob Sie NET START verwenden oder nicht.

Der Dienstname sollte der Dienstname sein, nicht der Anzeigename.

LittleBobbyTables - Au Revoir
quelle
1
Vielen Dank für Ihre Hilfe, während ich versuche, das, was Sie gepostet haben, zu integrieren, verbessere ich meine Batch-Fähigkeiten erheblich;)
citronas
14

Das sollte es tun:

FOR %%a IN (%Svcs%) DO (SC query %%a | FIND /i "RUNNING"
IF ERRORLEVEL 1 SC start %%a)
Kristina Brooks
quelle
10

Sprachunabhängige Version.

@Echo Off
Set ServiceName=Jenkins


SC queryex "%ServiceName%"|Find "STATE"|Find /v "RUNNING">Nul&&(
    echo %ServiceName% not running 
    echo Start %ServiceName%

    Net start "%ServiceName%">nul||(
        Echo "%ServiceName%" wont start 
        exit /b 1
    )
    echo "%ServiceName%" started
    exit /b 0
)||(
    echo "%ServiceName%" working
    exit /b 0
)
Dr.eel
quelle
Ja! "Space" schlägt immer plötzlich in deinen Rücken!
Dr.eel
2
Fast perfekte Antwort. Ich würde mich nur auf diese Zeile beschränken: Nettostart "% ServiceName%"> nul || (
Cesar
Ich habe das Skript universell gemacht, damit ich es in Windows Scheduler-Aufgaben verwenden kann. Ersetzen Sie einfach Set ServiceName=Jenkinsmit Set ServiceName=%~1und nennen Sie es wiewatch-service.bat "Jenkins"
Dr.eel
@ Ant_222 Es wird 'queryex' anstelle von 'query' verwendet, was sprachabhängig ist. Und warum denkst du, ist es kein Windows-Batch? Haben Sie versucht, es zu verwenden?
Dr.eel
5

Ich habe gerade diesen Thread gefunden und wollte ihn zur Diskussion hinzufügen, wenn die Person keine Batchdatei zum Neustarten von Diensten verwenden möchte. In Windows gibt es eine Option, wenn Sie zu Dienste, Diensteigenschaften und dann zur Wiederherstellung wechseln. Hier können Sie Parameter für den Dienst einstellen. Möchten Sie den Dienst neu starten, wenn der Dienst beendet wird. Sie können auch einen zweiten Fehlerversuch ausführen lassen, der etwas anderes als beim Neustart des Computers ausführt.

Sagelightning
quelle
2
Dies ist eine nützliche Antwort, es ist jedoch wichtig zu beachten, dass dies nur funktioniert, wenn der Dienst mit exit (-1) gestoppt wurde. Wenn der Dienst ordnungsgemäß beendet wurde (auch mit Fehlermeldung), wird die automatische Wiederherstellung nicht ausgelöst. Es wird auch nicht ausgelöst, wenn der Dienst vom Benutzer manuell beendet wurde.
Art Gertner
@sagelightning: Wir benötigen Administratorzugriff, um dies zu versuchen.
Kumar M
@ArtGertner - Das Beenden (über den Task-Manager) eines Serviceprozesses wird als "Absturz" interpretiert und löst eine Wiederherstellung aus.
Martin Ba
3

Cuando se use Windows en Español, el código debe quedar asi (bei Verwendung von Windows auf Spanisch lautet der Code):

for /F "tokens=3 delims=: " %%H in ('sc query MYSERVICE ^| findstr "        ESTADO"') do (
  if /I "%%H" NEQ "RUNNING" (
    REM Put your code you want to execute here
    REM For example, the following line
    net start MYSERVICE
  )
)

Reemplazar MYSERVICE con el nombre del servicio que se desea procesar. Puedes ver el nombre del servicio viendo las propiedades del servicio. (Ersetzen Sie MYSERVICE durch den Namen des zu verarbeitenden Dienstes. Den Namen des Dienstes finden Sie in den Diensteigenschaften.)

Daniel Serrano
quelle
10
Es ist für jeden besser, wenn Sie Ihre Antwort auf Englisch schreiben.
j0k
2
Ich bin mir nicht sicher, warum die Abstimmung. Dies ist ein wichtiger Punkt und ein Grund, Zeichenfolgenvergleiche nach Möglichkeit zu vermeiden. In diesem Fall müssen Sie die Zeichenfolge abhängig von der Standardsprache der Windows-Zielinstallation ändern.
lc.
2
@lc: Wäre es sinnvoll, für jede Sprache eine Antwort anzugeben? Es kann sinnvoller sein, auf eine Ressource zu verweisen (oder diese einzuschließen), die angibt, welche Zeichenfolge nach einer bestimmten Sprache gesucht werden soll.
Mike Bailey
2
@echo off

color 1F


@sc query >%COMPUTERNAME%_START.TXT


find /I "AcPrfMgrSvc" %COMPUTERNAME%_START.TXT >nul

IF ERRORLEVEL 0 EXIT

IF ERRORLEVEL 1 NET START "AcPrfMgrSvc"
Logan78
quelle
2

Für Windows Server 2012 hat das unten für mich funktioniert. Ersetzen Sie nur "SERVICENAME" durch den tatsächlichen Servicenamen:

@ECHO OFF
SET SvcName=SERVICENAME

SC QUERYEX "%SvcName%" | FIND "STATE" | FIND /v "RUNNING" > NUL && (
    ECHO %SvcName% is not running 
    ECHO START %SvcName%

    NET START "%SvcName%" > NUL || (
        ECHO "%SvcName%" wont start 
        EXIT /B 1
    )
    ECHO "%SvcName%" is started
    EXIT /B 0
) || (
    ECHO "%SvcName%" is running
    EXIT /B 0
)
Magige Daniel
quelle
1

Ich wollte auch eine E-Mail senden, wenn der Dienst auf diese Weise gestartet wurde, also fügte ich ein bisschen zum @ IC-Code hinzu, dachte nur, ich würde es posten, falls es jemandem helfen sollte. Ich habe SendMail verwendet, aber es gibt andere Befehlszeilenoptionen. Wie sende ich eine einfache E-Mail aus einer Windows-Batchdatei?

set service=MyServiceName

for /F "tokens=3 delims=: " %%H in ('sc query %service% ^| findstr "        STATE"') do (
  if /I "%%H" NEQ "RUNNING" (

    net start %service%

    for /F "tokens=3 delims=: " %%H in ('sc query %service% ^| findstr "        STATE"') do (
      if /I "%%H" EQ "RUNNING" (
        SendMail /smtpserver localhost /to [email protected] /from [email protected] /subject Service Autostart Notification /body Autostart on service %service% succeded.
      ) else (
        SendMail /smtpserver localhost /to [email protected] /from [email protected] /subject Service Autostart Notification /body Autostart on service %service% failed.
      )
    )

  )
)
BYoung
quelle
1

Starten des Dienstes mit dem Powershell-Skript. Sie können dies mit dem Taskplaner verknüpfen und in Intervallen oder nach Bedarf auslösen. Erstellen Sie diese Datei als PS1-Datei, dh als Datei mit der Erweiterung PS1, und lassen Sie diese Datei vom Taskplaner aus auslösen.

So starten Sie den Dienst

Wenn Sie es im Taskplaner auf dem Server verwenden, verwenden Sie dies in Argumenten

-noprofile -executionpolicy bypass -file "C: \ Service Restart Scripts \ StopService.PS1"

Überprüfen Sie dies, indem Sie dasselbe auf cmd ausführen, wenn es funktioniert. Es sollte auch auf dem Taskplaner funktionieren

$Password = "Enter_Your_Password"
$UserAccount = "Enter_Your_AccountInfor"
$MachineName = "Enter_Your_Machine_Name"
$ServiceList = @("test.SocketService","test.WcfServices","testDesktopService","testService")
$PasswordSecure = $Password | ConvertTo-SecureString -AsPlainText -Force
$Credential = new-object -typename System.Management.Automation.PSCredential -argumentlist $UserAccount, $PasswordSecure 

$LogStartTime = Get-Date -Format "MM-dd-yyyy hh:mm:ss tt"
$FileDateTimeStamp = Get-Date -Format "MM-dd-yyyy_hh"
$LogFileName = "C:\Users\krakhil\Desktop\Powershell\Logs\StartService_$FileDateTimeStamp.txt" 


#code to start the service

"`n####################################################################" > $LogFileName
"####################################################################" >> $LogFileName
"######################  STARTING SERVICE  ##########################" >> $LogFileName

for($i=0;$i -le 3; $i++)
{
"`n`n" >> $LogFileName
$ServiceName = $ServiceList[$i]
"$LogStartTime => Service Name: $ServiceName" >> $LogFileName

Write-Output "`n####################################"
Write-Output "Starting Service - " $ServiceList[$i]

"$LogStartTime => Starting Service: $ServiceName" >> $LogFileName
Start-Service $ServiceList[$i]

$ServiceState = Get-Service | Where-Object {$_.Name -eq $ServiceList[$i]}

if($ServiceState.Status -eq "Running")
{
"$LogStartTime => Started Service Successfully: $ServiceName" >> $LogFileName
Write-Host "`n Service " $ServiceList[$i] " Started Successfully"
}
else
{
"$LogStartTime => Unable to Stop Service: $ServiceName" >> $LogFileName
Write-Output "`n Service didn't Start. Current State is - "
Write-Host $ServiceState.Status
}
}

#code to stop the service

"`n####################################################################" > $LogFileName
"####################################################################" >> $LogFileName
"######################  STOPPING SERVICE  ##########################" >> $LogFileName

for($i=0;$i -le 3; $i++)
{
"`n`n" >> $LogFileName
$ServiceName = $ServiceList[$i]
"$LogStartTime => Service Name: $ServiceName" >> $LogFileName

Write-Output "`n####################################"
Write-Output "Stopping Service - " $ServiceList[$i]

"$LogStartTime => Stopping Service: $ServiceName" >> $LogFileName
Stop-Service $ServiceList[$i]

$ServiceState = Get-Service | Where-Object {$_.Name -eq $ServiceList[$i]}

if($ServiceState.Status -eq "Stopped")
{
"$LogStartTime => Stopped Service Successfully: $ServiceName" >> $LogFileName
Write-Host "`n Service " $ServiceList[$i] " Stopped Successfully"
}
else
{
"$LogStartTime => Unable to Stop Service: $ServiceName" >> $LogFileName
Write-Output "`nService didn't Stop. Current State is - "
Write-Host $ServiceState.Status
}
}
KR Akhil
quelle
0
@Echo off

Set ServiceName=wampapache64

SC queryex "%ServiceName%"|Find "STATE"|Find /v "RUNNING">Nul&&(

echo %ServiceName% not running
echo  

Net start "%ServiceName%"


    SC queryex "%ServiceName%"|Find "STATE"|Find /v "RUNNING">Nul&&(
        Echo "%ServiceName%" wont start
    )
        echo "%ServiceName%" started

)||(
    echo "%ServiceName%" was working and stopping
    echo  

    Net stop "%ServiceName%"

)


pause
Aylian Craspa
quelle
0

Im Zusammenhang mit der Antwort von @DanielSerrano wurde ich kürzlich von der Lokalisierung des sc.exeBefehls gebissen, und zwar auf Spanisch. Mein Vorschlag ist, die Zeile und das Token, die den numerischen Dienststatus enthalten, genau zu bestimmen und zu interpretieren, was viel robuster sein sollte:

@echo off

rem TODO: change to the desired service name
set TARGET_SERVICE=w32time

set SERVICE_STATE=
rem Surgically target third line, as some locales (such as Spanish) translated the utility's output
for /F "skip=3 tokens=3" %%i in ('""%windir%\system32\sc.exe" query "%TARGET_SERVICE%" 2>nul"') do (
  if not defined SERVICE_STATE set SERVICE_STATE=%%i
)
rem Process result
if not defined SERVICE_STATE (
  echo ERROR: could not obtain service state!
) else (
  rem NOTE: values correspond to "SERVICE_STATUS.dwCurrentState"
  rem https://msdn.microsoft.com/en-us/library/windows/desktop/ms685996(v=vs.85).aspx
  if not %SERVICE_STATE%==4 (
    echo WARNING: service is not running
    rem TODO: perform desired operation
    rem net start "%TARGET_SERVICE%"
  ) else (
    echo INFORMATION: service is running
  )
)

Getestet mit:

  • Windows XP (32-Bit) Englisch
  • Windows 10 (32-Bit) Spanisch
  • Windows 10 (64-Bit) Englisch
Helder Magalhães
quelle
0

Vielleicht ein viel einfacherer Weg? Fügen Sie hier einfach die Liste der Antworten hinzu:

@for /f "tokens=1,* delims=: " %%a in ('sc queryex state=Inactive') do net start "%%b"
Gerhard
quelle