批处理文件如何等待服务停止完成?

43

我正在使用批处理文件停止Windows服务。我正在使用sc命令,但考虑到下面的问题,我也可以接受其他想法。问题在于,当服务停止时(对scstop参数似乎只是请求停止而不等待停止),批处理文件会继续执行。

如何修改批处理文件,以便在停止完成之前不继续执行?

7个回答

37
你可以使用同步的NET stop,即它会等待服务停止。
参见: - NET stop

2
然而,如果服务已经停止,net stop 将抛出一般错误代码 2(访问被拒绝)。 - Wernight
49
这不完全正确。如果服务需要4分钟才能完全停止并退出,那么“net stop”命令将在20-40秒后返回,但服务进程尚未终止。它会返回“无法停止服务”...但这是具有误导性的。已发送停止命令给服务,只是未在 SCM 超时时间内完全退出。 - Jonesome Reinstate Monica
3
我知道这个帖子有点老了,但我刚刚在Windows Server 2012 R2上测试了一下 - 我有一个服务,需要大约三分钟才能停止...当运行'net stop'命令时,该命令直到服务可执行文件真正停止并从任务管理器中消失后,CMD文件才会完成。与一些旧评论所说的不同,它在更新的服务器上可以运行。 - Hudey
1
net stop返回后,如果您使用sc query "My Service Name" | find "STATE"检查状态,则某些服务可能处于STOP_PENDING状态。 - ssh

35
sc stop webdriveservice
:loop
sc query webdriveservice | find "STOPPED"
if errorlevel 1 (
  timeout 1
  goto loop
)

另一个带有重复次数限制的版本:

sc stop webdriveservice
set count=1
set limit=10
:loop
sc query webdriveservice | find "STOPPED"
if errorlevel 1 (
  timeout 1
  set /a count += 1
  if %count% lss %limit% goto loop
)

优秀的答案。只有一个问题: 为什么使用 TIMEOUT 而不是 SLEEP?TIMEOUT 会被按键绕过,我认为这在批处理文件中不是一个理想的效果(当焦点位于 cmd 窗口时,很容易出现误按键)。 - thewild
实际上,它是2003资源工具包的一部分。我以为它是标准的Windows安装程序,我的错。 - thewild
timeout 5 /nobreak 只会在CTRL+C被按下时退出。 - ssh

14

不是我点踩的(虽然我能猜到是谁),但这个答案也包含了错误信息。NET STOP会等待服务停止,直到某个时间点。我从来没有遇到过一个服务尝试停止整整四分钟,所以我不能说NET STOP等待多长时间,但它确实等待了相当长的一段时间,与sc stop不同。 - LittleBobbyTables - Au Revoir
@LittleBobbyTables 帖子已更新以解决你所观察到的问题。如果你查看微软团队所写的内容(下面的链接),你会发现 SCM 一次只与一个服务对话,因此它不会无限期地等待任何一个服务。NET SEND 只是向 SCM 发送命令的一种方式,与服务管理器中的方式相同。http://blogs.msdn.com/b/bclteam/archive/2009/02/19/in-depth-how-net-managed-services-interact-with-the-servicecontrolmanager-scm-kim-hamilton.aspx - Jonesome Reinstate Monica
1
从@Jonesome链接的博客中获取更多信息:控制超时的注册表键是HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\WaitToKillServiceTimeout。默认值显然为20秒,但在我的Windows 8.1 Enterprise版本上为5秒(可能被组策略修改)。 - Stajs
@Stajs 在 Windows 2012 上,我将 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\WaitToKillServiceTimeout 设置为 DWORD 120000,但它完全没有效果 - 即使服务正在关闭但尚未停止,net stop 仍在10-15秒后返回,不会在另外45秒内停止。 - DisappointedByUnaccountableMod

3

我认为net stop [Service]应该等待服务完全停止后再继续进行。而sc stop [Service]只是向服务发送一个“停止”消息。


@Jonesome - 为什么不提供一个更好的答案,而是选择给出负评呢? - LittleBobbyTables - Au Revoir
公平的评价!已完成!下降投票的原因是两个答案都包含错误信息(我在win7和win2008上进行了测试,并且从经验中知道XP和其他版本会表现相同)。 - Jonesome Reinstate Monica
这不完全正确。如果服务需要4分钟才能真正停止和退出,那么"net stop"命令将在20-40秒后返回,但是服务进程尚未终止。它返回"The service could not be stopped"…但这是误导性的。已经向服务发送了停止命令,只是在SCM超时范围内没有完全退出。 - huang

2
我曾遇到过与 net stop 类似的问题。当服务确实停止时,该命令会返回,但可执行文件可能仍在运行。
出于升级原因,这并不够好,我们需要等待进程完成。
我使用了一个简单的循环来等待服务可执行文件实际完成:
net stop "ServiceName"
:loop1
set _CmdResult=""
for /f "tokens=1" %%a in ('TASKLIST ^| FINDSTR ServiceName.exe') do set _CmdResult=%%a
if not %_CmdResult% == ""  (
  timeout 5
  goto loop1
)

一旦可执行文件完成,循环将停止。

1
这段代码有点粗糙,但对我很有效,可以确保我能够安排每天运行的批处理文件来重新启动服务。
NET STOP [服务名称]
:TryAgain
TIMEOUT /T 10 /NOBREAK
NET START [服务名称]
IF %ERRORLEVEL% NEQ 0 GOTO TryAgain
我意识到,如果服务无法成功启动,这段代码可能会导致无限循环。我只是想展示如何使用TIMEOUT解决NET STOP命令所需时间不足以停止服务的问题。

-1

在命令之间使用&&符号。 &&符号等待前一个命令完成后再执行下一个命令。

所有命令必须在同一行上。您可以在一行中使用任意多个命令。

您还可以使用pause命令。这样,它会要求在继续下一个过程之前按任意键。

例如:

sc qdescription "MyServiceName" && echo. && sc stop "MyServiceName" && echo. && echo          [ "MyServiceName" service stopped ] && echo. && pause

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接