Merge pull request #27958 from twangboy/update_win_task

Added new functionality to win_task.py
This commit is contained in:
Mike Place 2015-10-15 06:30:31 -06:00
commit 6624ec1f48

View file

@ -15,6 +15,7 @@ from __future__ import absolute_import
import salt.utils
from datetime import datetime
import logging
import time
# Import 3rd Party Libraries
import pythoncom
@ -67,7 +68,14 @@ TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD = 6
TASK_RUNLEVEL_LUA = 0
TASK_RUNLEVEL_HIGHEST = 1
# TASK_TRIGGER_TYPE2
# TASK_STATE_TYPE
TASK_STATE_UNKNOWN = 0
TASK_STATE_DISABLED = 1
TASK_STATE_QUEUED = 2
TASK_STATE_READY = 3
TASK_STATE_RUNNING = 4
# TASK_TRIGGER_TYPE
TASK_TRIGGER_EVENT = 0
TASK_TRIGGER_TIME = 1
TASK_TRIGGER_DAILY = 2
@ -105,6 +113,33 @@ action_types = {'Execute': TASK_ACTION_EXEC,
'Email': TASK_ACTION_SEND_EMAIL,
'Message': TASK_ACTION_SHOW_MESSAGE}
states = {TASK_STATE_UNKNOWN: 'Unknown',
TASK_STATE_DISABLED: 'Disabled',
TASK_STATE_QUEUED: 'Queued',
TASK_STATE_READY: 'Ready',
TASK_STATE_RUNNING: 'Running'}
instances = {'Parallel': TASK_INSTANCES_PARALLEL,
'Queue': TASK_INSTANCES_QUEUE,
'No New Instance': TASK_INSTANCES_IGNORE_NEW,
'Stop Existing': TASK_INSTANCES_STOP_EXISTING}
results = {0x0: 'The operation completed successfully',
0x1: 'Incorrect or unknown function called',
0x2: 'File not found',
0xA: 'The environment is incorrect',
0x41300: 'Task is ready to run at its next scheduled time',
0x41301: 'Task is currently running',
0x41302: 'Task is disabled',
0x41303: 'Task has not yet run',
0x41304: 'There are no more runs scheduled for this task',
0x41306: 'Task was terminated by the user',
0x8004130F: 'Credentials became corrupted',
0x8004131F: 'An instance of this task is already running',
0x800704DD: 'The service is not available (Run only when logged in?)',
0xC000013A: 'The application terminated as a result of CTRL+C',
0xC06D007E: 'Unknown software exception'}
def __virtual__():
'''
@ -148,6 +183,37 @@ def _get_date_time_format(dt_string):
return False
def _get_date_value(date):
'''
Function for dealing with PyTime values with invalid dates. ie: 12/30/1899
which is the windows task scheduler value for Never
:param obj date: A PyTime object
:return: A string value representing the date or the word "Never" for
invalid date strings
:rtype: str
'''
try:
return '{0}'.format(date)
except ValueError:
return 'Never'
def _reverse_lookup(dictionary, value):
'''
Lookup the key in a dictionary by it's value. Will return the first match.
:param dict dictionary: The dictionary to search
:param str value: The value to search for.
:return: Returns the first key to match the value
:rtype: str
'''
return dictionary.keys()[dictionary.values().index(value)]
def _save_task_definition(name,
task_folder,
task_definition,
@ -687,12 +753,6 @@ def edit_task(name=None,
'''
# TODO: Add more detailed return for items changed
# Define Lookup Dictionaries
instances = {'Parallel': TASK_INSTANCES_PARALLEL,
'Queue': TASK_INSTANCES_QUEUE,
'No New Instance': TASK_INSTANCES_IGNORE_NEW,
'Stop Existing': TASK_INSTANCES_STOP_EXISTING}
# Check for passed task_definition
# If not passed, open a task definition for an existing task
save_definition = False
@ -953,6 +1013,211 @@ def run(name, location='\\'):
return False
def run_wait(name, location='\\'):
r'''
Run a scheduled task and return when the task finishes
:param str name: The name of the task to run.
:param str location: A string value representing the location of the task.
Default is '\\' which is the root for the task scheduler
(C:\Windows\System32\tasks).
:return: True if successful, False if unsuccessful
:rtype: bool
'''
# Check for existing folder
if name not in list_tasks(location):
return '{0} not found in {1}'.format(name, location)
# connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to delete the folder from
task_folder = task_service.GetFolder(location)
task = task_folder.GetTask(name)
# Is the task already running
if task.State == TASK_STATE_RUNNING:
return 'Task already running'
try:
task.Run('')
time.sleep(1)
running = True
except pythoncom.com_error:
return False
while running:
running = False
running_tasks = task_service.GetRunningTasks(0)
if running_tasks.Count:
for item in running_tasks:
if item.Name == name:
running = True
else:
running = False
return True
def stop(name, location='\\'):
r'''
Stop a scheduled task.
:param str name: The name of the task to stop.
:param str location: A string value representing the location of the task.
Default is '\\' which is the root for the task scheduler
(C:\Windows\System32\tasks).
:return: True if successful, False if unsuccessful
:rtype: bool
'''
# Check for existing folder
if name not in list_tasks(location):
return '{0} not found in {1}'.format(name, location)
# connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to delete the folder from
task_folder = task_service.GetFolder(location)
task = task_folder.GetTask(name)
try:
task.Stop(0)
return True
except pythoncom.com_error as error:
return False
def status(name, location='\\'):
r'''
Determine the status of a task. Is it Running, Queued, Ready, etc.
:param str name: The name of the task for which to return the status
:param str location: A string value representing the location of the task.
Default is '\\' which is the root for the task scheduler
(C:\Windows\System32\tasks).
:return: The current status of the task. Will be one of the following:
- Unknown
- Disabled
- Queued
- Ready
- Running
:rtype: string
'''
# Check for existing folder
if name not in list_tasks(location):
return '{0} not found in {1}'.format(name, location)
# connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to delete the folder from
task_folder = task_service.GetFolder(location)
task = task_folder.GetTask(name)
return states[task.State]
def info(name, location='\\'):
r'''
Get the details about a task in the task scheduler.
:param str name: The name of the task for which to return the status
:param str location: A string value representing the location of the task.
Default is '\\' which is the root for the task scheduler
(C:\Windows\System32\tasks).
:return:
:rtype: dict
'''
# Check for existing folder
if name not in list_tasks(location):
return '{0} not found in {1}'.format(name, location)
# connect to the task scheduler
pythoncom.CoInitialize()
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to delete the folder from
task_folder = task_service.GetFolder(location)
task = task_folder.GetTask(name)
properties = {'enabled': task.Enabled,
'last_run': _get_date_value(task.LastRunTime),
'last_run_result': results[task.LastTaskResult],
'missed_runs': task.NumberOfMissedRuns,
'next_run': _get_date_value(task.NextRunTime),
'status': states[task.State]}
def_set = task.Definition.Settings
settings = {}
settings['allow_demand_start'] = def_set.AllowDemandStart
settings['force_stop'] = def_set.AllowHardTerminate
if def_set.DeleteExpiredTaskAfter == '':
settings['delete_after'] = False
elif def_set.DeleteExpiredTaskAfter == 'PT0S':
settings['delete_after'] = 'Immediately'
else:
settings['delete_after'] = _reverse_lookup(duration, def_set.DeleteExpiredTaskAfter)
if def_set.ExecutionTimeLimit == '':
settings['execution_time_limit'] = False
else:
settings['execution_time_limit'] = _reverse_lookup(duration, def_set.ExecutionTimeLimit)
settings['multiple_instances'] = _reverse_lookup(instances, def_set.MultipleInstances)
if def_set.RestartInterval == '':
settings['restart_interval'] = False
else:
settings['restart_interval'] = _reverse_lookup(duration, def_set.RestartInterval)
if settings['restart_interval']:
settings['restart_count'] = def_set.RestartCount
settings['stop_if_on_batteries'] = def_set.StopIfGoingOnBatteries
settings['wake_to_run'] = def_set.WakeToRun
conditions = {}
conditions['ac_only'] = def_set.DisallowStartIfOnBatteries
conditions['run_if_idle'] = def_set.RunOnlyIfIdle
conditions['run_if_network'] = def_set.RunOnlyIfNetworkAvailable
conditions['start_when_available'] = def_set.StartWhenAvailable
if conditions['run_if_idle']:
idle_set = def_set.IdleSettings
conditions['idle_duration'] = idle_set.IdleDuration
conditions['idle_restart'] = idle_set.RestartOnIdle
conditions['idle_stop_on_end'] = idle_set.StopOnIdleEnd
conditions['idle_wait_timeout'] = idle_set.WaitTimeout
if conditions['run_if_network']:
net_set = def_set.NetworkSettings
conditions['network_id'] = net_set.Id
conditions['network_name'] = net_set.Name
properties['settings'] = settings
properties['conditions'] = conditions
ret = properties
return ret
def add_action(name=None,
location='\\',
action_type='Execute',