# Python 2.7
# Re-enroll script using XML-based Windows Scheduled Task (SYSTEM)
# Task does:
#   1) ITSMService.exe -c 2
#   2) timeout 65
#   3) net stop ITSMService
#   4) timeout 35
#   5) net start ITSMService
#   6) delete itself
#
# Script does:
#   - Writes unenroll.txt (admin password)
#   - Writes enrollment_config.ini
#   - Creates/overwrites the scheduled task
#   - DOES NOT run ITSMService.exe directly (unenroll happens inside the task)

import os
import time
import ctypes
import subprocess

try:
    from datetime import datetime, timedelta
except Exception:
    datetime = None
    timedelta = None


class DisableFileSystemRedirection(object):
    _disable = ctypes.windll.kernel32.Wow64DisableWow64FsRedirection
    _revert = ctypes.windll.kernel32.Wow64RevertWow64FsRedirection

    def __enter__(self):
        self.old_value = ctypes.c_long()
        self.success = self._disable(ctypes.byref(self.old_value))

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.success:
            self._revert(self.old_value)


def write_text_file(path, content, binary=False, encoding=None):
    folder = os.path.dirname(path)
    if folder and (not os.path.exists(folder)):
        try:
            os.makedirs(folder)
        except Exception:
            pass

    f = None
    try:
        if binary:
            f = open(path, "wb")
            if encoding:
                f.write(content.encode(encoding))
            else:
                f.write(content)
        else:
            f = open(path, "w")
            f.write(content)
    finally:
        if f:
            f.close()


def build_start_boundary(seconds_ahead):
    if datetime and timedelta:
        now = datetime.now()
        future = now + timedelta(seconds=seconds_ahead)
        date_str = future.strftime("%Y-%m-%d")
        time_str = future.strftime("%H:%M:%S")
        return date_str, time_str, date_str + "T" + time_str

    t = time.time() + seconds_ahead
    lt = time.localtime(t)
    date_str = "%04d-%02d-%02d" % (lt.tm_year, lt.tm_mon, lt.tm_mday)
    time_str = "%02d:%02d:%02d" % (lt.tm_hour, lt.tm_min, lt.tm_sec)
    return date_str, time_str, date_str + "T" + time_str


def create_task_xml(task_name, start_boundary, itsm_exe_path):
    # Use explicit full paths for reliability under SYSTEM
    net_exe = r"C:\Windows\System32\net.exe"
    schtasks_exe = r"C:\Windows\System32\schtasks.exe"
    timeout_exe = r"C:\Windows\System32\timeout.exe"

    # NOTE: no cmd.exe / no powershell.exe
    xml = u'''<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <Triggers>
    <TimeTrigger>
      <StartBoundary>''' + start_boundary + u'''</StartBoundary>
      <Enabled>true</Enabled>
    </TimeTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-18</UserId>
      <RunLevel>LeastPrivilege</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>true</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>false</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT30M</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>''' + itsm_exe_path + u'''</Command>
      <Arguments>-c 2</Arguments>
    </Exec>
    <Exec>
      <Command>''' + timeout_exe + u'''</Command>
      <Arguments>/t 65 /nobreak</Arguments>
    </Exec>
    <Exec>
      <Command>''' + net_exe + u'''</Command>
      <Arguments>stop ITSMService</Arguments>
    </Exec>
    <Exec>
      <Command>''' + timeout_exe + u'''</Command>
      <Arguments>/t 35 /nobreak</Arguments>
    </Exec>
    <Exec>
      <Command>''' + net_exe + u'''</Command>
      <Arguments>start ITSMService</Arguments>
    </Exec>
    <Exec>
      <Command>''' + schtasks_exe + u'''</Command>
      <Arguments>/delete /TN "''' + task_name + u'''" /f</Arguments>
    </Exec>
  </Actions>
</Task>'''
    return xml


def run_schtasks_create_from_xml(task_name, xml_file_path):
    with DisableFileSystemRedirection():
        return subprocess.call([
            r"C:\Windows\System32\schtasks.exe",
            "/create",
            "/tn", task_name,
            "/XML", xml_file_path,
            "/F"
        ])


# ----------------------------
# Main
# ----------------------------
host = itsm.getParameter("host")
port = itsm.getParameter("port")
token = itsm.getParameter("token")
pwd = itsm.getParameter("custom_admin_password")

enrollment = "[General]\n"
enrollment += "host = %s\n" % host
enrollment += "port = %s\n" % port
enrollment += "remove_third_party = false\n"
enrollment += "suite = 4\n"
enrollment += "token = %s\n" % token

programdata = os.environ.get("programdata") or os.environ.get("ProgramData")
if not programdata:
    raise Exception("ProgramData environment variable not found")

# Itarian path (replaced COMODO -> Itarian)
unenroll_txt_path = programdata + "\\Itarian\\Endpoint Manager\\unenroll.txt"

drive = os.environ.get("SystemDrive") or "C:"
if os.path.exists(drive + "\\Program Files (x86)"):
    base_path = drive + "\\Program Files (x86)\\Itarian\\Endpoint Manager"
else:
    base_path = drive + "\\Program Files\\Itarian\\Endpoint Manager"

ep_path = base_path + "\\enrollment_config.ini"
itsm_path = base_path + "\\ITSMService.exe"

# 1) Write unenroll.txt
try:
    write_text_file(unenroll_txt_path, pwd)
    print "Written:", unenroll_txt_path
except Exception as e:
    raise Exception("Failed to write unenroll.txt: %s" % str(e))

# 2) Write enrollment_config.ini
try:
    write_text_file(ep_path, enrollment)
    print "Written:", ep_path
except Exception as e:
    raise Exception("Failed to write enrollment_config.ini: %s" % str(e))

# 3) Create ONE scheduled task that does: unenroll -> wait 65 -> restart ITSMService -> self-delete
task_name = "ITSM_Unenroll_Then_Restart"
temp_dir = os.environ.get("TEMP") or (drive + "\\Windows\\Temp")
xml_path = temp_dir + "\\TaskXML_ITSM_Unenroll_Then_Restart.xml"

try:
    # Start in 60 seconds (change to 120 for 2 minutes, etc.)
    date_str, time_str, start_boundary = build_start_boundary(60)

    xml = create_task_xml(task_name, start_boundary, itsm_path)

    # Write UTF-16 with BOM (matches XML header)
    write_text_file(xml_path, xml, binary=True, encoding="utf-16")
    print "Task XML written:", xml_path
    print "Scheduling task '%s' for %s on %s (StartBoundary %s)" % (task_name, time_str, date_str, start_boundary)

    rc = run_schtasks_create_from_xml(task_name, xml_path)
    print "schtasks create return code:", rc
    if rc != 0:
        raise Exception("schtasks /create failed with code %d" % rc)

    print "Unenrollment + restart has been pushed via scheduled task."
except Exception as e:
    raise Exception("Failed to schedule task: %s" % str(e))
finally:
    try:
        if os.path.exists(xml_path):
            os.remove(xml_path)
    except Exception:
        pass
