¿Cómo verificar si un servicio se está ejecutando a través de un archivo por lotes e iniciarlo, si no se está ejecutando?

90

Quiero escribir un archivo por lotes que realice las siguientes operaciones:

  • Compruebe si se está ejecutando un servicio
    • Si se está ejecutando, salga del lote
    • Si no se está ejecutando, inicie el servicio

Los ejemplos de código que busqué en Google hasta ahora resultaron no funcionar, así que decidí no publicarlos.

El inicio de un servicio se realiza mediante:

net start "SERVICENAME"
  1. ¿Cómo puedo verificar si un servicio se está ejecutando y cómo hacer una declaración if en un archivo por lotes?
  2. Estoy un poco confundido. ¿Cuál es el argumento que tengo que pasar al inicio neto? ¿El nombre del servicio o su nombre para mostrar?
citronas
fuente
3
Programación sucia: cuando lo único que desea hacer es iniciar el servicio si no se está ejecutando, simplemente emita el comando de inicio. Si no se está ejecutando, iniciará el servicio. Si se está ejecutando, aparece un mensaje de error, pero el servicio se está ejecutando (y no se detiene). Sucio pero funciona. Sin embargo, cuando desee ejecutar otros comentarios solo si tuvo que iniciar el servicio, definitivamente elija la versión más limpia de lc.
Peter Schuetze
@Peter Schuetze: Sí, su objeción es correcta si iniciar el servicio es el único propósito. También incluí inicios de registro, etc., así que me quedé con la solución de lc.
citronas

Respuestas:

163

Para comprobar el estado de un servicio, utilice sc query <SERVICE_NAME>. Si hay bloques en archivos por lotes, consulte la documentación .

El siguiente código verificará el estado del servicio MyServiceNamey lo iniciará si no se está ejecutando (el bloque if se ejecutará si el servicio no se está ejecutando):

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

Explicación de lo que hace:

  1. Consulta las propiedades del servicio.
  2. Busca la línea que contiene el texto "ESTADO"
  3. Tokeniza esa línea y saca el tercer token, que es el que contiene el estado del servicio.
  4. Prueba el estado resultante con la cadena "RUNNING"

En cuanto a su segunda pregunta, el argumento al que querrá pasar net startes el nombre del servicio, no el nombre para mostrar.

lc.
fuente
Increíble. Gracias por tu esfuerzo. ¿Desafortunadamente no funciona? Quizás soy demasiado estúpido para esto. Reemplacé "MyServiceName" con "SCardSvr" (escapó) como prueba, puse todo en un archivo por lotes, lo ejecuté, pero el servicio no se inicia. Incluso si reemplazo net start con otra cosa, como imprimir en un archivo, no se ejecutará. ¿Le importaría echar un segundo vistazo, por favor? =)
citronas
Vaya, tenía algunas cosas extra en la primera línea allí ... Prueba esto. Y si no funciona, ¿qué sucede cuando se ejecuta sc query "SCardSvr"desde una línea de comando?
lc.
1
¿Tiene "SCardSvr" entre comillas? No creo que deba ser,
LittleBobbyTables - Au Revoir
@LittleBobbyTables: Tienes razón. Sin comillas lo hizo funcionar. Soy tan estúpido: - | Gracias por su ayuda
citronas
@Mark Es bueno tener en cuenta. Supongo que tendrá que reemplazar esa cadena con lo que sea necesario para el idioma del sistema operativo de destino. Asumo "CORRER" también.
lc.
34

Para alternar un servicio, utilice lo siguiente;

NET START "Coordinador de transacciones distribuidas" || NET STOP "Coordinador de transacciones distribuidas"

Cooperativas
fuente
1
Funciona debido al código de salida desde el principio. Si el comando de inicio falla es probablemente porque ya se está ejecutando (y de cualquier manera, detenerlo posteriormente no hará daño), así que intente detenerlo.
lc.
3
el comando está estructurado de tal manera que si net start falla, lo detiene (debido a || que significa otra cosa), pero si net start se ejecuta, entonces net stop no se ejecuta. ¡brillante!
Doctor DOS
1
Esta es la mejor respuesta en mi opinión, y tal vez @citronas debería considerar marcarla como la respuesta aceptada: simple, inteligente y elegante, y se adapta a un sitio como StackOverflow. ¡Hazlo simple!
Sopalajo de Arrierez
2
No quiero ser quisquilloso (bueno, tal vez solo un poco), pero en ||realidad es un ORoperador, aunque en este caso es funcionalmente una ELSEdeclaración. Ésta es una diferencia sutil pero importante. Todavía tengo mi +1: hago esto todo el tiempo en secuencias de comandos de shell de Unix / Linux, no sé por qué nunca pensé en hacer esto en lotes de Windows.
Doug R.
Esto parece peligrosamente simplificado en exceso. Nunca querría usarlo para algo que esté automatizando para el procesamiento por lotes o dándole a otra persona para que lo use ... pero es justo lo que el médico ordenó para un ícono rápido que puedo poner en mi propio escritorio para un servicio que necesito alternar rápidamente de vez en cuando.
Joel Coehoorn
19

Puede usar el siguiente comando para ver si un servicio se está ejecutando o no:

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

Cuando lo ejecuto para mi NOD32 Antivirus, obtengo:

STATE                       : 4 RUNNING

Si se detuviera, obtendría:

STATE                       : 1 STOPPED

Puede usar esto en una variable para luego determinar si usa NET START o no.

El nombre del servicio debe ser el nombre del servicio, no el nombre para mostrar.

LittleBobbyTables - Au Revoir
fuente
1
Gracias por su ayuda, al intentar integrar lo que publicó, aumenté mucho mis habilidades por lotes;)
citronas
14

Deberias hacer eso:

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

Versión independiente del idioma.

@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
fuente
¡Sí! ¡El "espacio" siempre golpea de repente en tu espalda!
Dr.eel
2
Respuesta casi perfecta. Solo arreglaría esta línea: Net start "% ServiceName%"> nul || (
Cesar
He hecho que el script sea universal, por lo que me permite usarlo en las tareas del Programador de Windows. Simplemente reemplácelo Set ServiceName=Jenkinscon Set ServiceName=%~1y watch-service.bat "Jenkins"
llámelo
@ Ant_222 Utiliza 'queryex' en lugar de 'query', que depende del idioma. ¿Y por qué cree que no es un lote de Windows? ¿Has intentado usarlo?
Dr.eel
5

Acabo de encontrar este hilo y quería agregarlo a la discusión si la persona no quiere usar un archivo por lotes para reiniciar los servicios. En Windows hay una opción si va a Servicios, propiedades del servicio y luego recuperación. Aquí puede establecer parámetros para el servicio. Me gusta reiniciar el servicio si el servicio se detiene. Además, incluso puede hacer que un segundo intento fallido haga algo diferente, como reiniciar la computadora.

rayo de salvia
fuente
2
Esa es una respuesta útil, sin embargo, es importante tener en cuenta que solo funcionará si el servicio se ha detenido con exit (-1). Si el servicio salió correctamente (incluso con un mensaje de error), la recuperación automática no se activará. Tampoco se activará si el usuario eliminó el servicio manualmente.
Art Gertner
@sagelightning: Necesitamos acceso de administrador para intentarlo de esta manera.
Kumar M
@ArtGertner: matar (a través del administrador de tareas) un proceso de servicio se interpretará como "bloqueo" y activará una recuperación.
Martin Ba
3

Cuando se usa Windows en español, el código debe quedar así (cuando se usa Windows en español, el código es):

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. (Reemplace MYSERVICE con el nombre del servicio que se procesará. Puede ver el nombre del servicio en las propiedades del servicio).

Daniel Serrano
fuente
10
Será mejor para todos si escribe su respuesta en inglés.
j0k
2
No estoy seguro de por qué el voto negativo. Este es un punto importante y una razón para evitar las comparaciones de cadenas si es posible. En este caso, debe cambiar la cadena según el idioma predeterminado de la instalación de Windows de destino.
lc.
2
@lc: ¿Sería razonable incluir una respuesta para cada idioma? Podría ser más útil hacer referencia (o incluir) un recurso que diga qué cadena buscar en un idioma determinado.
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
fuente
2

Para Windows Server 2012 a continuación es lo que funcionó para mí. Reemplace solo "SERVICENAME" con el nombre real del servicio:

@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
fuente
1

También quería que se enviara un correo electrónico si el servicio se iniciaba de esta manera, así que agregué un poco al código @Ic, solo pensé en publicarlo en caso de que ayudara a alguien. Usé SendMail pero hay otras opciones de línea de comandos. ¿Cómo enviar un correo electrónico simple desde un archivo por lotes de 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
fuente
1

Inicio del servicio usando el script de Powershell. Puede vincularlo al programador de tareas y activarlo a intervalos o según sea necesario. Cree esto como un archivo PS1, es decir, un archivo con extensión PS1 y luego deje que este archivo se active desde el programador de tareas.

Para iniciar el servicio de parada

en el programador de tareas si lo está usando en el servidor, use esto en los argumentos

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

verifique ejecutando lo mismo en cmd si funciona, también debería funcionar en el programador de tareas

$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
fuente
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
fuente
0

Relacionado con la respuesta de @DanielSerrano, recientemente me ha mordido la localización del sc.execomando, es decir, en español. Mi propuesta es señalar la línea y el token que contiene el estado de servicio numérico e interpretarlo, que debería ser mucho más robusto:

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

Probado con:

  • Windows XP (32 bits) Inglés
  • Windows 10 (32 bits) español
  • Windows 10 (64 bits) Inglés
Helder Magalhães
fuente
0

¿Quizás de una forma mucho más sencilla? Solo agregando a la lista de respuestas aquí:

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