Как получить ID собственного процесса из командной строки в Windows

Вопрос или проблема

Я пытаюсь найти способ получить собственный PID из командной строки (для последующего использования в bat-скриптах).

Пока единственный полезный способ, который я нашел, — использовать getpids.exe отсюда: http://www.scheibli.com/projects/getpids/index.html, но я ищу команду, которая встроена в Windows.

Мне нужен “надёжный” способ. Без каких-либо предположений о том, что мой процесс является единственным cmd.exe или что-то подобное.

Поскольку ни одно из других решений не является надежным и встроенным, я решил предложить следующее решение, но обратите внимание, что вам нужно как-то парсить/сохранять результаты:

title mycmd
tasklist /v /fo csv | findstr /i "mycmd"

Использование PowerShell + WMI:

powershell (Get-WmiObject Win32_Process -Filter ProcessId=$PID).ParentProcessId

Использование WMIC:

for /f %a in ('wmic os get LocalDateTime ^| findstr [0-9]') do set NOW=%a
wmic process where "Name="wmic.exe" and CreationDate > '%NOW%'" get ParentProcessId | findstr [0-9]

(как всегда, удвойте знак % с for в пакетных файлах)

Расширяя ответ Тони Рота:

title uniqueTitle
for /f "tokens=2 USEBACKQ" %f IN (`tasklist /NH /FI "WINDOWTITLE eq uniqueTitle*"`) Do echo %f

Использование фильтра WINDOWTITLE исключает необходимость в pipe, так что вы можете вставить это в цикл for и назначить его переменной с помощью SET, если хотите:

title uniqueTitle
for /f "tokens=2 USEBACKQ" %f IN (`tasklist /NH /FI "WINDOWTITLE eq uniqueTitle*"`) Do set ourPID=%f

Удаление /v делает процесс быстрее, а /NH убирает строку заголовка. Вам нужен шаблон после "uniqueTitle", потому что заголовок окна на самом деле содержит текущую команду (иначе это бы продолжалось и продолжалось, если попытаться полностью его сопоставить).

Я считаю, что следующий способ надёжен, при условии, что пользователь имеет доступ к WMIC и TEMP указывает на правильный путь, где у пользователя есть права на запись. Это конечный результат совместной работы на http://www.dostips.com/forum/viewtopic.php?f=3&t=6133.

@echo off

:getPID  [RtnVar]
::
:: Сохраняет ID процесса (PID) текущего выполняемого скрипта в переменной окружения RtnVar.
:: Если вызвано без аргументов, просто выводит PID на экран.
::
setlocal disableDelayedExpansion
:getLock
set "lock=%temp%\%~nx0.%time::=.%.lock"
set "uid=%lock:\=:b%"
set "uid=%uid:,=:c%"
set "uid=%uid:'=:q%"
set "uid=%uid:_=:u%"
setlocal enableDelayedExpansion
set "uid=!uid:%%=:p!"
endlocal & set "uid=%uid%"
2>nul ( 9>"%lock%" (
  for /f "skip=1" %%A in (
    'wmic process where "name="cmd.exe" and CommandLine like '%%<%uid%>%%'" get ParentProcessID'
  ) do for %%B in (%%A) do set "PID=%%B"
  (call )
))||goto :getLock
del "%lock%" 2>nul
endlocal & if "%~1" equ "" (echo(%PID%) else set "%~1=%PID%"
exit /b

Скрипт устанавливает эксклюзивный замок на временный файл, который включает текущее время в название. Коллизия может произойти только если два процесса с одинаковыми именами попытаются получить PID в тот же 0.01 секундный интервал времени, в этом случае только один из них будет успешным.

Любой процесс, который потерпит неудачу, будет повторено пробовать снова с новым путем замка, пока не добьется успеха.

Полный путь к файлу замка преобразуется в уникальный ID, который можно использовать в запросе WMIC. WMIC выполняется в команде FOR /F, то есть он выполняется в дочернем процессе cmd.exe, именно поэтому возвращается ParentProcessID процесса cmd.exe.

  1. Диспетчер задач Windows, нужно зайти в Вид -> Выбрать столбцы.. и выбрать PID.
  2. “tasklist /v” чтобы получить подробную информацию о задаче в командной строке.
  3. Process Explorer от live.sysinternals.com.

если вы знаете, что запущен только один cmd.exe, можно получить PID так:

for /F "tokens=1,2" %%i in ('tasklist /FI "IMAGENAME eq cmd.exe" /fo table /nh') do set pid=%%j

echo %pid%

Это должно сработать:

tasklist /v

Если вы хотите найти PID образа “notepad.exe”, следующий код вам подойдет:

for /F "tokens=1,2" %i in ('tasklist') do (
 if "%i" equ "notepad.exe" (set x=%j)
)
echo %x%

Если у вас есть комплект ресурсов Windows 2003, прогоните его через qgrep, чтобы получить только нужную строку. Затем можно извлечь PID отсюда (это предполагает, что у вас запущен только один cmd в данный момент времени),

tasklist /v | qgrep cmd

cmd.exe 2040 RDP-Tcp#447 0 1,804 K В работе MACHINE\Administrator  0:00:00 Командная строка

Посмотрите на этот маленький трюк с пакетом. Он устанавливает заголовок cmd в специальное значение, а затем использует tasklist, чтобы найти его. Изобретательно

\\Greg

ЭТО КОРОТКИЙ ПУТЬ ПОЛУЧЕНИЯ ИДЕНТИФИКАТОРА ПРОЦЕССА ДЛЯ ОТКРЫТОГО CMD

tasklist /v /fi "imagename EQ cmd.exe" /FO LIST | FIND "PID:"

Это решение даст вам ТОЛЬКО идентификатор процесса, и никакой лишней информации, которую включает верхний ответ.

title mycmd
tasklist /v /fo csv | findstr /i "mycmd" > PIDinfo.txt

set /p PIDinfo=<PIDinfo.txt
set PID1=%PIDinfo:~11,5%
set PID2=%PIDinfo:~11,4%

if %PID2% gtr 8100 (
    set PID=%PID2%
) else (
    set PID=%PID1%
)

echo %PID%

Объяснение:

-не существует PID для cmd.exe, превышающего 18100, поэтому проверяем, больше ли PID2 8100, чтобы узнать, четырёхзначный или пятизначный номер

случай 1: пятизначный PID, например, 17504 имеет значение PID1 17504 и значение PID2 1750, так что используем PID1

случай 2: четырёхзначный PID, например, 8205 имеет значение PID1 8205″ и значение PID2 8205, так что используем PID2

случай 3: четырёхзначный PID, например, 4352 имеет значение PID1 4352″ и значение PID2 4352, так что используем PID2

вы можете попробовать getcmdPid.bat — это самокомпилируемое .net приложение, встроенное в bat-скрипт, и возвращает PID в виде errorlevel:

call getcmdPid
echo %errorlevel%

Чтобы получить PID для текущего пользователя, смотрите мой пример для перезапуска процесса проводника:

@echo off
for /F "tokens=1,2" %%i in ('tasklist /FI "IMAGENAME eq explorer.exe" /FI "USERNAME eq %USERDOMAIN%\%USERNAME%" /FO table /NH') do taskkill /F /PID %%j
start explorer.exe

Из вышеперечисленного я использовал это для получения текущего идентификатора процесса в batch-файле: для /f %a in (‘powershell “$proc=Get-WmiObject Win32_Process -Filter ProcessId=$PID; $proc.ParentProcessId”‘) do set PID=%a

Я нашел самое простое решение в комментарии от Nicolas Melay:

for /F %%a in ('PowerShell -ex bypass "(gwmi Win32_Process -f ProcessID=$((gwmi Win32_Process -f ProcessId=$PID).ParentProcessID)).ParentProcessID"') do set my_pid=%%a

Он использует PowerShell, чтобы получить PID родительского процесса, так как for вводит дополнительный cmd.exe.

Это раньше работало, похоже, не работает в чистом Windows 11, в Windows 10 с обновлением да! Непонятно, почему это должно было измениться.

for /f %%A in (
‘2^>nul wmic process where “ParentProcessID=%myPID% and not CommandLine like ‘%%<%UID%>%%'” get ProcessID’
) do for %%B in (%%A) do if “!PIDs: %%B =!” equ “!PIDs!” set “PID=%%B”

Ответ или решение

Чтобы узнать идентификатор процесса (PID) собственного экземпляра командной строки в Windows, можно воспользоваться несколькими подходами, которые не требуют установки дополнительных инструментов и используют встроенные возможности операционной системы. В этом детальном руководстве я опишу несколько способов, которые помогут вам получить PID надежно и эффективно.

Использование команды tasklist

  1. Настройка уникального заголовка:

    • Сначала измените заголовок окна командной строки на уникальное имя. Это поможет вам легко обнаружить процесс.
      title MyUniqueCmdTitle
  2. Получение PID с помощью tasklist:

    • Используйте tasklist с фильтром на заголовок окна, чтобы отфильтровать нужный процесс и получить его PID.
      for /f "tokens=2 USEBACKQ" %%f in (`tasklist /NH /FI "WINDOWTITLE eq MyUniqueCmdTitle*"`) do set MyPID=%%f
      echo %MyPID%
    • Этот метод использует фильтр на заголовок, что исключает необходимость использования канала, упрощая интеграцию в скрипт.

Использование PowerShell

PowerShell предоставляет мощные возможности управления и может использоваться для извлечения информации о процессе.

  1. Запуск PowerShell из командной строки:
    for /F %%a in ('PowerShell -Command "(Get-WmiObject Win32_Process -Filter ProcessId=$PID).ParentProcessId"') do set MyPID=%%a
    echo %MyPID%
    • Эта команда запускает PowerShell, чтобы получить идентификатор родительского процесса текущего процесса командной строки, затем сохраняет его в переменной MyPID.

Использование WMIC (Windows Management Instrumentation Command)

WMIC — это мощный инструмент для управления системой Windows, который может использоваться для получения PID.

  1. Метод с WMIC:
    for /f %a in ('wmic process where "name='cmd.exe'" get processid ^| findstr [0-9]') do set MyPID=%a
    echo %MyPID%

Заключение

Как видно, существует несколько способов получения PID своего процесса командной строки в Windows, используя встроенные инструменты. Каждый метод имеет свои преимущества и может подходить в зависимости от конкретных требований и контекста использования. Например, использование PowerShell может быть предпочтительным благодаря его гибкости, в то время как методы с tasklist или WMIC легче интегрируются в стандартные командные сценарии.

При использовании этих методов важно учитывать права доступа и возможные ограничения в различных версиях Windows, чтобы обеспечить стабильную и корректную работу скрипта.

Оцените материал
Добавить комментарий

Капча загружается...