Arbelac
Arbelac

Reputation: 1904

How to force stops one or more services that is in a state of 'stop pending'

I want to stop a Windows service and it's hung or stuck with a status of Stopping. We are using mixed operating systems such as Windows 2008/2012R2.

$ServerList = 'C:\Powershell\SCXAgentDSC\list.txt'  
$SCXAgents = Get-Content -Path $ServerList  

foreach ($scxagent in $SCXAgents) {
  $Hostname = $scxagent
  Write-Host $Hostname
  #Ping host
  $IP = (Test-Connection $hostname -Count 1 -ErrorAction SilentlyContinue |
        Select-Object -ExpandProperty ProtocolAddress)
  if ($IP -eq $null) {
    continue
  }
  #Get state of service 
  $servicestate = Get-Service -ComputerName $Hostname service_name -ErrorAction SilentlyContinue
  #If service is stopped or does not exist, continue otherwise set to stopped and disabled
  if ($servicestate.status -eq 'Stopped' -or $servicestate.status -eq $null) {
    continue
  } else {
    (Get-Service -ComputerName $Hostname service_name).Stop()
    Set-Service -ComputerName $Hostname -Name service_name -StartupType Disabled
    Write-Host "stopped services" -BackgroundColor yellow
    $RPMLines = Get-Service -ComputerName $Hostname service_name

    if ($RPMLines.status -match "Stopped") {
      $ServiceStatus = "STOPPED"
    } else {
      $ServiceStatus = "RUNNING"
    }
    # Port testing (22 and 1270)
    try {
      if ((New-Object System.Net.Sockets.TcpClient("$scxagent", "1270")).Connected -eq $true) {
        $AgentPortStatus = "OK"
      } else {
        $AgentPortStatus = "NOT OK"
      }
    } catch {
      $AgentPortStatus = "NOT OK"
    }
    try {
      if ((New-Object System.Net.Sockets.TcpClient("$scxagent", "22")).Connected) {
        $sshstatus = "OK"
      } else {
        $sshstatus = "NOT OK"
      }
    } catch {
      $sshstatus = "NOT OK"
    }

    Write-Output "$scxagent | SSH : $sshstatus | AgentPort : $AgentPortStatus | AgentServStatus : $ServiceStatus"
  }
}

Also, Above my code I'd like to have output formatted into the one line, am I correct? e.g.:

scxagent       sshstatus     AgentPortStatus    AgentServStatus
Server1        OK            OK                 STOPPED
Server2        NOT OK        NOT OK             RUNNING
etc.

Last Update:

if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) {
  $arguments = "& '" + $myinvocation.mycommand.definition + "'"
  Start-Process powershell -Verb runAs -ArgumentList $arguments
  break
}

$ServerList = 'C:\Powershell\SCXAgentDSC\list.txt'  
$SCXAgents = Get-Content -Path $ServerList  

foreach ($scxagent in $SCXAgents) {
  $Hostname = $scxagent
  Write-Host $Hostname
  #Ping host
  $IP = (Test-Connection $hostname -Count 1 -ErrorAction SilentlyContinue |
        Select-Object -ExpandProperty ProtocolAddress)
  if ($IP -eq $null) {
    continue
  }
  #Get state of service 
  $servicestate = Get-Service -ComputerName $Hostname service_name -ErrorAction SilentlyContinue
  #If service is stopped or does not exist, continue otherwise set to stopped and disabled
  if ($servicestate.Status -eq 'Stopped' -or $servicestate.Status -eq $null) {
    continue
  } else {
    $pid = Get-WmiObject -Computer $hostname -Class Win32_Service -Filter "Name='service_name'" |
           Select-Object -Expand ProcessID

    (Get-Process -Computer $hostname -PID $pid).Kill()

    (Get-Service -ComputerName $Hostname service_name).Stop()
    Set-Service -ComputerName $Hostname -Name service_name -StartupType Disabled
    Write-Host "stopped services" -BackgroundColor yellow

    $RPMLines = Get-Service -ComputerName $Hostname service_name

    if ($RPMLines.Status -match "Stopped") {
      $ServiceStatus = "stop"
    } else {
      $ServiceStatus = "start"
    }
    # Port testing (22 and 1270)
    try {
      if ((New-Object System.Net.Sockets.TcpClient("$scxagent", "1270")).Connected -eq $true ) {
        $AgentPortStatus = "OK"
      } else {
        $AgentPortStatus = "NOT OK"
      }
    } catch {
      $AgentPortStatus = "NOT OK"
    }
    try {
      if ((New-Object System.Net.Sockets.TcpClient("$scxagent", "22")).Connected) {
        $sshstatus = "OK"
      } else {
        $sshstatus = "NOT OK"
      }
    } catch {
      $sshstatus = "NOT OK"
    }

    Write-Output "$scxagent | SSH : $sshstatus | AgentPort : $AgentPortStatus | AgentServStatus : $ServiceStatus"

    Read-Host -Prompt "Press Enter to continue"
  }
}

Error Message:

ERROR: Cannot overwrite variable PID because it is read-only or constant.
getservice.ps1 (32): ERROR: At Line: 32 char: 3
ERROR: +         $pid = Get-WmiObject -Computer $hostname -Class Win32_Service -Filter "Name='A ...
ERROR: +    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ERROR:     + CategoryInfo          : WriteError: (PID:String) [], SessionStateUnauthorizedAccessException
ERROR:     + FullyQualifiedErrorId : VariableNotWritable

Upvotes: 1

Views: 3250

Answers (1)

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200293

If a service hangs after receiving a stop request the only way to "force-stop" it is killing the process, as @autsvet already mentioned. Use the PID to identify the process:

$processID = Get-WmiObject -Computer $hostname -Class Win32_Service -Filter "Name='service_name'" |
             Select-Object -Expand ProcessID

(Get-Process -Computer $hostname -PID $processID).Kill()

Note that some services are configured to not allow tampering with their process. In such cases you could try to change the process settings. If that doesn't work (or you can't do it for some reason) you'll have to resort to rebooting the system.

Upvotes: 2

Related Questions