如何使用 Python 和 win32com 访问 Windows 调度程序 "Actions"

How to access Windows Scheduler "Actions" with Python and win32com

我正在尝试获取 Windows 调度程序中任务的操作。 Eryk Sun 的优秀代码片段 is "almost" enough to get me the action associated with the task, but I'm stumped trying to interpret Microsofts documentation https://docs.microsoft.com/en-us/windows/win32/api/taskschd/ 并将其翻译成 win32com.client 会接受的内容。 我可以提取的示例:

 import win32com.client
 scheduler = win32com.client.Dispatch('Schedule.Service')
 scheduler.Connect()
 folders = [scheduler.GetFolder('\')]
 while folders:
    folder = folders.pop(0)
    folders += list(folder.GetFolders(0))
    for task in folder.GetTasks(0):
        print('Name       : %s' % task.Name)
        print('Path       : %s' % task.Path)
        print('Last Run   : %s' % task.LastRunTime)
        print('Last Result: %s\n' % task.LastTaskResult)

我缺少的是如何获取与每个任务关联的“操作”

还有几个要跳过的箍。 MS 文档 link 包含所有信息,但有点简洁。您还必须比平时更深入地了解 win32com。

GetTasks(0)returns一个IRegisteredTask接口,它本身有一个属性Definition那个returns一个ITaskDefinition接口.此 returns 的 Actions 属性 一个 IActionsCollection 接口是 IAction 接口的集合。呸!

不幸的是,IAction 是一个基础 class,除了告诉您操作的 Type 之外,它没有做太多事情。派生接口有4种类型,最常见的是IExecAction,然后是IComHandlerActionIEmailActionIShowMessageAction。后两个好像在我的系统上没有用到,所以没测试过。

下一步取决于你如何使用win32com.client:早 绑定 (win32com.client.gencache.EnsureDispatch()) 或后期绑定 (win32com.client.dynamic.Dispatch()).

如果你使用early-binding,你需要cast IAction 接口到由Type (使用 win32com.client.CastTo())。如果您使用 late-binding,那么您只需调用 type-specific 方法并希望获得最佳结果。我个人的偏好是 early-binding,因为它强制执行更多 type-safety,并允许您使用常量定义而不是 magic numbers

Early-binding代码:

import win32com.client

scheduler = win32com.client.gencache.EnsureDispatch('Schedule.Service')

def PrintAction(action):
    ty = action.Type

    if ty == win32com.client.constants.TASK_ACTION_COM_HANDLER: #=5
        print("COM Handler Action")
        coma = win32com.client.CastTo(action,"IComHandlerAction")
        print(coma.ClassId,coma.Data)
    elif ty == win32com.client.constants.TASK_ACTION_EXEC: #=0
        print("Exec Action")
        execa = win32com.client.CastTo(action,"IExecAction")
        print(execa.Path,execa.Arguments)
    elif ty == win32com.client.constants.TASK_ACTION_SEND_EMAIL: #=6 This might not work
        print("Send Email Action") 
        maila = win32com.client.CastTo(action,"IEmailAction")
        print(maila.Subject,maila.To)
    elif ty == win32com.client.constants.TASK_ACTION_SHOW_MESSAGE: #=7
        print("Show Message Action")
        showa = win32com.client.CastTo(action,"IShowMessageAction")
        print(showa.Title,showa.MessageBody)
    else:
        print("Unknown Action Type!") #Don't expect this


scheduler.Connect()
folders = [scheduler.GetFolder('\')]
while folders:
    folder = folders.pop(0)
    folders += list(folder.GetFolders(0))
    for task in folder.GetTasks(0):
        print('Name       : %s' % task.Name)
        print('Path       : %s' % task.Path)
        print('Last Run   : %s' % task.LastRunTime)
        print('Last Result: %s' % task.LastTaskResult)
        defn = task.Definition
        actions = defn.Actions
        for action in actions:
            PrintAction(action)
            print()

Late-binding代码:

以不同方式创建 scheduler 对象,并替换 PrintAction() 函数:

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

def PrintAction(action):
    ty = action.Type

    if ty == 5: 
        print("COM Handler Action")
        print(action.ClassId,action.Data)
    elif ty == 0: 
        print("Exec Action")
        print(action.Path,action.Arguments)
    elif ty == 6: # This might not work
        print("Send Email Action") 
        print(action.Subject,action.To)
    elif ty == 7: 
        print("Show Message Action")
        print(action.Title,action.MessageBody)
    else:
        print("Unknown Action Type!")

其中一个输出条目为例:

Name       : Retry
Path       : \Microsoft\Windows\Management\Provisioning\Retry
Last Run   : 1999-11-30 00:00:00+00:00
Last Result: 267011
Exec Action
%windir%\system32\ProvTool.exe /turn 5 /source ProvRetryTask