113 lines
4.4 KiB
PowerShell
113 lines
4.4 KiB
PowerShell
|
function Stop-AlkamiService {
|
||
|
<#
|
||
|
.SYNOPSIS
|
||
|
Attempts to stop a service and kills the process if it doesn't complete shutdown within a configurable limit
|
||
|
|
||
|
.PARAMETER ServiceName
|
||
|
Name of the service to stop
|
||
|
|
||
|
.PARAMETER ServiceTimeoutSeconds
|
||
|
Number of seconds to wait for the service to stop
|
||
|
#>
|
||
|
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
|
||
|
[OutputType([System.Boolean])]
|
||
|
Param(
|
||
|
[Parameter(Mandatory = $true)]
|
||
|
[Alias("sName")]
|
||
|
[string]$ServiceName,
|
||
|
|
||
|
[Parameter(Mandatory = $false)]
|
||
|
[Alias("Seconds")]
|
||
|
[int]$ServiceTimeoutSeconds = 15
|
||
|
)
|
||
|
|
||
|
$logLead = (Get-LogLeadName)
|
||
|
$serviceTimeout = [System.TimeSpan]::FromSeconds($ServiceTimeoutSeconds)
|
||
|
try {
|
||
|
$service = Get-Service -Name $ServiceName | Select-Object -First 1
|
||
|
} catch {
|
||
|
Write-Warning "$logLead : $_"
|
||
|
}
|
||
|
|
||
|
if ($null -eq $service -or $service.Status -eq [ServiceProcess.ServiceControllerStatus]::Stopped) {
|
||
|
Write-Host ("$logLead : Service {0} not found or was already stopped" -f $ServiceName)
|
||
|
return $true
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
$processes = @(Get-ProcessFromService $service)
|
||
|
if ($processes.Count -eq 0) {
|
||
|
Write-Host "$logLead : No running processes found for $($service.Name)"
|
||
|
return $true
|
||
|
}
|
||
|
|
||
|
$process = ($processes | Select-Object -First 1)
|
||
|
Write-Host "$logLead : Stopping PID: $($process.Id) for [$($process.ProcessName)] at [$($process.path)]"
|
||
|
|
||
|
# Warn about having too many processes
|
||
|
$otherProcesses = ($processes | Select-Object -Skip 1)
|
||
|
if ($otherProcesses.Count -gt 0) {
|
||
|
Write-Warning "$logLead : Found multiple processes for this service information. Please investigate."
|
||
|
Write-Host "$logLead : Only processing for the first process returned in the list"
|
||
|
foreach ($extraProcess in $otherProcesses) {
|
||
|
Write-Warning "$logLead : NOT STOPPING: PID: $($process.Id) for [$($process.ProcessName)] at [$($process.path)]"
|
||
|
}
|
||
|
}
|
||
|
} catch {
|
||
|
Write-Warning ("$logLead : {0}" -f ($Error[0] | Format-List -Force))
|
||
|
}
|
||
|
|
||
|
$service.Refresh()
|
||
|
if ($PSCmdlet.ShouldProcess($ServiceName, "Stopping Service")) {
|
||
|
if ($service.Status -ne "StopPending" -and $service.CanStop -eq $true) {
|
||
|
try {
|
||
|
Invoke-SCExe @("stop", $serviceName)
|
||
|
} catch {
|
||
|
Write-Warning ("$logLead : {0}" -f ($Error[0] | Format-List -Force))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
if ($PSCmdlet.ShouldProcess($ServiceName, "Wait for Service Stop")) {
|
||
|
$service.WaitForStatus([ServiceProcess.ServiceControllerStatus]::Stopped, $serviceTimeout)
|
||
|
$waitInterval = 0
|
||
|
|
||
|
do {
|
||
|
Start-Sleep -Seconds 1
|
||
|
$waitInterval++
|
||
|
} while ($null -ne (Get-Process -Id $process.Id -ErrorAction SilentlyContinue) -and ($waitInterval -lt $serviceTimeout.Seconds))
|
||
|
|
||
|
|
||
|
# If the timeout expires, the catch block will handle killing the service
|
||
|
# If the service stops gracefully but the process doesn't quit, we'll kill it here
|
||
|
if ($null -ne (Get-Process -Id $process.Id -ErrorAction SilentlyContinue)) {
|
||
|
try {
|
||
|
Write-Warning ("$logLead : Old process still running after timeout. Killing process with ID {0}" -f $process.Id)
|
||
|
Stop-ProcessIfFound $process.Name
|
||
|
} catch {
|
||
|
# Do nothing, the process terminated before we could kill it
|
||
|
Write-Host "$logLead : The process terminated before we could kill it."
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
catch [ServiceProcess.TimeoutException] {
|
||
|
if ($null -ne $process.Id -or $process.Count -gt 0) {
|
||
|
Write-Warning ("$logLead : Timeout stopping service {0} after {1} seconds. The process will be killed." -f $ServiceName, $serviceTimeout.Seconds)
|
||
|
Stop-ProcessIfFound $process.Name
|
||
|
} else {
|
||
|
Write-Warning ("$logLead : The process ID could not be determined before shutdown.")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Check one more time if the service is stopped.
|
||
|
#$service = Get-Service -Name $ServiceName | Select-Object -First 1
|
||
|
$service.Refresh()
|
||
|
$stopped = $service.Status -eq "Stopped"
|
||
|
if ($PSCmdlet.ShouldProcess($ServiceName, "Determining Return Value")) {
|
||
|
return $stopped
|
||
|
} else {
|
||
|
return $true
|
||
|
}
|
||
|
}
|