2026-01-27 15:44:52 +01:00
|
|
|
from time import time
|
|
|
|
|
import subprocess
|
|
|
|
|
from _socket import socket
|
|
|
|
|
import argparse
|
|
|
|
|
import time
|
|
|
|
|
import socket
|
|
|
|
|
import subprocess
|
|
|
|
|
|
|
|
|
|
TARGET_LINK = "f0:2f:74:30:0c:d0"
|
|
|
|
|
TARGET_HOSTNAME = "tower.home.the.malice.zone"
|
|
|
|
|
TARGET_IP = socket.gethostbyname(TARGET_HOSTNAME)
|
|
|
|
|
|
|
|
|
|
def remote_cmd(command):
|
2026-01-27 16:00:34 +01:00
|
|
|
print(f"Executing: ssh tower '{command}'")
|
|
|
|
|
response = subprocess.run(f"ssh tower '{command}'", shell=True, capture_output=True, text=True)
|
2026-01-27 15:44:52 +01:00
|
|
|
return (response.returncode, response.stdout, response.stderr)
|
|
|
|
|
|
|
|
|
|
def weboot():
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Rebooting to windows")
|
2026-01-27 15:44:52 +01:00
|
|
|
code, stdout, stderr = remote_cmd("sudo efibootmgr -n 0000")
|
|
|
|
|
if code == 0:
|
|
|
|
|
code, stdout, stderr = remote_cmd("sudo reboot")
|
|
|
|
|
time.sleep(60)
|
|
|
|
|
if code != 0:
|
|
|
|
|
raise RuntimeError(f"weboot failed {stderr}")
|
|
|
|
|
return code, stdout, stderr
|
|
|
|
|
|
|
|
|
|
def send_wol():
|
2026-01-27 16:00:34 +01:00
|
|
|
print(f"Broadcasting WOL packet to {TARGET_LINK}")
|
2026-01-27 15:44:52 +01:00
|
|
|
response = subprocess.run(f"wakeonlan {TARGET_LINK}", shell=True, capture_output=True, text=True)
|
|
|
|
|
return (response.returncode, response.stdout, response.stderr)
|
|
|
|
|
|
|
|
|
|
def get_os():
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Determining target OS")
|
2026-01-27 15:44:52 +01:00
|
|
|
code, stdout, stderr = remote_cmd("whoami")
|
|
|
|
|
if code == 255 and "No route to host" in stderr:
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Target is offline")
|
2026-01-27 15:44:52 +01:00
|
|
|
return "offline"
|
|
|
|
|
elif code != 0:
|
|
|
|
|
raise RuntimeError(f"win_or_linux failed {stderr}")
|
2026-01-27 16:00:34 +01:00
|
|
|
if "windows" in stdout.lower():
|
|
|
|
|
print("Target is running Windows")
|
2026-01-27 15:44:52 +01:00
|
|
|
return "windows"
|
|
|
|
|
else:
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Target is running Linux")
|
2026-01-27 15:44:52 +01:00
|
|
|
return "linux"
|
|
|
|
|
|
|
|
|
|
def swap_os():
|
|
|
|
|
match get_os():
|
|
|
|
|
case "windows":
|
|
|
|
|
code, stdout, stderr = remote_cmd("shutdown /r")
|
|
|
|
|
case "linux":
|
|
|
|
|
code, stdout, stderr = weboot()
|
|
|
|
|
case "offline":
|
|
|
|
|
return False
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def boot_linux():
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Booting Linux")
|
2026-01-27 15:44:52 +01:00
|
|
|
match get_os():
|
|
|
|
|
case "windows":
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Tower is busy")
|
2026-01-27 15:44:52 +01:00
|
|
|
return False
|
|
|
|
|
case "linux":
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Linux is already running")
|
2026-01-27 15:44:52 +01:00
|
|
|
return True
|
|
|
|
|
case "offline":
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Booting via WOL")
|
2026-01-27 15:44:52 +01:00
|
|
|
send_wol()
|
|
|
|
|
time.sleep(60)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def boot_windows():
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Booting Windows")
|
2026-01-27 15:44:52 +01:00
|
|
|
match get_os():
|
|
|
|
|
case "windows":
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Windows is already running")
|
2026-01-27 15:44:52 +01:00
|
|
|
return True
|
|
|
|
|
case "linux":
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Tower is busy")
|
2026-01-27 15:44:52 +01:00
|
|
|
return False
|
|
|
|
|
case "offline":
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Booting via WOL")
|
2026-01-27 15:44:52 +01:00
|
|
|
boot_linux()
|
|
|
|
|
weboot()
|
|
|
|
|
if get_os() == "windows":
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def reboot():
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Rebooting target")
|
2026-01-27 15:44:52 +01:00
|
|
|
orig_os = get_os()
|
|
|
|
|
match orig_os:
|
|
|
|
|
case "windows":
|
|
|
|
|
code, stdout, stderr = remote_cmd("shutdown /r")
|
|
|
|
|
time.sleep(60)
|
|
|
|
|
weboot()
|
|
|
|
|
return True
|
|
|
|
|
case "linux":
|
|
|
|
|
code, stdout, stderr = remote_cmd("sudo reboot")
|
|
|
|
|
return True
|
|
|
|
|
case "offline":
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Target is offline, cannot reboot")
|
2026-01-27 15:44:52 +01:00
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def shutdown():
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Shutting down target")
|
2026-01-27 15:44:52 +01:00
|
|
|
match get_os():
|
|
|
|
|
case "windows":
|
|
|
|
|
code, stdout, stderr = remote_cmd("shutdown /s")
|
2026-01-27 16:00:34 +01:00
|
|
|
time.sleep(30)
|
2026-01-27 15:44:52 +01:00
|
|
|
return True
|
|
|
|
|
case "linux":
|
|
|
|
|
code, stdout, stderr = remote_cmd("sudo shutdown -h now")
|
2026-01-27 16:00:34 +01:00
|
|
|
time.sleep(30)
|
2026-01-27 15:44:52 +01:00
|
|
|
return True
|
|
|
|
|
case "offline":
|
2026-01-27 16:00:34 +01:00
|
|
|
print("Target is already offline")
|
2026-01-27 15:44:52 +01:00
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def action_do(action):
|
|
|
|
|
match action:
|
2026-01-27 16:00:34 +01:00
|
|
|
case "get_os":
|
|
|
|
|
os = get_os()
|
|
|
|
|
print(f"Current OS: {os}")
|
2026-01-27 15:44:52 +01:00
|
|
|
case "boot_linux":
|
|
|
|
|
if boot_linux():
|
|
|
|
|
print("Linux is now running")
|
|
|
|
|
else:
|
|
|
|
|
print("Failed to boot Linux")
|
|
|
|
|
case "boot_windows":
|
|
|
|
|
if boot_windows():
|
|
|
|
|
print("Windows is now running")
|
|
|
|
|
else:
|
|
|
|
|
print("Failed to boot Windows")
|
|
|
|
|
case "swap_os":
|
|
|
|
|
if swap_os():
|
|
|
|
|
print("OS swapped successfully")
|
|
|
|
|
else:
|
|
|
|
|
print("Failed to swap OS")
|
|
|
|
|
case "reboot":
|
|
|
|
|
if reboot():
|
|
|
|
|
print("Reboot command sent successfully")
|
|
|
|
|
else:
|
|
|
|
|
print("Failed to reboot")
|
|
|
|
|
case "shutdown":
|
|
|
|
|
if shutdown():
|
|
|
|
|
print("Shutdown command sent successfully")
|
|
|
|
|
else:
|
|
|
|
|
print("Failed to shutdown")
|
|
|
|
|
case "winupdate":
|
|
|
|
|
if get_os() != "offline":
|
|
|
|
|
print("Target is in use, belaying update 1h")
|
|
|
|
|
time.sleep(3600)
|
|
|
|
|
action_do("winupdate")
|
2026-01-27 16:00:34 +01:00
|
|
|
if boot_windows():
|
|
|
|
|
print("Initiating Windows update")
|
|
|
|
|
else:
|
|
|
|
|
print("Failed to boot Windows for update")
|
|
|
|
|
return
|
2026-01-27 15:44:52 +01:00
|
|
|
code, stdout, stderr = remote_cmd("powershell -Command \"& {Install-WindowsUpdate -AcceptAll -AutoReboot}\"")
|
|
|
|
|
if code == 0:
|
|
|
|
|
print("Windows update initiated successfully")
|
|
|
|
|
else:
|
|
|
|
|
print(f"Failed to initiate Windows update: {stderr}")
|
|
|
|
|
#first reboot to windows
|
|
|
|
|
time.sleep(300)
|
|
|
|
|
weboot()
|
|
|
|
|
#second reboot after update
|
|
|
|
|
time.sleep(600)
|
|
|
|
|
reboot()
|
|
|
|
|
#shutdown
|
|
|
|
|
time.sleep(300)
|
|
|
|
|
shutdown()
|
|
|
|
|
|
2026-01-27 16:00:34 +01:00
|
|
|
def main():
|
2026-01-27 15:44:52 +01:00
|
|
|
parser = argparse.ArgumentParser(description="WOL and reboot utility")
|
2026-01-27 16:00:34 +01:00
|
|
|
parser.add_argument("action", choices=["get_os", "boot_linux", "boot_windows", "swap_os", "reboot", "shutdown", "winupdate"], help="Action to perform")
|
2026-01-27 15:44:52 +01:00
|
|
|
action_do(parser.parse_args().action)
|
|
|
|
|
|
2026-01-27 16:00:34 +01:00
|
|
|
if __name__ == "__main__":
|
|
|
|
|
main()
|