Comment vérifier si un service est en cours d'exécution via un fichier de commandes et le démarrer, s'il ne fonctionne pas?

90

Je souhaite écrire un fichier de commandes qui effectue les opérations suivantes:

  • Vérifiez si un service est en cours d'exécution
    • S'il est en cours d'exécution, quittez le lot
    • S'il n'est pas en cours d'exécution, démarrez le service

Les exemples de code que j'ai recherchés sur Google jusqu'à présent se sont avérés ne pas fonctionner, j'ai donc décidé de ne pas les publier.

Le démarrage d'un service se fait par:

net start "SERVICENAME"
  1. Comment puis-je vérifier si un service est en cours d'exécution et comment faire une instruction if dans un fichier batch?
  2. Je suis un peu confus. Quel est l'argument que je dois transmettre au net start? Le nom du service ou son nom d'affichage?
citronas
la source
3
Programmation sale: lorsque la seule chose que vous voulez faire est de démarrer le service s'il n'est pas en cours d'exécution, émettez simplement la commande de démarrage. S'il ne fonctionne pas, il démarrera le service. S'il est en cours d'exécution, vous obtenez un message d'erreur mais le service est en cours d'exécution (et ne s'arrête pas). Sale mais ça marche. Cependant, lorsque vous souhaitez exécuter d'autres commentaires uniquement si vous deviez démarrer le service, optez définitivement pour la version plus propre de lc.
Peter Schuetze
@Peter Schuetze: Oui, votre objection est correcte si le démarrage du service est le seul but. J'ai également inclus les débuts de journalisation et cetera, donc je me suis tenu à la solution de lc.
citronas

Réponses:

163

Pour vérifier l'état d'un service, utilisez sc query <SERVICE_NAME>. Pour si des blocs dans des fichiers de commandes, consultez la documentation .

Le code suivant vérifiera l'état du service MyServiceNameet le démarrera s'il n'est pas en cours d'exécution (le bloc if sera exécuté si le service n'est pas en cours d'exécution):

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"
  )
)

Explication de ce qu'il fait:

  1. Interroge les propriétés du service.
  2. Recherche la ligne contenant le texte "STATE"
  3. Tokenizes cette ligne et extrait le troisième jeton, qui est celui contenant l'état du service.
  4. Teste l'état résultant par rapport à la chaîne "RUNNING"

Quant à votre deuxième question, l'argument que vous voudrez passer net startest le nom du service, pas le nom d'affichage.

lc.
la source
Impressionnant. Merci pour votre effort. Malheureusement ça ne marche pas? Peut-être que je suis trop stupide pour ça. J'ai remplacé "MyServiceName" par "SCardSvr" (échappé) comme test, j'ai tout mis dans un fichier batch, je l'ai exécuté, mais le service ne démarre pas. Même si je remplace net start par autre chose, comme l'impression dans un fichier, il ne sera pas exécuté. Pourriez-vous jeter un second coup d'œil s'il vous plaît? =)
citronas
Oups, j'avais des trucs supplémentaires dans la première ligne ... Essayez ceci. Et si cela ne fonctionne pas, que se passe-t-il lorsque vous exécutez à sc query "SCardSvr"partir d'une ligne de commande?
lc.
1
Avez-vous "SCardSvr" entre guillemets? Je ne crois pas que cela devrait être,
LittleBobbyTables - Au Revoir
@LittleBobbyTables: Vous avez raison. Sans guillemets, ça marche. Je suis tellement stupide: - | Merci pour votre aide
citronas
@Mark Bon à noter. Je suppose que vous devrez remplacer cette chaîne par ce qu'elle doit être pour la langue du système d'exploitation cible. Je suppose également "RUNNING".
lc.
34

Pour basculer un service, utilisez ce qui suit;

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

Coopératives
la source
1
Cela fonctionne à cause du code de sortie du début. Si la commande de démarrage échoue, c'est probablement parce qu'elle est déjà en cours d'exécution (et de toute façon, l'arrêter par la suite ne fera pas de mal), alors vous essayez de l'arrêter.
lc.
3
la commande est structurée de telle sorte que si net start échoue, elle l'arrête alors (à cause du || qui signifie autre), mais si net start s'exécute, alors net stop ne s'exécute pas. brillant!
Docteur DOS
1
C'est la meilleure réponse à mon avis, et peut-être que @citronas devrait envisager de la marquer comme la réponse acceptée: simple, intelligente et élégante, et s'adapte à un site comme StackOverflow. Faites simple!
Sopalajo de Arrierez
2
Ne pas être pointilleux (OK, peut-être juste un peu), mais le ||est en fait un ORopérateur, même si dans ce cas c'est fonctionnellement une ELSEinstruction. C'est une différence subtile mais importante. J'ai toujours mon +1 - Je fais cela tout le temps dans les scripts shell Unix / Linux, je ne sais pas pourquoi je n'ai jamais pensé à faire cela dans Windows batch.
Doug R.
Cela semble dangereusement simplifié. Je ne voudrais jamais l'utiliser pour quelque chose que j'automatisais pour le traitement par lots ou que je donnais à quelqu'un d'autre ... mais c'est juste ce que le médecin a ordonné pour une icône rapide que je peux mettre sur mon propre bureau pour un service dont j'ai besoin basculer rapidement de temps en temps.
Joel Coehoorn
19

Vous pouvez utiliser la commande suivante pour voir si un service est en cours d'exécution ou non:

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

Lorsque je l'exécute pour mon antivirus NOD32, j'obtiens:

STATE                       : 4 RUNNING

S'il était arrêté, j'aurais:

STATE                       : 1 STOPPED

Vous pouvez l'utiliser dans une variable pour déterminer ensuite si vous utilisez NET START ou non.

Le nom du service doit être le nom du service, pas le nom d'affichage.

LittleBobbyTables - Au Revoir
la source
1
Merci pour votre aide, tout en essayant d'intégrer ce que vous avez posté, j'augmente beaucoup mes compétences en batch;)
citronas
14

Ça devrait le faire:

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

Version indépendante de la langue.

@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
la source
Oui! "Space" frappe toujours soudainement dans votre dos!
Dr.eel
2
Réponse presque parfaite. Je corrigerais juste cette ligne: Net start "% ServiceName%"> nul || (
Cesar
J'ai rendu le script universel afin qu'il me permette de l'utiliser dans les tâches du planificateur Windows. Remplacez-le simplement Set ServiceName=Jenkinspar Set ServiceName=%~1et appelez-le commewatch-service.bat "Jenkins"
Dr.eel
@ Ant_222 Il utilise 'queryex' au lieu de 'query' qui dépend de la langue. Et pourquoi pensez-vous que ce n'est pas un lot Windows? Avez-vous essayé de l'utiliser?
Dr.eel
5

Je viens de trouver ce fil et je voulais ajouter à la discussion si la personne ne veut pas utiliser un fichier batch pour redémarrer les services. Dans Windows, il existe une option si vous allez dans Services, propriétés du service, puis récupération. Ici, vous pouvez définir les paramètres du service. Aime redémarrer le service si le service s'arrête. En outre, vous pouvez même demander à une deuxième tentative d'échec de faire quelque chose de différent, comme pour redémarrer l'ordinateur.

foudre
la source
2
C'est une réponse utile, mais il est important de noter que cela ne fonctionnera que si le service s'est arrêté avec exit (-1). Si le service s'est arrêté correctement (même avec un message d'erreur), la récupération automatique ne se déclenchera pas. Il ne se déclenchera pas non plus si le service a été tué manuellement par l'utilisateur.
Art Gertner
@sagelightning: Nous avons besoin d'un accès administrateur pour essayer de cette façon.
Kumar M
@ArtGertner - Tuer (via le gestionnaire de tâches) un processus de service sera interprété comme un "crash" et déclenchera une récupération.
Martin Ba
3

Pour utiliser Windows en espagnol, el código debe quedar asi (lorsque vous utilisez Windows en espagnol, le code est):

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. (Remplacez MYSERVICE par le nom du service à traiter. Vous pouvez voir le nom du service dans les propriétés du service.)

Daniel Serrano
la source
10
Ce sera mieux pour tout le monde si vous écrivez votre réponse en anglais.
j0k
2
Je ne sais pas pourquoi le vote négatif. C'est un point important et une raison d'éviter les comparaisons de chaînes si possible. Dans ce cas, vous devez modifier la chaîne en fonction de la langue par défaut de l'installation Windows cible.
lc.
2
@lc: Serait-il raisonnable d'inclure une réponse pour chaque langue? Il peut être plus utile de référencer (ou d'inclure) une ressource indiquant la chaîne à rechercher dans une langue donnée.
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
la source
2

Pour Windows Server 2012, voici ce qui a fonctionné pour moi. Remplacez uniquement "SERVICENAME" par le nom réel du service:

@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
la source
1

Je voulais aussi qu'un e-mail soit envoyé si le service était démarré de cette façon, alors j'ai ajouté un peu au code @Ic, je pensais simplement que je le publierais au cas où cela aiderait quelqu'un. J'ai utilisé SendMail mais il existe d'autres options de ligne de commande Comment envoyer un simple e-mail à partir d'un fichier batch Windows?

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
la source
1

Démarrage du service à l'aide du script Powershell. Vous pouvez le lier au planificateur de tâches et le déclencher à intervalles ou au besoin. Créez-le en tant que fichier PS1, c'est-à-dire avec l'extension PS1, puis laissez ce fichier être déclenché à partir du planificateur de tâches.

Pour démarrer le service d'arrêt

dans le planificateur de tâches si vous l'utilisez sur le serveur, utilisez ceci dans les arguments

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

vérifiez en exécutant la même chose sur cmd si cela fonctionne, cela devrait également fonctionner sur le planificateur de tâches

$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
la source
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
la source
0

Lié à la réponse de @DanielSerrano, j'ai été récemment peu par la localisation de la sc.execommande, à savoir en espagnol. Ma proposition est de localiser la ligne et le jeton qui contient l'état de service numérique et de l'interpréter, ce qui devrait être beaucoup plus robuste:

@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
  )
)

Testé avec:

  • Windows XP (32 bits) anglais
  • Windows 10 (32 bits) espagnol
  • Windows 10 (64 bits) anglais
Helder Magalhães
la source
0

Peut-être d'une manière beaucoup plus simple? Il suffit d'ajouter à la liste des réponses ici:

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