如何在不重启计算机的情况下卸载Windows服务并删除其文件

48

我的当前项目涉及部署一个作为Windows服务运行的升级版.exe文件。为了用新版本覆盖现有的.exe文件,我目前需要执行以下步骤:

  1. 停止服务
  2. 卸载服务
  3. 重新启动系统(这样Windows才会释放对该文件的控制)
  4. 部署新的.exe文件
  5. 重新安装服务
  6. 启动升级后的服务。

我想避免重启,以便进行完全脚本化/自动化的升级。

有没有办法避免重启?也许有一种命令行工具可以强制Windows放弃对旧的.exe文件的控制吗?


感谢大家的帮助!我发现问题的根源是由WMI对.exe文件的句柄。请查看我的新问题:http://stackoverflow.com/questions/302315/want-to-script-window-wmi-wmiprvseexe-to-release-handle-on-file - Nate Sauber
5
须知:如果您已打开“服务管理器”,则需要在重新安装服务之前关闭它,否则会出现“服务已标记为删除”的错误。 - ChandlerPelhams
根据我的经验(https://dev59.com/63HYa4cB1Zd3GeqPM44n#16293612),"[SC] CreateService FAILED 1072: The specified service has been marked for deletion" 错误取决于卸载的服务是否已被先停止。我尝试通过打开服务管理工具来复现该错误,但未能成功。 - J0e3gan
10个回答

78
sc delete "service name"

将会删除一个服务。我发现比起寻找installutil,sc实用工具更易于定位。记得先停止该服务,如果你还没有这么做。


15
在Windows 7及以上版本中,执行"sc delete "服务名称""命令可以删除指定的服务。 - Esben Skov Pedersen
1
是的,最终微软也会像*nix一样使用“--”。一步一个脚印 =) - StingyJack
在我的情况下,命令是: sc delete "服务名称" 请注意,您必须以管理员身份执行命令行。 - k.honsali
7
我发现 sc delete 命令在卸载服务时并不能停止正在运行的服务,而是标记该服务待删除,这也符合其文档所描述的。请参考链接:https://dev59.com/63HYa4cB1Zd3GeqPM44n#16293612。 - J0e3gan

18

我遇到了与你类似的问题。我有一个系统服务,想要在更新时将其卸载并重新安装。但在某些系统上,如果不重启可能无法正常工作。问题在于DeleteService()的调用会返回ok,但CreateService()的后续调用会告诉我该服务仍然存在,但已标记为删除(错误代码1072)。注册表也会反映这一点,因为子键仍然存在(位于HKLM\System\CurrentControlSet\Services下),但“DeleteFlag”设置为1。从那时起,只有重启才能解决这个问题。

以下是一些无效的尝试:

  • 使用“sc delete”:它存在与我相同的问题。该调用会返回ok,但服务实际上没有被删除,并且在注册表中仍带有DeleteFlag = 1。
  • 删除注册表中的键。服务管理器似乎保留了内存中的数据库,而注册表只是下次启动时的副本。
  • 添加等待循环,等待.exe文件准备好被覆盖,杀死进程等。
  • 关闭服务的句柄。哪些句柄?

但以下方法有效:

我在stackoverflow上看到一些文章提到net.exe也有启动/停止功能(我只知道sc.exe实用程序)。奇怪的是,“net stop svcname”加上“sc delete svcname”起作用了!所以net.exe一定做了我没做的事情。

但是,net.exe不包含ControlService()的导入,那么它如何停止该服务呢?我发现,net.exe会生成net1.exe,但net1.exe也没有导入ControlService()。我使用了一个很棒的API Monitor实用程序(http://www.rohitab.com/apimonitor)来查看net1.exe正在做什么,但它从未调用过任何看起来有希望的东西。

但是我发现它从NETAPI32.DLL中导入了NetServiceControl()函数(它的名称中至少包含“Service”)。MSDN表示该函数已经过时。尽管如此,我在LMSvc.h中找到了原型,并在此处找到了一些参数描述:http://cyberkinetica.homeunix.net/os2tk45/srvfpgr/369_L2_NetServiceControlorN.html。当您加载NETAPI32.DLL并使用NetServiceControl(NULL, service_name, 3, 0, 0)(3表示SERVICE_CTRL_UNINSTALL,用于停止)之后,服务将被停止。然后可以删除并重新安装而无需DeleteFlag或重新启动!

所以这不是删除问题,而是正确停止服务的问题。 NetServiceControl()可以解决问题。抱歉发帖较长,但我认为它可能会对有类似问题的人有所帮助。(仅供参考,我使用的是Win7 SP1 x64。)


你如何可靠地模拟“标记为删除”状态?我所做的是使用正常的服务API打开一个服务句柄来模拟它。但是,当句柄打开时,这种方法不起作用。只有在关闭句柄后,服务才会自动消失。 - shoosh
谢谢!我正在寻找“net stop”和“sc stop”之间的区别。 - Nerielle
很棒的分析! - Max

14

您是否无法使用以下命令在更新之前停止服务(并在更新后重新启动)?

net stop <service name>
net start <service name>

每当我测试/部署服务时,只要服务被停止,我就可以上传文件而无需重新安装。我不确定你遇到的问题是否不同。


4
这一直是我的经验 - 我仅通过停止并替换.EXE文件就不断更新服务。这只是一个普通的过程。 - Will Dean
同样的情况发生在我身上——按照描述的方式运行了数月的Windows服务套件(在Windows 7上运行)成功了。 - J0e3gan

3

如果在 .net 中(我不确定它是否适用于所有的windows服务)

  • 停止服务(这可能是你遇到问题的原因)
  • InstallUtil -u [可执行文件名称]
  • Installutil -i [可执行文件名称]
  • 重新启动服务...

除非我改变了服务的公共接口,否则我通常会升级我的服务版本而不需要卸载/重新安装...我所做的只是停止服务,替换文件,然后重新启动服务...


在我的情况下,由于某些权限问题,我无法执行该操作。 - k.honsali

3
正如StingyJack和mcbala提到的,以及Mike L的评论所指出的,在Windows 2000计算机上卸载/重新安装.Net服务时,“installutil /u”确实需要重启,即使服务之前已经停止。“sc / delete”,则不需要重启 - 它会立即删除服务(只要它已经停止)。
事实上,我经常想知道为什么“installutil /u”需要重启...是“sc /delete”做错了什么/留下了什么问题吗?

+1对于资格认证“只要它停止了”是合适的。这与我的经验一致-尽管在Windows 7上。 - J0e3gan

2

乔纳森和查尔斯都是正确的...您必须先停止服务,然后卸载/重新安装。将他们两个人的答案结合起来可以制作出完美的批处理文件或PowerShell脚本。

我要提醒大家一个艰难的教训——Windows 2000 Server(可能也包括客户端操作系统)在重新安装之前无论如何都需要重新启动。这里必须有一个注册表键没有完全清除,直到重启后才能清除。Windows Server 2003、Windows XP及更高版本的操作系统不会遇到这种问题。


2

(所以Windows释放对文件的控制)

相反,在服务停止后立即按Ctrl+Alt+Del并终止服务的.exe。然后,您可以在无需重新启动计算机的情况下卸载该服务。我曾经遇到过这种情况,这解决了您需要重新启动计算机的部分。


2

如果需要手动删除服务:

  1. 运行Regedit或regedt32。
  2. 在以下键下找到您的服务的注册表键条目: HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services
  3. 删除注册表键。

在服务中更新列表之前,您需要重新启动计算机。


0

停止和删除服务的批处理文件

@echo off
title Service Uninstaller
color 0A
set blank=
set service=blank
:start
echo.&echo.&echo.
SET /P service=Enter the name of the service you want to uninstall:  

IF "%service%"=="" (ECHO Nothing is entered
GoTo :start)
cls
echo.&echo.&echo We will delete the service: %service%
ping -n 5 -w 1 127.0.0.1>nul
::net stop %service%
ping -n 2 -w 1 127.0.0.1>nul
sc delete %service%
pause
:end

0

我正在使用.NET Framework附带的InstallUtil.exe。

卸载的用法是:InstallUtil '\path\to\assembly\with\the\installer\classes' /u,例如:installutil MyService.HostService.exe /u

/u开关表示卸载,没有它,该工具将执行服务的正常安装。如果服务正在运行,则实用程序会停止该服务,我从未遇到过Windows锁定服务文件的问题。您可以在MSDN上阅读有关InstallUtil的其他选项。

P.S.:如果您的路径变量中没有installutil,请使用完整路径,例如:C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe "C:\MyServiceFolder\MyService.HostService.exe" /u或者如果您需要64位版本,则可以在'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\'中找到它。路径中的版本号因.NET版本而异。


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