停止/启动远程 Windows 服务并等待它打开/关闭

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1405372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 06:42:24  来源:igfitidea点击:

Stopping/Starting a remote Windows service and waiting for it to open/close

windowswindows-services

提问by ripper234

The top answer to this questiontells me how to stop/start a remote service. Great. Now, all I need is to wait for the actual stop/start to complete. So, what I'm looking for is a dos command to:

这个问题的最佳答案告诉我如何停止/启动远程服务。伟大的。现在,我只需要等待实际停止/启动完成。所以,我正在寻找的是一个 dos 命令:

  1. Start a service, should return only after the service is started (or after a timeout, raising error level)
  2. Stop a service, return only after the service is stopped
  1. 启动服务,应该只在服务启动后返回(或超时后,提高错误级别)
  2. 停止一个服务,服务停止后才返回

回答by Eric Falsken

I created a set of batch scripts that use sc.exe to do just this. They are attached below. To run these scripts, you should be a user with administration rights on the target machine and running this from a computer that is a member of the same domain. It's possible to set it up to be able to run from outside of the domain (like from a VPN) but there are a lot of layers of security to work through involving firewalls, DCOM and security credentials.

我创建了一组使用 sc.exe 执行此操作的批处理脚本。它们附在下面。要运行这些脚本,您应该是在目标计算机上具有管理权限的用户,并从属于同一域的计算机上运行该脚本。可以将其设置为能够从域外部(例如从 VPN)运行,但是有很多安全层需要处理,包括防火墙、DCOM 和安全凭证。

One of these days, I'm going to figure out the PowerShell equivalent, which should be much easier.

其中一天,我将找出 PowerShell 等效项,这应该会容易得多。

safeServiceStart.bat

安全服务启动.bat

@echo off
:: This script originally authored by Eric Falsken

IF [%1]==[] GOTO usage
IF [%2]==[] GOTO usage

ping -n 1 %1 | FIND "TTL=" >NUL
IF errorlevel 1 GOTO SystemOffline
SC \%1 query %2 | FIND "STATE" >NUL
IF errorlevel 1 GOTO SystemOffline

:ResolveInitialState
SC \%1 query %2 | FIND "STATE" | FIND "STOPPED" >NUL
IF errorlevel 0 IF NOT errorlevel 1 GOTO StartService
SC \%1 query %2 | FIND "STATE" | FIND "RUNNING" >NUL
IF errorlevel 0 IF NOT errorlevel 1 GOTO StartedService
SC \%1 query %2 | FIND "STATE" | FIND "PAUSED" >NUL
IF errorlevel 0 IF NOT errorlevel 1 GOTO SystemOffline
echo Service State is changing, waiting for service to resolve its state before making changes
sc \%1 query %2 | Find "STATE"
timeout /t 2 /nobreak >NUL
GOTO ResolveInitialState

:StartService
echo Starting %2 on \%1
sc \%1 start %2 >NUL

GOTO StartingService
:StartingServiceDelay
echo Waiting for %2 to start
timeout /t 2 /nobreak >NUL
:StartingService
SC \%1 query %2 | FIND "STATE" | FIND "RUNNING" >NUL
IF errorlevel 1 GOTO StartingServiceDelay

:StartedService
echo %2 on \%1 is started
GOTO:eof

:SystemOffline
echo Server \%1 is not accessible or is offline
GOTO:eof

:usage
echo %0 [system name] [service name]
echo Example: %0 server1 MyService
echo.
GOTO:eof

safeServiceStop.bat

安全服务停止.bat

@echo off
:: This script originally authored by Eric Falsken

IF [%1]==[] GOTO usage
IF [%2]==[] GOTO usage

ping -n 1 %1 | FIND "TTL=" >NUL
IF errorlevel 1 GOTO SystemOffline
SC \%1 query %2 | FIND "STATE" >NUL
IF errorlevel 1 GOTO SystemOffline

:ResolveInitialState
SC \%1 query %2 | FIND "STATE" | FIND "RUNNING" >NUL
IF errorlevel 0 IF NOT errorlevel 1 GOTO StopService
SC \%1 query %2 | FIND "STATE" | FIND "STOPPED" >NUL
IF errorlevel 0 IF NOT errorlevel 1 GOTO StopedService
SC \%1 query %2 | FIND "STATE" | FIND "PAUSED" >NUL
IF errorlevel 0 IF NOT errorlevel 1 GOTO SystemOffline
echo Service State is changing, waiting for service to resolve its state before making changes
sc \%1 query %2 | Find "STATE"
timeout /t 2 /nobreak >NUL
GOTO ResolveInitialState

:StopService
echo Stopping %2 on \%1
sc \%1 stop %2 %3 >NUL

GOTO StopingService
:StopingServiceDelay
echo Waiting for %2 to stop
timeout /t 2 /nobreak >NUL
:StopingService
SC \%1 query %2 | FIND "STATE" | FIND "STOPPED" >NUL
IF errorlevel 1 GOTO StopingServiceDelay

:StopedService
echo %2 on \%1 is stopped
GOTO:eof

:SystemOffline
echo Server \%1 or service %2 is not accessible or is offline
GOTO:eof

:usage
echo Will cause a remote service to STOP (if not already stopped).
echo This script will waiting for the service to enter the stopped state if necessary.
echo.
echo %0 [system name] [service name] {reason}
echo Example: %0 server1 MyService
echo.
echo For reason codes, run "sc stop"
GOTO:eof

safeServiceRestart.bat

安全服务重启.bat

@echo off
:: This script originally authored by Eric Falsken

if [%1]==[] GOTO usage
if [%2]==[] GOTO usage

ping -n 1 %1 | FIND "TTL=" >NUL
IF errorlevel 1 GOTO SystemOffline
SC \%1 query %2 | FIND "STATE" >NUL
IF errorlevel 1 GOTO SystemOffline

:ResolveInitialState
SC \%1 query %2 | FIND "STATE" | FIND "RUNNING" >NUL
IF errorlevel 0 IF NOT errorlevel 1 GOTO StopService
SC \%1 query %2 | FIND "STATE" | FIND "STOPPED" >NUL
IF errorlevel 0 IF NOT errorlevel 1 GOTO StartService
SC \%1 query %2 | FIND "STATE" | FIND "PAUSED" >NUL
IF errorlevel 0 IF NOT errorlevel 1 GOTO SystemOffline
echo Service State is changing, waiting for service to resolve its state before making changes
sc \%1 query %2 | Find "STATE"
timeout /t 2 /nobreak >NUL
GOTO ResolveInitialState

:StopService
echo Stopping %2 on \%1
sc \%1 stop %2 %3 >NUL

GOTO StopingService
:StopingServiceDelay
echo Waiting for %2 to stop
timeout /t 2 /nobreak >NUL
:StopingService
SC \%1 query %2 | FIND "STATE" | FIND "STOPPED" >NUL
IF errorlevel 1 GOTO StopingServiceDelay

:StopedService
echo %2 on \%1 is stopped
GOTO StartService

:StartService
echo Starting %2 on \%1
sc \%1 start %2 >NUL

GOTO StartingService
:StartingServiceDelay
echo Waiting for %2 to start
timeout /t 2 /nobreak >NUL
:StartingService
SC \%1 query %2 | FIND "STATE" | FIND "RUNNING" >NUL
IF errorlevel 1 GOTO StartingServiceDelay

:StartedService
echo %2 on \%1 is started
GOTO:eof

:SystemOffline
echo Server \%1 or service %2 is not accessible or is offline
GOTO:eof

:usage
echo Will restart a remote service, waiting for the service to stop/start (if necessary)
echo.
echo %0 [system name] [service name] {reason}
echo Example: %0 server1 MyService
echo.
echo For reason codes, run "sc stop"
GOTO:eof

回答by andreister

What about powershell and WaitForStatus? Eg, the script below would restart SQL Server on a remote machine:

powershell 和 WaitForStatus 怎么样?例如,下面的脚本将在远程机器上重新启动 SQL Server:

$computer = "COMPUTER_NAME"
$me = new-object -typename System.Management.Automation.PSCredential -argumentlist "DOMAIN\user", (convertto-securestring "password" -asplaintext -force)
$restartSqlServer = { 
    $sqlServer = get-service mssqlserver
    $waitInterval = new-timespan -seconds 5
    if (-not ($sqlServer.Status -eq "Stopped")) {
        $sqlServer.Stop()
        $sqlServer.WaitForStatus('Stopped', $waitInterval) 
    }
    $sqlServer.Start()
    $sqlServer.WaitForStatus('Running', $waitInterval) 
}     
icm -ComputerName $computer -ScriptBlock $restartSqlServer -Credential $me 

回答by Stephen Martin

I've never actually seen something that does this specifically but it would be quite easy to knock such a utility out in C\C#\VB or any other language that gives easy access to the Service API. Here's a sample of something in C#.

我实际上从未见过专门执行此操作的东西,但是在 C\C#\VB 或任何其他可以轻松访问服务 API 的语言中删除这样的实用程序会很容易。这是 C# 中的一些示例。

using System;
using System.ComponentModel;
using System.ServiceProcess;

namespace SCSync
{
    class Program
    {
        private const int ERROR_SUCCESS = 0;

        private const int ERROR_INVALID_COMMAND_LINE = 1;
        private const int ERROR_NO_ACCESS = 2;
        private const int ERROR_COMMAND_TIMEOUT = 3;
        private const int ERROR_NO_SERVICE = 4;
        private const int ERROR_NO_SERVER = 5;
        private const int ERROR_INVALID_STATE = 6;
        private const int ERROR_UNSPECIFIED = 7;

        static int Main(string[] args)
        {

            if (args.Length < 2 || args.Length > 4)
            {
                ShowUsage();
                return ERROR_INVALID_COMMAND_LINE;
            }

            string serviceName = args[0];
            string command = args[1].ToUpper();
            string serverName = ".";
            string timeoutString = "30";
            int timeout;

            if (args.Length > 2)
            {
                if (args[2].StartsWith(@"\"))
                {
                    serverName = args[2].Substring(2);
                    if (args.Length > 3)
                    {
                        timeoutString = args[3];
                    }
                }
                else
                {
                    timeoutString = args[2];
                }
            }

            if (!int.TryParse(timeoutString, out timeout))
            {
                Console.WriteLine("Invalid timeout value.\n");
                ShowUsage();
                return ERROR_INVALID_COMMAND_LINE;
            }

            try
            {
                ServiceController sc = new ServiceController(serviceName, serverName);
                switch (command)
                {
                    case "START":
                        sc.Start();
                        sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 0, timeout));
                        break;
                    case "STOP":
                        sc.Stop();
                        sc.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 0, 0, timeout));
                        break;
                    case "PAUSE":
                        sc.Pause();
                        sc.WaitForStatus(ServiceControllerStatus.Paused, new TimeSpan(0, 0, 0, timeout));
                        break;
                    case "CONTINUE":
                        sc.Continue();
                        sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 0, timeout));
                        break;
                    default:
                        Console.WriteLine("Invalid command value.\n");
                        ShowUsage();
                        return ERROR_INVALID_COMMAND_LINE;
                }
            }
            catch (System.ServiceProcess.TimeoutException)
            {
                Console.WriteLine("Operation timed out.\n");
                return ERROR_COMMAND_TIMEOUT;
            }
            catch (UnauthorizedAccessException)
            {
                Console.WriteLine("You are not authorized to perform this action.\n");
                return ERROR_NO_ACCESS;
            }
            catch (InvalidOperationException opEx)
            {
                Win32Exception winEx = opEx.InnerException as Win32Exception;
                if (winEx != null)
                {
                    switch (winEx.NativeErrorCode)
                    {
                        case 5: //ERROR_ACCESS_DENIED
                            Console.WriteLine("You are not authorized to perform this action.\n");
                            return ERROR_NO_ACCESS;
                        case 1722: //RPC_S_SERVER_UNAVAILABLE
                            Console.WriteLine("The server is unavailable or does not exist.\n");
                            return ERROR_NO_SERVER;
                        case 1060: //ERROR_SERVICE_DOES_NOT_EXIST
                            Console.WriteLine("The service does not exist.\n");
                            return ERROR_NO_SERVICE;
                        case 1056: //ERROR_SERVICE_ALREADY_RUNNING
                            Console.WriteLine("The service is already running.\n");
                            return ERROR_INVALID_STATE;
                        case 1062: //ERROR_SERVICE_NOT_ACTIVE
                            Console.WriteLine("The service is not running.\n");
                            return ERROR_INVALID_STATE;
                        default:
                            break;
                    }
                }
                Console.WriteLine(opEx.ToString());
                return ERROR_UNSPECIFIED;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                return ERROR_UNSPECIFIED;
            }

            return ERROR_SUCCESS;
        }

        private static void ShowUsage()
        {
            Console.WriteLine("SCSync usage:\n");
            Console.WriteLine("SCSync.exe service command <server> <timeout>\n");
            Console.WriteLine("    service   The name of the service upon which the command will act. (Required)");
            Console.WriteLine("    command   The command to execute - one of: start|stop|pause|continue. (Required)");
            Console.WriteLine("    server    The name of the server on which the target service runs. This must start with \. (Optional)");
            Console.WriteLine("    timeout   The timeout period in seconds in which the command should finish. The default is 30 seconds. (Optional)");
            Console.WriteLine("\n");
        }
    }
}

The WaitForStatus is just a polling loop and could be easily replaced in any other language. The rest is just OpenService and ControlService.

WaitForStatus 只是一个轮询循环,可以很容易地用任何其他语言替换。剩下的就是 OpenService 和 ControlService。

回答by Edward Olamisan

Eric Falsken's solution works perfectly. +1.

Eric Falsken 的解决方案非常有效。+1。

But I'd like to add that the timeout command would sometimes fail with error: "Input redirection is not supported, exiting the process immediately"

但我想补充一点,超时命令有时会失败并显示错误:“不支持输入重定向,立即退出进程”

To fix this I've had to replace the timeout command:

为了解决这个问题,我不得不替换超时命令:

timeout /t 2 /nobreak >NUL

with the following:

具有以下内容:

ping -n 2 127.0.0.1  1>NUL

回答by George Perkins

Edit on 10/20/2011 - updated my code. I posted it before fully debugging. Many thanks to Eric Falsken. What a great solution. I tweaked Eric's code (BTW look for a couple of typographical errors if you intend to use it). I added logging and some additional error-checking for some conditions Eric didn't account for. Since I'm most interested in a service restart (not just stopping and/or starting), I only built upon Eric's restart code. Anyway, I'm posting my version, hope you like it!

2011 年 10 月 20 日编辑 - 更新了我的代码。我在完全调试之前发布了它。非常感谢 Eric Falsken。多么棒的解决方案。我调整了 Eric 的代码(顺便说一句,如果您打算使用它,请查找一些印刷错误)。我为 Eric 没有考虑的某些条件添加了日志记录和一些额外的错误检查。因为我最感兴趣的是服务重启(不仅仅是停止和/或启动),所以我只构建了 Eric 的重启代码。无论如何,我正在发布我的版本,希望你喜欢它!

@ECHO off
:: This script originally authored by Eric Falsken http://stackoverflow.com/
:: Revised for by George Perkins 10/20/2011
IF [%1]==[] GOTO Usage
IF [%2]==[] GOTO Usage

:SetLocalVariables
SET /A MyDelay=0 
SET MyHours=%time:~0,2%
IF %MyHours%==0 SET MyHours=00
IF %MyHours%==1 SET MyHours=01
IF %MyHours%==2 SET MyHours=02
IF %MyHours%==3 SET MyHours=03
IF %MyHours%==4 SET MyHours=04
IF %MyHours%==5 SET MyHours=05
IF %MyHours%==6 SET MyHours=06
IF %MyHours%==7 SET MyHours=07
IF %MyHours%==8 SET MyHours=08
IF %MyHours%==9 SET MyHours=09
SET MyMinutes=%time:~3,2%
SET MySeconds=%time:~6,2%
SET MyHundredths=%time:~9,2%
SET MyMonth=%date:~4,2%
SET MyDay=%date:~-7,2%
SET MyCentury=%date:~-4,4%
SET MyTimeStamp=%MyCentury%%MyMonth%%MyDay%%MyHours%%MyMinutes%%MySeconds%
IF "%3" == "" (
         SET MyLog=C:\Temp
   ) ELSE (
         SET MyLog=%3
   ) 
SET MyLogFile=%MyLog%\ServiceRestart%MyTimeStamp%.log
ECHO.
ECHO. >> %MyLogFile%
ECHO ------------- ------------- %MyHours%:%MyMinutes%:%MySeconds%.%MyHundredths% %MyMonth%/%MyDay%/%MyCentury% ------------- ------------- 
ECHO ------------- ------------- %MyHours%:%MyMinutes%:%MySeconds%.%MyHundredths% %MyMonth%/%MyDay%/%MyCentury% ------------- ------------- >> %MyLogFile% 
ECHO Begin batch program %0. 
ECHO Begin batch program %0. >> %MyLogFile%
ECHO Logging to file %MyLogFile%. 
ECHO Logging to file %MyLogFile%. >> %MyLogFile% 
ECHO Attempting to restart service %2 on computer %1.
ECHO Attempting to restart service %2 on computer %1. >> %MyLogFile%

PING -n 1 %1 | FIND "TTL=" >> %MyLogFile%
IF errorlevel 1 IF NOT errorlevel 2 GOTO SystemOffline
SC \%1 query %2 | FIND "FAILED 1060" >> %MyLogFile%
IF errorlevel 0 IF NOT errorlevel 1 GOTO InvalidServiceName
SC \%1 query %2 | FIND "STATE" >> %MyLogFile%
IF errorlevel 1 IF NOT errorlevel 2 GOTO SystemOffline

:ResolveInitialState
SET /A MyDelay+=1
SC \%1 query %2 | FIND "STATE" | FIND "RUNNING" >> %MyLogFile%
IF errorlevel 0 IF NOT errorlevel 1 GOTO StopService
SC \%1 query %2 | FIND "STATE" | FIND "STOPPED" >> %MyLogFile%
IF errorlevel 0 IF NOT errorlevel 1 GOTO StartService
SC \%1 query %2 | FIND "STATE" | FIND "PAUSED" >> %MyLogFile%
IF errorlevel 0 IF NOT errorlevel 1 GOTO SystemOffline
ECHO Service State is changing, waiting %MyDelay% seconds for service to resolve its state before making changes.
ECHO Service State is changing, waiting %MyDelay% seconds for service to resolve its state before making changes. >> %MyLogFile%
TIMEOUT /t %MyDelay% /nobreak >> %MyLogFile%
GOTO ResolveInitialState

:StopService
SET /A MyDelay=0
ECHO Stopping %2 on \%1.
ECHO Stopping %2 on \%1. >> %MyLogFile%
SC \%1 stop %2 | FIND "FAILED" >> %MyLogFile%
IF errorlevel 0 IF NOT errorlevel 1 GOTO Unstoppable

:StoppingServiceDelay
SET /A MyDelay+=1
IF %MyDelay%==21 GOTO MaybeUnStoppable
ECHO Waiting %MyDelay% seconds for %2 to stop.
ECHO Waiting %MyDelay% seconds for %2 to stop. >> %MyLogFile%
TIMEOUT /t %MyDelay% /nobreak >> %MyLogFile%
:StoppingService
SC \%1 query %2 | FIND "STATE" | FIND "STOPPED" >> %MyLogFile%
IF errorlevel 0 IF NOT errorlevel 1 GOTO StoppedService
SC \%1 query %2 | FIND "STATE" | FIND "STOP_PENDING" >> %MyLogFile%
IF errorlevel 0 IF NOT errorlevel 1 GOTO StoppingServiceDelay
GOTO StoppingServiceDelay

:MaybeUnStoppable
:: If we got here we waited approximately 3 mintues and the service has not stopped.
SC \%1 query %2 | FIND "NOT_STOPPABLE" >> %MyLogFile%
IF errorlevel 0 IF NOT errorlevel 1 GOTO OneLastChance
GOTO Unstoppable 

:OneLastChance
SC \%1 stop %2 >> %MyLogFile%
SET /A MyDelay+=1
ECHO Waiting %MyDelay% seconds for %2 to stop.
ECHO Waiting %MyDelay% seconds for %2 to stop. >> %MyLogFile%
TIMEOUT /t %MyDelay% /nobreak >> %MyLogFile%
SC \%1 query %2 | FIND "STATE" | FIND "STOPPED" >> %MyLogFile%
IF errorlevel 0 IF NOT errorlevel 1 GOTO StoppedService
SC \%1 query %2 | FIND "STATE" | FIND "RUNNING" >> %MyLogFile%
IF errorlevel 1 IF NOT errorlevel 2 GOTO UnknownState
SC \%1 query %2 | FIND "NOT_STOPPABLE" >> %MyLogFile%
IF errorlevel 0 IF NOT errorlevel 1 GOTO Unstoppable
GOTO StoppingServiceDelay

:StoppedService
ECHO %2 on \%1 is stopped.
ECHO %2 on \%1 is stopped. >> %MyLogFile%
GOTO StartService

:StartService
SET /A MyDelay=0 
ECHO Starting %2 on \%1.
ECHO Starting %2 on \%1. >> %MyLogFile%
SC \%1 start %2 >> %MyLogFile%

GOTO StartingService
:StartingServiceDelay
SET /A MyDelay+=1
ECHO Waiting %MyDelay% seconds for %2 to start.
ECHO Waiting %MyDelay% seconds for %2 to start. >> %MyLogFile%
TIMEOUT /t %MyDelay% /nobreak >> %MyLogFile%
:StartingService
SC \%1 query %2 | FIND "STATE" | FIND "RUNNING" >> %MyLogFile%
IF errorlevel 1 IF NOT errorlevel 2 GOTO StartingServiceDelay

:StartedService
ECHO %2 on \%1 is started.
ECHO %2 on \%1 is started. >> %MyLogFile%
GOTO EndExit

:SystemOffline
ECHO Failure! Server \%1 or service %2 is not accessible or is offline!
ECHO Failure! Server \%1 or service %2 is not accessible or is offline! >> %MyLogFile%
ECHO See log file %MyLogFile% for details!
GOTO EndExit

:InvalidServiceName
ECHO Failure! Service %2 is not valid!
ECHO Failure! Service %2 is not valid! >> %MyLogFile%
ECHO See log file %MyLogFile% for details!
GOTO EndExit

:UnknownState
ECHO Failure! Service %2 in an unknown state and cannot be stopped!
ECHO Failure! Service %2 in an unknown state and cannot be stopped! >> %MyLogFile%
ECHO See log file %MyLogFile% for details!
GOTO EndExit

:UnStoppable
ECHO Failure! Service %2 cannot be stopped! Check dependencies or system state.
ECHO Failure! Service %2 cannot be stopped! Check dependencies or system state. >> %MyLogFile%
ECHO See log file %MyLogFile% for details!
GOTO EndExit

:Usage
ECHO Will restart a remote service, waiting for the service to stop/start (if necessary).
ECHO.
ECHO Usage:
ECHO %0 [system name] [service name] [logfile path]
ECHO Example: %0 server1 MyService C:\Temp\Log
ECHO.
GOTO EndExit

:EndExit
ECHO.
ECHO %0 Ended.
ECHO.

回答by Jan Remunda

What about PowerShell and Restart-Service commandlet? :)

PowerShell 和Restart-Service commandlet怎么样?:)

Get-Service W3SVC -computer myserver | Restart-Service

回答by Armando Contestabile

I improved the script of Eric Falsken and revised by Gerorge Perkins.

我改进了 Eric Falsken 的脚本并由 Gerorge Perkins 修订。

Changes:

变化:

  • now it is not only a restart script. The script can start, stop and restart a local or remote service;
  • removed logging (if you want this, you can use it simply by launching SCRIPT_NAME.bat > logfile.txt);
  • sparse optimizations.

    @ECHO off
    :: This script originally authored by Eric Falsken http://stackoverflow.com/
    :: Revised by George Perkins 10/20/2011
    :: Revised by Armando Contestabile 02/23/2015
    IF "%1"=="" GOTO Usage
    IF "%2"=="" GOTO Usage
    
    SET ACTION=%1
    SET SERVICENAME=%2
    
    IF "%3"=="" (
        SET SYSTEMNAME=%COMPUTERNAME%
    ) ELSE (
        SET SYSTEMNAME=%3
    )
    
    IF "%ACTION%" == "stop" (
        SET ACTION=STOP
    ) ELSE IF "%ACTION%" == "STOP" (
        SET ACTION=STOP
    ) ELSE IF "%ACTION%" == "start" (
        SET ACTION=START
    ) ELSE IF "%ACTION%" == "START" (
        SET ACTION=START
    ) ELSE IF "%ACTION%" == "restart" (
        SET ACTION=RESTART
    ) ELSE IF "%ACTION%" == "RESTART" (
        SET ACTION=RESTART
    ) ELSE GOTO Usage
    
    SET STATE=
    SET CURRENT_STATUS=
    SET /A DEFAULT_DELAY=5
    SET /A SLEEP_COUNT=0
    SET /A RESTARTED=0
    SET /A MAX_WAIT_PERIODS=5
    
    ECHO.
    ECHO Attempting to %ACTION% service %SERVICENAME% on computer %SYSTEMNAME%.
    
    PING -n 1 %SYSTEMNAME% | FIND "TTL=" >nul 2>&1
    IF ERRORLEVEL 1 IF NOT ERRORLEVEL 2 (
        ECHO Failure! Server \%SYSTEMNAME% or service %SERVICENAME% is not accessible or is offline!
        EXIT /B 1
    )
    SC \%SYSTEMNAME% query %SERVICENAME% | FIND "FAILED 1060" >nul 2>&1
    IF ERRORLEVEL 0 IF NOT ERRORLEVEL 1 (
        ECHO Failure! Service %SERVICENAME% is not valid!
        EXIT /B 2
    )
    SC \%SYSTEMNAME% query %SERVICENAME% | FIND "STATE" >nul 2>&1
    IF ERRORLEVEL 1 IF NOT ERRORLEVEL 2 (
        ECHO Failure! Server \%SYSTEMNAME% or service %SERVICENAME% is not accessible or is offline!
        EXIT /B 3
    )
    
    :Dispatch
    FOR /f "tokens=*" %%i IN ('SC \%SYSTEMNAME% query %SERVICENAME% ^| FIND "STATE"') DO SET STATE=%%i
    
    ECHO %STATE% | FINDSTR /C:"1" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=STOPPED
    ECHO %STATE% | FINDSTR /C:"2" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=START_PENDING
    ECHO %STATE% | FINDSTR /C:"3" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=STOP_PENDING
    ECHO %STATE% | FINDSTR /C:"4" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=RUNNING
    ECHO %STATE% | FINDSTR /C:"5" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=CONTINUE_PENDING
    ECHO %STATE% | FINDSTR /C:"6" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=PAUSE_PENDING
    ECHO %STATE% | FINDSTR /C:"7" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=PAUSED
    
    ECHO Current status of service is %CURRENT_STATUS%
    
    IF NOT "%CURRENT_STATUS%"=="RUNNING" IF NOT "%CURRENT_STATUS%"=="STOPPED" IF NOT "%CURRENT_STATUS%"=="PAUSED" (
        IF "%SLEEP_COUNT%"=="%MAX_WAIT_PERIODS%" (
            ECHO Service state won't change. Script exececution is canceled.
            EXIT /B 4
        )
        ECHO Service State is changing, waiting %DEFAULT_DELAY% seconds...
        SLEEP %DEFAULT_DELAY%
        SET /A SLEEP_COUNT+=1
        GOTO Dispatch
    )
    
    IF "%ACTION%"=="START" (
        IF "%CURRENT_STATUS%"=="RUNNING" (
            ECHO Service %SERVICENAME% is running.
            GOTO EndExit
        ) ELSE (
            GOTO StartService
        )
    ) ELSE IF "%ACTION%"=="RESTART" (
        IF "%CURRENT_STATUS%"=="RUNNING" (
            IF %RESTARTED%==1 (
                ECHO Service %SERVICENAME% restarted.
                GOTO EndExit
            )
            SET /A SLEEP_COUNT=0
            GOTO StopService
        ) ELSE (
            SET /A RESTARTED=1
            GOTO StartService
        )
    ) ELSE IF "%ACTION%"=="STOP" (
        IF "%CURRENT_STATUS%"=="STOPPED"  (
            ECHO Service %SERVICENAME% is stopped.
            GOTO EndExit
        ) ELSE (
            GOTO StopService
        )
    )
    
    :StartService
    ECHO Starting %SERVICENAME% on \%SYSTEMNAME%
    SC \%SYSTEMNAME% start %SERVICENAME% >nul 2>&1
    SET SLEEP_COUNT=0
    GOTO Dispatch
    
    :StopService
    ECHO Stopping %SERVICENAME% on \%SYSTEMNAME%
    SC \%SYSTEMNAME% stop %SERVICENAME% >nul 2>&1
    SET SLEEP_COUNT=0
    GOTO Dispatch
    
    :Usage
    ECHO This script can start/stop/restart a local or remote service, waiting for the service to stop/start ^(if necessary^).
    ECHO.
    ECHO Usage:
    ECHO %0 ^<start^|stop^|restart^> ^<SERVICE^> [SYSTEM]
    ECHO.
    ECHO If no SYSTEM is provided, the script attempts to execute on the local system.
    EXIT /B 5
    
    :EndExit
    ECHO.
    EXIT /B 0
    
  • 现在它不仅仅是一个重启脚本。该脚本可以启动、停止和重启本地或远程服务;
  • 删除日志记录(如果你想要这个,你可以简单地通过启动 SCRIPT_NAME.bat > logfile.txt 来使用它);
  • 稀疏优化。

    @ECHO off
    :: This script originally authored by Eric Falsken http://stackoverflow.com/
    :: Revised by George Perkins 10/20/2011
    :: Revised by Armando Contestabile 02/23/2015
    IF "%1"=="" GOTO Usage
    IF "%2"=="" GOTO Usage
    
    SET ACTION=%1
    SET SERVICENAME=%2
    
    IF "%3"=="" (
        SET SYSTEMNAME=%COMPUTERNAME%
    ) ELSE (
        SET SYSTEMNAME=%3
    )
    
    IF "%ACTION%" == "stop" (
        SET ACTION=STOP
    ) ELSE IF "%ACTION%" == "STOP" (
        SET ACTION=STOP
    ) ELSE IF "%ACTION%" == "start" (
        SET ACTION=START
    ) ELSE IF "%ACTION%" == "START" (
        SET ACTION=START
    ) ELSE IF "%ACTION%" == "restart" (
        SET ACTION=RESTART
    ) ELSE IF "%ACTION%" == "RESTART" (
        SET ACTION=RESTART
    ) ELSE GOTO Usage
    
    SET STATE=
    SET CURRENT_STATUS=
    SET /A DEFAULT_DELAY=5
    SET /A SLEEP_COUNT=0
    SET /A RESTARTED=0
    SET /A MAX_WAIT_PERIODS=5
    
    ECHO.
    ECHO Attempting to %ACTION% service %SERVICENAME% on computer %SYSTEMNAME%.
    
    PING -n 1 %SYSTEMNAME% | FIND "TTL=" >nul 2>&1
    IF ERRORLEVEL 1 IF NOT ERRORLEVEL 2 (
        ECHO Failure! Server \%SYSTEMNAME% or service %SERVICENAME% is not accessible or is offline!
        EXIT /B 1
    )
    SC \%SYSTEMNAME% query %SERVICENAME% | FIND "FAILED 1060" >nul 2>&1
    IF ERRORLEVEL 0 IF NOT ERRORLEVEL 1 (
        ECHO Failure! Service %SERVICENAME% is not valid!
        EXIT /B 2
    )
    SC \%SYSTEMNAME% query %SERVICENAME% | FIND "STATE" >nul 2>&1
    IF ERRORLEVEL 1 IF NOT ERRORLEVEL 2 (
        ECHO Failure! Server \%SYSTEMNAME% or service %SERVICENAME% is not accessible or is offline!
        EXIT /B 3
    )
    
    :Dispatch
    FOR /f "tokens=*" %%i IN ('SC \%SYSTEMNAME% query %SERVICENAME% ^| FIND "STATE"') DO SET STATE=%%i
    
    ECHO %STATE% | FINDSTR /C:"1" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=STOPPED
    ECHO %STATE% | FINDSTR /C:"2" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=START_PENDING
    ECHO %STATE% | FINDSTR /C:"3" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=STOP_PENDING
    ECHO %STATE% | FINDSTR /C:"4" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=RUNNING
    ECHO %STATE% | FINDSTR /C:"5" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=CONTINUE_PENDING
    ECHO %STATE% | FINDSTR /C:"6" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=PAUSE_PENDING
    ECHO %STATE% | FINDSTR /C:"7" >nul
    IF %ERRORLEVEL%==0 SET CURRENT_STATUS=PAUSED
    
    ECHO Current status of service is %CURRENT_STATUS%
    
    IF NOT "%CURRENT_STATUS%"=="RUNNING" IF NOT "%CURRENT_STATUS%"=="STOPPED" IF NOT "%CURRENT_STATUS%"=="PAUSED" (
        IF "%SLEEP_COUNT%"=="%MAX_WAIT_PERIODS%" (
            ECHO Service state won't change. Script exececution is canceled.
            EXIT /B 4
        )
        ECHO Service State is changing, waiting %DEFAULT_DELAY% seconds...
        SLEEP %DEFAULT_DELAY%
        SET /A SLEEP_COUNT+=1
        GOTO Dispatch
    )
    
    IF "%ACTION%"=="START" (
        IF "%CURRENT_STATUS%"=="RUNNING" (
            ECHO Service %SERVICENAME% is running.
            GOTO EndExit
        ) ELSE (
            GOTO StartService
        )
    ) ELSE IF "%ACTION%"=="RESTART" (
        IF "%CURRENT_STATUS%"=="RUNNING" (
            IF %RESTARTED%==1 (
                ECHO Service %SERVICENAME% restarted.
                GOTO EndExit
            )
            SET /A SLEEP_COUNT=0
            GOTO StopService
        ) ELSE (
            SET /A RESTARTED=1
            GOTO StartService
        )
    ) ELSE IF "%ACTION%"=="STOP" (
        IF "%CURRENT_STATUS%"=="STOPPED"  (
            ECHO Service %SERVICENAME% is stopped.
            GOTO EndExit
        ) ELSE (
            GOTO StopService
        )
    )
    
    :StartService
    ECHO Starting %SERVICENAME% on \%SYSTEMNAME%
    SC \%SYSTEMNAME% start %SERVICENAME% >nul 2>&1
    SET SLEEP_COUNT=0
    GOTO Dispatch
    
    :StopService
    ECHO Stopping %SERVICENAME% on \%SYSTEMNAME%
    SC \%SYSTEMNAME% stop %SERVICENAME% >nul 2>&1
    SET SLEEP_COUNT=0
    GOTO Dispatch
    
    :Usage
    ECHO This script can start/stop/restart a local or remote service, waiting for the service to stop/start ^(if necessary^).
    ECHO.
    ECHO Usage:
    ECHO %0 ^<start^|stop^|restart^> ^<SERVICE^> [SYSTEM]
    ECHO.
    ECHO If no SYSTEM is provided, the script attempts to execute on the local system.
    EXIT /B 5
    
    :EndExit
    ECHO.
    EXIT /B 0
    

回答by James Holland

Eric Falsken's scripts are fantastic for this purpose. But note that they use the timeout command which is only available in Vista/Server2003 and newer. For an XP machine you can use sleep.exe from the NT Resource Kit instead. (This should be a commment to Eric's answer but not enough rep to do that).

Eric Falsken 的脚本非常适合这个目的。但请注意,它们使用的 timeout 命令仅在 Vista/Server2003 及更新版本中可用。对于 XP 计算机,您可以改用 NT Resource Kit 中的 sleep.exe。(这应该是对 Eric 回答的评论,但没有足够的代表来做到这一点)。

回答by Joe

NET START and NET STOP shouldn't return until the service has indicated that the service has started or stopped successfully.

NET START 和 NET STOP 在服务指示服务已成功启动或停止之前不应返回。

回答by Matt Davis

I don't believe you can do this with a straight dos command. You might check Code Projector other similar sites to see if there's a custom solution for this already.

我不相信你可以用一个直接的 dos 命令来做到这一点。您可以检查Code Project或其他类似站点,看看是否已经有针对此的自定义解决方案。

If not, you could write a secondary Windows service that does this for you by exposing the start/stop functionality through a WCF endpoint. To access this secondary service remotely, you could write a simple console app that connects to this service to start/stop the Windows service in question. Since it's a console app, it would mimic the desired behavior of working from the command line and not returning until complete (or an error occurred). It's not the straightforward, simple solution you're looking for, but I'll throw it out there for consideration.

如果没有,您可以编写一个辅助 Windows 服务,通过 WCF 端点公开启动/停止功能来为您执行此操作。要远程访问此辅助服务,您可以编写一个简单的控制台应用程序,连接到此服务以启动/停止有问题的 Windows 服务。由于它是一个控制台应用程序,它会模仿从命令行工作的期望行为,并且直到完成(或发生错误)才返回。这不是您正在寻找的直接、简单的解决方案,但我会将其丢弃以供考虑。