Jak sprawdzić, czy usługa działa za pośrednictwem pliku wsadowego i uruchomić ją, jeśli nie działa?


90

Chcę napisać plik wsadowy, który wykonuje następujące operacje:

  • Sprawdź, czy usługa jest uruchomiona
    • Jeśli to działa, zamknij pakiet
    • Jeśli nie działa, uruchom usługę

Próbki kodu, które do tej pory wygooglowałem, okazały się nie działać, więc postanowiłem ich nie publikować.

Uruchomienie usługi odbywa się poprzez:

net start "SERVICENAME"
  1. Jak mogę sprawdzić, czy usługa jest uruchomiona i jak złożyć instrukcję if w pliku wsadowym?
  2. Jestem nieco zdezorientowany. Jaki argument mam przekazać na start netto? Nazwa usługi czy jej nazwa wyświetlana?

3
Brudne programowanie: jeśli jedyną rzeczą, którą chcesz zrobić, jest uruchomienie usługi, jeśli nie jest uruchomiona, po prostu wydaj polecenie start. Jeśli nie działa, uruchomi usługę. Jeśli jest uruchomiona, pojawia się komunikat o błędzie, ale usługa działa (i nie zatrzymuje się). Brudne, ale działa. Jeśli jednak chcesz wykonać inne komentarze tylko wtedy, gdy musisz uruchomić usługę, zdecydowanie wybierz czystszą wersję z lc.
Peter Schuetze

@Peter Schuetze: Tak, twój sprzeciw jest słuszny, jeśli uruchomienie usługi jest jedynym celem. Dołączyłem również logowanie startów i tak dalej, więc trzymałem się rozwiązania lc.
citronas

Odpowiedzi:


164

Aby sprawdzić stan usługi, użyj sc query <SERVICE_NAME>. Jeśli blokuje się w plikach wsadowych, zapoznaj się z dokumentacją .

Poniższy kod sprawdzi stan usługi MyServiceNamei uruchomi ją, jeśli nie jest uruchomiona (blok if zostanie wykonany, jeśli usługa nie jest uruchomiona):

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

Wyjaśnienie, co robi:

  1. Pyta o właściwości usługi.
  2. Szuka wiersza zawierającego tekst „STATE”
  3. Tokenizuje tę linię i wyciąga trzeci token, czyli ten zawierający stan usługi.
  4. Testuje wynikowy stan na podstawie ciągu „RUNNING”

Jeśli chodzi o drugie pytanie, argumentem, do którego chcesz przekazać, net startjest nazwa usługi, a nie nazwa wyświetlana.


Niesamowite. Dzięki za twój wysiłek. Niestety to nie działa? Może jestem na to za głupi. Zamieniłem "MyServiceName" na "SCardSvr" (uciekł) jako test, umieściłem wszystko w pliku wsadowym, wykonałem go, ale usługa się nie uruchamia. Nawet jeśli zastąpię net start czymś innym, np. Wydrukowaniem do pliku, to nie zostanie wykonane. Czy mógłbyś ponownie spojrzeć? =)
citronas

Ups, w pierwszej linii miałem kilka dodatkowych rzeczy ... Spróbuj tego. A jeśli to nie zadziała, co się stanie, gdy uruchomisz sc query "SCardSvr"z wiersza poleceń?
lc.

1
Czy masz w cudzysłowie słowo „SCardSvr”? Nie sądzę, żeby tak było,
LittleBobbyTables - Au Revoir

@LittleBobbyTables: Masz rację. Bez cytatów to działało. Jestem taki głupi: - | Dzięki za pomoc
citronas

@Mark Warto zauważyć. Wydaje mi się, że będziesz musiał zamienić ten ciąg na wszystko, co musi być dla docelowego języka systemu operacyjnego. Zakładam również „BIEGANIE”.
lc.

34

Aby przełączyć usługę, użyj następującego;

NET START "Koordynator transakcji rozproszonych" || NET STOP "Koordynator transakcji rozproszonych"


1
Działa z powodu kodu wyjścia od początku. Jeśli polecenie uruchomienia nie powiedzie się, prawdopodobnie dlatego, że już działa (i tak czy inaczej, późniejsze jego zatrzymanie nie zaszkodzi), więc spróbuj je zatrzymać.
lc.

3
polecenie jest zbudowane w taki sposób, że jeśli net start się nie powiedzie, to następnie je zatrzymuje (z powodu ||, co oznacza inaczej), ale jeśli uruchomi się net start, to net stop nie zostanie wykonany. znakomity!
Doctor DOS

1
Moim zdaniem jest to najlepsza odpowiedź i może @citronas powinien rozważyć oznaczenie jej jako akceptowanej odpowiedzi: prosta, inteligentna i elegancka oraz pasuje do witryny takiej jak StackOverflow. Uprość to!
Sopalajo de Arrierez

2
Nie żeby być dziurawym (OK, może trochę), ale w ||rzeczywistości jest ORoperatorem, chociaż w tym przypadku jest to instrukcja funkcjonalnaELSE . To subtelna, ale ważna różnica. Nadal mam +1 - robię to cały czas w skryptach powłoki Unix / Linux, nie wiem, dlaczego nigdy nie pomyślałem o zrobieniu tego w systemie Windows.
Doug R.

Wydaje się to niebezpiecznie uproszczone. Nigdy nie chciałbym go używać do czegoś, co automatyzowałem do przetwarzania wsadowego lub dawałem komuś innemu do użycia ... ale to jest właśnie to, co lekarz zamówił na szybką ikonę, którą mogę umieścić na własnym pulpicie w celu wykonania usługi, której potrzebuję szybko przełączaj się od czasu do czasu.
Joel Coehoorn

20

Możesz użyć następującego polecenia, aby sprawdzić, czy usługa jest uruchomiona, czy nie:

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

Kiedy uruchamiam go dla mojego NOD32 Antivirus, otrzymuję:

STATE                       : 4 RUNNING

Gdyby został zatrzymany, dostałbym:

STATE                       : 1 STOPPED

Możesz użyć tego w zmiennej, aby następnie określić, czy używasz NET START, czy nie.

Nazwa usługi powinna być nazwą usługi, a nie nazwą wyświetlaną.


1
Dziękuję za pomoc, próbując zintegrować to, co opublikowałeś, znacznie zwiększam swoje umiejętności wsadowe;)
citronas

14

Że należy to zrobić:

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

11

Wersja niezależna od języka.

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

Tak! „Space” zawsze uderza nagle w plecy!
Dr eel

2
Prawie doskonała odpowiedź. Po prostu naprawiłbym ten wiersz: Net start "% ServiceName%"> nul || (
Cesar

Stworzyłem ten skrypt jako uniwersalny, dzięki czemu mogę go używać w zadaniach harmonogramu systemu Windows. Wystarczy wymienić Set ServiceName=Jenkinsz Set ServiceName=%~1i nazywają to jakwatch-service.bat "Jenkins"
Dr.eel

@ Ant_222 Używa „queryex” zamiast „query”, które jest zależne od języka. I dlaczego myślisz, że to nie jest partia systemu Windows? Czy próbowałeś go użyć?
Dr eel

5

Właśnie znalazłem ten wątek i chciałem dodać go do dyskusji, jeśli osoba nie chce używać pliku wsadowego do ponownego uruchamiania usług. W systemie Windows jest opcja, jeśli przejdziesz do Usługi, właściwości usługi, a następnie odzyskiwanie. Tutaj możesz ustawić parametry usługi. Chciałbym ponownie uruchomić usługę, jeśli usługa zostanie zatrzymana. Możesz także wykonać drugą nieudaną próbę zrobienia czegoś innego, jak w przypadku ponownego uruchomienia komputera.


2
Jest to przydatna odpowiedź, jednak należy pamiętać, że będzie ona działać tylko wtedy, gdy usługa została zatrzymana z wyjściem (-1). Jeśli usługa zakończyła się pomyślnie (nawet z komunikatem o błędzie), automatyczne odzyskiwanie nie zostanie wyzwolone. Nie uruchomi się również, jeśli usługa została ręcznie zabita przez użytkownika.
Art Gertner

@sagelightning: Aby spróbować w ten sposób, potrzebujemy dostępu administratora.
Kumar M

@ArtGertner - zabicie (przez menedżera zadań) procesu usługi zostanie zinterpretowane jako „awaria” i spowoduje przywrócenie.
Martin Ba

3

Cuando se używaj Windows en Español, el código debe quedar asi (gdy używasz Windows w języku hiszpańskim, kod to):

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. (Zastąp MYSERVICE nazwą usługi do przetworzenia. Nazwę usługi można zobaczyć we właściwościach usługi).


10
Dla każdego będzie lepiej, jeśli napiszesz odpowiedź po angielsku.
j0k

2
Nie jestem pewien, dlaczego głosowano przeciw. Jest to ważna kwestia i powód, aby w miarę możliwości unikać porównań ciągów. W takim przypadku musisz zmienić ciąg w zależności od domyślnego języka docelowej instalacji systemu Windows.
lc.

2
@lc: Czy rozsądne byłoby uwzględnienie odpowiedzi dla każdego języka? Bardziej przydatne może być odniesienie (lub dołączenie) zasobu, który mówi, jaki ciąg wyszukiwać w danym języku.
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"

2

W przypadku Windows Server 2012 poniżej działało dla mnie. Zastąp tylko „SERVICENAME” rzeczywistą nazwą usługi:

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

1

Chciałem również, aby e-mail został wysłany, jeśli usługa została uruchomiona w ten sposób, więc dodałem trochę do kodu @Ic, po prostu pomyślałem, że opublikuję go na wypadek, gdyby to komuś pomogło. Użyłem SendMail, ale są inne opcje wiersza poleceń. Jak wysłać prostą wiadomość e-mail z pliku wsadowego systemu 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 me@mydomain.com /from watchdog@mydomain.com /subject Service Autostart Notification /body Autostart on service %service% succeded.
      ) else (
        SendMail /smtpserver localhost /to me@mydomain.com /from watchdog@mydomain.com /subject Service Autostart Notification /body Autostart on service %service% failed.
      )
    )

  )
)

1

Uruchamianie usługi przy użyciu skryptu Powershell. Możesz połączyć to z harmonogramem zadań i wyzwalać je w odstępach czasu lub w razie potrzeby. Utwórz to jako plik PS1, tj. Plik z rozszerzeniem PS1, a następnie pozwól, aby ten plik był uruchamiany z harmonogramu zadań.

Aby rozpocząć, zatrzymaj usługę

w harmonogramie zadań, jeśli używasz go na serwerze, użyj tego w argumentach

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

sprawdź, uruchamiając to samo na cmd, jeśli działa, powinien również działać na harmonogramie zadań

$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
}
}

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

0

Związane z odpowiedzią @DanielSerrano, ostatnio byłem trochę od lokalizacji sc.exepolecenia, a mianowicie po hiszpańsku. Moją propozycją jest wskazanie linii i tokena, który zawiera numeryczny stan usługi i zinterpretowanie go, co powinno być znacznie bardziej niezawodne:

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

Testowane z:

  • Windows XP (32-bitowy) angielski
  • Windows 10 (32-bitowy) hiszpański
  • Windows 10 (64-bitowy) angielski

0

Może o wiele prostszy sposób? Dodam tylko do listy odpowiedzi tutaj:

@for /f "tokens=1,* delims=: " %%a in ('sc queryex state=Inactive') do net start "%%b"
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.