How to kill a Windows running exe with Python - python

How to End task this exe file in background processes:
my code:
import os
import subprocess
import time
import win32com.client
wmi=win32com.client.GetObject('winmgmts:')
for p in wmi.InstancesOf('win32_process'):
# print(p.Name)
if p.Name == 'boltzmann.exe':
print("Ok")

In my Code I used process chrome.exe as an example (replace it with boltzmann.exe):
import os
import subprocess
import time
import win32com.client
import signal
wmi=win32com.client.GetObject('winmgmts:')
def getpid(process_name):
import os
return [item.split()[1] for item in os.popen('tasklist').read().splitlines()[4:] if process_name in item.split()]
for p in wmi.InstancesOf('win32_process'):
if p.Name == 'chrome.exe':
process_id = getpid('chrome.exe')
if len(process_id) > 1:
for x in process_id:
pid = int(x)
os.kill(pid, signal.SIGTERM)
else:
pid = int("".join(getpid('chrome.exe')))
os.kill(pid, signal.SIGTERM)
I tried my best to make this all using inbuilt libraries so that you won't have to import lot of stuff
SOME NOTES:
The process name is case sensitive
If the Process is running on higher priority then process won't terminate, and a access denied error will appear

Related

Can I get the PID of program launched by a subprogram?

My python script runs a program, let's call it X.exe
from subprocess import Popen
process = Popen('D:X.exe')
I can get its PID via
process.pid
After some time (which I know) X.exe launches another program - Y.exe. Can I get the PID of the Y.exe process? NOTE: I DON'T KNOW WHAT THE Y.exe WINDOW WILL BE NAMED
you can see the children of a process using psutil simply as follows.
import psutil
import subprocess
import time
proc = subprocess.Popen("start /wait", shell=True) # start another cmd.exe
time.sleep(0.5) # wait for child to start
process_object = psutil.Process(proc.pid)
children = process_object.children()
print(f"child pid is {children[0].pid}")
proc.wait()
child pid is 18292

How to get the pid of the process started by subprocess.run and kill it

I'm using Windows 10 and Python 3.7.
I ran the following command.
import subprocess
exeFilePath = "C:/Users/test/test.exe"
subprocess.run(exeFilePath)
The .exe file launched with this command, I want to force-quit when the button is clicked or when the function is executed.
Looking at a past question, it has been indicated that the way to force quit is to get a PID and do an OS.kill as follows.
import signal
os.kill(self.p.pid, signal.CTRL_C_EVENT)
However, I don't know how to get the PID of the process started in subprocess.run.
What should I do?
Assign a variable to your subprocess
import os
import signal
import subprocess
exeFilePath = "C:/Users/test/test.exe"
p = subprocess.Popen(exeFilePath)
print(p.pid) # the pid
os.kill(p.pid, signal.SIGTERM) #or signal.SIGKILL
In same cases the process has children
processes. You need to kill all processes to terminate it. In that case you can use psutil
#python -m pip install —user psutil
import psutil
#remember to assign subprocess to a variable
def kills(pid):
'''Kills all process'''
parent = psutil.Process(pid)
for child in parent.children(recursive=True):
child.kill()
parent.kill()
#assumes variable p
kills(p.pid)
This will kill all processes in that PID

python subprocess waiting for grandchild on Windows with stdout set

I have a script that is part of an automated test suite. It runs very slowly on Windows but not on Linux and I have found out why. The process that we are testing ('frank') creates a child process (so a grandchild). The python code won't return until that grandchild process also ends (on Windows - doesn't do this on Linux). The grandchild process will kill itself off after 5 seconds if there is no parent (it hangs around in case another process talks to it)
I've found I can stop the communicate function from hanging in this way if I don't capture stdout. But I need stdout. I read somewhere that the communicate function is waiting for all pipes to be closed. I know that the stdout handle is duplicated for the grandchild but I can't change the code I'm testing.
I've been searching for a solution. I tried some creation flags (still in the code) but that didn't help.
This is the cut down test -
import os
import sys
import threading
import subprocess
def read_from_pipe(process):
last_stdout = process.communicate()[0]
print (last_stdout)
CREATE_NEW_PROCESS_GROUP = 0x00000200
DETACHED_PROCESS = 0x00000008
# start process
command = 'frank my arguments'
cwd = "C:\\dev\\ui_test\\frank_test\\workspace\\report183"
p = subprocess.Popen(command,
stdout=subprocess.PIPE,
cwd=cwd)
# run thread to read from output
t = threading.Thread(target=read_from_pipe, args=[p])
t.start()
t.join(30)
print('finished')
Any ideas?
Thanks.
Peter.
After tips from #eryksun and a lot of Googling, I have this rather complicated lot of code! At one point, I considered cheating and doing os.system and redirecting to a temp file but then I realised that our test code allows for a command timing out. os.system would just block forever if the child process doesn't die.
import os
import sys
import threading
import subprocess
import time
if os.name == 'nt':
import msvcrt
import ctypes
# See https://stackoverflow.com/questions/55160319/python-subprocess-waiting-for-grandchild-on-windows-with-stdout-set for details on Windows code
# Based on https://github.com/it2school/Projects/blob/master/2017/Python/party4kids-2/CarGame/src/pygame/tests/test_utils/async_sub.py
from ctypes.wintypes import DWORD
if sys.version_info >= (3,):
null_byte = '\x00'.encode('ascii')
else:
null_byte = '\x00'
def ReadFile(handle, desired_bytes, ol = None):
c_read = DWORD()
buffer = ctypes.create_string_buffer(desired_bytes+1)
success = ctypes.windll.kernel32.ReadFile(handle, buffer, desired_bytes, ctypes.byref(c_read), ol)
buffer[c_read.value] = null_byte
return ctypes.windll.kernel32.GetLastError(), buffer.value
def PeekNamedPipe(handle):
c_avail = DWORD()
c_message = DWORD()
success = ctypes.windll.kernel32.PeekNamedPipe(handle, None, 0, None, ctypes.byref(c_avail), ctypes.byref(c_message))
return "", c_avail.value, c_message.value
def read_available(handle):
buffer, bytesToRead, result = PeekNamedPipe(handle)
if bytesToRead:
hr, data = ReadFile(handle, bytesToRead, None)
return data
return b''
def read_from_pipe(process):
if os.name == 'posix':
last_stdout = process.communicate()[0]
else:
handle = msvcrt.get_osfhandle(process.stdout.fileno())
last_stdout = b''
while process.poll() is None:
last_stdout += read_available(handle)
time.sleep(0.1)
last_stdout += read_available(handle)
print (last_stdout)
# start process
command = 'frank my arguments'
cwd = "C:\\dev\\ui_test\\frank_test\\workspace\\report183"
p = subprocess.Popen(command,
stdout=subprocess.PIPE,
cwd=cwd)
# run thread to read from output
t = threading.Thread(target=read_from_pipe, args=[p])
t.start()
t.join(30)
print('finished')

Is it possible to wait until a task in the windows taskmanager has stopped?

So basically, i want python to run another programm and wait till that program is not visible in the taskmanger and then continue with the script.
Any Ideas?
As #eryksun suggested, the subprocess module can handle the waiting as well:
import subprocess
process = subprocess.Popen(["notepad.exe"], shell=False)
process.wait()
print ("notepad.exe closed")
You could use something like this, tracking the process id of the opened program:
import subprocess, win32com.client, time
wmi=win32com.client.GetObject('winmgmts:')
process = subprocess.Popen(["notepad.exe"], shell=False)
pid = process.pid
flag = True
while flag:
flag = False
for p in wmi.InstancesOf('win32_process'):
if pid == int(p.Properties_('ProcessId')):
flag = True
time.sleep(.1)
print ("notepad.exe closed")
Output when notepad is closed:
notepad.exe closed
>>>
Here's an example of a simple way to see if something is running on Windows that uses its built-in tasklist command:
import os
import subprocess
target = 'notepad.exe'
results = subprocess.check_output(['tasklist'], universal_newlines=True)
if any(line.startswith(target) for line in results.splitlines()):
print(target, 'is running')
else:
print(target, 'is *not* running')
It can be done with pywinauto:
from pywinauto import Application
app = Application().connect(process=pid) # or connect(title_re="") or other options
app.wait_for_process_exit(timeout=50, retry_interval=0.1)

How do I kill all other running python processes without killing the parent process

I would like to stop all python processes without killing the current running script. Here is the code I wrote so far.
import psutil
import os
for proc in psutil.process_iter():
pinfo = proc.as_dict(attrs=['pid', 'name'])
procname = str(pinfo['name'])
procpid = str(pinfo['pid'])
if "python" in procname:
print("Stopped Python Process ", proc)
proc.kill()
Change your if's condition, from the current
if "python" in procname:
to
if "python" in procname and procpid != str(os.getpid()):
You need to get which pid your program have. And check if all one of the element you iterate through do not have the same pid.
import psutil
import os
this_proc = os.getpid()
for proc in psutil.process_iter():
procd = proc.as_dict(attrs=['pid', 'name'])
if "python" in str(procd['name']) and procd['pid'] != this_proc:
proc.kill()

Categories