Score:2

PS Stop-Process fails to stop a subprocess launched from cmd.exe

xk flag

Preface: I've boiled down a problem I'm having to this simple reproduction, which admittedly looks pretty strange out of context.

From powershell (PS), if I use Start-Process to start notepad and capture the process ID, I can kill it with Stop-Process, no problem:

PS > $x = Start-Process notepad.exe -PassThru
...
PS > Stop-Process $x.id

I can do the same with cmd.exe, again without problem:

PS > $x = Start-Process cmd.exe -PassThru
...
PS > Stop-Process $x.id

Looking at TaskManager, this actually launches two processes: cmd.exe and conhost.exe. The PID returned from Start-Process belongs to cmd.exe, and killing it via Stop-Process terminates both.

However if I start a long-running sub-process like ping -t 127.0.0.1 within the console, stopping with Stop-Process kills cmd.exe, conhost.exe, but leaves the window with ping.exe running, as if nothing was killed.

If instead I use taskkill /PID <process-id> or terminate the process from TaskManager, all three processes (cmd, conhost, and ping) are terminated as expected.

Question

Why doesn't Stop-Process <pid> terminate the process in the same way as taskkill /PID <pid>? Is there any way to get Stop-Process to terminate cmd.exe and the long-running ping subprocess?

Repro

Start cmd.exe from powershell and note the PID.

PS > $x = Start-Process cmd.exe -PassThru
PS > $x.id
23652

From the command prompt, start a long-running subprocess like ping:

> ping -t 127.0.0.1

Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
...

Open Task Manager and note the processes created in the same tree as ping.exe. For me these are:

Windows Command Processor 
   23652 cmd.exe 
   25260 conhost.exe
   22140 PING.EXE

Attempt to terminate via the process id returned from Start-Process:

PS > Stop-Process 23652

At this point, cmd.exe and conhost.exe are terminated, but TaskManager still shows ping running as a top-level process.

TCP/IP Ping Command   PING.EXE  22140

and the command prompt window remains, with the title C:\Windows\system32\cmd.exe - ping -t 127.0.0.1.

Type CTRL+C from the "command prompt". PING will stop, and the window will disappear.

cod3monk3y avatar
xk flag
Maybe related. Seems to indicate `-Force` switch should send SIGKILL, but adding this switch doesn't change the observed behavior - https://github.com/PowerShell/PowerShell/issues/13664
cod3monk3y avatar
xk flag
[MS taskkill reference](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/taskkill)
Score:2
lk flag

First of all, thank you, your description above put me into the right direction for solving my problem.

So I dug into your question:

Why doesn't Stop-Process terminate the process in the same way as taskkill /PID ?

I'm not sure, I can't find any documentation on it, but considering my testing it simply does not stop any child processed that are still running, and in your testing a child process in created for ping.exe which is obviously still running.

Is there any way to get Stop-Process to terminate cmd.exe and the long-running ping subprocess?

Yes, but not in one go. In your test setup, running the following command would show you all child processes:

Get-WmiObject -Class Win32_Process -Filter "ParentProcessId ='$($x.id)'" | Select-Object ParentProcessId,ProcessId,CommandLine

Using Stop-Process with the output from ProcessId would kill all the child process and as killing the conhost process would also kill the cmd process this would do it.

The command below would do it all in one go:

Get-WmiObject -Class Win32_Process -Filter "ParentProcessId ='$($x.id)'" | Select-Object ParentProcessId,ProcessId,CommandLine | ForEach-Object {Stop-process $_.processId}

Just as: taskkill /pid $x.id /t /f

cod3monk3y avatar
xk flag
Thanks so much for digging in. Your solution worked for me in my repro example, and I think the approach of iterating over child processes will work for my original use case as well (launching detached processes from python).
GetShifting avatar
lk flag
You're welcome, glad I could help!
cod3monk3y avatar
xk flag
I found a related solution on SO which uses a [recursive function to stop the entire process tree](https://stackoverflow.com/a/55942155/1174169), which should kill grand-child processes as well.
cod3monk3y avatar
xk flag
Also related: [killing all processes whose parent process no longer exists](https://stackoverflow.com/a/18991520/1174169). However, the solution is non-recursive and would terminate *all* process without a parent, including ones you didn't start yourself.
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.