That a Windows service hangs (that is, becomes unresponsive or fails to stop) is a common issue admins face. With the help of PowerShell, you can easily restart a service. In this post, I also share my PowerShell script, which allows you to restart a hanging service on multiple computers.
Avatar

Recently, I was checking the state of update deployment when I noticed a computer had not reported in a long time. It was an RDS server to which many users were connected. Attempting to stop the Windows Update service from the Services console (services.msc) would cause the service to hang for a while. Eventually, it threw a warning message that the service had failed to stop.

Stopping a Windows service using the Services GUI

Stopping a Windows service using the Services GUI

Right-clicking a service in the Services console and selecting Stop is followed by a pop-up window if the service doesn't stop immediately. With a hanging service, this progress bar will persist for a while, but eventually, it will fail with the error message Windows could not stop the service.

Windows could not stop the Windows Update service

Windows could not stop the Windows Update service

You can close the window, but if you refresh the status of the service, it will simply display Stopping forever.

Service is hung in the stopping state

Service is hung in the stopping state

At this point, a quick solution would be to simply restart the server, which usually eliminates the issue. However, there are situations when this is not desirable or even possible. I couldn't just disconnect users in the middle of their work because Windows Update was misbehaving.

Fortunately, there is a workaround that usually solves the problem.

Stop a hanging service without restarting

First, this isn't a guarantee that it will work in 100% of the cases. Nothing is ever 100% in Windows or any other OS. However, it will work most of the time. With the disclaimer out of the way, let us see how.

A service is a process that runs in the background. If it is a process, you can find it in Task Manager (or with the Get-Processing PowerShell cmdlet), and then kill it.

Services almost always run as an instance of the svchost.exe process—the Windows service host process. If you check Task Manager (or Get-Process) for svchost.exe, you'll see many instances of it running. Which is the one corresponding to your hanging service?

Well, the answer is not available in Task Manager, but it is easy to find in the WMI repository using PowerShell:

(Get-CimInstance -ComputerName "COMPUTER_NAME" -ClassName Win32_Service -Filter "name = 'SERVICE_NAME'")

In my case, the service is Windows Update (wuauserv). The output of the command is shown below:

Process information for the hanging service

Process information for the hanging service

Bingo—we have the process ID. The only thing to do now is stop the process by using—you guessed it—PowerShell.

$Process = Get-CimInstance -ClassName Win32_Service -filter "name = 'wuauserv'"
Stop-Process -Id $Process.ProcessId 

In this case, I omitted the computer name since I ran the command locally, but in the next section, I will show you how to make this work easily for one or more remote computers.

Service stopped

Service stopped

Now, the service is stopped and can be restarted using the Services console or PowerShell:

Start-Service wuauserv

After this, the service should be running.

Service is running

Service is running

If, however, the service is still misbehaving, you may need to investigate further (using Procmon.exe, for instance), or maybe restarting the computer when possible.

You can also use any tool that allows you to explore the deep labyrinths of WMI. However, PowerShell is easy, already available, and can be used to automate. This will help us in the next section.

Restart a Windows service with a PowerShell script

Of course, avoiding a restart and interrupting your colleague's work is nice, but it is even nicer if you can automate, for instance, if you have many computers that have the same issue with a service.

Below, I include a short PowerShell function I wrote that allows you to accomplish exactly that: restart one or more services on one or more computers. As always, you should test before running a script in production.

Subscribe to 4sysops newsletter!

 function Stop-HangingService {
    <#
    .Synopsis
        Stops a hanging service
    .DESCRIPTION
        Stops a single service on a single computer if the service status is Starting or Stopping.
        These are transient states that a service should not be in for more than a few seconds,
        and they are a good indicator that a service may be hanging. If the service is in a running
        or stopped state, you are informed and no further action is taken
    .PARAMETER NAME
        One or more services. The service name(s) is needed, not the Display Name(s)
    .PARAMETER COMPUTERNAME
        One or more computers on which the hanging service(s) should be stopped
    .EXAMPLE
        Stop-HangingService -Name BITS
        Stops the service BITS (if it is in a hanging state) on the local computer
    .EXAMPLE
        Stop-HangingService -Name Wuauserv -ComputerName Srv1,Srv2 -Verbose
        Stops the hanging Windows Update service on the computers Srv1 and Srv2
    .EXAMPLE
        (Get-ADComputer -SearchBase $SqlServersOu -filter *).Name | Stop-HangingService -Name SQLAgent
        Stops the hanging service SQLAgent on all the computers in the specified OU
    #>

    [CmdletBinding()]
    Param(
        [Parameter(Mandatory,Position = 0,HelpMessage = "Name of the service you're trying to stop")][string[]]$Name,
        [Parameter(ValueFromPipeline,Position = 1)][string[]]$ComputerName = $env:COMPUTERNAME
    )

    Begin {
        Write-Verbose "$(Get-Date -Format HH:mm:ss) BEGIN  : $($MyInvocation.MyCommand)"
        $StartTime = Get-Date

        #region Helper function, stops a single service on a single computer
        function Stop-SingleService {
        <#
        .Synopsis
            This is a helper function that stops a single service on a single computer. It is a helper
            function for Stop-HangingService
        #>
            [CmdletBinding()]
            Param(
            [Parameter(Mandatory,HelpMessage = "Name of the service you're trying to stop")][string]$Name,
            [Parameter()][string]$ComputerName = $env:COMPUTERNAME
            )
            try {
                    Write-Verbose "$(Get-Date -Format HH:mm:ss) PROCESS: Retrieve status of service $Name on $($ComputerName.ToUpper())"
                    $Service = Get-Service -Name $Name -ComputerName $ComputerName -ErrorAction Stop
                } #try
            catch {
                Write-Verbose "$(Get-Date -Format HH:mm:ss) PROCESS: The service $Name could not be found on $($ComputerName.ToUpper())"
                return
            } #catch

            if ($Service.Status -like "*Stopping*" -or $Service.Status -like "*Starting*") {
                Write-Verbose "$(Get-Date -Format HH:mm:ss) PROCESS: Get Process ID for service $Name"           
                $Process = (Get-CimInstance -ComputerName $ComputerName -ClassName Win32_Service -filter "name = '$Name'")

                Write-Verbose "$(Get-Date -Format HH:mm:ss) PROCESS: Stopping process ID $($Process.ProcessId) for service $Name on $($ComputerName.ToUpper())"
                Invoke-Command -ComputerName $ComputerName -ScriptBlock {Stop-Process -Id $using:Process.ProcessId -Force}

            }
            else {
                Write-Verbose "$(Get-Date -Format HH:mm:ss) PROCESS: The service $Name is not hanging on $($ComputerName.ToUpper())"
            }
        }
        #endregion Helper function

    } #Begin

    Process {
        foreach ($c in $ComputerName) {
            foreach ($n in $Name) {
            
                Stop-SingleService -ComputerName $c -Name $n

            }
        }

    } #Process


    End {
        $EndTime = Get-Date
        Write-Verbose "$(Get-Date -Format HH:mm:ss) FINISH : $($MyInvocation.MyCommand). The operation completed in $(New-TimeSpan -Start $StartTime -End $EndTime )"
        
    }

} #function Stop-HangingService 

Conclusion

In this post, you learned how you can (often) avoid restarting a computer because a service hangs. You also received a PowerShell script that allows you to restart a service on multiple computers.

 

avataravatar
3 Comments
  1. Avatar
    Anand Punjabi (Rank 2) 12 months ago

    Hi Emanuel
    Just one correction in your command for stopping the process mentioned above
    Stop-Process -Id $Process.ProcessId.
    Rgds

    avataravataravatar
  2. Avatar
    reyhan 12 months ago

    thanks alot of information keren banget

Leave a reply

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account