예제 #1
0
    def spawnImmediateTask(self, jobid, taskid_complex=None, params=None):
        '''
        Run task immediately using basic configuration of job
        
        @param jobid:int
        @param taskid_complex: string 
        @param params: string
        '''
        job = Job.getByJobID(jobid)
        if not job:
            raise ValueError("Job(id:%d) is not existed or not enabled." % (jobid))
        if params :
            job.set_command(job._substituteReservedWord(params))

        if taskid_complex:
            task = Task(job.get_jobid(), uuid.uuid1().hex, datetime.now(),
                            job.getCommandToExcute(), job.get_retry(), job, job.get_depend(), taskid_complex)
        else:
            task = Task(job.get_jobid(), uuid.uuid1().hex, datetime.now(),
                            job.getCommandToExcute(), job.get_retry(), job, job.get_depend())
        t = TaskRunner(0, task, self._status, self, params)
        t.daemon = True
        task.save()
        self._status.add_waiting_task(task, t)
        t.start()
        
        return task
예제 #2
0
 def spawnTasks(self, start_time, end_time):
     '''
     Spawn thread based on Job's timer.
     
     According to start_time and end_time,Job satisfied the job will be 
     wrapped as Task which launched by Timer thread.For Timer accept delay as
     its first parameter,we convert job's timer to delay seconds here.
     These Timer tasks will be started in main thread.
     
     '''
     tasks = []
     jobs = []
     self._lock.acquire()
     try:
         for hour in range(start_time.hour, end_time.hour):
             if hour in self.hour_index:
                 jobs.extend(self.hour_index[hour])
         jobs = set(jobs)
         
         # Clear second and be care of start minute
         determine_time = start_time
         if start_time.second != 0:
             determine_time = start_time + timedelta(minutes=1)
         determine_time = datetime.combine(determine_time.date(), time(hour=determine_time.hour, minute=determine_time.minute))
         
         while determine_time < end_time:
             for job in jobs:
                 if TimeMatcher.matchTimePattern(job.get_time_pattern(), determine_time):
                     task = Task(job.get_jobid(), uuid.uuid1().hex, determine_time,
                                 job.getCommandToExcute(), job.get_retry(), job, job.get_depend())
                     t = TaskRunner((determine_time - datetime.now()).seconds + 1,
                                                    task, self._status, self)
                     t.daemon = True
                     t.start()
                     task.save()
                     tasks.append(task)
                     self._status.add_waiting_task(task, t)
             determine_time = determine_time + timedelta(minutes=1)
                                                                                                                                                                                                                                                                                                                                                                                            
         self._lock.release()
     except Exception, e:
         self._lock.release()
         raise e;
예제 #3
0
파일: agent.py 프로젝트: admdev8/winagent
    async def ping_check(self, data):
        try:
            cmd = ["ping", data["ip"]]
            r = await asyncio.create_subprocess_exec(
                *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
            )

            stdout, stderr = await r.communicate()

            success = ["Reply", "bytes", "time", "TTL"]

            if stdout:
                output = stdout.decode("utf-8", errors="ignore")
                if all(x in output for x in success):
                    status = "passing"
                else:
                    status = "failing"

            elif stderr:
                status = "failing"
                output = stderr.decode("utf-8", errors="ignore")

            payload = {
                "status": status,
                "more_info": output,
            }

            self.logger.debug(payload)

            resp = requests.patch(
                f"{self.astor.server}/api/v1/{data['id']}/checkrunner/",
                json.dumps(payload),
                headers=self.headers,
                timeout=15,
            )

            if (
                status == "failing"
                and data["assigned_task"]
                and data["assigned_task"]["enabled"]
            ):
                from taskrunner import TaskRunner

                task = TaskRunner(
                    task_pk=data["assigned_task"]["id"],
                    log_level=self.log_level,
                    log_to=self.log_to,
                )
                await task.run_while_in_event_loop()

            return status
        except Exception as e:
            self.logger.debug(e)
            return "failing"
예제 #4
0
파일: agent.py 프로젝트: admdev8/winagent
    async def disk_check(self, data, exists=True):
        try:
            disk = psutil.disk_usage(data["disk"])
        except Exception:
            exists = False
            self.logger.error(f"Disk {data['disk']} does not exist")

        if exists:
            percent_used = round(disk.percent)
            total = bytes2human(disk.total)
            free = bytes2human(disk.free)

            if (100 - percent_used) < data["threshold"]:
                status = "failing"
            else:
                status = "passing"

            more_info = f"Total: {total}B, Free: {free}B"
        else:
            status = "failing"
            more_info = f"Disk {data['disk']} does not exist"

        payload = {
            "status": status,
            "more_info": more_info,
        }

        self.logger.debug(payload)

        resp = requests.patch(
            f"{self.astor.server}/api/v1/{data['id']}/checkrunner/",
            json.dumps(payload),
            headers=self.headers,
            timeout=15,
        )

        if (
            status == "failing"
            and data["assigned_task"]
            and data["assigned_task"]["enabled"]
        ):
            from taskrunner import TaskRunner

            task = TaskRunner(
                task_pk=data["assigned_task"]["id"],
                log_level=self.log_level,
                log_to=self.log_to,
            )
            await task.run_while_in_event_loop()

        return status
예제 #5
0
 def spawnTask(self, jobid, start_time, end_time):
     '''
     Spawn thread based on one Job's timer
     
     @param jobid:int
     @param start_time:datetime ,start time of time section
     @param end_time:datetime ,end time of time section
     '''
     tasks = []
     self._lock.acquire()
     try:
         job = Job.getByJobID(jobid)
         if not job:
             raise ValueError("Job(id:%d) is not exsited or not enabled." % (jobid))
         
         # Clear second and be care of start minute
         determine_time = start_time
         if start_time.second != 0:
             determine_time = start_time + timedelta(minutes=1)
         determine_time = datetime.combine(determine_time.date(), time(hour=determine_time.hour, minute=determine_time.minute))
         
         while determine_time < end_time:
             if TimeMatcher.matchTimePattern(job.get_time_pattern(), determine_time):
                 task = Task(job.get_jobid(), uuid.uuid1().hex, determine_time,
                             job.getCommandToExcute(), job.get_retry(), job, job.get_depend())
                 t = TaskRunner((determine_time - datetime.now()).seconds + 1,
                                                                    task, self._status, self)
                 t.daemon = True
                 t.start()
                 task.save()
                 tasks.append(task)
                 self._status.add_waiting_task(task, t)
             determine_time = determine_time + timedelta(minutes=1)
                                                                                                                                                                                                                                                                                                                                                                                            
         self._lock.release()
     except Exception, e:
         self._lock.release()
         raise e;
예제 #6
0
# so that people can have different configs for different builds

# prepare the environment file
config_env = config.asDict()
config_env.update(os.environ)
if myconfig:
    config_env.update(myconfig.asDict())
    
tasks = Task([ Job("pre-flight", "./scripts/pre-flight.sh", env=config_env), 
               Job("win_build", "./scripts/build-windows.sh", env=config_env),
               Job("lin_build", "./scripts/build-linux.sh", env=config_env),
               Job("mac_build", "./scripts/build-mac.sh", env=config_env),
             ])
             
print "Build getting started at: ", time.ctime()


# Run the first task, which will create the docs and sources tarballs
tr = TaskRunner(tasks)
rc = tr.run()

if rc == 0 and config.delete_temps == "yes":
    shutil.rmtree(config.WX_TEMP_DIR)

# cleanup the DAILY_BUILD file
if config.KIND == "daily":
    os.unlink("DAILY_BUILD")
    
print "Build finished at: ", time.ctime()
sys.exit(0)
# so that people can have different configs for different builds

# prepare the environment file
config_env = config.asDict()
config_env.update(os.environ)
if myconfig:
    config_env.update(myconfig.asDict())

tasks = Task([
    Job("pre-flight", "./scripts/pre-flight.sh", env=config_env),
    Job("win_build", "./scripts/build-windows.sh", env=config_env),
    Job("lin_build", "./scripts/build-linux.sh", env=config_env),
    Job("mac_build", "./scripts/build-mac.sh", env=config_env),
])

print "Build getting started at: ", time.ctime()

# Run the first task, which will create the docs and sources tarballs
tr = TaskRunner(tasks)
rc = tr.run()

if rc == 0 and config.delete_temps == "yes":
    shutil.rmtree(config.WX_TEMP_DIR)

# cleanup the DAILY_BUILD file
if config.KIND == "daily":
    os.unlink("DAILY_BUILD")

print "Build finished at: ", time.ctime()
sys.exit(0)
예제 #8
0
import sys
from taskrunner import Task, TaskRunner
    
if __name__ == '__main__':

    # setup taskrunner
    taskRunner = TaskRunner(
        enableHelp = True, 
        defaultTask = Task('default', 'qs version && printf \"\n\" && qs help'), 
        versionTask = Task(['v', 'version'], 'echo \"QuickScript Version 1.3\nCreated by Nicholas Ramsay \"', 'Shows the current QuickScript version.')
    )

    # get tasks from file and add to taskRunner
    with open('tasks.csv', 'r') as f:
        for l in f.readlines(0):
            segments = l.split(', ')
            taskRunner.AddTask(Task(segments[0].split(' '), segments[1], segments[2]))


    # Run the command line argument task
    try:
        if len(sys.argv[1:]) < 1:
            taskRunner.RunTask('')
        else:
            for arg in sys.argv[1:]:
                taskRunner.RunTask(arg)
            
    except Exception as e:
        print('\033[91m' + str(e) + '\033[0m\n')
        taskRunner.RunTask('help')
예제 #9
0
파일: agent.py 프로젝트: admdev8/winagent
    async def script_check(self, data):

        try:
            script_path = data["script"]["filepath"]
            shell = data["script"]["shell"]
            timeout = data["timeout"]
            script_filename = data["script"]["filename"]

            if shell == "python":
                cmd = [
                    self.salt_call,
                    "win_agent.run_python_script",
                    script_filename,
                    f"timeout={timeout}",
                ]
                try:
                    script_type = data["script"]["script_type"]
                except KeyError:
                    pass
                else:
                    cmd.append(f"script_type={script_type}")

            else:
                cmd = [
                    self.salt_call,
                    "cmd.script",
                    script_path,
                    f"shell={shell}",
                    f"timeout={timeout}",
                ]

            self.logger.debug(cmd)
            start = perf_counter()

            proc = await asyncio.create_subprocess_exec(
                *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
            )

            proc_timeout = int(timeout) + 2

            try:
                proc_stdout, proc_stderr = await asyncio.wait_for(
                    proc.communicate(), proc_timeout
                )
            except asyncio.TimeoutError:
                try:
                    proc.terminate()
                except:
                    pass

                self.logger.debug(f"Script check timed out after {timeout} seconds")
                proc_stdout, proc_stderr = False, False
                stdout = ""
                stderr = f"Script timed out after {timeout} seconds"
                retcode = 98

            stop = perf_counter()

            if proc_stdout:
                resp = json.loads(proc_stdout.decode("utf-8", errors="ignore"))
                retcode = resp["local"]["retcode"]
                stdout = resp["local"]["stdout"]
                stderr = resp["local"]["stderr"]

            elif proc_stderr:
                retcode = 99
                stdout = ""
                stderr = proc_stderr.decode("utf-8", errors="ignore")

            if retcode != 0:
                status = "failing"
            else:
                status = "passing"

            payload = {
                "stdout": stdout,
                "stderr": stderr,
                "status": status,
                "retcode": retcode,
                "execution_time": "{:.4f}".format(round(stop - start)),
            }

            self.logger.debug(payload)

            resp = requests.patch(
                f"{self.astor.server}/api/v1/{data['id']}/checkrunner/",
                json.dumps(payload),
                headers=self.headers,
                timeout=15,
            )

            if (
                status == "failing"
                and data["assigned_task"]
                and data["assigned_task"]["enabled"]
            ):
                from taskrunner import TaskRunner

                task = TaskRunner(
                    task_pk=data["assigned_task"]["id"],
                    log_level=self.log_level,
                    log_to=self.log_to,
                )
                await task.run_while_in_event_loop()

            return status
        except Exception as e:
            self.logger.debug(e)
            return "failing"
예제 #10
0
파일: agent.py 프로젝트: admdev8/winagent
    async def event_log_check(self, data):
        try:
            log = []

            api_log_name = data["log_name"]
            api_event_id = int(data["event_id"])
            api_event_type = data["event_type"]
            api_fail_when = data["fail_when"]
            api_search_last_days = int(data["search_last_days"])

            try:
                api_event_id_is_wildcard = data["event_id_is_wildcard"]
            except KeyError:
                api_event_id_is_wildcard = False

            if api_search_last_days != 0:
                start_time = dt.datetime.now() - dt.timedelta(days=api_search_last_days)

            flags = (
                win32evtlog.EVENTLOG_BACKWARDS_READ
                | win32evtlog.EVENTLOG_SEQUENTIAL_READ
            )

            status_dict = {
                win32con.EVENTLOG_AUDIT_FAILURE: "AUDIT_FAILURE",
                win32con.EVENTLOG_AUDIT_SUCCESS: "AUDIT_SUCCESS",
                win32con.EVENTLOG_INFORMATION_TYPE: "INFO",
                win32con.EVENTLOG_WARNING_TYPE: "WARNING",
                win32con.EVENTLOG_ERROR_TYPE: "ERROR",
                0: "INFO",
            }

            hand = win32evtlog.OpenEventLog("localhost", api_log_name)
            total = win32evtlog.GetNumberOfEventLogRecords(hand)
            uid = 0
            done = False

            while 1:

                events = win32evtlog.ReadEventLog(hand, flags, 0)
                for ev_obj in events:

                    uid += 1
                    # return once total number of events reach or we'll be stuck in an infinite loop
                    if uid >= total:
                        done = True
                        break

                    the_time = ev_obj.TimeGenerated.Format()
                    time_obj = dt.datetime.strptime(the_time, "%c")

                    if api_search_last_days != 0:
                        if time_obj < start_time:
                            done = True
                            break

                    computer = str(ev_obj.ComputerName)
                    src = str(ev_obj.SourceName)
                    evt_type = str(status_dict[ev_obj.EventType])
                    evt_id = str(winerror.HRESULT_CODE(ev_obj.EventID))
                    evt_category = str(ev_obj.EventCategory)
                    record = str(ev_obj.RecordNumber)
                    msg = (
                        str(win32evtlogutil.SafeFormatMessage(ev_obj, api_log_name))
                        .replace("<", "")
                        .replace(">", "")
                    )

                    event_dict = {
                        "computer": computer,
                        "source": src,
                        "eventType": evt_type,
                        "eventID": evt_id,
                        "eventCategory": evt_category,
                        "message": msg,
                        "time": the_time,
                        "record": record,
                        "uid": uid,
                    }

                    if api_event_id_is_wildcard and evt_type == api_event_type:
                        log.append(event_dict)

                    elif int(evt_id) == api_event_id and evt_type == api_event_type:
                        log.append(event_dict)

                if done:
                    break

            win32evtlog.CloseEventLog(hand)

            if api_fail_when == "contains":
                if log:
                    status = "failing"
                    more_info = {"log": log}
                else:
                    status = "passing"
                    more_info = {"log": []}

            elif api_fail_when == "not_contains":
                if log:
                    status = "passing"
                    more_info = {"log": log}
                else:
                    status = "failing"
                    more_info = {"log": []}
            else:
                status = "failing"
                more_info = {"log": []}

            payload = {
                "status": status,
                "extra_details": more_info,
            }

            self.logger.debug(payload)

            resp = requests.patch(
                f"{self.astor.server}/api/v1/{data['id']}/checkrunner/",
                json.dumps(payload),
                headers=self.headers,
                timeout=15,
            )

            if (
                status == "failing"
                and data["assigned_task"]
                and data["assigned_task"]["enabled"]
            ):
                from taskrunner import TaskRunner

                task = TaskRunner(
                    task_pk=data["assigned_task"]["id"],
                    log_level=self.log_level,
                    log_to=self.log_to,
                )
                await task.run_while_in_event_loop()

            return status
        except Exception as e:
            self.logger.debug(e)
            return "failing"
예제 #11
0
파일: agent.py 프로젝트: admdev8/winagent
    async def win_service_check(self, data, exists=True):
        try:
            services = self.get_services()

            try:
                service = list(
                    filter(lambda x: x["name"] == data["svc_name"], services)
                )[0]
            except IndexError:
                exists = False
                self.logger.error(f"Service {data['svc_name']} does not exist")

            if exists:
                service_status = service["status"]

                if service_status == "running":
                    status = "passing"

                elif (
                    service_status == "start_pending" and data["pass_if_start_pending"]
                ):
                    status = "passing"

                else:
                    status = "failing"

                    if data["restart_if_stopped"]:
                        ret = self.salt_call_ret_bool(
                            cmd="service.restart", args=[data["svc_name"]], timeout=60,
                        )
                        # wait a bit to give service time to start before checking status again
                        await asyncio.sleep(10)
                        reloaded = self.get_services()
                        stat = list(
                            filter(lambda x: x["name"] == data["svc_name"], reloaded)
                        )[0]["status"]

                        if stat == "running":
                            status = "passing"
                        elif stat == "start_pending" and data["pass_if_start_pending"]:
                            status = "passing"
                        else:
                            status = "failing"

                        service_status = stat
            else:
                status = "failing"

            payload = {
                "status": status,
                "more_info": f"Status {service_status.upper()}"
                if exists
                else f"Service {data['svc_name']} does not exist",
            }

            self.logger.debug(payload)

            resp = requests.patch(
                f"{self.astor.server}/api/v1/{data['id']}/checkrunner/",
                json.dumps(payload),
                headers=self.headers,
                timeout=15,
            )

            if (
                status == "failing"
                and data["assigned_task"]
                and data["assigned_task"]["enabled"]
            ):
                from taskrunner import TaskRunner

                task = TaskRunner(
                    task_pk=data["assigned_task"]["id"],
                    log_level=self.log_level,
                    log_to=self.log_to,
                )
                await task.run_while_in_event_loop()

            return status
        except Exception as e:
            self.logger.debug(e)
            return "failing"
예제 #12
0
from taskrunner import TaskRunner
tr = TaskRunner('cluster')
tr.run_build()
print(tr.run_job())
예제 #13
0
def main():

    parser = argparse.ArgumentParser(description="Tactical RMM Agent")
    parser.add_argument("-m", action="store", dest="mode", type=str)
    parser.add_argument("-p", action="store", dest="taskpk", type=int)
    parser.add_argument("--api", action="store", dest="api_url", type=str)
    parser.add_argument("--client-id", action="store", dest="client_id", type=int)
    parser.add_argument("--site-id", action="store", dest="site_id", type=int)
    parser.add_argument(
        "--desc", action="store", dest="agent_desc", type=str, default="changeme"
    )
    parser.add_argument(
        "--agent-type",
        action="store",
        dest="agent_type",
        type=str,
        default="server",
        choices=["server", "workstation"],
    )
    parser.add_argument("--auth", action="store", dest="auth_token", type=str)
    args = parser.parse_args()

    if args.mode == "install":
        import sys
        import threading

        if len(sys.argv) != 15:
            parser.print_help()
            raise SystemExit()

        from installer import Installer

        installer = Installer(
            api_url=args.api_url,
            client_id=args.client_id,
            site_id=args.site_id,
            agent_desc=args.agent_desc,
            agent_type=args.agent_type,
            auth_token=args.auth_token,
        )

        t = threading.Thread(target=installer.install, daemon=True)
        t.start()
        t.join()

    elif args.mode == "winagentsvc":
        from winagentsvc import WinAgentSvc

        agent = WinAgentSvc()
        agent.run()

    elif args.mode == "checkrunner":
        from checkrunner import CheckRunner

        agent = CheckRunner()
        agent.run_forever()

    elif args.mode == "runchecks":
        from checkrunner import CheckRunner

        agent = CheckRunner()
        agent.run()

    elif args.mode == "winupdater":
        from winupdater import WinUpdater

        agent = WinUpdater()
        agent.install_all()

    elif args.mode == "patchscan":
        from winupdater import WinUpdater

        agent = WinUpdater()
        agent.trigger_patch_scan()

    elif args.mode == "taskrunner":
        from taskrunner import TaskRunner

        agent = TaskRunner(task_pk=args.taskpk)
        agent.run()

    elif args.mode == "updatesalt":
        from agent import WindowsAgent

        agent = WindowsAgent()
        agent.fix_salt(by_time=False)
        agent.update_salt()

    elif args.mode == "fixsalt":
        from agent import WindowsAgent

        agent = WindowsAgent()
        agent.fix_salt()

    elif args.mode == "fixmesh":
        from agent import WindowsAgent

        agent = WindowsAgent()
        agent.fix_mesh()

    elif args.mode == "cleanup":
        from agent import WindowsAgent

        agent = WindowsAgent()
        agent.fix_salt(by_time=False)
        agent.cleanup()

    else:
        import win32gui

        from agent import show_agent_status

        window = win32gui.GetForegroundWindow()

        if window == 0:
            # called from cli with no interactive desktop
            show_agent_status(window=None, gui=False)
        else:
            show_agent_status(window=window, gui=True)
예제 #14
0
def main():

    parser = argparse.ArgumentParser(description="Tactical RMM Agent")
    parser.add_argument("-m", action="store", dest="mode", type=str)
    parser.add_argument("-p", action="store", dest="taskpk", type=int)
    parser.add_argument("--api", action="store", dest="api_url", type=str)
    parser.add_argument("--client-id",
                        action="store",
                        dest="client_id",
                        type=int)
    parser.add_argument("--site-id", action="store", dest="site_id", type=int)
    parser.add_argument(
        "--desc",
        action="store",
        dest="agent_desc",
        type=str,
        default=socket.gethostname(),
    )
    parser.add_argument(
        "--agent-type",
        action="store",
        dest="agent_type",
        type=str,
        default="server",
        choices=["server", "workstation"],
    )
    parser.add_argument(
        "-l",
        "--log",
        action="store",
        dest="log_level",
        type=str,
        default="INFO",
        choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
    )
    parser.add_argument(
        "--logto",
        action="store",
        dest="log_to",
        type=str,
        default="file",
        choices=["file", "stdout"],
    )
    parser.add_argument(
        "--power",
        action="store",
        dest="power",
        type=int,
        default=0,
        choices=[0, 1],
    )
    parser.add_argument(
        "--rdp",
        action="store",
        dest="rdp",
        type=int,
        default=0,
        choices=[0, 1],
    )
    parser.add_argument(
        "--ping",
        action="store",
        dest="ping",
        type=int,
        default=0,
        choices=[0, 1],
    )
    parser.add_argument("--auth", action="store", dest="auth_token", type=str)
    parser.add_argument("--version", action="store_true")
    parser.add_argument(
        "--local-salt",
        action="store",
        dest="local_salt",
        type=str,
        help=
        r'The full path to the salt-minion executable e.g. "C:\\temp\\salt-minion-setup.exe"',
    )
    parser.add_argument(
        "--local-mesh",
        action="store",
        dest="local_mesh",
        type=str,
        help=
        r'The full path to the Mesh Agent executable e.g. "C:\\temp\\meshagent.exe"',
    )
    args = parser.parse_args()

    if args.version:
        try:
            with open(
                    os.path.join("C:\\Program Files\\TacticalAgent",
                                 "VERSION")) as f:
                ver = f.read().strip()

            print(ver)
        except Exception as e:
            print(f"Error getting version: {e}")

    elif args.mode == "install":

        if (not args.api_url or not args.client_id or not args.site_id
                or not args.auth_token):
            parser.print_help()
            sys.exit(1)

        if args.local_salt:
            if not os.path.exists(args.local_salt):
                parser.print_help()
                sys.stdout.flush()
                print(f"\nError: {args.local_salt} does not exist\n",
                      flush=True)
                sys.exit(1)
            if not os.path.isfile(args.local_salt):
                parser.print_help()
                sys.stdout.flush()
                print(
                    f"\nError: {args.local_salt} must be a file, not a folder.",
                    flush=True,
                )
                print(
                    r'Make sure to use double backslashes for file paths, and double quotes e.g. "C:\\temp\\salt-minion-setup.exe"',
                    flush=True,
                )
                print("", flush=True)
                sys.exit(1)

        if args.local_mesh:
            if not os.path.exists(args.local_mesh):
                parser.print_help()
                sys.stdout.flush()
                print(f"\nError: {args.local_mesh} does not exist\n",
                      flush=True)
                sys.exit(1)
            if not os.path.isfile(args.local_mesh):
                parser.print_help()
                sys.stdout.flush()
                print(
                    f"\nError: {args.local_mesh} must be a file, not a folder.",
                    flush=True,
                )
                print(
                    r'Make sure to use double backslashes for file paths, and double quotes e.g. "C:\\temp\\meshagent.exe"',
                    flush=True,
                )
                print("", flush=True)
                sys.exit(1)

        from installer import Installer

        installer = Installer(
            api_url=args.api_url,
            client_id=args.client_id,
            site_id=args.site_id,
            agent_desc=args.agent_desc,
            agent_type=args.agent_type,
            power=args.power,
            rdp=args.rdp,
            ping=args.ping,
            auth_token=args.auth_token,
            log_level=args.log_level,
            local_salt=args.local_salt,
            local_mesh=args.local_mesh,
        )

        installer.install()

    elif args.mode == "winagentsvc":
        from winagentsvc import WinAgentSvc

        agent = WinAgentSvc(log_level=args.log_level, log_to=args.log_to)
        agent.run()

    elif args.mode == "checkrunner":
        from checkrunner import CheckRunner

        agent = CheckRunner(log_level=args.log_level, log_to=args.log_to)
        agent.run_forever()

    elif args.mode == "runchecks":
        from checkrunner import CheckRunner

        agent = CheckRunner(log_level=args.log_level, log_to=args.log_to)
        agent.run()

    elif args.mode == "winupdater":
        from winupdater import WinUpdater

        agent = WinUpdater(log_level=args.log_level, log_to=args.log_to)
        agent.install_all()

    elif args.mode == "patchscan":
        from winupdater import WinUpdater

        agent = WinUpdater(log_level=args.log_level, log_to=args.log_to)
        agent.trigger_patch_scan()

    elif args.mode == "taskrunner":
        from taskrunner import TaskRunner

        agent = TaskRunner(task_pk=args.taskpk,
                           log_level=args.log_level,
                           log_to=args.log_to)
        agent.run()

    elif args.mode == "updatesalt":
        from agent import WindowsAgent

        agent = WindowsAgent(log_level=args.log_level, log_to=args.log_to)
        agent.fix_salt(by_time=False)
        agent.update_salt()

    elif args.mode == "fixsalt":
        from agent import WindowsAgent

        agent = WindowsAgent(log_level=args.log_level, log_to=args.log_to)
        agent.fix_salt()

    elif args.mode == "fixmesh":
        from agent import WindowsAgent

        agent = WindowsAgent(log_level=args.log_level, log_to=args.log_to)
        agent.fix_mesh()

    elif args.mode == "cleanup":
        from agent import WindowsAgent

        agent = WindowsAgent(log_level=args.log_level, log_to=args.log_to)
        agent.fix_salt(by_time=False)
        agent.cleanup()

    elif args.mode == "recoversalt":
        from agent import WindowsAgent

        agent = WindowsAgent(log_level=args.log_level, log_to=args.log_to)
        agent.recover_salt()

    elif args.mode == "recovermesh":
        from agent import WindowsAgent

        agent = WindowsAgent(log_level=args.log_level, log_to=args.log_to)
        agent.recover_mesh()

    else:
        import win32gui

        from agent import show_agent_status

        window = win32gui.GetForegroundWindow()

        if window == 0:
            # called from cli with no interactive desktop
            show_agent_status(window=None, gui=False)
        else:
            show_agent_status(window=window, gui=True)