จะตรวจสอบได้อย่างไรว่าบริการกำลังทำงานผ่านไฟล์แบตช์และเริ่มทำงานหากไม่ได้ทำงาน


91

ฉันต้องการเขียนแบตช์ไฟล์ที่ดำเนินการดังต่อไปนี้:

  • ตรวจสอบว่าบริการกำลังทำงานอยู่หรือไม่
    • หากกำลังทำงานอยู่ให้ออกจากชุดงาน
    • หากยังไม่ทำงานให้เริ่มบริการ

ตัวอย่างโค้ดที่ฉัน googled จนถึงขณะนี้ใช้งานไม่ได้ดังนั้นฉันจึงตัดสินใจที่จะไม่โพสต์

การเริ่มต้นบริการทำได้โดย:

net start "SERVICENAME"
  1. ฉันจะตรวจสอบได้อย่างไรว่าบริการกำลังทำงานอยู่และจะสร้างคำสั่ง if ใน batchfile ได้อย่างไร
  2. ฉันสับสนนิดหน่อย อะไรคือข้อโต้แย้งที่ฉันต้องส่งต่อไปยัง net start? ชื่อบริการหรือชื่อที่แสดง?

3
การเขียนโปรแกรมสกปรก: เมื่อสิ่งเดียวที่คุณต้องการทำคือเริ่มบริการหากยังไม่ทำงานเพียงแค่ออกคำสั่งเริ่ม หากยังไม่ทำงานจะเริ่มให้บริการ หากกำลังทำงานกว่าคุณจะได้รับข้อความแสดงข้อผิดพลาด แต่บริการกำลังทำงานอยู่ (และไม่หยุดทำงาน) สกปรก แต่ใช้งานได้ อย่างไรก็ตามเมื่อคุณต้องการดำเนินการกับความคิดเห็นอื่น ๆ เฉพาะในกรณีที่คุณต้องเริ่มบริการให้ไปที่เวอร์ชันที่สะอาดกว่าจาก lc
Peter Schuetze

@Peter Schuetze: ใช่การคัดค้านของคุณถูกต้องหากการเริ่มบริการเป็นเพียงจุดประสงค์เดียว ฉันรวมการบันทึกเริ่มต้นและอื่น ๆ ด้วยดังนั้นฉันจึงยึดติดกับโซลูชันของ lc
citronas

คำตอบ:


164

sc query <SERVICE_NAME>หากต้องการตรวจสอบสถานะการให้บริการของการใช้งาน เพราะว่าถ้าบล็อกในไฟล์ชุดตรวจสอบเอกสาร

รหัสต่อไปนี้จะตรวจสอบสถานะของบริการMyServiceNameและเริ่มต้นหากไม่ทำงาน (บล็อก if จะถูกเรียกใช้งานหากบริการไม่ทำงาน):

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

คำอธิบายว่ามันทำอะไร:

  1. สอบถามคุณสมบัติของบริการ
  2. ค้นหาบรรทัดที่มีข้อความ "STATE"
  3. สร้างโทเค็นบรรทัดนั้นและดึงโทเค็นที่ 3 ออกมาซึ่งเป็นโทเค็นที่มีสถานะของบริการ
  4. ทดสอบสถานะผลลัพธ์เทียบกับสตริง "RUNNING"

สำหรับคำถามที่สองอาร์กิวเมนต์ที่คุณต้องการส่งผ่านnet startคือชื่อบริการไม่ใช่ชื่อที่แสดง


น่ากลัว ขอบคุณสำหรับความพยายามของคุณ น่าเสียดายที่มันไม่ทำงาน? บางทีฉันอาจจะโง่เกินไปสำหรับเรื่องนี้ ฉันแทนที่ "MyServiceName" ด้วย "SCardSvr" (Escape) เป็นการทดสอบใส่ทุกอย่างลงใน batchfile ดำเนินการ แต่บริการไม่เริ่มทำงาน แม้ว่าฉันจะแทนที่ net start ด้วยอย่างอื่นเช่นการพิมพ์ลงในไฟล์ก็จะไม่ถูกดำเนินการ คุณช่วยดูครั้งที่สองได้ไหม =)
citronas

อ๊ะฉันมีของพิเศษในบรรทัดแรกที่นั่น ... ลองดูสิ และถ้าไม่ได้ผลจะเกิดอะไรขึ้นเมื่อคุณเรียกใช้sc query "SCardSvr"จากบรรทัดคำสั่ง?
lc.

1
คุณมี "SCardSvr" ในเครื่องหมายคำพูดหรือไม่ ฉันไม่เชื่อว่ามันควรจะเป็น
LittleBobbyTables - Au Revoir

@LittleBobbyTables: คุณพูดถูก ไม่มีเครื่องหมายคำพูดทำให้มันใช้งานได้ ฉันโง่มาก: - | ขอบคุณสำหรับความช่วยเหลือ
citronas

@Mark ควรทราบ ฉันเดาว่าคุณจะต้องแทนที่สตริงนั้นด้วยสิ่งที่จำเป็นสำหรับภาษา OS เป้าหมาย ฉันถือว่า "RUNNING" ด้วย
lc.

34

ในการสลับบริการให้ใช้ดังต่อไปนี้

NET START "ผู้ประสานงานธุรกรรมแบบกระจาย" || NET STOP "ผู้ประสานงานธุรกรรมแบบกระจาย"


1
ทำงานได้เนื่องจากรหัสออกตั้งแต่เริ่มต้น หากคำสั่ง start ล้มเหลวอาจเป็นเพราะมันทำงานอยู่แล้ว (และไม่ว่าจะหยุดด้วยวิธีใดก็ไม่เจ็บ) ดังนั้นให้ลองหยุด
lc.

3
คำสั่งมีโครงสร้างเช่นนั้นหาก net start ล้มเหลวคำสั่งนั้นจะหยุดทำงาน (เนื่องจาก || ซึ่งหมายถึงอื่น) แต่ถ้า net start ทำงานดังนั้น net stop จะไม่ทำงาน แจ่ม!
Doctor DOS

1
นี่เป็นคำตอบที่ดีที่สุดในความคิดของฉันและบางที @citronas ควรพิจารณาทำเครื่องหมายว่าเป็นคำตอบที่ยอมรับ: เรียบง่ายฉลาดและสง่างามและเหมาะกับไซต์อย่าง StackOverflow ทำให้ง่าย!
Sopalajo de Arrierez

2
เพื่อไม่ให้ nitpicky (OK อาจจะแค่เล็ก ๆ น้อย ๆ ) แต่||เป็นจริงORผู้ประกอบการแม้ว่าในกรณีนี้มันเป็นหน้าที่ELSEคำสั่ง นี่คือความแตกต่างที่ลึกซึ้ง แต่สำคัญ ยังคงได้ +1 ของฉัน - ฉันทำสิ่งนี้ตลอดเวลาในเชลล์สคริปต์ Unix / Linux ไม่รู้ว่าทำไมฉันไม่เคยคิดที่จะทำสิ่งนี้ใน Windows batch
Doug R.

สิ่งนี้ดูเหมือนจะใหญ่เกินไปอย่างอันตราย ฉันไม่เคยต้องการใช้มันเพื่อสิ่งที่ฉันกำลังดำเนินการโดยอัตโนมัติสำหรับการประมวลผลชุดงานหรือมอบให้คนอื่นใช้ ... แต่เป็นเพียงสิ่งที่แพทย์สั่งสำหรับไอคอนด่วนที่ฉันสามารถวางไว้บนเดสก์ท็อปของตัวเองสำหรับบริการที่ฉันต้องการ สลับอย่างรวดเร็วในขณะนี้แล้ว
Joel Coehoorn

20

คุณสามารถใช้คำสั่งต่อไปนี้เพื่อดูว่าบริการกำลังทำงานอยู่หรือไม่:

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

เมื่อฉันเรียกใช้สำหรับ NOD32 Antivirus ฉันจะได้รับ:

STATE                       : 4 RUNNING

หากหยุดทำงานฉันจะได้รับ:

STATE                       : 1 STOPPED

คุณสามารถใช้สิ่งนี้ในตัวแปรเพื่อกำหนดว่าคุณใช้ NET START หรือไม่

ชื่อบริการควรเป็นชื่อบริการไม่ใช่ชื่อที่แสดง


1
ขอบคุณสำหรับความช่วยเหลือในขณะที่พยายามผสานรวมสิ่งที่คุณโพสต์ฉันเพิ่มทักษะแบทช์ของฉันขึ้นมาก)
citronas


12

ภาษาเวอร์ชันอิสระ

@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

2
คำตอบเกือบสมบูรณ์แบบ ฉันจะแก้ไขบรรทัดนี้: Net start "% ServiceName%"> nul || (
Cesar

ฉันได้สร้างสคริปต์ให้เป็นสากลเพื่อให้ฉันใช้ในงาน Windows Scheduler ได้ เพียงแค่เปลี่ยนSet ServiceName=Jenkinsด้วยSet ServiceName=%~1และเรียกมันเหมือนwatch-service.bat "Jenkins"
Dr.eel

@ Ant_222 ใช้ 'queryex' แทน 'query' ซึ่งขึ้นอยู่กับภาษา และทำไมคุณถึงคิดว่ามันไม่ใช่ Windows batch? ได้ลองใช้กันหรือยัง?
Dr.eel

5

ฉันเพิ่งพบหัวข้อนี้และต้องการเพิ่มในการสนทนาหากบุคคลนั้นไม่ต้องการใช้ไฟล์แบตช์เพื่อเริ่มบริการใหม่ ใน Windows มีตัวเลือกถ้าคุณไปที่บริการคุณสมบัติของบริการแล้วกู้คืน คุณสามารถตั้งค่าพารามิเตอร์สำหรับบริการได้ที่นี่ ต้องการเริ่มบริการใหม่หากบริการหยุดลง นอกจากนี้คุณยังสามารถพยายามล้มเหลวครั้งที่สองเพื่อทำสิ่งที่แตกต่างออกไปเช่นในการรีสตาร์ทคอมพิวเตอร์


2
นั่นเป็นคำตอบที่มีประโยชน์อย่างไรก็ตามสิ่งสำคัญที่ควรทราบจะใช้ได้เฉพาะเมื่อบริการหยุดลงโดยมี exit (-1) หากบริการออกอย่างสง่างาม (แม้จะมีข้อความแสดงข้อผิดพลาด) การกู้คืนอัตโนมัติจะไม่ทำงาน นอกจากนี้ยังไม่ทริกเกอร์หากบริการถูกฆ่าด้วยตนเองโดยผู้ใช้
Art Gertner

@sagelightning: เราต้องการการเข้าถึงระดับผู้ดูแลระบบเพื่อลองใช้วิธีนี้
Kumar M

@ArtGertner - การฆ่า (ผ่านตัวจัดการงาน) กระบวนการบริการจะถูกตีความว่า "ขัดข้อง" และจะเรียกการกู้คืน
Martin Ba

3

Cuando se ใช้ Windows en Español, el código debe quedar asi (เมื่อใช้ Windows เป็นภาษาสเปนรหัสคือ):

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 (แทนที่ MYSERVICE ด้วยชื่อของบริการที่จะดำเนินการคุณสามารถดูชื่อของบริการในคุณสมบัติของบริการ)


11
จะดีกว่าสำหรับทุกคนถ้าคุณเขียนคำตอบเป็นภาษาอังกฤษ
j0k

2
ไม่แน่ใจว่าทำไมถึงโหวตลด นี่เป็นจุดสำคัญและเป็นเหตุผลที่ควรหลีกเลี่ยงการเปรียบเทียบสตริงหากเป็นไปได้ ในกรณีนี้คุณต้องเปลี่ยนสตริงโดยขึ้นอยู่กับภาษาเริ่มต้นของการติดตั้ง Windows เป้าหมาย
lc.

2
@lc: การใส่คำตอบสำหรับแต่ละภาษานั้นสมเหตุสมผลหรือไม่ การอ้างอิง (หรือรวม) ทรัพยากรอาจมีประโยชน์มากกว่าซึ่งระบุว่าสตริงใดที่จะค้นหาภาษาที่กำหนด
Mike Bailey


2

สำหรับ Windows Server 2012 ด้านล่างคือสิ่งที่ใช้ได้ผลสำหรับฉัน แทนที่ "SERVICENAME" ด้วยชื่อบริการจริงเท่านั้น:

@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

ฉันต้องการอีเมลที่ส่งไปหากบริการเริ่มต้นด้วยวิธีนี้ดังนั้นจึงเพิ่มรหัส @Ic เพียงเล็กน้อยแค่คิดว่าฉันจะโพสต์ไว้เผื่อว่าจะช่วยใครได้ ฉันใช้ SendMail แต่มีตัวเลือกบรรทัดคำสั่งอื่น ๆจะส่งอีเมลธรรมดาจากไฟล์แบตช์ 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

เริ่มต้นบริการโดยใช้สคริปต์ Powershell คุณสามารถเชื่อมโยงสิ่งนี้กับตัวกำหนดตารางเวลางานและเรียกใช้เป็นช่วง ๆ หรือตามต้องการ สร้างไฟล์นี้เป็นไฟล์ PS1 เช่นไฟล์ที่มีนามสกุล PS1 จากนั้นปล่อยให้ไฟล์นี้ถูกทริกเกอร์จากตัวกำหนดตารางเวลางาน

เพื่อเริ่มหยุดให้บริการ

ในตัวกำหนดตารางเวลางานหากคุณกำลังใช้บนเซิร์ฟเวอร์ให้ใช้สิ่งนี้ในอาร์กิวเมนต์

-noprofile -executionpolicy บายพาส -file "C: \ Service Restart Scripts \ StopService.PS1"

ตรวจสอบโดยการรันเหมือนกันบน cmd ว่ามันใช้งานได้หรือไม่ควรทำงานกับตัวกำหนดตารางเวลางานด้วย

$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

เกี่ยวข้องกับคำตอบโดย @DanielSerrano ฉันเพิ่งได้รับการแปลsc.exeคำสั่งเป็นภาษาสเปนเมื่อไม่นานมานี้ ข้อเสนอของฉันคือการปักหมุดบรรทัดและโทเค็นซึ่งมีสถานะการบริการที่เป็นตัวเลขและตีความซึ่งควรจะมีประสิทธิภาพมากกว่านี้:

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

ทดสอบด้วย:

  • Windows XP (32 บิต) ภาษาอังกฤษ
  • Windows 10 (32 บิต) ภาษาสเปน
  • Windows 10 (64 บิต) ภาษาอังกฤษ

0

อาจจะเป็นวิธีที่ง่ายกว่ามาก? เพียงเพิ่มในรายการคำตอบที่นี่:

@for /f "tokens=1,* delims=: " %%a in ('sc queryex state=Inactive') do net start "%%b"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.