Как получить задачи из планировщика windows?

Поиск информации о планировщике показал, что есть следующие места, откуда можно получить задачи:

  • Как файлы:
    • C:\Windows\Tasks, задачи описывались в бинарных файлах .job (до Windows Vista, соответствует Task Scheduler 1.0)
    • C:\Windows\System32\Tasks, там каждая задача описывается в виде XML (появилось начиная с Windows Vista, соответствует Task Scheduler 2.0)
  • В реестре:
    • HKLM\Software\Microsoft\Windows NT\CurrentVersion\Schedule\Taskcache
  • Из утилит:
  • API:
    • COM-объекты
    • WMI

Возможно, есть и другие способы получить задачи планировщика.

Как видно, вариантов достаточно и мне показался привлекательным с COM-объектами, хотя и другие варианты тоже могут быть использованы.

Как на python получить список задач планировщика?


Ответы (1 шт):

Автор решения: gil9red

Текущий способ использует API для работы с COM-объектами, а конкретно с Schedule.Service

Источники:

Внешние зависимости:

  • Модуль win32com.client, устанавливать библиотеку pywin32

Остались, правда, некоторые непонятные моменты с полями EmailAction: attachments и header_fields, что усложняется тем, что это действие запрещено (для отправки почты рекомендуется использовать, например, ExecAction с скриптом на VBS или PowerShell).

Реализация:

import datetime as DT
import enum
from dataclasses import dataclass, field
from typing import List, TypeVar

import win32com.client


TASK_ENUM_HIDDEN = 1


class TaskStateEnum(enum.IntEnum):
    Unknown = 0
    Disabled = enum.auto()
    Queued = enum.auto()
    Ready = enum.auto()
    Running = enum.auto()


class TaskActionEnum(enum.IntEnum):
    Exec = 0
    ComHandler = 5
    SendEmail = 6
    ShowMessage = 7


@dataclass
class ExecAction:
    path: str
    working_directory: str
    arguments: str

    @classmethod
    def get_from(cls, action: win32com.client.CDispatch) -> 'ExecAction':
        return cls(
            path=action.Path,
            working_directory=action.WorkingDirectory,
            arguments=action.Arguments,
        )


@dataclass
class ComHandlerAction:
    class_id: str
    data: str

    @classmethod
    def get_from(cls, action: win32com.client.CDispatch) -> 'ComHandlerAction':
        return cls(
            class_id=action.ClassId,
            data=action.Data,
        )


@dataclass
class EmailAction:
    from_: str
    to: str
    subject: str
    body: str
    server: str
    # attachments: ???  # TODO: Unknown
    bcc: str
    cc: str
    # header_fields: ???  # TODO: Unknown
    reply_to: str

    @classmethod
    def get_from(cls, action: win32com.client.CDispatch) -> 'EmailAction':
        return cls(
            from_=action.From,
            to=action.To,
            subject=action.Subject,
            body=action.Body,
            server=action.Server,
            # attachments=???  # TODO: Unknown
            bcc=action.Bcc,
            cc=action.Cc,
            # header_fields=xxx,  # TODO: Unknown
            reply_to=action.ReplyTo,
        )


@dataclass
class ShowMessageAction:
    title: str
    message_body: str

    @classmethod
    def get_from(cls, action: win32com.client.CDispatch) -> 'ShowMessageAction':
        return cls(
            title=action.Title,
            message_body=action.MessageBody,
        )


ActionType = TypeVar('ActionType', ExecAction, ComHandlerAction, EmailAction, ShowMessageAction)


@dataclass
class Task:
    name: str
    path: str
    hidden: bool
    state: str
    enabled: bool
    last_run_time: DT.datetime
    last_task_result: int
    next_run_time: DT.datetime
    number_of_missed_runs: int
    actions: List[ActionType] = field(default_factory=list)

    @classmethod
    def get_from(cls, task: win32com.client.CDispatch) -> 'Task':
        try:
            hidden = task.Definition.Settings.Hidden
        except:
            hidden = False

        try:
            def_actions = task.Definition.Actions
        except:
            def_actions = []

        actions = []

        for action_com_obj in def_actions:
            action_type = TaskActionEnum(action_com_obj.Type)

            if action_type == TaskActionEnum.Exec:
                actions.append(ExecAction.get_from(action_com_obj))
            elif action_type == TaskActionEnum.ComHandler:
                actions.append(ComHandlerAction.get_from(action_com_obj))
            elif action_type == TaskActionEnum.SendEmail:
                actions.append(EmailAction.get_from(action_com_obj))
            elif action_type == TaskActionEnum.ShowMessage:
                actions.append(ShowMessageAction.get_from(action_com_obj))

        return cls(
            name=task.Name,
            path=task.Path,
            hidden=hidden,
            state=TaskStateEnum(task.State).name,
            enabled=task.Enabled,
            last_run_time=task.LastRunTime,
            last_task_result=task.LastTaskResult,
            next_run_time=task.NextRunTime,
            number_of_missed_runs=task.NumberOfMissedRuns,
            actions=actions,
        )


def get_tasks() -> List[Task]:
    items = []

    scheduler = win32com.client.Dispatch('Schedule.Service')
    scheduler.Connect()

    folders = [scheduler.GetFolder('\\')]
    while folders:
        folder = folders.pop(0)
        folders += list(folder.GetFolders(0))
        for task_com_obj in folder.GetTasks(TASK_ENUM_HIDDEN):
            items.append(
                Task.get_from(task_com_obj)
            )

    return items

Проверка:

items = get_tasks()
print(f'Total task: {len(items)}')

hidden_tasks = [task for task in items if task.hidden]
print(f'Total hidden tasks: {len(hidden_tasks)}')

enabled_tasks = [task for task in items if task.enabled]
print(f'Total enabled tasks: {len(enabled_tasks)}')

hidden_and_enabled_tasks = [task for task in items if task.hidden and task.enabled]
print(f'Total hidden and enabled tasks: {len(hidden_and_enabled_tasks)}')

print()

print('First 10 tasks:')
for i, task in enumerate(items[:10], 1):
    print(f'    {i}. {task}')

Результат:

Total task: 152
Total hidden tasks: 36
Total enabled tasks: 121
Total hidden and enabled tasks: 27

First 10 tasks:
    1. Task(name='Adobe Acrobat Update Task', path='\\Adobe Acrobat Update Task', hidden=False, state='Ready', enabled=True, last_run_time=pywintypes.datetime(2022, 2, 16, 10, 48, 56, tzinfo=TimeZoneInfo('GMT Standard Time', True)), last_task_result=0, next_run_time=pywintypes.datetime(2022, 2, 16, 22, 0, tzinfo=TimeZoneInfo('GMT Standard Time', True)), number_of_missed_runs=0, actions=[ExecAction(path='C:\\Program Files (x86)\\Common Files\\Adobe\\ARM\\1.0\\AdobeARM.exe', working_directory='', arguments='')])
    2. Task(name='OneDrive Reporting Task-S-1-5-21-3234346791-3903088639-3192236989-5129', path='\\OneDrive Reporting Task-S-1-5-21-3234346791-3903088639-3192236989-5129', hidden=False, state='Ready', enabled=True, last_run_time=pywintypes.datetime(2022, 2, 15, 20, 35, 18, tzinfo=TimeZoneInfo('GMT Standard Time', True)), last_task_result=0, next_run_time=pywintypes.datetime(2022, 2, 16, 20, 35, 18, tzinfo=TimeZoneInfo('GMT Standard Time', True)), number_of_missed_runs=0, actions=[ExecAction(path='%localappdata%\\Microsoft\\OneDrive\\OneDriveStandaloneUpdater.exe', working_directory='', arguments='/reporting')])
    3. Task(name='OneDrive Standalone Update Task-S-1-5-21-3234346791-3903088639-3192236989-5129', path='\\OneDrive Standalone Update Task-S-1-5-21-3234346791-3903088639-3192236989-5129', hidden=False, state='Ready', enabled=True, last_run_time=pywintypes.datetime(2022, 2, 15, 19, 58, 47, tzinfo=TimeZoneInfo('GMT Standard Time', True)), last_task_result=-2147160572, next_run_time=pywintypes.datetime(2022, 2, 16, 22, 46, 49, tzinfo=TimeZoneInfo('GMT Standard Time', True)), number_of_missed_runs=0, actions=[ExecAction(path='%localappdata%\\Microsoft\\OneDrive\\OneDriveStandaloneUpdater.exe', working_directory='', arguments='')])
    4. Task(name='RtkAudUService64_BG', path='\\RtkAudUService64_BG', hidden=False, state='Running', enabled=True, last_run_time=pywintypes.datetime(2022, 2, 10, 11, 7, 26, tzinfo=TimeZoneInfo('GMT Standard Time', True)), last_task_result=267009, next_run_time=pywintypes.datetime(1899, 12, 30, 0, 0, tzinfo=TimeZoneInfo('GMT Standard Time', True)), number_of_missed_runs=0, actions=[ExecAction(path='""C:\\Windows\\System32\\DriverStore\\FileRepository\\realtekservice.inf_amd64_63ffa3cb4ae6dbc0\\RtkAudUService64.exe""', working_directory='', arguments='-background')])
    5. Task(name='RunUninstallTool_SkipUac', path='\\RunUninstallTool_SkipUac', hidden=False, state='Ready', enabled=True, last_run_time=pywintypes.datetime(2022, 1, 10, 12, 20, 44, tzinfo=TimeZoneInfo('GMT Standard Time', True)), last_task_result=0, next_run_time=pywintypes.datetime(1899, 12, 30, 0, 0, tzinfo=TimeZoneInfo('GMT Standard Time', True)), number_of_missed_runs=0, actions=[ExecAction(path='C:\\Program Files\\Uninstall Tool\\UninstallTool.exe', working_directory='', arguments='$(Arg0)')])
    6. Task(name='Firefox Default Browser Agent 308046B0AF4A39CB', path='\\Mozilla\\Firefox Default Browser Agent 308046B0AF4A39CB', hidden=False, state='Ready', enabled=True, last_run_time=pywintypes.datetime(2022, 2, 16, 11, 8, 43, tzinfo=TimeZoneInfo('GMT Standard Time', True)), last_task_result=0, next_run_time=pywintypes.datetime(2022, 2, 17, 11, 8, 42, tzinfo=TimeZoneInfo('GMT Standard Time', True)), number_of_missed_runs=0, actions=[ExecAction(path='C:\\Program Files\\Mozilla Firefox\\default-browser-agent.exe', working_directory='', arguments='do-task "308046B0AF4A39CB"')])
    7. Task(name='S-1-5-21-3234346791-3903088639-3192236989-5129', path='\\Lenovo\\Lenovo Service Bridge\\S-1-5-21-3234346791-3903088639-3192236989-5129', hidden=False, state='Ready', enabled=True, last_run_time=pywintypes.datetime(2022, 2, 16, 11, 11, 56, tzinfo=TimeZoneInfo('GMT Standard Time', True)), last_task_result=0, next_run_time=pywintypes.datetime(1899, 12, 30, 0, 0, tzinfo=TimeZoneInfo('GMT Standard Time', True)), number_of_missed_runs=0, actions=[ExecAction(path='"C:\\Users\\<...>\\AppData\\Local\\Programs\\Lenovo\\Lenovo Service Bridge\\LSBUpdater.exe"', working_directory='', arguments='')])
    8. Task(name='Background monitor', path='\\Lenovo\\Power Manager\\Background monitor', hidden=False, state='Running', enabled=True, last_run_time=pywintypes.datetime(2022, 2, 10, 11, 6, 56, tzinfo=TimeZoneInfo('GMT Standard Time', True)), last_task_result=267009, next_run_time=pywintypes.datetime(1899, 12, 30, 0, 0, tzinfo=TimeZoneInfo('GMT Standard Time', True)), number_of_missed_runs=0, actions=[ExecAction(path='"C:\\Windows\\SysWOW64\\Lenovo\\PowerMgr\\PowerMgr.exe"', working_directory='', arguments='')])
    9. Task(name='Office 15 Subscription Heartbeat', path='\\Microsoft\\Office\\Office 15 Subscription Heartbeat', hidden=False, state='Ready', enabled=True, last_run_time=pywintypes.datetime(2022, 2, 16, 2, 52, 14, tzinfo=TimeZoneInfo('GMT Standard Time', True)), last_task_result=0, next_run_time=pywintypes.datetime(2022, 2, 17, 0, 42, 32, tzinfo=TimeZoneInfo('GMT Standard Time', True)), number_of_missed_runs=0, actions=[ExecAction(path='%ProgramFiles%\\Common Files\\Microsoft Shared\\Office16\\OLicenseHeartbeat.exe', working_directory='', arguments='')])
    10. Task(name='OfficeTelemetryAgentFallBack2016', path='\\Microsoft\\Office\\OfficeTelemetryAgentFallBack2016', hidden=False, state='Ready', enabled=True, last_run_time=pywintypes.datetime(2022, 2, 15, 23, 36, 56, tzinfo=TimeZoneInfo('GMT Standard Time', True)), last_task_result=0, next_run_time=pywintypes.datetime(1899, 12, 30, 0, 0, tzinfo=TimeZoneInfo('GMT Standard Time', True)), number_of_missed_runs=0, actions=[ExecAction(path='"C:\\Program Files\\Microsoft Office\\Office16\\msoia.exe"', working_directory='', arguments='scan upload mininterval:2880')])
→ Ссылка