forked from saltstack/salt
/
win_task.py
2190 lines (1735 loc) · 70.1 KB
/
win_task.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa383608(v=vs.85).aspx
'''
Windows Task Scheduler Module
.. versionadded:: 2016.3.0
A module for working with the Windows Task Scheduler.
You can add and edit existing tasks.
You can add and clear triggers and actions.
You can list all tasks, folders, triggers, and actions.
'''
# Import Python libs
from __future__ import absolute_import, unicode_literals, print_function
import logging
import time
from datetime import datetime
# Import Salt libs
import salt.utils.platform
import salt.utils.winapi
# Import 3rd-party libraries
try:
import pythoncom
import win32com.client
HAS_DEPENDENCIES = True
except ImportError:
HAS_DEPENDENCIES = False
from salt.ext.six.moves import range
log = logging.getLogger(__name__)
# Define the module's virtual name
__virtualname__ = 'task'
# Define Constants
# TASK_ACTION_TYPE
TASK_ACTION_EXEC = 0
TASK_ACTION_COM_HANDLER = 5
TASK_ACTION_SEND_EMAIL = 6
TASK_ACTION_SHOW_MESSAGE = 7
# TASK_COMPATIBILITY
TASK_COMPATIBILITY_AT = 0
TASK_COMPATIBILITY_V1 = 1
TASK_COMPATIBILITY_V2 = 2
TASK_COMPATIBILITY_V3 = 3
# TASK_CREATION
TASK_VALIDATE_ONLY = 0x1
TASK_CREATE = 0x2
TASK_UPDATE = 0x4
TASK_CREATE_OR_UPDATE = 0x6
TASK_DISABLE = 0x8
TASK_DONT_ADD_PRINCIPAL_ACE = 0x10
TASK_IGNORE_REGISTRATION_TRIGGERS = 0x20
# TASK_INSTANCES_POLICY
TASK_INSTANCES_PARALLEL = 0
TASK_INSTANCES_QUEUE = 1
TASK_INSTANCES_IGNORE_NEW = 2
TASK_INSTANCES_STOP_EXISTING = 3
# TASK_LOGON_TYPE
TASK_LOGON_NONE = 0
TASK_LOGON_PASSWORD = 1
TASK_LOGON_S4U = 2
TASK_LOGON_INTERACTIVE_TOKEN = 3
TASK_LOGON_GROUP = 4
TASK_LOGON_SERVICE_ACCOUNT = 5
TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD = 6
# TASK_RUNLEVEL_TYPE
TASK_RUNLEVEL_LUA = 0
TASK_RUNLEVEL_HIGHEST = 1
# 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
TASK_TRIGGER_WEEKLY = 3
TASK_TRIGGER_MONTHLY = 4
TASK_TRIGGER_MONTHLYDOW = 5
TASK_TRIGGER_IDLE = 6
TASK_TRIGGER_REGISTRATION = 7
TASK_TRIGGER_BOOT = 8
TASK_TRIGGER_LOGON = 9
TASK_TRIGGER_SESSION_STATE_CHANGE = 11
duration = {'Immediately': 'PT0M',
'Indefinitely': 'PT0M',
'Do not wait': 'PT0M',
'30 seconds': 'PT30S',
'1 minute': 'PT1M',
'5 minutes': 'PT5M',
'10 minutes': 'PT10M',
'15 minutes': 'PT15M',
'30 minutes': 'PT30M',
'1 hour': 'PT1H',
'2 hours': 'PT2H',
'4 hours': 'PT4H',
'8 hours': 'PT8H',
'12 hours': 'PT12H',
'1 day': ['P1D', 'PT24H'],
'3 days': ['P3D', 'PT72H'],
'30 days': 'P30D',
'90 days': 'P90D',
'180 days': 'P180D',
'365 days': 'P365D'}
action_types = {'Execute': TASK_ACTION_EXEC,
'Email': TASK_ACTION_SEND_EMAIL,
'Message': TASK_ACTION_SHOW_MESSAGE}
trigger_types = {'Event': TASK_TRIGGER_EVENT,
'Once': TASK_TRIGGER_TIME,
'Daily': TASK_TRIGGER_DAILY,
'Weekly': TASK_TRIGGER_WEEKLY,
'Monthly': TASK_TRIGGER_MONTHLY,
'MonthlyDay': TASK_TRIGGER_MONTHLYDOW,
'OnIdle': TASK_TRIGGER_IDLE,
'OnTaskCreation': TASK_TRIGGER_REGISTRATION,
'OnBoot': TASK_TRIGGER_BOOT,
'OnLogon': TASK_TRIGGER_LOGON,
'OnSessionChange': TASK_TRIGGER_SESSION_STATE_CHANGE}
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?)',
0x800710E0: 'The operator or administrator has refused the request',
0xC000013A: 'The application terminated as a result of CTRL+C',
0xC06D007E: 'Unknown software exception'}
def __virtual__():
'''
Only works on Windows systems
'''
if salt.utils.platform.is_windows():
if not HAS_DEPENDENCIES:
log.warning('Could not load dependencies for %s', __virtualname__)
return __virtualname__
return (False, "Module win_task: module only works on Windows systems")
def _get_date_time_format(dt_string):
'''
Copied from win_system.py (_get_date_time_format)
Function that detects the date/time format for the string passed.
:param str dt_string:
A date/time string
:return: The format of the passed dt_string
:rtype: str
'''
valid_formats = [
'%I:%M:%S %p',
'%I:%M %p',
'%H:%M:%S',
'%H:%M',
'%Y-%m-%d',
'%m-%d-%y',
'%m-%d-%Y',
'%m/%d/%y',
'%m/%d/%Y',
'%Y/%m/%d'
]
for dt_format in valid_formats:
try:
datetime.strptime(dt_string, dt_format)
return dt_format
except ValueError:
continue
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
'''
value_index = -1
for idx, dict_value in enumerate(dictionary.values()):
if type(dict_value) == list:
if value in dict_value:
value_index = idx
break
elif value == dict_value:
value_index = idx
break
return list(dictionary)[value_index]
def _lookup_first(dictionary, key):
'''
Lookup the first value given a key. Returns the first value if the key
refers to a list or the value itself.
:param dict dictionary: The dictionary to search
:param str key: The key to get
:return: Returns the first value available for the key
:rtype: str
'''
value = dictionary[key]
if type(value) == list:
return value[0]
else:
return value
def _save_task_definition(name,
task_folder,
task_definition,
user_name,
password,
logon_type):
'''
Internal function to save the task definition.
:param str name: The name of the task.
:param str task_folder: The object representing the folder in which to save
the task
:param str task_definition: The object representing the task to be saved
:param str user_name: The user_account under which to run the task
:param str password: The password that corresponds to the user account
:param int logon_type: The logon type for the task.
:return: True if successful, False if not
:rtype: bool
'''
try:
task_folder.RegisterTaskDefinition(name,
task_definition,
TASK_CREATE_OR_UPDATE,
user_name,
password,
logon_type)
return True
except pythoncom.com_error as error:
hr, msg, exc, arg = error.args # pylint: disable=W0633
fc = {-2147024773: 'The filename, directory name, or volume label syntax is incorrect',
-2147024894: 'The system cannot find the file specified',
-2147216615: 'Required element or attribute missing',
-2147216616: 'Value incorrectly formatted or out of range',
-2147352571: 'Access denied'}
try:
failure_code = fc[exc[5]]
except KeyError:
failure_code = 'Unknown Failure: {0}'.format(error)
log.debug('Failed to modify task: %s', failure_code)
return 'Failed to modify task: {0}'.format(failure_code)
def list_tasks(location='\\'):
r'''
List all tasks located in a specific location in the task scheduler.
:param str location: A string value representing the folder from which you
want to list tasks. Default is '\\' which is the root for the task
scheduler (C:\Windows\System32\tasks).
:return: Returns a list of tasks.
:rtype: list
CLI Example:
.. code-block:: bash
salt 'minion-id' task.list_tasks
'''
# Create the task service object
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Get the folder to list tasks from
task_folder = task_service.GetFolder(location)
tasks = task_folder.GetTasks(0)
ret = []
for task in tasks:
ret.append(task.Name)
return ret
def list_folders(location='\\'):
r'''
List all folders located in a specific location in the task scheduler.
:param str location: A string value representing the folder from which you
want to list tasks. Default is '\\' which is the root for the task
scheduler (C:\Windows\System32\tasks).
:return: Returns a list of folders.
:rtype: list
CLI Example:
.. code-block:: bash
salt 'minion-id' task.list_folders
'''
# Create the task service object
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Get the folder to list folders from
task_folder = task_service.GetFolder(location)
folders = task_folder.GetFolders(0)
ret = []
for folder in folders:
ret.append(folder.Name)
return ret
def list_triggers(name, location='\\'):
r'''
List all triggers that pertain to a task in the specified location.
:param str name: The name of the task for which list triggers.
:param str location: A string value representing the location of the task
from which to list triggers. Default is '\\' which is the root for the
task scheduler (C:\Windows\System32\tasks).
:return: Returns a list of triggers.
:rtype: list
CLI Example:
.. code-block:: bash
salt 'minion-id' task.list_triggers <task_name>
'''
# Create the task service object
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Get the folder to list folders from
task_folder = task_service.GetFolder(location)
task_definition = task_folder.GetTask(name).Definition
triggers = task_definition.Triggers
ret = []
for trigger in triggers:
ret.append(trigger.Id)
return ret
def list_actions(name, location='\\'):
r'''
List all actions that pertain to a task in the specified location.
:param str name: The name of the task for which list actions.
:param str location: A string value representing the location of the task
from which to list actions. Default is '\\' which is the root for the
task scheduler (C:\Windows\System32\tasks).
:return: Returns a list of actions.
:rtype: list
CLI Example:
.. code-block:: bash
salt 'minion-id' task.list_actions <task_name>
'''
# Create the task service object
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Get the folder to list folders from
task_folder = task_service.GetFolder(location)
task_definition = task_folder.GetTask(name).Definition
actions = task_definition.Actions
ret = []
for action in actions:
ret.append(action.Id)
return ret
def create_task(name,
location='\\',
user_name='System',
password=None,
force=False,
**kwargs):
r'''
Create a new task in the designated location. This function has many keyword
arguments that are not listed here. For additional arguments see:
- :py:func:`edit_task`
- :py:func:`add_action`
- :py:func:`add_trigger`
:param str name: The name of the task. This will be displayed in the task
scheduler.
:param str location: A string value representing the location in which to
create the task. Default is '\\' which is the root for the task
scheduler (C:\Windows\System32\tasks).
:param str user_name: The user account under which to run the task. To
specify the 'System' account, use 'System'. The password will be
ignored.
:param str password: The password to use for authentication. This should set
the task to run whether the user is logged in or not, but is currently
not working.
:param bool force: If the task exists, overwrite the existing task.
:return: True if successful, False if unsuccessful
:rtype: bool
CLI Example:
.. code-block:: bash
salt 'minion-id' task.create_task <task_name> user_name=System force=True action_type=Execute cmd='del /Q /S C:\\Temp' trigger_type=Once start_date=2016-12-1 start_time=01:00
'''
# Check for existing task
if name in list_tasks(location) and not force:
# Connect to an existing task definition
return '{0} already exists'.format(name)
# connect to the task scheduler
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Create a new task definition
task_definition = task_service.NewTask(0)
# Modify task settings
edit_task(task_definition=task_definition,
user_name=user_name,
password=password,
**kwargs)
# Add Action
add_action(task_definition=task_definition, **kwargs)
# Add Trigger
add_trigger(task_definition=task_definition, **kwargs)
# get the folder to create the task in
task_folder = task_service.GetFolder(location)
# Save the task
_save_task_definition(name=name,
task_folder=task_folder,
task_definition=task_definition,
user_name=task_definition.Principal.UserID,
password=password,
logon_type=task_definition.Principal.LogonType)
# Verify task was created
if name in list_tasks(location):
return True
else:
return False
def create_task_from_xml(name,
location='\\',
xml_text=None,
xml_path=None,
user_name='System',
password=None):
r'''
Create a task based on XML. Source can be a file or a string of XML.
:param str name: The name of the task. This will be displayed in the task
scheduler.
:param str location: A string value representing the location in which to
create the task. Default is '\\' which is the root for the task
scheduler (C:\Windows\System32\tasks).
:param str xml_text: A string of xml representing the task to be created.
This will be overridden by `xml_path` if passed.
:param str xml_path: The path to an XML file on the local system containing
the xml that defines the task. This will override `xml_text`
:param str user_name: The user account under which to run the task. To
specify the 'System' account, use 'System'. The password will be
ignored.
:param str password: The password to use for authentication. This should set
the task to run whether the user is logged in or not, but is currently
not working.
:return: True if successful, False if unsuccessful
:rtype: bool
CLI Example:
.. code-block:: bash
salt 'minion-id' task.create_task_from_xml <task_name> xml_path=C:\task.xml
'''
# Check for existing task
if name in list_tasks(location):
# Connect to an existing task definition
return '{0} already exists'.format(name)
if not xml_text and not xml_path:
return 'Must specify either xml_text or xml_path'
# Create the task service object
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Load xml from file, overrides xml_text
# Need to figure out how to load contents of xml
if xml_path:
xml_text = xml_path
# Get the folder to list folders from
task_folder = task_service.GetFolder(location)
# Determine logon type
if user_name:
if user_name.lower() == 'system':
logon_type = TASK_LOGON_SERVICE_ACCOUNT
user_name = 'SYSTEM'
password = None
else:
if password:
logon_type = TASK_LOGON_PASSWORD
else:
logon_type = TASK_LOGON_INTERACTIVE_TOKEN
else:
password = None
# Save the task
try:
task_folder.RegisterTask(name,
xml_text,
TASK_CREATE,
user_name,
password,
logon_type)
except pythoncom.com_error as error:
hr, msg, exc, arg = error.args # pylint: disable=W0633
fc = {-2147216615: 'Required element or attribute missing',
-2147216616: 'Value incorrectly formatted or out of range',
-2147352571: 'Access denied'}
try:
failure_code = fc[exc[5]]
except KeyError:
failure_code = 'Unknown Failure: {0}'.format(error)
log.debug('Failed to create task: %s', failure_code)
# Verify creation
if name in list_tasks(location):
return True
else:
return False
def create_folder(name, location='\\'):
r'''
Create a folder in which to create tasks.
:param str name: The name of the folder. This will be displayed in the task
scheduler.
:param str location: A string value representing the location in which to
create the folder. Default is '\\' which is the root for the task
scheduler (C:\Windows\System32\tasks).
:return: True if successful, False if unsuccessful
:rtype: bool
CLI Example:
.. code-block:: bash
salt 'minion-id' task.create_folder <folder_name>
'''
# Check for existing folder
if name in list_folders(location):
# Connect to an existing task definition
return '{0} already exists'.format(name)
# Create the task service object
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# Get the folder to list folders from
task_folder = task_service.GetFolder(location)
task_folder.CreateFolder(name)
# Verify creation
if name in list_folders(location):
return True
else:
return False
def edit_task(name=None,
location='\\',
# General Tab
user_name=None,
password=None,
description=None,
enabled=None,
hidden=None,
# Conditions Tab
run_if_idle=None,
idle_duration=None,
idle_wait_timeout=None,
idle_stop_on_end=None,
idle_restart=None,
ac_only=None,
stop_if_on_batteries=None,
wake_to_run=None,
run_if_network=None,
network_id=None,
network_name=None,
# Settings Tab
allow_demand_start=None,
start_when_available=None,
restart_every=None,
restart_count=3,
execution_time_limit=None,
force_stop=None,
delete_after=None,
multiple_instances=None,
**kwargs):
r'''
Edit the parameters of a task. Triggers and Actions cannot be edited yet.
:param str name: The name of the task. This will be displayed in the task
scheduler.
:param str location: A string value representing the location in which to
create the task. Default is '\\' which is the root for the task
scheduler (C:\Windows\System32\tasks).
:param str user_name: The user account under which to run the task. To
specify the 'System' account, use 'System'. The password will be
ignored.
:param str password: The password to use for authentication. This should set
the task to run whether the user is logged in or not, but is currently
not working.
.. note::
The combination of user_name and password determine how the task runs.
For example, if a username is passed without at password the task will
only run when the user is logged in. If a password is passed as well
the task will run whether the user is logged on or not. If you pass
'System' as the username the task will run as the system account (the
password parameter is ignored.
:param str description: A string representing the text that will be
displayed in the description field in the task scheduler.
:param bool enabled: A boolean value representing whether or not the task is
enabled.
:param bool hidden: A boolean value representing whether or not the task is
hidden.
:param bool run_if_idle: Boolean value that indicates that the Task
Scheduler will run the task only if the computer is in an idle state.
:param str idle_duration: A value that indicates the amount of time that the
computer must be in an idle state before the task is run. Valid values
are:
- 1 minute
- 5 minutes
- 10 minutes
- 15 minutes
- 30 minutes
- 1 hour
:param str idle_wait_timeout: A value that indicates the amount of time that
the Task Scheduler will wait for an idle condition to occur. Valid
values are:
- Do not wait
- 1 minute
- 5 minutes
- 10 minutes
- 15 minutes
- 30 minutes
- 1 hour
- 2 hours
:param bool idle_stop_on_end: Boolean value that indicates that the Task
Scheduler will terminate the task if the idle condition ends before the
task is completed.
:param bool idle_restart: Boolean value that indicates whether the task is
restarted when the computer cycles into an idle condition more than
once.
:param bool ac_only: Boolean value that indicates that the Task Scheduler
will launch the task only while on AC power.
:param bool stop_if_on_batteries: Boolean value that indicates that the task
will be stopped if the computer begins to run on battery power.
:param bool wake_to_run: Boolean value that indicates that the Task
Scheduler will wake the computer when it is time to run the task.
:param bool run_if_network: Boolean value that indicates that the Task
Scheduler will run the task only when a network is available.
:param guid network_id: GUID value that identifies a network profile.
:param str network_name: Sets the name of a network profile. The name is
used for display purposes.
:param bool allow_demand_start: Boolean value that indicates that the task
can be started by using either the Run command or the Context menu.
:param bool start_when_available: Boolean value that indicates that the Task
Scheduler can start the task at any time after its scheduled time has
passed.
:param restart_every: A value that specifies the interval between task
restart attempts. Valid values are:
- False (to disable)
- 1 minute
- 5 minutes
- 10 minutes
- 15 minutes
- 30 minutes
- 1 hour
- 2 hours
:param int restart_count: The number of times the Task Scheduler will
attempt to restart the task. Valid values are integers 1 - 999.
:param execution_time_limit: The amount of time allowed to complete the
task. Valid values are:
- False (to disable)
- 1 hour
- 2 hours
- 4 hours
- 8 hours
- 12 hours
- 1 day
- 3 days
:param bool force_stop: Boolean value that indicates that the task may be
terminated by using TerminateProcess.
:param delete_after: The amount of time that the Task Scheduler will
wait before deleting the task after it expires. Requires a trigger with
an expiration date. Valid values are:
- False (to disable)
- Immediately
- 30 days
- 90 days
- 180 days
- 365 days
:param str multiple_instances: Sets the policy that defines how the Task
Scheduler deals with multiple instances of the task. Valid values are:
- Parallel
- Queue
- No New Instance
- Stop Existing
:return: True if successful, False if unsuccessful
:rtype: bool
CLI Example:
.. code-block:: bash
salt 'minion-id' task.edit_task <task_name> description='This task is awesome'
'''
# TODO: Add more detailed return for items changed
# Check for passed task_definition
# If not passed, open a task definition for an existing task
save_definition = False
if kwargs.get('task_definition', False):
task_definition = kwargs.get('task_definition')
else:
save_definition = True
# Make sure a name was passed
if not name:
return 'Required parameter "name" not passed'
# Make sure task exists to modify
if name in list_tasks(location):
# Connect to the task scheduler
with salt.utils.winapi.Com():
task_service = win32com.client.Dispatch("Schedule.Service")
task_service.Connect()
# get the folder to create the task in
task_folder = task_service.GetFolder(location)
# Connect to an existing task definition
task_definition = task_folder.GetTask(name).Definition
else:
# Not found and create_new not set, return not found
return '{0} not found'.format(name)
# General Information
if save_definition:
task_definition.RegistrationInfo.Author = 'Salt Minion'
task_definition.RegistrationInfo.Source = "Salt Minion Daemon"
if description is not None:
task_definition.RegistrationInfo.Description = description
# General Information: Security Options
if user_name:
# Determine logon type
if user_name.lower() == 'system':
logon_type = TASK_LOGON_SERVICE_ACCOUNT
user_name = 'SYSTEM'
password = None
else:
task_definition.Principal.Id = user_name
if password:
logon_type = TASK_LOGON_PASSWORD
else:
logon_type = TASK_LOGON_INTERACTIVE_TOKEN
task_definition.Principal.UserID = user_name
task_definition.Principal.DisplayName = user_name
task_definition.Principal.LogonType = logon_type
task_definition.Principal.RunLevel = TASK_RUNLEVEL_HIGHEST
else:
user_name = None
password = None
# Settings
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa383480(v=vs.85).aspx
if enabled is not None:
task_definition.Settings.Enabled = enabled
# Settings: General Tab
if hidden is not None:
task_definition.Settings.Hidden = hidden
# Settings: Conditions Tab (Idle)
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa380669(v=vs.85).aspx
if run_if_idle is not None:
task_definition.Settings.RunOnlyIfIdle = run_if_idle
if task_definition.Settings.RunOnlyIfIdle:
if idle_stop_on_end is not None:
task_definition.Settings.IdleSettings.StopOnIdleEnd = idle_stop_on_end
if idle_restart is not None:
task_definition.Settings.IdleSettings.RestartOnIdle = idle_restart
if idle_duration is not None:
if idle_duration in duration:
task_definition.Settings.IdleSettings.IdleDuration = _lookup_first(duration, idle_duration)
else:
return 'Invalid value for "idle_duration"'
if idle_wait_timeout is not None:
if idle_wait_timeout in duration:
task_definition.Settings.IdleSettings.WaitTimeout = _lookup_first(duration, idle_wait_timeout)
else:
return 'Invalid value for "idle_wait_timeout"'
# Settings: Conditions Tab (Power)
if ac_only is not None:
task_definition.Settings.DisallowStartIfOnBatteries = ac_only
if stop_if_on_batteries is not None:
task_definition.Settings.StopIfGoingOnBatteries = stop_if_on_batteries
if wake_to_run is not None:
task_definition.Settings.WakeToRun = wake_to_run
# Settings: Conditions Tab (Network)
# https://msdn.microsoft.com/en-us/library/windows/desktop/aa382067(v=vs.85).aspx
if run_if_network is not None:
task_definition.Settings.RunOnlyIfNetworkAvailable = run_if_network
if task_definition.Settings.RunOnlyIfNetworkAvailable:
if network_id:
task_definition.Settings.NetworkSettings.Id = network_id
if network_name:
task_definition.Settings.NetworkSettings.Name = network_name
# Settings: Settings Tab
if allow_demand_start is not None:
task_definition.Settings.AllowDemandStart = allow_demand_start
if start_when_available is not None:
task_definition.Settings.StartWhenAvailable = start_when_available
if restart_every is not None:
if restart_every is False:
task_definition.Settings.RestartInterval = ''
else:
if restart_every in duration:
task_definition.Settings.RestartInterval = _lookup_first(duration, restart_every)
else:
return 'Invalid value for "restart_every"'
if task_definition.Settings.RestartInterval:
if restart_count is not None:
if restart_count in range(1, 999):
task_definition.Settings.RestartCount = restart_count
else:
return '"restart_count" must be a value between 1 and 999'
if execution_time_limit is not None:
if execution_time_limit is False:
task_definition.Settings.ExecutionTimeLimit = 'PT0S'
else:
if execution_time_limit in duration:
task_definition.Settings.ExecutionTimeLimit = _lookup_first(duration, execution_time_limit)
else:
return 'Invalid value for "execution_time_limit"'