Команда tasklist с описанием
Я пытаюсь выяснить tasklist
команда, которая дает Description
а также, как показано в пользовательском интерфейсе Taskmangaer? Я пытаюсь запустить его из Python, если это невозможно, есть ли эквивалентная команда Python, чтобы получить список всех задач с описанием?
tasklist /?
1 ответ
Это немного сложнее, чем вы можете себе представить, и вам действительно нужна веская причина, чтобы пройти через все неприятности, чтобы оправдать это. Во-первых, пользовательский интерфейс диспетчера задач не получает информацию от tasklist.exe
, хотя вы можете быть довольно близко с:
import csv
import subprocess
try:
tl_out = subprocess.check_output(["tasklist", "/fo", "csv", "/v"])
except subprocess.CalledProcessError as e:
print("Call to `tasklist` failed: {}".format(e))
exit(1)
tl_csv = csv.DictReader(tl_out.splitlines())
for row in tl_csv:
print(row) # prints a dict for each task with all available fields
# Available fields (may vary from platform to platform) are:
# 'Status', 'CPU Time', 'Image Name', 'Session Name', 'Window Title',
# 'PID', 'User Name', 'Session#', 'Mem Usage'
Тем не менее, чтобы добраться до Description
поле (и многие другие из пользовательского интерфейса диспетчера задач) вам придется по крайней мере получить данные из WMI. Усугублять проблему, WMIC
в Windows 7 есть ошибка при экспорте в CSV, что делает все это еще более сложным, так как для максимальной переносимости нам нужно использовать list
отформатировать и разобрать его самим:
import subprocess
try:
wmi_out = subprocess.check_output(["wmic", "process", "list", "full", "/format:list"])
except subprocess.CalledProcessError as e:
print("Call to `wmic` failed: {}".format(e))
exit(1)
# parse the WMI list:
wmi_entries = []
for task in wmi_out.strip().split("\r\r\n\r\r\n"):
wmi_entries.append(dict(e.split("=", 1) for e in task.strip().split("\r\r\n")))
for row in wmi_entries:
print(row) # prints a dict for each task with all available fields
# Available fields (may vary from platform to platform) are:
# 'CSName', 'CommandLine', 'Description', 'ExecutablePath', 'ExecutionState', 'Handle',
# 'HandleCount', 'InstallDate', 'KernelModeTime', 'MaximumWorkingSetSize',
# 'MinimumWorkingSetSize', 'Name', 'OSName', 'OtherOperationCount', 'OtherTransferCount',
# 'PageFaults', 'PageFileUsage', 'ParentProcessId', 'PeakPageFileUsage',
# 'PeakVirtualSize', 'PeakWorkingSetSize', 'Priority', 'PrivatePageCount', 'ProcessId',
# 'QuotaNonPagedPoolUsage', 'QuotaPagedPoolUsage', 'QuotaPeakNonPagedPoolUsage',
# 'QuotaPeakPagedPoolUsage', 'ReadOperationCount', 'ReadTransferCount', 'SessionId',
# 'Status', 'TerminationDate', 'ThreadCount', 'UserModeTime', 'VirtualSize',
# 'WindowsVersion', 'WorkingSetSize', 'WriteOperationCount', 'WriteTransferCount'
Если вам не нужны все эти поля, вы всегда можете ограничить wmic
чтобы получить поля, которые вы хотите (т.е. wmi_out = subprocess.check_output(["wmic", "process", "get", "ProcessId,ExecutablePath,Description", "/format:list"])
получить только Description
в ProcessId
).
Но не думайте, что ваши проблемы закончились - мы только начали. Пока у нас есть Description
поле (и несколько других для загрузки), вы заметите, что для процессов, которые не объявляют свое описание (большинство из них, программисты Windows, видимо, ленивы) или служб без описания - значение description просто содержит имя исполняемого файла, т.е. если вы работаете с простым старым блокнотом, а пользовательский интерфейс диспетчера задач покажет вам Notepad
как описание, его словарная запись будет иметь notepad.exe
- это потому, что пользовательский интерфейс диспетчера задач использует совершенно другой подход к списку задач и получает описание непосредственно из исполняемого файла процесса.
Таким образом, вам на самом деле нужен дополнительный шаг для извлечения описания исполняемого файла непосредственно из его таблицы ресурсов, что, вероятно, является "самым простым", если вызвать Win32 API для доступа к описанию, поэтому сначала нужно установить модуль pyWin32:
import subprocess
import win32api
# gets executable description via W32API
def get_executable_desc(path, default=''):
try:
language, codepage = win32api.GetFileVersionInfo(path, "\\VarFileInfo\\Translation")[0]
return win32api.GetFileVersionInfo(path, "\\StringFileInfo\\{:04x}{:04x}\\FileDescription".format(language, codepage)) or default
except:
return default
try:
wmi_out = subprocess.check_output(["wmic", "process", "list", "full", "/format:list"])
except subprocess.CalledProcessError as e:
print("Call to `tasklist` failed: {}".format(e))
exit(1)
# parse the WMI list:
wmi_entries = []
for task in wmi_out.strip().split("\r\r\n\r\r\n"):
entry = dict(e.split("=", 1) for e in task.strip().split("\r\r\n"))
entry['Description'] = get_executable_desc(entry.get("ExecutablePath", None), entry.get("Description", None))
wmi_entries.append(entry)
for row in wmi_entries:
print(row) # prints a dict for each task with all available fields
Вуаля! Описания теперь заполняются (где это возможно, или, по крайней мере, содержат имя исполняемого файла), но, поскольку нам пришлось использовать Win32 API, чтобы получить описания, мы могли бы также получить список задач через него - это быстрее и более кратко:
from win32api import GetFileVersionInfo, OpenProcess
from win32con import PROCESS_QUERY_INFORMATION, PROCESS_VM_READ
from win32process import EnumProcesses, EnumProcessModules, GetModuleFileNameEx
import pywintypes
# gets executable description via W32API
def get_executable_desc(path, default=''):
try:
language, codepage = GetFileVersionInfo(path, "\\VarFileInfo\\Translation")[0]
return GetFileVersionInfo(path, "\\StringFileInfo\\{:04x}{:04x}\\FileDescription".format(language, codepage)) or default
except:
return default
# gets the process list via W32API
def get_process_list():
proc_list = []
processes = EnumProcesses()
if not processes:
return [] # optionally raise an exception, no ProcessIds could be obtained
for proc in processes:
try:
handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, pywintypes.FALSE, proc)
modules = EnumProcessModules(handle)
if not modules:
continue # task died in the meantime?
path = GetModuleFileNameEx(handle, modules[0])
proc_list.append({"ProcessId": proc, "ExecutablePath": path, "Description": get_executable_desc(path, path)})
except pywintypes.error as e:
continue # optionally report the error stored in `e`
return proc_list
tasks = get_process_list()
for row in tasks:
print(row) # prints a dict for each task with ProcessId, ExecutablePath and Description fields
Это только получит ProcessId, ExecutablePath и Description, но вы можете дополнительно изучить Win32 API, если вам нужно больше полей.
Опять же, я не понимаю, какой ценности Description
Поле состоит в том, чтобы пройти через все эти неприятности, но если вы действительно, действительно хотите этого - вот как это получить.