user4350786
user4350786

Reputation:

How to Correctly Check if a Process is running and Stop it

What is the correct way of determining if a process is running, for example FireFox, and stopping it?

I did some looking around and the best way I found was this:

if((get-process "firefox" -ea SilentlyContinue) -eq $Null){ 
        echo "Not Running" 
}

else{ 
    echo "Running"
    Stop-Process -processname "firefox"
 }

Is this the ideal way of doing it? If not, what the correct way of doing so?

Upvotes: 100

Views: 262630

Answers (6)

Krombir
Krombir

Reputation: 363

The accepted answer is a bit outdated in terms of powershell syntax. Current version:

# get Firefox process
$firefox = Get-Process firefox -ErrorAction SilentlyContinue
if ($firefox) {
  # try gracefully first
  $firefox.CloseMainWindow()
  # kill after five seconds
  Start-Sleep -Seconds 5
  if (!$firefox.HasExited) {
    $firefox | Stop-Process -Force
  }
}
Remove-Variable firefox

Upvotes: 0

Joey
Joey

Reputation: 354834

The way you're doing it you're querying for the process twice. Also Lynn raises a good point about being nice first. I'd probably try something like the following:

# get Firefox process
$firefox = Get-Process firefox
if ($firefox) {
  # try gracefully first
  $firefox.CloseMainThread()
  # kill after five seconds
  Sleep 5
  if (!$firefox.started) {
    $firefox | Stop-Process -Force
  }
}
Remove-Variable firefox

Upvotes: 165

Timo
Timo

Reputation: 3227

To start with process-killing, here python, my 2 cents:

Get-Process python3.9|Stop-Process

Upvotes: 2

Kit
Kit

Reputation: 61

@jmp242 - the generic System.Object type does not contain the CloseMainWindow method, but statically casting the System.Diagnostics.Process type when collecting the ProcessList variable works for me. Updated code (from this answer) with this casting (and looping changed to use ForEach-Object) is below.

function Stop-Processes {
    param(
        [parameter(Mandatory=$true)] $processName,
                                     $timeout = 5
    )
    [System.Diagnostics.Process[]]$processList = Get-Process $processName -ErrorAction SilentlyContinue

    ForEach ($Process in $processList) {
        # Try gracefully first
        $Process.CloseMainWindow() | Out-Null
    }

    # Check the 'HasExited' property for each process
    for ($i = 0 ; $i -le $timeout; $i++) {
        $AllHaveExited = $True
        $processList | ForEach-Object {
            If (-NOT $_.HasExited) {
                $AllHaveExited = $False
            }                    
        }
        If ($AllHaveExited -eq $true){
            Return
        }
        Start-Sleep 1
    }
    # If graceful close has failed, loop through 'Stop-Process'
    $processList | ForEach-Object {
        If (Get-Process -ID $_.ID -ErrorAction SilentlyContinue) {
            Stop-Process -Id $_.ID -Force -Verbose
        }
    }
}

Upvotes: 5

smo
smo

Reputation: 41

Thanks @Joey. It's what I am looking for.

I just bring some improvements:

  • to take into account multiple processes
  • to avoid reaching the timeout when all processes have terminated
  • to package the whole in a function

function Stop-Processes {
    param(
        [parameter(Mandatory=$true)] $processName,
                                     $timeout = 5
    )
    $processList = Get-Process $processName -ErrorAction SilentlyContinue
    if ($processList) {
        # Try gracefully first
        $processList.CloseMainWindow() | Out-Null

        # Wait until all processes have terminated or until timeout
        for ($i = 0 ; $i -le $timeout; $i ++){
            $AllHaveExited = $True
            $processList | % {
                $process = $_
                If (!$process.HasExited){
                    $AllHaveExited = $False
                }                    
            }
            If ($AllHaveExited){
                Return
            }
            sleep 1
        }
        # Else: kill
        $processList | Stop-Process -Force        
    }
}

Upvotes: 4

AdamL
AdamL

Reputation: 13191

If you don't need to display exact result "running" / "not runnuning", you could simply:

ps notepad -ErrorAction SilentlyContinue | kill -PassThru

If the process was not running, you'll get no results. If it was running, you'll receive get-process output, and the process will be stopped.

Upvotes: 24

Related Questions