команда списка задач с описанием

Я пытаюсь выяснить команду tasklist, которая также дает Description, как показано в пользовательском интерфейсе Taskmangaer? Я пытаюсь запустить ее из python, если это невозможно, есть ли эквивалентная команда python для получения списка всех задач с описанием?

tasklist /?

person user3508811    schedule 16.05.2017    source источник
comment
О каких задачах вы говорите? Если это связано с ОС... какую ОС вы используете? На этот вопрос нельзя ответить так, как он есть сейчас...   -  person Riccardo Petraglia    schedule 24.05.2017
comment
@RiccardoPetraglia - я говорю о Windows7, 10 .... задачах, означающих все процессы, запущенные на этой машине.   -  person user3508811    schedule 24.05.2017
comment
Похоже, это важная деталь... ;)   -  person Riccardo Petraglia    schedule 26.05.2017


Ответы (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'

Обновление кода для Python3 (используйте кодировку для поиска по байтам):

s1 = "\r\r\n\r\r\n".encode()
s2 = "\r\r\n".encode()
for task in wmi_out.strip().split(s1):
   wmi_entries.append(dict(e.split("=".encode(), 1) for e in task.strip().split(s2)))

Если вам не нужны все эти поля, вы всегда можете ограничить wmic, чтобы получить нужные вам поля (например, wmi_out = subprocess.check_output(["wmic", "process", "get", "ProcessId,ExecutablePath,Description", "/format:list"]), чтобы получить только Description на ProcessId).

Но не думайте, что ваши проблемы закончились - мы только начали. Хотя теперь у нас есть поле Description (и несколько других для загрузки), вы заметите, что для процессов, которые не объявляют свое описание (большинство из них, очевидно, программисты Windows ленивы) или служб без описания - значение описания просто содержит имя исполняемого файла, то есть если вы используете старый добрый Блокнот, в то время как пользовательский интерфейс диспетчера задач покажет вам 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, чтобы пройти через все эти проблемы, но если вы действительно, очень хотите - вот как его получить.

person zwer    schedule 18.05.2017
comment
причина, по которой мне нужно описание, заключается в том, что у меня есть повторяющиеся исполняемые файлы, работающие как python.exe, описание дает мне представление о том, что такое соответствующий скрипт Python, чтобы я мог предпринять корректирующие действия.... есть ли лучший способ удовлетворить мое требование? - person user3508811; 19.05.2017
comment
Вы не получите это из поля Description (если только вы не используете разные интерпретаторы/виртуальные среды для каждого скрипта), вам больше повезет, используя второй пример и проверив поле CommandLine каждой задачи. Если все, что вам нужно, это идентифицировать различные запущенные скрипты Python, вы можете даже сократить команду WMIC до: wmic process where "name='python.exe'" get /format:list вместо получения полного списка задач. - person zwer; 19.05.2017
comment
Второй пример (первый с использованием WMI, но без взаимодействия с Win32 API) и использование поля CommandLine для определения запущенного сценария (вы можете получить фактический сценарий + любые аргументы, используемые row["CommandLine"].split(" ", 1)[1], если CommandLine не пусто, конечно). - person zwer; 19.05.2017