Reputation: 279
I'm trying to get the action(s) for the tasks in the Windows Scheduler. Eryk Sun's excellent code snippet Python check for Completed and failed Task Windows scheduler is "almost" enough to get me the action associated with the task, but I'm stumped trying to interpret Microsofts documentation https://learn.microsoft.com/en-us/windows/win32/api/taskschd/ and translate it into something win32com.client will accept. A sample of what I can extract:
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)
What I'm missing is how to get the "Actions" associated with each task
Upvotes: 2
Views: 2746
Reputation: 4261
There are few more hoops to jump through. The MS documentation link has all the information, but it's a little terse. You also have to dig a bit deeper into win32com than usual.
GetTasks(0)
returns an IRegisteredTask
interface, which itself has a property Definition
that returns an ITaskDefinition
interface. The Actions
property of this returns an IActionsCollection
interface which is a collection of IAction
interfaces. Phew!
Unfortunately, IAction is a base class which doesn't do much except tell you the Type
of the action. There are 4 types of derived interface, the most common of which is IExecAction
, then IComHandlerAction
, IEmailAction
and IShowMessageAction
. The last two don't seem to be used on my system, so I haven't tested them.
The next step depends on how you use win32com.client
: early
binding (win32com.client.gencache.EnsureDispatch()
) or late binding (win32com.client.dynamic.Dispatch()
).
If you use early-binding, you need to cast the IAction interface to the particular action interface given by Type (using win32com.client.CastTo()
). If you use late-binding, then you just call the type-specific method and hope for the best. My personal preference is for early-binding, as it enforces more type-safety, and allows you to use constant definitions rather than magic numbers
.
Early-binding code:
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 code:
Create the scheduler
object differently, and replace the PrintAction()
function:
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!")
One of the output entries as an example:
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
Upvotes: 4