Я убиваю некоторые задачи в cmd, используя следующую команду:
taskkill /f /im software* /t
Он выполняет свою работу и убивает все задачи с этим IMAGENAME; но, глядя на то, что это дало мне, я увидел кое-что интересное. Смотри ниже:
SUCCESS: The process with PID 14712 (child process of PID 9068) has been terminated. SUCCESS: The process with PID 12184 (child process of PID 9068) has been terminated. SUCCESS: The process with PID 16344 (child process of PID 9068) has been terminated. SUCCESS: The process with PID 6816 (child process of PID 9068) has been terminated. SUCCESS: The process with PID 10656 (child process of PID 9068) has been terminated. SUCCESS: The process with PID 14912 (child process of PID 9068) has been terminated. SUCCESS: The process with PID 11908 (child process of PID 9068) has been terminated. SUCCESS: The process with PID 9068 (child process of PID 10060) has been terminated.
Итак, как и ожидалось, все процессы привязаны к одной централизованной задаче PID = 9068. Но тогда этот процесс также является дочерним процессом для PID = 10060, который является PID для explorer.exe. У этого задания нет GUI. Поэтому я удивлен, увидев, что это дочерний процесс explorer.
Итак, вот вопрос: какие процессы будут под explorer.exe в окна?
Вопрос: Если я хочу избежать уничтожения (с помощью taskkill) любого процесса, который является непосредственно дочерним процессом explorer.exe, как я могу подойти к этому?
Это то, что у меня есть до сих пор. Для начала нам нужно получить pid для explorer.exe:
TASKLIST /NH /FI "IMAGENAME eq explorer.exe"
Затем я думаю о написании функции, которая убивает pid, проверяет его родительский процесс, если родительский pid равен explorer.exe, он завершает процесс, если нет, то убивает процесс. Все это должно происходить в одной и той же функции, чтобы избежать работы с динамическими pid, упомянутыми в комментариях.
Я могу найти родительский процесс для каждого pid, используя следующее:
wmic process get processid,parentprocessid,executablepath|find "process id goes here")
Я благодарен за помощь в написании функции.
@ErykSun - Немного отступить. Просто избегайте закрытия прямых дочерних процессов explorer.exe. Я подумываю написать UDF, который принимает pid, проверяет, находится ли он под explorer.exe (используя это, чтобы найти родительский wmic process get processid,parentprocessid,executablepath|find "process id goes here"), затем if "pid of parent" = "pid of explorer.exe" завершает работу, а если нет, это убивает процесс. Я не знаю, как сделать это рекурсивным. так, например, в этом случае сам 9068 не будет закрыт, но его дочерние процессы будут. Не уверен, возможно ли это. это?
Должно ли это быть реализовано с помощью только пакетных сценариев (cmd.exe) и утилит командной строки, таких как wmic.exe, tasklist.exe. а taskkill.exe? Если нет, я бы предложил использовать Python или PowerShell. Я не поклонник PowerShell, но у него есть то преимущество, что он уже установлен в большинстве систем Windows.
Основная проблема с попыткой убить дерево процессов в Windows заключается в том, что ОС его не поддерживает. Идентификатор родительского процесса устанавливается при создании процесса, но он статичен, поэтому дочерние ветви в дереве могут быть осиротевшими, а PID завершенных процессов в дереве могут даже повторно использоваться новыми процессами. (Последнее можно проверить, проверив отметки времени создания. Идентификатор родительского процесса, который ссылается на процесс, который был создан после дочернего процесса, очевидно, не является настоящим родительским элементом.)
Вам нужен процесс оболочки для сеанса. Заменять проводник не принято, но при запуске процесс, который хочет запускаться в качестве оболочки рабочего стола для сеанса, регистрируется в диспетчере окон через SetShellWindowEx. В C / C++ вы можете получить его окно рабочего стола верхнего уровня через GetShellWindow. Затем получите его PID через GetWindowThreadProcessId. Оболочка может порождать несколько экземпляров самой себя, как это делает Explorer для файловых браузеров, поэтому вам нужно будет сохранить путь к ее образу из OpenProcess и QueryFullProcessImageNameW и проверить, является ли родитель оболочкой, сравнив пути к изображениям.
@ErykSun powershell и cmd в порядке.
не понимаю смысла вопроса, но формально сделать это очень легко. позвоните в NtQuerySystemInformation(SystemProcessInformation.. и проверьте SYSTEM_PROCESS_INFORMATION::InheritedFromUniqueProcessId перед тем, как решить убить процесс или нет
Но при перечислении процессов для поиска дочерних элементов цели необходимо проверить временную метку создания, чтобы подтвердить, что цель старше из-за повторного использования PID. Современная Windows пытается избежать повторного использования PID, но нет никаких гарантий. Просмотрите дерево, используя список записей (pid, timestamp), начиная с цели. Вставьте пластинку с конца. Откройте ручку. Проверьте отметку времени. Попробуйте завершить / прекратить процесс. Подождите на ручке и закройте ее. Если ожидание прошло успешно, сделайте снимок запущенных процессов. Добавить потомков цели в список, исключая слишком старые процессы. Повторение.





Родительский процесс не имеет ничего общего с тем, является ли дочерний процесс графическим, консольным или служебным приложением. Если Explorer является родительским, это означает только то, что Explorer вызвал CreateProcess или что другой процесс, названный CreateProcess или CreateProcessAsUser, заменил дескриптор для Explorer как дочерний PROC_THREAD_ATTRIBUTE_PARENT_PROCESS.
Например, если пользователь дважды щелкнет значок сценария .py в проводнике, оболочка найдет ассоциацию файлов (например, с использованием внутренней реализации интерфейса IQueryAssociations) и выполнит соответствующую программу со сценарием в качестве аргумента с помощью команды как "C:\Windows\py.exe" "path\to\script.py". Если он выполняется напрямую, Explorer вызывает CreateProcess с этой командной строкой в качестве аргумента. Если он «запускается от имени администратора», Explorer отправляет запрос в службу информации о приложении, которая создает процесс с повышенными правами через CreateProcessAsUser, при этом Explorer устанавливается в качестве родительского с помощью вышеупомянутого атрибута создания процесса.
Следующий сценарий .bat может помочь понять родительские / дочерние процессы и их поведение ...
@ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
echo "%~1%~2%~3" | findstr /I "\? /h \-h">NUL 2>&1
if %errorlevel% EQU 0 goto :usage
set "_explorerName=explorer.exe"
set "_NameToKill=%~1"
set "_Terminate=%~2"
set "_KillForce=%~3"
if NOT defined _NameToKill if not [%1]==[] (
rem debugging
set "_NameToKill=CMD.EXE"
rem debugging: start a child process
start "" /MIN notepad.exe
)
for /F "tokens=1,2 delims=," %%G in ('
TASKLIST /NH /FI "IMAGENAME eq %_explorerName%" /FO CSV
') do (
set "_explorerPID=%%~H"
)
ECHO checking '%_NameToKill%*' as child of %_explorerName% ^(PID=%_explorerPID%^)
for /F "skip=1 tokens=1-3" %%G in ('
wmic process WHERE "Name like '%_NameToKill%%%' and ParentProcessId=%_explorerPID%" get Name^,ParentProcessId^,ProcessId^,Status
') do (
if NOT "%%H"= = "" (
echo %%G
for /F "skip=1 tokens=1-3" %%g in ('
2^>NUL wmic process WHERE "ParentProcessId=%%I" get Name^,ParentProcessId^,ProcessId^,Status
') do (
if NOT "%%h"= = "" (
echo ProcessId=%%i, ParentProcessId=%%h, %%g child of %%G ^(%%I^)
if defined _Terminate (
if /I "%%~g"= = "conhost.exe" (
rem debugging
taskkill /PID %%i /T
) else (
taskkill /PID %%i %_Terminate% %_KillForce%
)
echo(
)
)
)
echo ParentProcessId=%%H, ProcessId=%%I, %%G child of %_explorerName% ^(%_explorerPID%^)
if defined _Terminate (
taskkill /PID %%I /T
echo(-
)
)
)
if [%1]==[] goto :usage
:endlocal
ENDLOCAL
goto :eof
:usage
echo USAGE:
echo %~nx0 -? ^| /? ^| /h ^| -h this help message
echo %~nx0 list all childs of %_explorerName%
echo %~nx0 ^<processName^> [/T] [/F] list all childs of a process
echo %~nx0 "" [/T] [/F] a particular test case for cmd.exe
echo(
echo Optional parameters /T and /F ^(or -T and -F^): see taskkill /?
goto :endlocal
К вашему сведению, у taskkill есть два способа закрыть процесс. С
/Fон пытается открыть дескриптор процесса с доступомPROCESS_TERMINATEи вызываетTerminateProcess. Без/Fон перечисляет окна процесса и отправляетWM_CLOSE, с которым процесс может справиться при своем нарушении. Для консольного приложения, если оно является владельцем консоли, taskkill отправляетWM_CLOSEв окно консоли, которое, в свою очередь, инструктирует сервер сеанса (csrss.exe) отправлятьCTRL_CLOSE_EVENTвсем процессам, подключенным к консоли. У них есть 5 секунд, чтобы изящно выйти, прежде чем они будут принудительно завершены.