I am trying to figure out a tasklist
command that gives the Description
aswell as shown in the Taskmangaer UI?I am trying to run it from python,if
That's a bit trickier than you might imagine and you really need a good reason to go through all the trouble to justify it. First of all, Task Manager UI doesn't get its information from tasklist.exe
, although you can get pretty close with:
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'
However, to get to the Description
field (and a lot others from the Task Manager UI) you'll have to pull the data from WMI at the very least. To make matters worse, WMIC
on Windows 7 has a bug when exporting to CSV making the whole thing even more complicated as for maximum portability we need to use the list
format and parse it ourselves:
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'
Code Update for Python3 (use encode for bytes-wise search):
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)))
If you don't need all these fields, you can always restrict wmic
to get you the fields you want (i.e. wmi_out = subprocess.check_output(["wmic", "process", "get", "ProcessId,ExecutablePath,Description", "/format:list"])
to get only Description
per ProcessId
).
But don't think your troubles are over - we just started. While we now have the Description
field (and a few others to boot), you'll notice that for processes that do not announce their description (most of them, Windows programmers be lazy apparently) or services without a description - the description value just contains the executable name i.e. if you're running plain old Notepad, while Task Manager UI will show you Notepad
as Description, its dictionary entry will have notepad.exe
- that is because Task Manager UI uses a completely different approach to task list and gets the description directly from the process executable.
So you actually need an additional step to retrieve the executable description directly from its resources table, which is probably the 'easiest' to do by invoking the Win32 API to get to the description, so you need to install the pyWin32 module first:
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
Voilà! Descriptions are now populated (where available, or at least hold the executable name), but since we had to use Win32 API to get to the descriptions, we might as well get the tasks list through it - it's faster and more concise:
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
This will only get ProcessId, ExecutablePath and Description but you can further explore Win32 API if you need more fields.
Again, I don't see of what value the Description
field is to go through all this trouble but if you really, really want it - this is how to get it.