Como verificar se um serviço está rodando via arquivo batch e iniciá-lo, caso não esteja rodando?

90

Quero escrever um arquivo em lote que execute as seguintes operações:

  • Verifique se um serviço está em execução
    • Se estiver em execução, saia do lote
    • Se não estiver em execução, inicie o serviço

Os exemplos de código que pesquisei até agora não funcionaram, então decidi não publicá-los.

O início de um serviço é feito por:

net start "SERVICENAME"
  1. Como posso verificar se um serviço está sendo executado e como fazer uma instrução if em um batchfile?
  2. Estou um pouco confuso. Qual é o argumento que devo passar para o início da rede? O nome do serviço ou seu nome de exibição?
citronas
fonte
3
Programação suja: quando a única coisa que você deseja fazer é iniciar o serviço se ele não estiver em execução, basta emitir o comando start. Se não estiver em execução, o serviço será iniciado. Se estiver em execução, você receberá uma mensagem de erro, mas o serviço está em execução (e não para). Sujo, mas funciona. No entanto, quando você quiser executar outros comentários apenas se tiver que iniciar o serviço, vá definitivamente com a versão mais limpa da lc.
Peter Schuetze
@Peter Schuetze: Sim, sua objeção está correta se iniciar o serviço é o único propósito. Eu também incluí inícios de registro et cetera, então continuei com a solução de lc.
Citronas,

Respostas:

163

Para verificar o estado de um serviço, use sc query <SERVICE_NAME>. Para se bloqueia em arquivos de lote, verifique a documentação .

O código a seguir verificará o status do serviço MyServiceNamee o iniciará se ele não estiver em execução (o bloco if será executado se o serviço não estiver em execução):

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

Explicação do que faz:

  1. Consulta as propriedades do serviço.
  2. Procura a linha que contém o texto "ESTADO"
  3. Tokeniza essa linha e extrai o terceiro token, que contém o estado do serviço.
  4. Testa o estado resultante em relação à string "RUNNING"

Quanto à sua segunda pergunta, o argumento que você deseja transmitir net starté o nome do serviço, não o nome de exibição.

lc.
fonte
Impressionante. Obrigado pelo seu esforço. Infelizmente isso não funciona? Talvez eu seja muito estúpido para isso. Substituí "MyServiceName" por "SCardSvr" (com escape) como um teste, coloquei tudo em um batchfile, executei, mas o serviço não inicia. Mesmo se eu substituir net start por outra coisa, como imprimir em um arquivo, ele não será executado. Você se importaria de dar uma segunda olhada, por favor? =)
citronas
Opa, eu tinha algumas coisas extras na primeira linha ... Tente isto. E se não funcionar, o que acontece quando você executa a sc query "SCardSvr"partir de uma linha de comando?
lc.
1
Você tem "SCardSvr" entre aspas? Eu não acredito que deveria ser,
LittleBobbyTables - Au Revoir
@LittleBobbyTables: Você está certo. Sem aspas fez funcionar. Eu sou tão estúpido: - | Obrigado pela sua ajuda
citronas
@Mark É bom observar. Eu acho que você terá que substituir essa string com o que for necessário para o idioma do sistema operacional de destino. Eu suponho que "RUNNING" também.
lc.
34

Para alternar um serviço, use o seguinte;

NET START "Coordenador de transações distribuídas" || NET STOP "Coordenador de transações distribuídas"

Coops
fonte
1
Funciona por causa do código de saída desde o início. Se o comando start falhar, provavelmente é porque ele já está em execução (e de qualquer forma, pará-lo subsequentemente não fará mal), então tente pará-lo.
lc.
3
o comando é estruturado de forma que se net start falhar, ele então o interrompe (devido ao || que significa outra coisa), mas se net start for executado, então net stop não será executado. brilhante!
Doutor DOS
1
Esta é a melhor resposta na minha opinião, e talvez @citronas deva considerar marcá-la como a resposta aceita: simples, inteligente e elegante, e se encaixa em um site como StackOverflow. Simplifique!
Sopalajo de Arrierez 01 de
2
Não quero ser minucioso (OK, talvez um pouco), mas na ||verdade é um ORoperador, embora neste caso seja funcionalmente uma ELSEinstrução. Esta é uma diferença sutil, mas importante. Ainda tenho o meu +1 - faço isso o tempo todo em scripts de shell Unix / Linux, não sei por que nunca pensei em fazer isso em lotes do Windows.
Doug R.
Isso parece extremamente simplificado. Eu nunca gostaria de usá-lo para algo que estava automatizando para processamento em lote ou dando a outra pessoa para usar ... mas é apenas o que o médico receitou para um ícone rápido que posso colocar em minha própria área de trabalho para um serviço que preciso alternar rapidamente de vez em quando.
Joel Coehoorn
19

Você pode usar o seguinte comando para ver se um serviço está sendo executado ou não:

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

Quando eu o executo para meu antivírus NOD32, recebo:

STATE                       : 4 RUNNING

Se fosse interrompido, eu obteria:

STATE                       : 1 STOPPED

Você pode usar isso em uma variável para determinar se você usa NET START ou não.

O nome do serviço deve ser o nome do serviço, não o nome de exibição.

LittleBobbyTables - Au Revoir
fonte
1
Obrigado pela ajuda, enquanto tento integrar o que você postou,
aumentei
14

Isso deve resolver:

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

Versão independente do 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
fonte
Sim! O "espaço" sempre bate de repente nas suas costas!
Dr.eel
2
Resposta quase perfeita. Eu apenas corrigiria esta linha: Net start "% ServiceName%"> nul || (
Cesar
Tornei o script universal para que ele me permita usá-lo nas tarefas do Windows Scheduler. Basta substituir Set ServiceName=Jenkinspor Set ServiceName=%~1e chamá-lo assimwatch-service.bat "Jenkins"
Dr.eel
@ Ant_222 Ele usa 'queryex' em vez de 'query', que depende do idioma. E por que você acha que não é lote do Windows? Você já tentou usar?
Dr.eel
5

Acabei de encontrar este tópico e gostaria de acrescentar à discussão se a pessoa não deseja usar um arquivo em lote para reiniciar serviços. No Windows, há uma opção se você acessar Serviços, propriedades do serviço e, em seguida, recuperação. Aqui você pode definir parâmetros para o serviço. Gostaria de reiniciar o serviço se o serviço parar. Além disso, você pode até mesmo fazer com que uma segunda tentativa de falha faça algo diferente, como reiniciar o computador.

sagelight
fonte
2
Essa é uma resposta útil, mas é importante notar, que só funcionará se o serviço for interrompido com exit (-1). Se o serviço foi encerrado normalmente (mesmo com mensagem de erro) A recuperação automática não será acionada. Ele também não será acionado se o serviço for encerrado manualmente pelo usuário.
Art Gertner
@sagelightning: Precisamos de acesso de administrador para tentar desta forma.
Kumar M
@ArtGertner - Matar (através do gerenciador de tarefas) um processo de serviço será interpretado como "travamento" e acionará uma recuperação.
Martin Ba
3

Cuando se usar Windows en Español, el código debe quedar asi (ao usar Windows em espanhol, o código é):

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 that se desea procesar. Puedes ver el nombre del servicio viendo las propiedades del servicio. (Substitua MYSERVICE pelo nome do serviço a ser processado. Você pode ver o nome do serviço nas propriedades do serviço.)

Daniel Serrano
fonte
10
Será melhor para todos se você escrever sua resposta em inglês.
j0k
2
Não sei por que o downvote. Este é um ponto importante e um motivo para evitar comparações de strings, se possível. Nesse caso, você deve alterar a string dependendo do idioma padrão da instalação do Windows de destino.
lc.
2
@lc: Seria razoável incluir uma resposta para cada idioma? Pode ser mais útil fazer referência (ou incluir) um recurso que diga qual string pesquisar para um determinado idioma.
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
fonte
2

Para o servidor Windows 2012 abaixo é o que funcionou para mim. Substitua apenas "SERVICENAME" pelo nome do serviço real:

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

Eu também queria que um e-mail fosse enviado se o serviço fosse iniciado dessa forma, então adicionei um pouco ao código @Ic apenas pensei em postá-lo caso ajudasse alguém. Eu usei SendMail, mas existem outras opções de linha de comando. Como enviar um e-mail simples de um arquivo de lote do 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
fonte
1

Iniciando o serviço usando o script Powershell. Você pode vincular isso ao agendador de tarefas e acioná-lo em intervalos ou conforme necessário. Crie-o como um arquivo PS1, ou seja, um arquivo com a extensão PS1 e, em seguida, deixe esse arquivo ser acionado a partir do agendador de tarefas.

Para iniciar o serviço de parada

no agendador de tarefas se você estiver usando no servidor use isso em argumentos

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

verifique executando o mesmo no cmd se funciona, deve funcionar no agendador de tarefas também

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

Relacionado com a resposta de @DanielSerrano, recentemente fui pouco por localização do sc.execomando, nomeadamente em espanhol. Minha proposta é apontar a linha e o token que contém o estado de serviço numérico e interpretá-lo, que deve ser muito mais 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
  )
)

Testado com:

  • Windows XP (32 bits) Inglês
  • Windows 10 (32 bits) espanhol
  • Windows 10 (64 bits) Inglês
Helder Magalhães
fonte
0

Talvez uma maneira muito mais simples? Apenas adicionando à lista de respostas aqui:

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