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:

pendingservice1.png

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:

Get-Service |
Where-Object {$_.Status -eq 'StopPending'} |
Format-List -Property * -Force

pendingservice2.png

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:

Get-Service | Get-Member

pendingservice3.png

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:

Get-Service | Get-Member
Where-Object {$_.Status -eq 'StopPending'} |
Stop-Service -Force

pendingservice4.png

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:

Get-WmiObject -Class win32_service |
Where-Object {$_.state -eq 'stop pending'}

pendingservice5a.png

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:

function Stop-PendingService {

<#
.SYNOPSIS
    Stops one or more services that is in a state of 'stop pending'.

.DESCRIPTION
     Stop-PendingService is a function that is designed to stop any service
     that is hung in the 'stop pending' state. This is accomplished by forcibly
     stopping the hung services underlying process.

.EXAMPLE
     Stop-PendingService

.NOTES
    Author:  Mike F Robbins
    Website: http://mikefrobbins.com
    Twitter: @mikefrobbins
#>

    $Services = Get-WmiObject -Class win32_service -Filter "state = 'stop pending'"
    if ($Services) {
        foreach ($service in $Services) {
            try {
                Stop-Process -Id $service.processid -Force -PassThru -ErrorAction Stop
            }
            catch {
                Write-Warning -Message "Unexpected Error. Error details: $_.Exception.Message"
            }
        }
    }
    else {
        Write-Output "There are currently no services with a status of 'Stopping'."
    }
}

Our Stop-PendingService function will stop any service that has a state of “Stop Pending” on the local computer:

pendingservice6.png

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:

. .\Stop-PendingService.ps1
Invoke-Command -ComputerName Server1 -ScriptBlock ${Function:\Stop-PendingService} -Credential (Get-Credential)

pendingservice7.png

ยต