Làm thế nào để kiểm tra xem một dịch vụ có đang chạy thông qua tệp hàng loạt và khởi động nó hay không, nếu nó không chạy?


90

Tôi muốn viết một tệp hàng loạt thực hiện các thao tác sau:

  • Kiểm tra xem một dịch vụ đang chạy
    • Nếu nó đang chạy, hãy thoát khỏi loạt
    • Nếu nó không chạy, hãy bắt đầu dịch vụ

Các mẫu mã mà tôi đã tìm kiếm cho đến nay hóa ra không hoạt động, vì vậy tôi quyết định không đăng chúng.

Bắt đầu một dịch vụ được thực hiện bằng cách:

net start "SERVICENAME"
  1. Làm cách nào để kiểm tra xem một dịch vụ có đang chạy hay không và làm cách nào để tạo câu lệnh if trong tệp lô hàng?
  2. Tôi hơi bối rối. Đối số mà tôi phải chuyển vào khi bắt đầu thực là gì? Tên dịch vụ hoặc tên hiển thị của nó?

3
Lập trình bẩn: khi điều duy nhất bạn muốn làm là khởi động dịch vụ nếu nó không chạy, chỉ cần ra lệnh start. Nếu nó không chạy, nó sẽ bắt đầu dịch vụ. Nếu nó đang chạy hơn bạn nhận được thông báo lỗi nhưng dịch vụ đang chạy (và không dừng lại). Bẩn nhưng nó hoạt động. Tuy nhiên, khi bạn chỉ muốn thực thi các nhận xét khác nếu bạn phải khởi động dịch vụ, thì hãy sử dụng phiên bản sạch hơn từ lc.
Peter Schuetze

@Peter Schuetze: Vâng, ý kiến ​​phản đối của bạn là đúng nếu việc bắt đầu dịch vụ là mục đích duy nhất. Tôi cũng bao gồm việc ghi nhật ký bắt đầu v.v., vì vậy tôi gắn bó với giải pháp của lc.
citronas

Câu trả lời:


163

Để kiểm tra trạng thái của dịch vụ, hãy sử dụng sc query <SERVICE_NAME>. Đối với các khối if trong các tệp hàng loạt, hãy kiểm tra tài liệu .

Đoạn mã sau sẽ kiểm tra trạng thái của dịch vụ MyServiceNamevà khởi động nó nếu nó không chạy (khối if sẽ được thực thi nếu dịch vụ không chạy):

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

Giải thích về những gì nó làm:

  1. Truy vấn các thuộc tính của dịch vụ.
  2. Tìm kiếm dòng có chứa văn bản "STATE"
  3. Mã hóa dòng đó và rút ra mã thông báo thứ 3, là mã chứa trạng thái của dịch vụ.
  4. Kiểm tra trạng thái kết quả so với chuỗi "RUNNING"

Đối với câu hỏi thứ hai của bạn, đối số bạn sẽ muốn chuyển đến net startlà tên dịch vụ, không phải tên hiển thị.


Tuyệt vời. Cảm ơn cho nỗ lực của bạn. Thật không may là nó không hoạt động? Có lẽ tôi quá ngu ngốc vì điều này. Tôi đã thay thế "MyServiceName" bằng "SCardSvr" (đã thoát) như một thử nghiệm, đặt mọi thứ vào một tệp tin hàng loạt, thực thi nó, nhưng dịch vụ không khởi động. Ngay cả khi tôi thay thế net start bằng thứ khác, chẳng hạn như in thành một tệp, nó sẽ không được thực thi. Bạn vui lòng xem lại lần thứ hai được không? =)
citronas 24/07/10

Rất tiếc, tôi có một số thứ bổ sung ở dòng đầu tiên ở đó ... Hãy thử điều này. Và nếu nó không hoạt động, điều gì sẽ xảy ra khi bạn chạy sc query "SCardSvr"từ một dòng lệnh?
lc.

1
Bạn có "SCardSvr" trong dấu ngoặc kép không? Tôi không tin rằng nó nên được,
LittleBobbyTables - Au Revoir

@LittleBobbyTables: Bạn nói đúng. Không có dấu ngoặc kép làm cho nó hoạt động. Em ngốc quá: - | Nhờ sự giúp đỡ của bạn
citronas

@Mark Tốt để lưu ý. Tôi đoán bạn sẽ phải thay thế chuỗi đó bằng bất cứ thứ gì nó cần cho ngôn ngữ hệ điều hành đích. Tôi cũng giả định là "CHẠY".
lc.

34

Để chuyển đổi một dịch vụ, hãy sử dụng như sau;

NET START "Điều phối viên Giao dịch Phân tán" || NET STOP "Điều phối viên Giao dịch Phân tán"


1
Nó hoạt động vì mã thoát ngay từ đầu. Nếu lệnh bắt đầu không thành công, có thể là do nó đã chạy (và một trong hai cách sau đó dừng nó sẽ không ảnh hưởng gì), vì vậy bạn hãy thử dừng nó.
lc.

3
lệnh được cấu trúc để nếu net start không thành công, nó sẽ dừng nó (do dấu || có nghĩa là khác), nhưng nếu net start chạy, thì net stop không thực hiện. xuất sắc!
Doctor DOS

1
Đây là câu trả lời tốt nhất theo ý kiến ​​của tôi và có lẽ @citronas nên xem xét đánh dấu nó là câu trả lời được chấp nhận: đơn giản, thông minh và trang nhã và phù hợp với một trang web như StackOverflow. Làm nó đơn giản!
Sopalajo de Arrierez

2
Không phải là nitpicky (OK, có thể chỉ một chút), nhưng ||thực sự là một ORtoán tử, mặc dù trong trường hợp này, về mặt chức năng nó là một ELSEcâu lệnh. Đây là một sự khác biệt tinh tế, nhưng quan trọng. Vẫn nhận được +1 của tôi - Tôi làm điều này mọi lúc trong tập lệnh shell Unix / Linux, không biết tại sao tôi chưa bao giờ nghĩ đến việc này trong lô Windows.
Doug R.

Điều này có vẻ đơn giản hóa một cách nguy hiểm. Tôi không bao giờ muốn sử dụng nó cho một thứ mà tôi đã tự động hóa để xử lý hàng loạt hoặc đưa cho người khác sử dụng ... nhưng đó chỉ là những gì bác sĩ yêu cầu cho một biểu tượng nhanh mà tôi có thể đặt trên màn hình của chính mình cho một dịch vụ tôi cần nhanh chóng chuyển đổi ngay bây giờ và sau đó.
Joel Coehoorn

19

Bạn có thể sử dụng lệnh sau để xem dịch vụ có đang chạy hay không:

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

Khi tôi chạy nó cho Phần mềm chống vi-rút NOD32 của mình, tôi nhận được:

STATE                       : 4 RUNNING

Nếu nó bị dừng, tôi sẽ nhận được:

STATE                       : 1 STOPPED

Bạn có thể sử dụng nó trong một biến để xác định xem bạn có sử dụng NET START hay không.

Tên dịch vụ phải là tên dịch vụ, không phải tên hiển thị.


1
Nhờ sự giúp đỡ của bạn, trong khi cố gắng để tích hợp những gì bạn được đăng, tôi nhiều increas kỹ năng thực thi của tôi;)
citronas

14

Nên làm vậy:

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

10

Phiên bản độc lập với ngôn ngữ.

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

Vâng! "Khoảng trống" luôn đánh bất ngờ sau lưng bạn!
Dr.eel

2
Câu trả lời gần như hoàn hảo. Tôi chỉ muốn sửa chữa để dòng này: bắt đầu Net "% ServiceName%"> nul || (
Cesar

Tôi đã làm cho tập lệnh trở nên phổ biến để nó cho phép tôi sử dụng trong các tác vụ của Bộ lập lịch Windows. Chỉ cần thay thế Set ServiceName=Jenkinsvới Set ServiceName=%~1và gọi nó như thếwatch-service.bat "Jenkins"
Dr.eel

@ Ant_222 Nó sử dụng 'queryex' thay vì 'query' phụ thuộc vào ngôn ngữ. Và tại sao bạn nghĩ rằng đó không phải là Windows loạt? Bạn đã thử sử dụng nó chưa?
Dr.eel

5

Tôi vừa tìm thấy chủ đề này và muốn thêm vào cuộc thảo luận nếu người đó không muốn sử dụng tệp hàng loạt để khởi động lại dịch vụ. Trong Windows có một tùy chọn nếu bạn đi tới Dịch vụ, thuộc tính dịch vụ, sau đó là khôi phục. Tại đây bạn có thể thiết lập các thông số cho dịch vụ. Thích khởi động lại dịch vụ nếu dịch vụ dừng. Ngoài ra, bạn thậm chí có thể có lần thử thất bại thứ hai làm một điều gì đó khác biệt như khi khởi động lại máy tính.


2
Đó là một câu trả lời hữu ích, tuy nhiên điều quan trọng cần lưu ý, điều đó sẽ chỉ hoạt động nếu dịch vụ đã dừng khi thoát (-1). Nếu dịch vụ thoát một cách duyên dáng (ngay cả khi có thông báo lỗi) Tự động khôi phục sẽ không kích hoạt. Nó cũng sẽ không kích hoạt nếu dịch vụ bị người dùng giết theo cách thủ công.
Art Gertner

@sagelightning: Chúng tôi cần quyền truy cập của quản trị viên để thử cách này.
Kumar M

@ArtGertner - Giết (thông qua trình quản lý tác vụ) một quy trình dịch vụ sẽ được hiểu là "sự cố" và sẽ kích hoạt khôi phục.
Martin Ba

3

Cuando sẽ sử dụng Windows en Español, el código debe quedar asi (khi sử dụng Windows bằng tiếng Tây Ban Nha, mã là):

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. (Thay MYSERVICE bằng tên của dịch vụ sẽ được xử lý. Bạn có thể thấy tên của dịch vụ trên các thuộc tính của dịch vụ.)


10
Sẽ tốt hơn cho mọi người nếu bạn viết câu trả lời của mình bằng tiếng Anh.
j0k

2
Không chắc chắn tại sao downvote. Đây là một điểm quan trọng và là lý do để tránh so sánh chuỗi nếu có thể. Trong trường hợp này, bạn phải thay đổi chuỗi tùy thuộc vào ngôn ngữ mặc định của cài đặt Windows đích.
lc.

2
@lc: Có hợp lý không khi bao gồm câu trả lời cho mỗi ngôn ngữ? Có thể hữu ích hơn khi tham chiếu (hoặc bao gồm) một tài nguyên cho biết chuỗi nào để tìm kiếm một ngôn ngữ nhất định.
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

Đối với Windows server 2012 dưới đây là những gì phù hợp với tôi. Chỉ thay thế "SERVICENAME" bằng tên dịch vụ thực tế:

@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

Tôi cũng muốn có một email được gửi nếu dịch vụ được bắt đầu theo cách này, vì vậy đã thêm một chút vào mã @Ic chỉ nghĩ rằng tôi sẽ đăng nó trong trường hợp nó giúp ích được cho bất kỳ ai. Tôi đã sử dụng SendMail nhưng có các tùy chọn dòng lệnh khác Làm thế nào để gửi một email đơn giản từ một tệp hàng loạt của 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

Khởi động Dịch vụ bằng tập lệnh Powershell. Bạn có thể liên kết cái này với bộ lập lịch tác vụ và kích hoạt nó theo khoảng thời gian hoặc khi cần thiết. Tạo tệp này dưới dạng tệp PS1 tức là tệp có phần mở rộng PS1 và sau đó để tệp này được kích hoạt từ bộ lập lịch tác vụ.

Để bắt đầu dịch vụ dừng

trong bộ lập lịch tác vụ nếu bạn đang sử dụng nó trên máy chủ, hãy sử dụng nó trong các đối số

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

xác minh bằng cách chạy tương tự trên cmd nếu nó hoạt động, nó cũng sẽ hoạt động trên bộ lập lịch tác vụ

$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

Liên quan đến câu trả lời của @DanielSerrano, gần đây tôi đã bản địa hóa sc.exelệnh, cụ thể là bằng tiếng Tây Ban Nha. Đề xuất của tôi là ghim dòng và mã thông báo giữ trạng thái dịch vụ số và diễn giải nó, điều này sẽ mạnh mẽ hơn nhiều:

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

Đã kiểm tra với:

  • Windows XP (32-bit) tiếng Anh
  • Windows 10 (32-bit) tiếng Tây Ban Nha
  • Windows 10 (64-bit) tiếng Anh

0

Có lẽ một cách đơn giản hơn nhiều? Chỉ cần thêm vào danh sách các câu trả lời ở đây:

@for /f "tokens=1,* delims=: " %%a in ('sc queryex state=Inactive') do net start "%%b"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.