关于强制停止服务的问题
强制停止服务
当停止某个服务的时候,因为某些为止的原因,服务的状态会一直处于STOP_PENDING,此时,就需要强制停止该服务
杀死服务对应的进程
用中文在百度搜索“杀死服务”,以及用英文在google搜索“kill service”,基本原理都一样:
找到目标服务的进程ID---PID,然后杀死即可
CMD命令
sc queryex servicename
taskkill /f /pid [PID]
PowerShell
$processId = Get-CimInstance -Class win32_service | ?{$_.Name -eq "YOURSERVICENAME"} | select -ExpandProperty ProcessId
kill $processId
如果我们要杀的是系统服务呢?
在我们的场景中,Winrm服务因为某些原因无法停止,于是我们就copy-paste以上代码去处理,结果引发了新的问题---无法访问网络路径。
简单来说,本来同一个域的server,是可以通过SMB协议访问,访问路径类似这样:\ServerName\C$\Windows。结果在杀死Winrm服务之后,无法访问了。
为什么呢?难道误杀了不成?
执行以下代码用于验证,是否其他服务也收到影响
Get-Service
"before kill"
$winrmSvc = Get-CimInstance -ClassName win32_service | ?{$_.Name -eq "winrm"}
$winrmPID = $winrmSvc.ProcessId
Stop-Process -Id $winrmPID -Force
"after kill"
Get-Service
结果:
WHAT?
除了Winrm服务停止之后,还有其他3个服务也被停止了。
这3个服务看样子并没有与Winrm有啥关系。
影响我们访问网络路径的服务是LanmanWorkstation
(试的)
启动该服务后,另外2个服务也自动启动了。
为什么会停止其他服务?
Winrm服务和LanmanWorkstation服务有啥关系?
经过一番查证,发现二者关系就如卡巴斯基和巴基斯坦的关系。
点开瞧瞧
WHAT?
为啥binPath一毛一样?参数还一样?
是不是就是因为他们是同一个进程,所以就给一并杀了?
binPath一毛一样的还有其他服务,不管进程执行的Command Line一样,ProcessID还一样!
多个service,共用一个进程(ID)!!!
为啥?问就是为了节约资源
Svchost.exe (Service Host, or SvcHost) is a system process that can host from one or more Windows services in the Windows NT family of operating systems.[1] Svchost is essential in the implementation of shared service processes, where a number of services can share a process in order to reduce resource consumption.
https://en.wikipedia.org/wiki/Svchost.exe
经过验证,发现在客户机上(win10这样的)没有这样的情况
而在服务器上(windows server 2012 R2这样的)是共享一个进程的
解决办法
- 重启
- 杀掉共享进程前,保存其他running的service,然后重启这些service(造成波动)
- 待研究
问题以及更新
- 按照解决方案二操作,需要注意2点
杀掉共享进程前,保存其他running的service,然后重启这些service
(1)杀掉进程后立刻启动服务,可能会出错。可稍微等等,等多少时间呢,经过我的测试,1ms就可以。当然,建议多设置点时间。同时增加重试机制,确保服务一定启动。
(2)需要重新启动的服务不光只有共享进程的那些服务,还需要包括依赖这些服务的服务,以及依赖的依赖...递归会用吧。
function Get-ServiceNameChain {
[cmdletbinding()]
param([System.String[]]$ServiceNameList)
$ServiceNameList| %{
$_
$currentService = Get-Service $_
$dependentServices = $currentService.DependentServices
if($dependentServices)
{
$dependentServiceNameList=@()
$dependentServices| ?{$_.StartType -eq "Automatic"} | %{$dependentServiceNameList += ($_.Name)}
Get-ServiceNameChain $dependentServiceNameList
}
}
}
- 方案二终究不是个好办法,会同时造成很多服务停止(服务依赖链上的所有服务都会停止),而且你无法保证一定能够全部正确的重启(启动要注意顺序)
所以,最好的办法就是
把你要强制停止的服务所在的进程进行分离,不要共享进程。
顺着这个思路,找到了这个文章:
https://docs.microsoft.com/en-us/windows/application-management/svchost-service-refactoring
微软说可以修改注册表可以分离进程,但文章针对的是Desktop SKU(就是我们用的win10之类的系统,非Windows Server)
使用文中关键词“Separating SvcHost services”在google搜索,得到:
https://superuser.com/questions/860117/isolate-hosted-service-svchost-exe-in-its-own-process
https://www.quora.com/How-do-I-divide-svchost-exe-processes-into-distinct-processes
二者答案都是:
sc config your_service_name type= own
//注意,等号后面的空格是必须的
哦,这个ServiceType有点印象,创建service的时候有这个参数
我们来看看它的可设置的值:
来源:https://docs.microsoft.com/en-us/dotnet/api/system.serviceprocess.servicetype?view=dotnet-plat-ext-6.0
上面type= own其实就是设置值为Win32OwnProcess
这...还能同时设置...
设置了发现并没有作用,偶然杀了之前的进程后,发现好像有作用。
lesson learn: 改了系统配置,没作用就重启电脑试试,先别着急放弃。
至此,最佳方案出炉。