PS Stop-Process 无法停止从 cmd.exe 启动的子进程

PS Stop-Process 无法停止从 cmd.exe 启动的子进程

前言:我把我遇到的一个问题归结为这个简单的复制,不可否认,从上下文来看,它看起来很奇怪。

从 powershell (PS),如果我使用Start-Process启动记事本并捕获进程 ID,我可以使用 终止它Stop-Process,没问题:

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

我可以用 做同样的事情cmd.exe,同样没有问题:

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

查看 TaskManager,这实际上启动了两个进程:cmd.exe 和控制台程序。返回的 PIDStart-Process属于 cmd.exe,通过 杀死它Stop-Process会终止两者。

然而ping -t 127.0.0.1如果我在控制台中启动一个长时间运行的子进程,则使用Stop-Processkills cmd.exe、conhost.exe 来停止,但是窗口上仍保留着 ping.exe 的运行,好像什么都没有被终止一样。

如果我使用taskkill /PID <process-id>或终止 TaskManager 中的进程,则所有三个进程(cmd、conhost 和 ping)都会按预期终止。

问题

为什么不Stop-Process <pid>以同样的方式终止进程taskkill /PID <pid>? 有什么方法可以Stop-Process终止cmd.exe长时间运行的ping子进程吗?

复制

从 powershell 启动 cmd.exe 并记下 PID。

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

从命令提示符下,启动一个长时间运行的子进程,如 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
...

打开任务管理器并注意与 ping.exe 在同一树中创建的进程。对我来说,这些是:

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

尝试通过返回的进程 ID 来终止Start-Process

PS > Stop-Process 23652

此时,cmd.exe和conhost.exe已终止,但TaskManager仍显示ping作为顶级进程正在运行。

TCP/IP Ping Command   PING.EXE  22140

且命令提示符窗口仍然存在,其标题为C:\Windows\system32\cmd.exe - ping -t 127.0.0.1

在“命令提示符”中键入 CTRL+C。PING 将停止,并且窗口将消失。

答案1

首先,谢谢您,您的上述描述为我解决问题提供了正确的方向。

所以我深入研究了你的问题:

为什么 Stop-Process 不能以与 taskkill /PID 相同的方式终止进程?

我不确定,我找不到任何相关文档,但考虑到我的测试,它根本就不会停止任何仍在运行的子进程,并且在您的测试中,为 ping.exe 创建的子进程显然仍在运行。

有什么方法可以让 Stop-Process 终止 cmd.exe 和长时间运行的 ping 子进程?

是的,但不是一次性完成的。在测试设置中,运行以下命令将显示所有子进程:

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

使用 Stop-Process 和 ProcessId 的输出将会杀死所有子进程,并且由于杀死 conhost 进程也会杀死 cmd 进程,因此这将执行此操作。

下面的命令可以一次性完成所有操作:

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

就像: taskkill /pid $x.id /t /f

相关内容