-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprocess.py
More file actions
270 lines (217 loc) · 9.5 KB
/
Copy pathprocess.py
File metadata and controls
270 lines (217 loc) · 9.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
import tkinter as tk
from tkinter import ttk, messagebox
import csv
import logging
from pathlib import Path
from constants import *
class ProcessManager:
"""
Class to manage and display processes in a GUI window
Allows killing processes on a remote machine using PsExec
"""
def __init__(self,csv_filename: Path,psexec_manager: 'PsExecManager',current_ip: str,current_hostname: str,psexec_path: str,log_path: str) -> None:
"""
Initialize the ProcessManager
Args:
csv_filename (str or Path): Path to the CSV file containing process list
psexec_manager (PsExecManager): Instance of PsExecManager to execute commands
current_ip (str): IP address of the remote machine
current_hostname (str): Hostname of the remote machine
psexec_path (str): Path to PsExec64.exe
log_path (str): Path to the log directory
"""
self.csv_filename = Path(csv_filename)
self.psexec_manager = psexec_manager
self.current_ip = current_ip
self.current_hostname = current_hostname
self.psexec_path = psexec_path
self.log_path = log_path
# Dictionary to store button references for each process
# Key: process name, Value: button widget
self.process_buttons = {}
# Create the main window
self.window = tk.Toplevel()
self.window.title(f"Process Manager - {self.current_hostname} ({self.current_ip})")
self.window.geometry(PROCESS_MANAGER_SIZE)
# Keep window on top of the main window
self.window.attributes('-topmost', True)
# Create the interface
self._create_widgets()
# Load processes from CSV
self._load_processes()
def _create_widgets(self) -> None:
"""
Create all GUI widgets for the process manager window
"""
# Title label
title_label = ttk.Label(
self.window,
text=f"Processes on {self.current_hostname}",
font=('Arial', 14, 'bold')
)
title_label.pack(pady=10)
# Create a frame for the scrollable list
list_frame = ttk.Frame(self.window)
list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
# Create canvas and scrollbar for scrolling
self.canvas = tk.Canvas(list_frame)
scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=self.canvas.yview)
# Create a frame inside the canvas to hold the process list
self.scrollable_frame = ttk.Frame(self.canvas)
# Configure the scrollable region
self.scrollable_frame.bind(
"<Configure>",
lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
)
# Create window in canvas
self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
self.canvas.configure(yscrollcommand=scrollbar.set)
# Pack canvas and scrollbar
self.canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
# Add mouse wheel scrolling support
self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
# Create bottom frame for buttons
bottom_frame = ttk.Frame(self.window)
bottom_frame.pack(pady=10)
# Refresh button to reload the process list
refresh_btn = ttk.Button(
bottom_frame,
text="Refresh List",
command=self._refresh_process_list
)
refresh_btn.pack(side=tk.LEFT, padx=5)
# Close button
close_btn = ttk.Button(
bottom_frame,
text="Close",
command=self.window.destroy
)
close_btn.pack(side=tk.LEFT, padx=5)
def _on_mousewheel(self, event):
"""
Handle mouse wheel scrolling
Args:
event: Mouse wheel event
"""
self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
def _load_processes(self):
"""
Load processes from CSV file and display them in the GUI
"""
# Check if CSV file exists
if not self.csv_filename.exists():
messagebox.showerror("Error", f"CSV file not found: {self.csv_filename}", parent=self.window)
logging.error(f"CSV file not found: {self.csv_filename}")
return
try:
# Read the CSV file
with open(self.csv_filename, 'r', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile)
# Read all rows in list
processes = list(reader)
# Sort the list by the 'name' column (ascending order)
processes.sort(key=lambda row: row.get('name', '').strip().lower())
# Counter for row positioning
row_index = 0
# Iterate through each process in the CSV
for row in processes:
process_name = row.get('name', '').strip()
# Skip empty names
if not process_name:
continue
# Create a frame for each process row
process_frame = ttk.Frame(self.scrollable_frame)
process_frame.grid(row=row_index, column=0, sticky="ew", pady=2, padx=5)
# Configure column weight for proper expansion
process_frame.columnconfigure(1, weight=1)
# Create kill button (initially green)
kill_btn = tk.Button(
process_frame,
text="Kill",
bg=COLOR_SUCCESS, # Green color
fg="white",
width=8,
command=lambda pname=process_name: self._kill_process(pname)
)
kill_btn.grid(row=0, column=0, padx=5)
# Store button reference for later updates
self.process_buttons[process_name] = kill_btn
# Create label with process name
process_label = ttk.Label(
process_frame,
text=process_name,
font=('Arial', 10)
)
process_label.grid(row=0, column=1, sticky="w", padx=5)
row_index += 1
logging.info(f"Loaded {row_index} processes from {self.csv_filename}")
except Exception as e:
messagebox.showerror("Error", f"Error reading CSV file: {e}", parent=self.window)
logging.error(f"Error reading CSV file {self.csv_filename}: {e}")
def _kill_process(self, process_name: str) -> None:
"""
Kill a process on the remote machine
Args:
process_name (str): Name of the process to kill
"""
# Confirm action with user
response = messagebox.askyesno(
"Confirm",
f"Are you sure you want to kill process '{process_name}'?",
parent=self.window
)
if not response:
return
try:
# Call the kill_process method from PsExecManager
result = self.psexec_manager.kill_process(process_name)
# Get the button for this process
button = self.process_buttons.get(process_name)
if result == 1:
# Success: change button to red and disable it
if button:
button.config(bg=COLOR_ERROR, state="disabled") # Red color
# messagebox.showinfo("Success", f"Process '{process_name}' killed successfully!")
logging.info(f"Process '{process_name}' killed on {self.current_hostname}")
else:
# Failure: show error message
messagebox.showerror(
"Error",
f"Failed to kill process '{process_name}'",
parent = self.window
)
logging.error(f"Failed to kill process '{process_name}' on {self.current_hostname}")
except Exception as e:
messagebox.showerror("Error", f"Error killing process: {e}", parent=self.window)
logging.error(f"Error killing process '{process_name}': {e}")
def _refresh_process_list(self):
"""
Refresh the process list by regenerating the CSV and reloading the display
"""
try:
# Clear existing widgets in scrollable frame
for widget in self.scrollable_frame.winfo_children():
widget.destroy()
# Clear button references
self.process_buttons.clear()
# Regenerate the process list CSV
self.psexec_manager.get_processes_to_csv()
# Reload processes from the updated CSV
self._load_processes()
# messagebox.showinfo("Success", "Process list refreshed successfully!")
logging.info(f"Process list refreshed for {self.current_hostname}")
except Exception as e:
messagebox.showerror("Error", f"Error refreshing process list: {e}", parent=self.window)
logging.error(f"Error refreshing process list for {self.current_hostname}: {e}")
def show(self):
"""
Show the process manager window
"""
self.window.mainloop()
def close(self):
"""
Close the process manager window if it exists
"""
if self.window and self.window.winfo_exists():
self.window.destroy()