40 lines
1.8 KiB
Python
40 lines
1.8 KiB
Python
"""Kill farm loop processes on Windows: wrappers first (tree kill), verify to zero.
|
|
Usage: python kill_farm_loops.py "regex_pattern" [max_rounds]
|
|
Pattern uses bracket-trick against self-match, e.g. 'treg_farm_v[3]|v3_loo[p]'.
|
|
Python subprocess instead of powershell one-liners: git-bash eats $_.
|
|
"""
|
|
import subprocess, sys, time, os
|
|
|
|
PATTERN = sys.argv[1] if len(sys.argv) > 1 else r'treg_farm_v[34]|v[34]_loo[p]'
|
|
MAX_ROUNDS = int(sys.argv[2]) if len(sys.argv) > 2 else 6
|
|
|
|
def ps(cmd):
|
|
return subprocess.run(['powershell', '-NoProfile', '-Command', cmd],
|
|
capture_output=True, text=True).stdout
|
|
|
|
def find(pattern):
|
|
out = ps(r'''Get-CimInstance Win32_Process | Where-Object {$_.CommandLine -match '%s'} | ForEach-Object {"$($_.ProcessId)|$($_.Name)|$($_.CommandLine)"}''' % pattern)
|
|
rows = []
|
|
for l in out.splitlines():
|
|
parts = l.split('|', 2)
|
|
if len(parts) >= 2 and parts[0].strip().isdigit():
|
|
rows.append((int(parts[0].strip()), parts[1].strip(), parts[2] if len(parts) > 2 else ''))
|
|
me = os.getpid()
|
|
return [r for r in rows if r[0] != me and 'kill_farm_loops' not in r[2] and 'Get-CimInstance' not in r[2]]
|
|
|
|
for rnd in range(MAX_ROUNDS):
|
|
rows = find(PATTERN)
|
|
if not rows:
|
|
print('ALL DEAD'); sys.exit(0)
|
|
print(f'round {rnd}:', [(p, n) for p, n, _ in rows])
|
|
# wrappers (bash/sh running the loop script) FIRST — otherwise they respawn python children
|
|
wrappers = [r for r in rows if '_loop' in r[2] or r[1].lower() in ('bash.exe', 'sh.exe')]
|
|
others = [r for r in rows if r not in wrappers]
|
|
for p, n, c in wrappers + others:
|
|
subprocess.run(['taskkill', '/F', '/T', '/PID', str(p)], capture_output=True)
|
|
time.sleep(3)
|
|
print('STILL ALIVE after %d rounds — manual check' % MAX_ROUNDS)
|
|
for p, n, c in find(PATTERN):
|
|
print(p, n, c[:120])
|
|
sys.exit(1)
|