Команда 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 Поле состоит в том, чтобы пройти через все эти неприятности, но если вы действительно, действительно хотите этого - вот как это получить.

Другие вопросы по тегам