PowerShell Function to Stop a Windows Service with a Status of Stopping
If you're reading this blog article, you've probably tried to stop a Windows Service and it's hung
or stuck with a status of Stopping
:
An average Windows Admin would say "The server is going to have to be rebooted to clear up this problem". This problem can be resolved with PowerShell though without the need for a restart.
The machine I'm testing these examples on just happens to be running PowerShell version 2 so I'll
use the v2 syntax to see if the Get-Service
cmdlet has any properties that may help. I want to see
values with the property names so I'll pipe the results to Format-List -Property * -Force
as shown
in the following example:
1Get-Service |
2Where-Object {$_.Status -eq 'StopPending'} |
3Format-List -Property * -Force
There doesn't appear to be any properties that can help so I'll pipe Get-Service
to Get-Member
to make sure there aren't any methods that could help:
1Get-Service | Get-Member
I don't see anything in those results either that could help, but maybe we can just pipe the service
with the issue to the Stop-Process
cmdlet and use the Force
parameter to stop it:
1Get-Service | Get-Member
2Where-Object {$_.Status -eq 'StopPending'} |
3Stop-Service -Force
No such luck. It's looking like that restart may not be such a bad idea, but let's give WMI a try before we resort to that option. We're prototyping at this point so we're not going to worry about filtering to the left:
1Get-WmiObject -Class win32_service |
2Where-Object {$_.state -eq 'stop pending'}
The ProcessId
property looks promising.
I'm sure most of you have either read about or seen examples on the Internet where someone tries to
pipe Get-Service
to Stop-Process
and maybe they're lucky enough to stop a process or two because
those couple of service names just happen to match up to the process names, but generally speaking,
service names and process names don't match up.
We're going to use a modified version of that same sort of example here, but we're going to use the
value of a service's "ProcessId" which we'll retrieve from WMI and feed that information to
Stop-Process
. While we're at it, we'll just write a simple function to accomplish this task and
apply all of those best practices such as filtering to the left:
1function Stop-PendingService {
2
3<#
4.SYNOPSIS
5 Stops one or more services that is in a state of 'stop pending'.
6
7.DESCRIPTION
8 Stop-PendingService is a function that is designed to stop any service
9 that is hung in the 'stop pending' state. This is accomplished by forcibly
10 stopping the hung services underlying process.
11
12.EXAMPLE
13 Stop-PendingService
14
15.NOTES
16 Author: Mike F Robbins
17 Website: http://mikefrobbins.com
18 Twitter: @mikefrobbins
19#>
20
21 $Services = Get-WmiObject -Class win32_service -Filter "state = 'stop pending'"
22 if ($Services) {
23 foreach ($service in $Services) {
24 try {
25 Stop-Process -Id $service.processid -Force -PassThru -ErrorAction Stop
26 }
27 catch {
28 Write-Warning -Message "Unexpected Error. Error details: $_.Exception.Message"
29 }
30 }
31 }
32 else {
33 Write-Output "There are currently no services with a status of 'Stopping'."
34 }
35}
Our Stop-PendingService
function will stop any service that has a state of "Stop Pending" on the
local computer:
Instead of writing a bunch of code in this function to connect to a remote machine, I'll just
leverage the power of PowerShell remoting via the Invoke-Command
cmdlet and have it run this
function that only exists on my local machine against the remote machine that has the service
Stopping
issue:
1. .\Stop-PendingService.ps1
2Invoke-Command -ComputerName Server1 -ScriptBlock ${Function:\Stop-PendingService} -Credential (Get-Credential)
µ