Introduction
Interacting with Windows shell to end process is very common, there are many ways to do so, like through the traditional batch script
but to gain more flexibility, using python is probably a better idea.
os.system
is not the most elegant way to use, and it is meant to be replaced bysubprocess
subprocess
comes with Python standard library and allows us to spawn new processes, connect to their input/output/error pipes, and obtain their return codespsutil
(python system and process utilities) is a cross-platform library for retrieving information on running processes and system utilization. However, it is a third-party library
Bare Minimum
the bare minimum command to kill process utilizes window’s taskkill
;
which doesn’t matter if we use os.system
or subprocess
1 | import os |
Using os.system
Now consider a more flexible case where we want to gather information about the processes like its PID, and then proceed on ending the process. One of the downside of window shell command is that the output can’t be passed on to other command, the output is just text. Therefore, we output the text to a csv file which we will later process.
1 | import csv |
Using subprocess
With subprocess
, we no longer need to create a temp file to store the output.
import csv | |
import os | |
import signal | |
import subprocess | |
PROCESS = 'notepad.exe' | |
STATUS = 'running' # running or not responding | |
CMD = r'tasklist /fi "IMAGENAME eq {}" /fi "STATUS eq {}" /fo "csv"'.format(PROCESS, STATUS) | |
# output as csv format | |
proc = subprocess.Popen(CMD, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) | |
# get pids of the process in selected status | |
reader = csv.reader(proc.stdout) | |
header = next(reader) | |
pids = [int(row[1]) for row in reader] | |
# kill process | |
for pid in pids: | |
os.kill(pid, signal.SIGTERM) # or signal.SIGKILL | |
print('killed process with pid: {}'.format(pid)) | |
proc.wait() |
Using psutil
1 | import psutil |
we can find process start time by using
1 | import time |
to kill process, either kill()
or terminate()
will work
respectfully, SIGKILL
or SIGTERM
1 | p = psutil.Process(PID) |
Bonus: Find Open Port (for socket connection)
1 | process = psutil.Process(pid=PID) |
Bonus: Find Main Window Title
ctypes
is a foreign function library for python, resulting a not-pythonic function
import ctypes | |
EnumWindows = ctypes.windll.user32.EnumWindows | |
EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) | |
GetWindowText = ctypes.windll.user32.GetWindowTextW | |
GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW | |
GetWindowProcessId = ctypes.windll.user32.GetWindowThreadProcessId | |
IsWindowVisible = ctypes.windll.user32.IsWindowVisible | |
winMapping = dict() | |
def find_maya_window(hwnd, lParam): | |
if IsWindowVisible(hwnd): | |
# window name | |
length = GetWindowTextLength(hwnd) | |
buff = ctypes.create_unicode_buffer(length + 1) | |
GetWindowText(hwnd, buff, length + 1) | |
if 'Autodesk Maya' in buff.value: | |
# pid | |
pid = ctypes.wintypes.DWORD() | |
GetWindowProcessId(hwnd, ctypes.byref(pid)) | |
winMapping[int(pid.value)] = buff.value | |
return True | |
# query the window title | |
EnumWindows(EnumWindowsProc(find_maya_window), 0) | |
for item in winMapping.items(): | |
print(item) |
Reference
ThisPointer - Python : Check if a process is running by name and find it’s Process ID (PID)
Johannes Sasongko - Win32 Python: Getting all window titles