1

I'm trying to write a more robust Stop-Service cmdlet (PSv3). Basically by having a function that calls Stop-Service then tests the service status to see that the service is really stopped and eventually escalating to a process kill of the service.

I'm trying to write or find a service that does not stop gracefully, but tends to linger on after receiving the stop notification.

My 'bad' service simply uses this:

    protected override void OnStop()
    {
        TheEventLog.WriteEntry("StrongBad in OnStop");
        Thread.Sleep(300000);
    }

But the service does stop within whatever timeout Stop-Service allows.

PS C:\WINDOWS\system32> Stop-Service -Name StrongBad
WARNING: Waiting for service 'Trogdor (StrongBad)' to stop...
WARNING: Waiting for service 'Trogdor (StrongBad)' to stop...
WARNING: Waiting for service 'Trogdor (StrongBad)' to stop...
WARNING: Waiting for service 'Trogdor (StrongBad)' to stop...
PS C:\WINDOWS\system32> Get-Service StrongBad

Status   Name               DisplayName
------   ----               -----------
Stopped  StrongBad          Trogdor

I really expected (and in this case want) the Stop-Service cmdlet to return a message saying the service failed to stop in the allotted time.

It seems I see similar to expected behavior when the service has dependencies:

PS C:\src\Enterprise\Enterprise\Systems\Scripts\Powershell\Includes> Stop-Service -Name nsi -Force
Stop-Service : Service 'Network Store Interface Service (nsi)' cannot be stopped due to the following error: Cannot stop LanmanWorkstation service on computer '.'.
At line:1 char:1
+ Stop-Service -Name nsi -Force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : CloseError: (System.ServiceProcess.ServiceController:ServiceController) [Stop-Service], ServiceCommandException
    + FullyQualifiedErrorId : CouldNotStopService,Microsoft.PowerShell.Commands.StopServiceCommand

Stop-Service : Collection was modified; enumeration operation may not execute.
At line:1 char:1
+ Stop-Service -Name nsi -Force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Stop-Service], InvalidOperationException
    + FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.StopServiceCommand
Arluin
  • 594
  • 1
  • 8
  • 21
  • Here's a related answer: http://stackoverflow.com/questions/12534170/stop-service-cmdlet-timeout-possible – Arluin Sep 03 '14 at 21:14
  • I got it so the service doesn't stop, and as the answer in the comment above indicates, Stop-Service doesn't eventually timeout, it will keep writing: WARNING: Waiting for service 'Trogdor (StrongBad)' to stop... – Arluin Sep 03 '14 at 22:43

2 Answers2

1

There is no way to get Stop-Service to timeout. It will gladly wait forever for the service to stop (ask me how I know). Per the this answer, you'll need to start a background job to stop the service, wait until it is done, and if the service isn't stopped, kill it:

Start-Job { Stop-Service StrongBad } | Wait-Job -Timeout 30
$svc = Get-Service StrongBad
if( $svc.Status -ne 'Stopped' )
{
    # This assumes the process name is strongbad
    Stop-Process StrongBad
}
Community
  • 1
  • 1
Aaron Jensen
  • 25,861
  • 15
  • 82
  • 91
0

It's really a two part question. The first part is how can I write a service that will not shutdown immediately so I can test my more robust stop-service.

The answer to that half of the question is that I need to set a WaitHint in the service when stopping:

        serviceStatus.dwCurrentState = ServiceState.SERVICE_STOP_PENDING;
        serviceStatus.dwWaitHint = 100000;
        SetServiceStatus(this.ServiceHandle, ref serviceStatus);

The second half of the question how do I make stop-service more robust is what @Aaron said but I generalized it more as:

$sb = [scriptblock]::Create("Stop-Service $ServiceName")
$jobid = Start-Job $sb  | Wait-Job -Timeout $Timeout
Arluin
  • 594
  • 1
  • 8
  • 21