7

Lets say I run a couple of processes from PowerShell:

$p1 = $(Start-Process -PassThru ./example.exe)
$p2 = $(Start-Process -PassThru ./example.exe)

example.exe is going to spawn a few child processes with the same name.

How do I kill just $p1 and its child processes, without killing $p2 and its child processes?

Just running Stop-Process $p1 only kills the parent process $p1, leaving it's children running.

All of the answers I seen so far involve killing all of the processes with a certain name, but that will not work here.

wheeler
  • 2,823
  • 3
  • 27
  • 43

5 Answers5

18

So I couldn't really find a good way to do this, so I wrote a helper function that uses recursion to walk down the process tree:

function Kill-Tree {
    Param([int]$ppid)
    Get-CimInstance Win32_Process | Where-Object { $_.ParentProcessId -eq $ppid } | ForEach-Object { Kill-Tree $_.ProcessId }
    Stop-Process -Id $ppid
}

To use it, put it somewhere in your PowerShell script, and then just call it like so:

Kill-Tree <process_id>
wheeler
  • 2,823
  • 3
  • 27
  • 43
0

If anyone landing here is looking for script to kill a process tree by specifying the name of the parent process, you can use @wheeler's Kill-Tree recursive function like so.

Note: By default, I find myself having to constantly kill eclipse and its child java process. So 'eclipse' is the default name of the process tree killed by this script, killProcTree.ps1, if a parent process name is not provided via the $procName call parameter:

Powershell script called 'killProcTree.ps1':

 
param(
    [string]$procName    = 'eclipse'
)

function Kill-Tree {
    Param([int]$ppid)
    echo "Kill-Tree: killing $ppid ..."
    Get-CimInstance Win32_Process | Where-Object { $_.ParentProcessId -eq $ppid } | ForEach-Object { Kill-Tree $_.ProcessId }
    Stop-Process -Id $ppid
}

[int]$mypid = 0
[string]$myProcessToKill = (Get-Process -Name $procName -ErrorAction 0)

if ($myProcessToKill -eq "") {
    echo "$procName is not running."
} else {
    $mypid = (Get-Process -Name $procName -ErrorAction 0).Id
    echo "The $procName PID is: $mypid"
    if ($mypid -gt 1) {
        echo "Killing $procName and its children..."
        Kill-Tree $mypid
    }
}
echo "Done!"
Darrin
  • 317
  • 1
  • 4
  • 10
  • This code snippet returns an error at line 18 : `Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Int32".` – Benoît Dubreuil Feb 06 '21 at 23:56
  • Perhaps a difference in versions. Runs great for me, I suppose if you have on some kind of "strict" settings (other than default settings) with regard to type casting and such, that could be a reason that you need to cast the "Id" returned to an [int] type to avoid the type conversion error. – Darrin Feb 08 '21 at 14:37
  • Quite a bit late, but I'm guessing that Benoit was searching for a process name that had multiple results (ever use Chrome? try `get-process 'chrome'`, it's kind of gross). A solution would be to do a `ForEach($mypid in $myProcessToKill){Kill-Tree $mypid}` – TheMadTechnician Aug 04 '21 at 23:40
  • Just FYI, all of what you wrote below the function can also be written like this: `Get-Process -Name $procName -ErrorAction SilentlyContinue | %{Kill-Tree $_.Id}` – Mike Anthony May 09 '22 at 08:41
-2

Start-Process with -Passthru returns a System.Diagnostics.Process object. This object has an Id property which is generated by Windows and is unique.

Stop-Process has multiple signatures One looks for the process by Id, one by Name, and one looks for it by the Process object.

You are using -Passthru and capturing the output of start-process into $p1, so you can just pass that object to Stop-Process.

Stop-Process $p1
StephenP
  • 3,895
  • 18
  • 18
-2

I know that this answer comes late... But a simpler way (works with PowerShell 5.1+) to achieve this is:

Get-Process -Name "Process Name" | Select-Object -Property Id | ForEach-Object -Process { Stop-Process -Id $_.Id -Force }
  • 1
    Doesn't answer the question, because the child processes are not killed. Moreover, all "process name" are killed and the OP doesn't want that. – AMissico Jan 23 '23 at 22:07
-2

Hi I'm noob and I don't know if that's what you mean but I figured out that if I want to kill a process that is visible in task manager I can do it like that: (name of the process provided in -> "name of the process" below. I pref live examples so I will present it that way)

Get-Process -Name "Battle.net" | kill

It kills all process ID's related to that process which contain the name "Battle.net"