win32-taskscheduler 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CHANGES +108 -93
- data/MANIFEST +10 -9
- data/README +72 -68
- data/Rakefile +34 -37
- data/certs/djberg96_pub.pem +21 -0
- data/examples/taskscheduler_example.rb +56 -56
- data/lib/win32-taskscheduler.rb +1 -0
- data/lib/win32/taskscheduler.rb +1383 -1368
- data/lib/win32/windows/helper.rb +45 -42
- data/test/test_taskscheduler.rb +690 -689
- data/win32-taskscheduler.gemspec +33 -34
- metadata +51 -21
- metadata.gz.sig +0 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDcDCCAligAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MREwDwYDVQQDDAhkamJl
|
3
|
+
cmc5NjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYDY29t
|
4
|
+
MB4XDTE2MTIxMjAwMTQ1M1oXDTE3MTIxMjAwMTQ1M1owPzERMA8GA1UEAwwIZGpi
|
5
|
+
ZXJnOTYxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv
|
6
|
+
bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVtTm/wETO8yKVKRPBO
|
7
|
+
VgPRvE94iEfKryOb/tQrmhGhchG2ALqdw/r54cGJvLaXeItrYJ6N8pSE/FSnN5jM
|
8
|
+
xugUhHBprPl+AsQ4E+IBy0dKwyU8XjFoVYzWvT1wnqwQdSazdgFCfQqb51QCgUIT
|
9
|
+
PGGakKlyzCb3Mbq30is8+QlRrqXt/JbpkUZbQwUqCdAulMT4oyPBk/L+48pbVX0s
|
10
|
+
4yj7YaVAqfGByAMTPXEmUS388lX+0xq8+GGir2Fuh0TpNW0ggr9BxprwqL0Mg4Oo
|
11
|
+
YhM5L1y8Plolo8mOTN3+K8I3afZ0lD0BtwniVb6g+Ut/4aBjKy2+GyFwwNOu0gSj
|
12
|
+
desCAwEAAaN3MHUwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFJfg
|
13
|
+
HmQ0uDU3Z9A9hB1lQMjr5VZSMB0GA1UdEQQWMBSBEmRqYmVyZzk2QGdtYWlsLmNv
|
14
|
+
bTAdBgNVHRIEFjAUgRJkamJlcmc5NkBnbWFpbC5jb20wDQYJKoZIhvcNAQEFBQAD
|
15
|
+
ggEBACjRCHRP944MHIQJNCglZbDnZowybV2HxmG1uhnvRwrOjBA7CXemc+QSAL7K
|
16
|
+
7eXC4FdojVEJrnU7ZxuCmfQU+fvkEQKOnah1osG1874aPiDlwtjHclpeqcDgTUI7
|
17
|
+
A7CF+OXK8x7ksFx205ruhPHKaPYtwVG/W/J+y7Wx8yl9rvwUgRBL5cVzTBiEz+AB
|
18
|
+
NRT7yoHXXfFXjuQWN1eHunSbNds2ZTGQd64yBCujb17Xdl+F9tu4klkTga3gxP3P
|
19
|
+
y3zoX1VttxnIZBojRM/s2A7c2aubMH2SVbXMR3ccVkB9XbYKl1OvCe7q85xEHit2
|
20
|
+
Kbpico5nnyHqf7YSPmvZe8bCU94=
|
21
|
+
-----END CERTIFICATE-----
|
@@ -1,56 +1,56 @@
|
|
1
|
-
#######################################################################
|
2
|
-
# taskscheduler_example.rb
|
3
|
-
#
|
4
|
-
# A test script for general futzing. You can run this example via the
|
5
|
-
# 'example' rake task.
|
6
|
-
#
|
7
|
-
# Modify as you see fit.
|
8
|
-
#######################################################################
|
9
|
-
require 'win32/taskscheduler'
|
10
|
-
require 'fileutils'
|
11
|
-
require 'pp'
|
12
|
-
include Win32
|
13
|
-
|
14
|
-
puts 'VERSION: ' + TaskScheduler::VERSION
|
15
|
-
|
16
|
-
ts = TaskScheduler.new
|
17
|
-
|
18
|
-
trigger = {
|
19
|
-
"start_year" => 2009,
|
20
|
-
"start_month" => 4,
|
21
|
-
"start_day" => 11,
|
22
|
-
"start_hour" => 7,
|
23
|
-
"start_minute" => 14,
|
24
|
-
"trigger_type" => TaskScheduler::DAILY,
|
25
|
-
"type" => { "days_interval" => 1 }
|
26
|
-
}
|
27
|
-
|
28
|
-
unless ts.enum.grep(/foo/).length > 0
|
29
|
-
ts.new_work_item("foo", trigger)
|
30
|
-
ts.application_name = "notepad.exe"
|
31
|
-
ts.save
|
32
|
-
puts "Task Added"
|
33
|
-
end
|
34
|
-
|
35
|
-
ts.activate("foo")
|
36
|
-
ts.priority = TaskScheduler::IDLE
|
37
|
-
ts.working_directory = "C:\\"
|
38
|
-
|
39
|
-
puts "App name: " + ts.application_name
|
40
|
-
puts "Creator: " + ts.creator
|
41
|
-
puts "Exit code: " + ts.exit_code.to_s
|
42
|
-
puts "Flags: " + ts.flags.to_s
|
43
|
-
puts "Max run time: " + ts.max_run_time.to_s
|
44
|
-
puts "Next run time: " + ts.next_run_time.to_s
|
45
|
-
puts "Parameters: " + ts.parameters
|
46
|
-
puts "Priority: " + ts.priority.to_s
|
47
|
-
puts "Status: " + ts.status
|
48
|
-
puts "Trigger count: " + ts.trigger_count.to_s
|
49
|
-
puts "Trigger string: " + ts.trigger_string(0)
|
50
|
-
puts "Working directory: " + ts.working_directory
|
51
|
-
puts "Trigger: "
|
52
|
-
|
53
|
-
pp ts.trigger(0)
|
54
|
-
|
55
|
-
ts.delete("foo")
|
56
|
-
puts "Task deleted"
|
1
|
+
#######################################################################
|
2
|
+
# taskscheduler_example.rb
|
3
|
+
#
|
4
|
+
# A test script for general futzing. You can run this example via the
|
5
|
+
# 'example' rake task.
|
6
|
+
#
|
7
|
+
# Modify as you see fit.
|
8
|
+
#######################################################################
|
9
|
+
require 'win32/taskscheduler'
|
10
|
+
require 'fileutils'
|
11
|
+
require 'pp'
|
12
|
+
include Win32
|
13
|
+
|
14
|
+
puts 'VERSION: ' + TaskScheduler::VERSION
|
15
|
+
|
16
|
+
ts = TaskScheduler.new
|
17
|
+
|
18
|
+
trigger = {
|
19
|
+
"start_year" => 2009,
|
20
|
+
"start_month" => 4,
|
21
|
+
"start_day" => 11,
|
22
|
+
"start_hour" => 7,
|
23
|
+
"start_minute" => 14,
|
24
|
+
"trigger_type" => TaskScheduler::DAILY,
|
25
|
+
"type" => { "days_interval" => 1 }
|
26
|
+
}
|
27
|
+
|
28
|
+
unless ts.enum.grep(/foo/).length > 0
|
29
|
+
ts.new_work_item("foo", trigger)
|
30
|
+
ts.application_name = "notepad.exe"
|
31
|
+
ts.save
|
32
|
+
puts "Task Added"
|
33
|
+
end
|
34
|
+
|
35
|
+
ts.activate("foo")
|
36
|
+
ts.priority = TaskScheduler::IDLE
|
37
|
+
ts.working_directory = "C:\\"
|
38
|
+
|
39
|
+
puts "App name: " + ts.application_name
|
40
|
+
puts "Creator: " + ts.creator
|
41
|
+
puts "Exit code: " + ts.exit_code.to_s
|
42
|
+
puts "Flags: " + ts.flags.to_s
|
43
|
+
puts "Max run time: " + ts.max_run_time.to_s
|
44
|
+
puts "Next run time: " + ts.next_run_time.to_s
|
45
|
+
puts "Parameters: " + ts.parameters
|
46
|
+
puts "Priority: " + ts.priority.to_s
|
47
|
+
puts "Status: " + ts.status
|
48
|
+
puts "Trigger count: " + ts.trigger_count.to_s
|
49
|
+
puts "Trigger string: " + ts.trigger_string(0)
|
50
|
+
puts "Working directory: " + ts.working_directory
|
51
|
+
puts "Trigger: "
|
52
|
+
|
53
|
+
pp ts.trigger(0)
|
54
|
+
|
55
|
+
ts.delete("foo")
|
56
|
+
puts "Task deleted"
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'win32/taskscheduler'
|
data/lib/win32/taskscheduler.rb
CHANGED
@@ -1,1368 +1,1383 @@
|
|
1
|
-
|
2
|
-
require 'win32ole'
|
3
|
-
require 'socket'
|
4
|
-
require 'time'
|
5
|
-
require 'structured_warnings'
|
6
|
-
|
7
|
-
# The Win32 module serves as a namespace only
|
8
|
-
module Win32
|
9
|
-
|
10
|
-
# The TaskScheduler class encapsulates a Windows scheduled task
|
11
|
-
class TaskScheduler
|
12
|
-
include Windows::
|
13
|
-
|
14
|
-
# The version of the win32-taskscheduler library
|
15
|
-
VERSION = '0.3.
|
16
|
-
|
17
|
-
# The Error class is typically raised if any TaskScheduler methods fail.
|
18
|
-
class Error < StandardError; end
|
19
|
-
|
20
|
-
# Triggers
|
21
|
-
|
22
|
-
# Trigger is set to run the task a single tim
|
23
|
-
TASK_TIME_TRIGGER_ONCE = 0
|
24
|
-
|
25
|
-
# Trigger is set to run the task on a daily interval
|
26
|
-
TASK_TIME_TRIGGER_DAILY = 1
|
27
|
-
|
28
|
-
# Trigger is set to run the task on specific days of a specific week & month
|
29
|
-
TASK_TIME_TRIGGER_WEEKLY = 2
|
30
|
-
|
31
|
-
# Trigger is set to run the task on specific day(s) of the month
|
32
|
-
TASK_TIME_TRIGGER_MONTHLYDATE = 3
|
33
|
-
|
34
|
-
# Trigger is set to run the task on specific day(s) of the month
|
35
|
-
TASK_TIME_TRIGGER_MONTHLYDOW = 4
|
36
|
-
|
37
|
-
# Trigger is set to run the task if the system remains idle for the amount
|
38
|
-
# of time specified by the idle wait time of the task
|
39
|
-
TASK_EVENT_TRIGGER_ON_IDLE = 5
|
40
|
-
|
41
|
-
# Trigger is set to run the task at system startup
|
42
|
-
TASK_EVENT_TRIGGER_AT_SYSTEMSTART = 6
|
43
|
-
|
44
|
-
# Trigger is set to run the task when a user logs on
|
45
|
-
TASK_EVENT_TRIGGER_AT_LOGON = 7
|
46
|
-
|
47
|
-
# Daily Tasks
|
48
|
-
|
49
|
-
# The task will run on Sunday
|
50
|
-
TASK_SUNDAY = 0x1
|
51
|
-
|
52
|
-
# The task will run on Monday
|
53
|
-
TASK_MONDAY = 0x2
|
54
|
-
|
55
|
-
# The task will run on Tuesday
|
56
|
-
TASK_TUESDAY = 0x4
|
57
|
-
|
58
|
-
# The task will run on Wednesday
|
59
|
-
TASK_WEDNESDAY = 0x8
|
60
|
-
|
61
|
-
# The task will run on Thursday
|
62
|
-
TASK_THURSDAY = 0x10
|
63
|
-
|
64
|
-
# The task will run on Friday
|
65
|
-
TASK_FRIDAY = 0x20
|
66
|
-
|
67
|
-
# The task will run on Saturday
|
68
|
-
TASK_SATURDAY = 0x40
|
69
|
-
|
70
|
-
# Weekly tasks
|
71
|
-
|
72
|
-
# The task will run between the 1st and 7th day of the month
|
73
|
-
TASK_FIRST_WEEK = 1
|
74
|
-
|
75
|
-
# The task will run between the 8th and 14th day of the month
|
76
|
-
TASK_SECOND_WEEK = 2
|
77
|
-
|
78
|
-
# The task will run between the 15th and 21st day of the month
|
79
|
-
TASK_THIRD_WEEK = 3
|
80
|
-
|
81
|
-
# The task will run between the 22nd and 28th day of the month
|
82
|
-
TASK_FOURTH_WEEK = 4
|
83
|
-
|
84
|
-
# The task will run the last seven days of the month
|
85
|
-
TASK_LAST_WEEK = 5
|
86
|
-
|
87
|
-
# Monthly tasks
|
88
|
-
|
89
|
-
# The task will run in January
|
90
|
-
TASK_JANUARY = 0x1
|
91
|
-
|
92
|
-
# The task will run in February
|
93
|
-
TASK_FEBRUARY = 0x2
|
94
|
-
|
95
|
-
# The task will run in March
|
96
|
-
TASK_MARCH = 0x4
|
97
|
-
|
98
|
-
# The task will run in April
|
99
|
-
TASK_APRIL = 0x8
|
100
|
-
|
101
|
-
# The task will run in May
|
102
|
-
TASK_MAY = 0x10
|
103
|
-
|
104
|
-
# The task will run in June
|
105
|
-
TASK_JUNE = 0x20
|
106
|
-
|
107
|
-
# The task will run in July
|
108
|
-
TASK_JULY = 0x40
|
109
|
-
|
110
|
-
# The task will run in August
|
111
|
-
TASK_AUGUST = 0x80
|
112
|
-
|
113
|
-
# The task will run in September
|
114
|
-
TASK_SEPTEMBER = 0x100
|
115
|
-
|
116
|
-
# The task will run in October
|
117
|
-
TASK_OCTOBER = 0x200
|
118
|
-
|
119
|
-
# The task will run in November
|
120
|
-
TASK_NOVEMBER = 0x400
|
121
|
-
|
122
|
-
# The task will run in December
|
123
|
-
TASK_DECEMBER = 0x800
|
124
|
-
|
125
|
-
# Flags
|
126
|
-
|
127
|
-
# Used when converting AT service jobs into work items
|
128
|
-
TASK_FLAG_INTERACTIVE = 0x1
|
129
|
-
|
130
|
-
# The work item will be deleted when there are no more scheduled run times
|
131
|
-
TASK_FLAG_DELETE_WHEN_DONE = 0x2
|
132
|
-
|
133
|
-
# The work item is disabled. Useful for temporarily disabling a task
|
134
|
-
TASK_FLAG_DISABLED = 0x4
|
135
|
-
|
136
|
-
# The work item begins only if the computer is not in use at the scheduled
|
137
|
-
# start time
|
138
|
-
TASK_FLAG_START_ONLY_IF_IDLE = 0x10
|
139
|
-
|
140
|
-
# The work item terminates if the computer makes an idle to non-idle
|
141
|
-
# transition while the work item is running
|
142
|
-
TASK_FLAG_KILL_ON_IDLE_END = 0x20
|
143
|
-
|
144
|
-
# The work item does not start if the computer is running on battery power
|
145
|
-
TASK_FLAG_DONT_START_IF_ON_BATTERIES = 0x40
|
146
|
-
|
147
|
-
# The work item ends, and the associated application quits, if the computer
|
148
|
-
# switches to battery power
|
149
|
-
TASK_FLAG_KILL_IF_GOING_ON_BATTERIES = 0x80
|
150
|
-
|
151
|
-
# The work item starts only if the computer is in a docking station
|
152
|
-
TASK_FLAG_RUN_ONLY_IF_DOCKED = 0x100
|
153
|
-
|
154
|
-
# The work item created will be hidden
|
155
|
-
TASK_FLAG_HIDDEN = 0x200
|
156
|
-
|
157
|
-
# The work item runs only if there is a valid internet connection
|
158
|
-
TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET = 0x400
|
159
|
-
|
160
|
-
# The work item starts again if the computer makes a non-idle to idle
|
161
|
-
# transition
|
162
|
-
TASK_FLAG_RESTART_ON_IDLE_RESUME = 0x800
|
163
|
-
|
164
|
-
# The work item causes the system to be resumed, or awakened, if the
|
165
|
-
# system is running on batter power
|
166
|
-
TASK_FLAG_SYSTEM_REQUIRED = 0x1000
|
167
|
-
|
168
|
-
# The work item runs only if a specified account is logged on interactively
|
169
|
-
TASK_FLAG_RUN_ONLY_IF_LOGGED_ON = 0x2000
|
170
|
-
|
171
|
-
# Triggers
|
172
|
-
|
173
|
-
# The task will stop at some point in time
|
174
|
-
TASK_TRIGGER_FLAG_HAS_END_DATE = 0x1
|
175
|
-
|
176
|
-
# The task can be stopped at the end of the repetition period
|
177
|
-
TASK_TRIGGER_FLAG_KILL_AT_DURATION_END = 0x2
|
178
|
-
|
179
|
-
# The task trigger is disabled
|
180
|
-
TASK_TRIGGER_FLAG_DISABLED = 0x4
|
181
|
-
|
182
|
-
# :stopdoc:
|
183
|
-
|
184
|
-
TASK_MAX_RUN_TIMES = 1440
|
185
|
-
TASKS_TO_RETRIEVE = 5
|
186
|
-
|
187
|
-
# Task creation
|
188
|
-
|
189
|
-
TASK_VALIDATE_ONLY = 0x1
|
190
|
-
TASK_CREATE = 0x2
|
191
|
-
TASK_UPDATE = 0x4
|
192
|
-
TASK_CREATE_OR_UPDATE = 0x6
|
193
|
-
TASK_DISABLE = 0x8
|
194
|
-
TASK_DONT_ADD_PRINCIPAL_ACE = 0x10
|
195
|
-
TASK_IGNORE_REGISTRATION_TRIGGERS = 0x20
|
196
|
-
|
197
|
-
# Task logon types
|
198
|
-
|
199
|
-
TASK_LOGON_NONE = 0
|
200
|
-
TASK_LOGON_PASSWORD = 1
|
201
|
-
TASK_LOGON_S4U = 2
|
202
|
-
TASK_LOGON_INTERACTIVE_TOKEN = 3
|
203
|
-
TASK_LOGON_GROUP = 4
|
204
|
-
TASK_LOGON_SERVICE_ACCOUNT = 5
|
205
|
-
TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD = 6
|
206
|
-
|
207
|
-
# Priority classes
|
208
|
-
|
209
|
-
REALTIME_PRIORITY_CLASS = 0
|
210
|
-
HIGH_PRIORITY_CLASS = 1
|
211
|
-
ABOVE_NORMAL_PRIORITY_CLASS = 2 # Or 3
|
212
|
-
NORMAL_PRIORITY_CLASS = 4 # Or 5, 6
|
213
|
-
BELOW_NORMAL_PRIORITY_CLASS = 7 # Or 8
|
214
|
-
IDLE_PRIORITY_CLASS = 9 # Or 10
|
215
|
-
|
216
|
-
CLSCTX_INPROC_SERVER = 0x1
|
217
|
-
CLSID_CTask = [0x148BD520,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
218
|
-
CLSID_CTaskScheduler = [0x148BD52A,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
219
|
-
IID_ITaskScheduler = [0x148BD527,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
220
|
-
IID_ITask = [0x148BD524,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
221
|
-
IID_IPersistFile = [0x0000010b,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46].pack('LSSC8')
|
222
|
-
|
223
|
-
# :startdoc:
|
224
|
-
|
225
|
-
attr_accessor :password
|
226
|
-
attr_reader :host
|
227
|
-
|
228
|
-
# Returns a new TaskScheduler object, attached to +folder+. If that
|
229
|
-
# folder does not exist, but the +force+ option is set to true, then
|
230
|
-
# it will be created. Otherwise an error will be raised. The default
|
231
|
-
# is to use the root folder.
|
232
|
-
#
|
233
|
-
# If +task+ and +trigger+ are present, then a new task is generated
|
234
|
-
# as well. This is effectively the same as .new + #new_work_item.
|
235
|
-
#
|
236
|
-
def initialize(task = nil, trigger = nil, folder = "\\", force = false)
|
237
|
-
@folder = folder
|
238
|
-
@force = force
|
239
|
-
|
240
|
-
@host = Socket.gethostname
|
241
|
-
@task = nil
|
242
|
-
@password = nil
|
243
|
-
|
244
|
-
raise ArgumentError, "invalid folder" unless folder.include?("\\")
|
245
|
-
|
246
|
-
unless [TrueClass, FalseClass].include?(force.class)
|
247
|
-
raise TypeError, "invalid force value"
|
248
|
-
end
|
249
|
-
|
250
|
-
begin
|
251
|
-
@service = WIN32OLE.new('Schedule.Service')
|
252
|
-
rescue WIN32OLERuntimeError => err
|
253
|
-
raise Error, err.inspect
|
254
|
-
end
|
255
|
-
|
256
|
-
@service.Connect
|
257
|
-
|
258
|
-
if folder != "\\"
|
259
|
-
begin
|
260
|
-
@root = @service.GetFolder(folder)
|
261
|
-
rescue WIN32OLERuntimeError => err
|
262
|
-
if force
|
263
|
-
@root.CreateFolder(folder)
|
264
|
-
@root = @service.GetFolder(folder)
|
265
|
-
else
|
266
|
-
raise ArgumentError, "folder '#{folder}' not found"
|
267
|
-
end
|
268
|
-
end
|
269
|
-
else
|
270
|
-
@root = @service.GetFolder(folder)
|
271
|
-
end
|
272
|
-
|
273
|
-
if task && trigger
|
274
|
-
new_work_item(task, trigger)
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
# Returns an array of scheduled task names.
|
279
|
-
#
|
280
|
-
def enum
|
281
|
-
# Get the task folder that contains the tasks.
|
282
|
-
taskCollection = @root.GetTasks(0)
|
283
|
-
|
284
|
-
array = []
|
285
|
-
|
286
|
-
taskCollection.each do |registeredTask|
|
287
|
-
array << registeredTask.Name
|
288
|
-
end
|
289
|
-
|
290
|
-
array
|
291
|
-
end
|
292
|
-
|
293
|
-
alias tasks enum
|
294
|
-
|
295
|
-
# Returns whether or not the specified task exists.
|
296
|
-
#
|
297
|
-
def exists?(task)
|
298
|
-
enum.include?(task)
|
299
|
-
end
|
300
|
-
|
301
|
-
# Activate the specified task.
|
302
|
-
#
|
303
|
-
def activate(task)
|
304
|
-
raise TypeError unless task.is_a?(String)
|
305
|
-
|
306
|
-
begin
|
307
|
-
registeredTask = @root.GetTask(task)
|
308
|
-
registeredTask.Enabled = 1
|
309
|
-
@task = registeredTask
|
310
|
-
rescue WIN32OLERuntimeError => err
|
311
|
-
raise Error, ole_error('activate', err)
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
# Delete the specified task name.
|
316
|
-
#
|
317
|
-
def delete(task)
|
318
|
-
raise TypeError unless task.is_a?(String)
|
319
|
-
|
320
|
-
begin
|
321
|
-
@root.DeleteTask(task, 0)
|
322
|
-
rescue WIN32OLERuntimeError => err
|
323
|
-
raise Error, ole_error('DeleteTask', err)
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
# Execute the current task.
|
328
|
-
#
|
329
|
-
def run
|
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
|
-
alias host
|
387
|
-
alias
|
388
|
-
|
389
|
-
|
390
|
-
#
|
391
|
-
#
|
392
|
-
|
393
|
-
|
394
|
-
raise
|
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
|
-
definition
|
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
|
-
taskDefinition.
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
when
|
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
|
-
trigger
|
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
|
-
when
|
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
|
-
when
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
when
|
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
|
-
when
|
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
|
-
|
1001
|
-
when
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
when
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
end
|
1123
|
-
|
1124
|
-
# Returns the
|
1125
|
-
#
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
#
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
#
|
1189
|
-
#
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
:
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1
|
+
require_relative 'windows/helper'
|
2
|
+
require 'win32ole'
|
3
|
+
require 'socket'
|
4
|
+
require 'time'
|
5
|
+
require 'structured_warnings'
|
6
|
+
|
7
|
+
# The Win32 module serves as a namespace only
|
8
|
+
module Win32
|
9
|
+
|
10
|
+
# The TaskScheduler class encapsulates a Windows scheduled task
|
11
|
+
class TaskScheduler
|
12
|
+
include Windows::TaskSchedulerHelper
|
13
|
+
|
14
|
+
# The version of the win32-taskscheduler library
|
15
|
+
VERSION = '0.3.2'.freeze
|
16
|
+
|
17
|
+
# The Error class is typically raised if any TaskScheduler methods fail.
|
18
|
+
class Error < StandardError; end
|
19
|
+
|
20
|
+
# Triggers
|
21
|
+
|
22
|
+
# Trigger is set to run the task a single tim
|
23
|
+
TASK_TIME_TRIGGER_ONCE = 0
|
24
|
+
|
25
|
+
# Trigger is set to run the task on a daily interval
|
26
|
+
TASK_TIME_TRIGGER_DAILY = 1
|
27
|
+
|
28
|
+
# Trigger is set to run the task on specific days of a specific week & month
|
29
|
+
TASK_TIME_TRIGGER_WEEKLY = 2
|
30
|
+
|
31
|
+
# Trigger is set to run the task on specific day(s) of the month
|
32
|
+
TASK_TIME_TRIGGER_MONTHLYDATE = 3
|
33
|
+
|
34
|
+
# Trigger is set to run the task on specific day(s) of the month
|
35
|
+
TASK_TIME_TRIGGER_MONTHLYDOW = 4
|
36
|
+
|
37
|
+
# Trigger is set to run the task if the system remains idle for the amount
|
38
|
+
# of time specified by the idle wait time of the task
|
39
|
+
TASK_EVENT_TRIGGER_ON_IDLE = 5
|
40
|
+
|
41
|
+
# Trigger is set to run the task at system startup
|
42
|
+
TASK_EVENT_TRIGGER_AT_SYSTEMSTART = 6
|
43
|
+
|
44
|
+
# Trigger is set to run the task when a user logs on
|
45
|
+
TASK_EVENT_TRIGGER_AT_LOGON = 7
|
46
|
+
|
47
|
+
# Daily Tasks
|
48
|
+
|
49
|
+
# The task will run on Sunday
|
50
|
+
TASK_SUNDAY = 0x1
|
51
|
+
|
52
|
+
# The task will run on Monday
|
53
|
+
TASK_MONDAY = 0x2
|
54
|
+
|
55
|
+
# The task will run on Tuesday
|
56
|
+
TASK_TUESDAY = 0x4
|
57
|
+
|
58
|
+
# The task will run on Wednesday
|
59
|
+
TASK_WEDNESDAY = 0x8
|
60
|
+
|
61
|
+
# The task will run on Thursday
|
62
|
+
TASK_THURSDAY = 0x10
|
63
|
+
|
64
|
+
# The task will run on Friday
|
65
|
+
TASK_FRIDAY = 0x20
|
66
|
+
|
67
|
+
# The task will run on Saturday
|
68
|
+
TASK_SATURDAY = 0x40
|
69
|
+
|
70
|
+
# Weekly tasks
|
71
|
+
|
72
|
+
# The task will run between the 1st and 7th day of the month
|
73
|
+
TASK_FIRST_WEEK = 1
|
74
|
+
|
75
|
+
# The task will run between the 8th and 14th day of the month
|
76
|
+
TASK_SECOND_WEEK = 2
|
77
|
+
|
78
|
+
# The task will run between the 15th and 21st day of the month
|
79
|
+
TASK_THIRD_WEEK = 3
|
80
|
+
|
81
|
+
# The task will run between the 22nd and 28th day of the month
|
82
|
+
TASK_FOURTH_WEEK = 4
|
83
|
+
|
84
|
+
# The task will run the last seven days of the month
|
85
|
+
TASK_LAST_WEEK = 5
|
86
|
+
|
87
|
+
# Monthly tasks
|
88
|
+
|
89
|
+
# The task will run in January
|
90
|
+
TASK_JANUARY = 0x1
|
91
|
+
|
92
|
+
# The task will run in February
|
93
|
+
TASK_FEBRUARY = 0x2
|
94
|
+
|
95
|
+
# The task will run in March
|
96
|
+
TASK_MARCH = 0x4
|
97
|
+
|
98
|
+
# The task will run in April
|
99
|
+
TASK_APRIL = 0x8
|
100
|
+
|
101
|
+
# The task will run in May
|
102
|
+
TASK_MAY = 0x10
|
103
|
+
|
104
|
+
# The task will run in June
|
105
|
+
TASK_JUNE = 0x20
|
106
|
+
|
107
|
+
# The task will run in July
|
108
|
+
TASK_JULY = 0x40
|
109
|
+
|
110
|
+
# The task will run in August
|
111
|
+
TASK_AUGUST = 0x80
|
112
|
+
|
113
|
+
# The task will run in September
|
114
|
+
TASK_SEPTEMBER = 0x100
|
115
|
+
|
116
|
+
# The task will run in October
|
117
|
+
TASK_OCTOBER = 0x200
|
118
|
+
|
119
|
+
# The task will run in November
|
120
|
+
TASK_NOVEMBER = 0x400
|
121
|
+
|
122
|
+
# The task will run in December
|
123
|
+
TASK_DECEMBER = 0x800
|
124
|
+
|
125
|
+
# Flags
|
126
|
+
|
127
|
+
# Used when converting AT service jobs into work items
|
128
|
+
TASK_FLAG_INTERACTIVE = 0x1
|
129
|
+
|
130
|
+
# The work item will be deleted when there are no more scheduled run times
|
131
|
+
TASK_FLAG_DELETE_WHEN_DONE = 0x2
|
132
|
+
|
133
|
+
# The work item is disabled. Useful for temporarily disabling a task
|
134
|
+
TASK_FLAG_DISABLED = 0x4
|
135
|
+
|
136
|
+
# The work item begins only if the computer is not in use at the scheduled
|
137
|
+
# start time
|
138
|
+
TASK_FLAG_START_ONLY_IF_IDLE = 0x10
|
139
|
+
|
140
|
+
# The work item terminates if the computer makes an idle to non-idle
|
141
|
+
# transition while the work item is running
|
142
|
+
TASK_FLAG_KILL_ON_IDLE_END = 0x20
|
143
|
+
|
144
|
+
# The work item does not start if the computer is running on battery power
|
145
|
+
TASK_FLAG_DONT_START_IF_ON_BATTERIES = 0x40
|
146
|
+
|
147
|
+
# The work item ends, and the associated application quits, if the computer
|
148
|
+
# switches to battery power
|
149
|
+
TASK_FLAG_KILL_IF_GOING_ON_BATTERIES = 0x80
|
150
|
+
|
151
|
+
# The work item starts only if the computer is in a docking station
|
152
|
+
TASK_FLAG_RUN_ONLY_IF_DOCKED = 0x100
|
153
|
+
|
154
|
+
# The work item created will be hidden
|
155
|
+
TASK_FLAG_HIDDEN = 0x200
|
156
|
+
|
157
|
+
# The work item runs only if there is a valid internet connection
|
158
|
+
TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET = 0x400
|
159
|
+
|
160
|
+
# The work item starts again if the computer makes a non-idle to idle
|
161
|
+
# transition
|
162
|
+
TASK_FLAG_RESTART_ON_IDLE_RESUME = 0x800
|
163
|
+
|
164
|
+
# The work item causes the system to be resumed, or awakened, if the
|
165
|
+
# system is running on batter power
|
166
|
+
TASK_FLAG_SYSTEM_REQUIRED = 0x1000
|
167
|
+
|
168
|
+
# The work item runs only if a specified account is logged on interactively
|
169
|
+
TASK_FLAG_RUN_ONLY_IF_LOGGED_ON = 0x2000
|
170
|
+
|
171
|
+
# Triggers
|
172
|
+
|
173
|
+
# The task will stop at some point in time
|
174
|
+
TASK_TRIGGER_FLAG_HAS_END_DATE = 0x1
|
175
|
+
|
176
|
+
# The task can be stopped at the end of the repetition period
|
177
|
+
TASK_TRIGGER_FLAG_KILL_AT_DURATION_END = 0x2
|
178
|
+
|
179
|
+
# The task trigger is disabled
|
180
|
+
TASK_TRIGGER_FLAG_DISABLED = 0x4
|
181
|
+
|
182
|
+
# :stopdoc:
|
183
|
+
|
184
|
+
TASK_MAX_RUN_TIMES = 1440
|
185
|
+
TASKS_TO_RETRIEVE = 5
|
186
|
+
|
187
|
+
# Task creation
|
188
|
+
|
189
|
+
TASK_VALIDATE_ONLY = 0x1
|
190
|
+
TASK_CREATE = 0x2
|
191
|
+
TASK_UPDATE = 0x4
|
192
|
+
TASK_CREATE_OR_UPDATE = 0x6
|
193
|
+
TASK_DISABLE = 0x8
|
194
|
+
TASK_DONT_ADD_PRINCIPAL_ACE = 0x10
|
195
|
+
TASK_IGNORE_REGISTRATION_TRIGGERS = 0x20
|
196
|
+
|
197
|
+
# Task logon types
|
198
|
+
|
199
|
+
TASK_LOGON_NONE = 0
|
200
|
+
TASK_LOGON_PASSWORD = 1
|
201
|
+
TASK_LOGON_S4U = 2
|
202
|
+
TASK_LOGON_INTERACTIVE_TOKEN = 3
|
203
|
+
TASK_LOGON_GROUP = 4
|
204
|
+
TASK_LOGON_SERVICE_ACCOUNT = 5
|
205
|
+
TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD = 6
|
206
|
+
|
207
|
+
# Priority classes
|
208
|
+
|
209
|
+
REALTIME_PRIORITY_CLASS = 0
|
210
|
+
HIGH_PRIORITY_CLASS = 1
|
211
|
+
ABOVE_NORMAL_PRIORITY_CLASS = 2 # Or 3
|
212
|
+
NORMAL_PRIORITY_CLASS = 4 # Or 5, 6
|
213
|
+
BELOW_NORMAL_PRIORITY_CLASS = 7 # Or 8
|
214
|
+
IDLE_PRIORITY_CLASS = 9 # Or 10
|
215
|
+
|
216
|
+
CLSCTX_INPROC_SERVER = 0x1
|
217
|
+
CLSID_CTask = [0x148BD520,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
218
|
+
CLSID_CTaskScheduler = [0x148BD52A,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
219
|
+
IID_ITaskScheduler = [0x148BD527,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
220
|
+
IID_ITask = [0x148BD524,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
|
221
|
+
IID_IPersistFile = [0x0000010b,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46].pack('LSSC8')
|
222
|
+
|
223
|
+
# :startdoc:
|
224
|
+
|
225
|
+
attr_accessor :password
|
226
|
+
attr_reader :host
|
227
|
+
|
228
|
+
# Returns a new TaskScheduler object, attached to +folder+. If that
|
229
|
+
# folder does not exist, but the +force+ option is set to true, then
|
230
|
+
# it will be created. Otherwise an error will be raised. The default
|
231
|
+
# is to use the root folder.
|
232
|
+
#
|
233
|
+
# If +task+ and +trigger+ are present, then a new task is generated
|
234
|
+
# as well. This is effectively the same as .new + #new_work_item.
|
235
|
+
#
|
236
|
+
def initialize(task = nil, trigger = nil, folder = "\\", force = false)
|
237
|
+
@folder = folder
|
238
|
+
@force = force
|
239
|
+
|
240
|
+
@host = Socket.gethostname
|
241
|
+
@task = nil
|
242
|
+
@password = nil
|
243
|
+
|
244
|
+
raise ArgumentError, "invalid folder" unless folder.include?("\\")
|
245
|
+
|
246
|
+
unless [TrueClass, FalseClass].include?(force.class)
|
247
|
+
raise TypeError, "invalid force value"
|
248
|
+
end
|
249
|
+
|
250
|
+
begin
|
251
|
+
@service = WIN32OLE.new('Schedule.Service')
|
252
|
+
rescue WIN32OLERuntimeError => err
|
253
|
+
raise Error, err.inspect
|
254
|
+
end
|
255
|
+
|
256
|
+
@service.Connect
|
257
|
+
|
258
|
+
if folder != "\\"
|
259
|
+
begin
|
260
|
+
@root = @service.GetFolder(folder)
|
261
|
+
rescue WIN32OLERuntimeError => err
|
262
|
+
if force
|
263
|
+
@root.CreateFolder(folder)
|
264
|
+
@root = @service.GetFolder(folder)
|
265
|
+
else
|
266
|
+
raise ArgumentError, "folder '#{folder}' not found"
|
267
|
+
end
|
268
|
+
end
|
269
|
+
else
|
270
|
+
@root = @service.GetFolder(folder)
|
271
|
+
end
|
272
|
+
|
273
|
+
if task && trigger
|
274
|
+
new_work_item(task, trigger)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# Returns an array of scheduled task names.
|
279
|
+
#
|
280
|
+
def enum
|
281
|
+
# Get the task folder that contains the tasks.
|
282
|
+
taskCollection = @root.GetTasks(0)
|
283
|
+
|
284
|
+
array = []
|
285
|
+
|
286
|
+
taskCollection.each do |registeredTask|
|
287
|
+
array << registeredTask.Name
|
288
|
+
end
|
289
|
+
|
290
|
+
array
|
291
|
+
end
|
292
|
+
|
293
|
+
alias tasks enum
|
294
|
+
|
295
|
+
# Returns whether or not the specified task exists.
|
296
|
+
#
|
297
|
+
def exists?(task)
|
298
|
+
enum.include?(task)
|
299
|
+
end
|
300
|
+
|
301
|
+
# Activate the specified task.
|
302
|
+
#
|
303
|
+
def activate(task)
|
304
|
+
raise TypeError unless task.is_a?(String)
|
305
|
+
|
306
|
+
begin
|
307
|
+
registeredTask = @root.GetTask(task)
|
308
|
+
registeredTask.Enabled = 1
|
309
|
+
@task = registeredTask
|
310
|
+
rescue WIN32OLERuntimeError => err
|
311
|
+
raise Error, ole_error('activate', err)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
# Delete the specified task name.
|
316
|
+
#
|
317
|
+
def delete(task)
|
318
|
+
raise TypeError unless task.is_a?(String)
|
319
|
+
|
320
|
+
begin
|
321
|
+
@root.DeleteTask(task, 0)
|
322
|
+
rescue WIN32OLERuntimeError => err
|
323
|
+
raise Error, ole_error('DeleteTask', err)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
# Execute the current task.
|
328
|
+
#
|
329
|
+
def run
|
330
|
+
check_for_active_task
|
331
|
+
@task.run(nil)
|
332
|
+
end
|
333
|
+
|
334
|
+
# This method no longer has any effect. It is a no-op that remains for
|
335
|
+
# backwards compatibility. It will be removed in 0.4.0.
|
336
|
+
#
|
337
|
+
def save(file = nil)
|
338
|
+
warn DeprecatedMethodWarning, "this method is no longer necessary"
|
339
|
+
check_for_active_task
|
340
|
+
# Do nothing, deprecated.
|
341
|
+
end
|
342
|
+
|
343
|
+
# Terminate (stop) the current task.
|
344
|
+
#
|
345
|
+
def terminate
|
346
|
+
check_for_active_task
|
347
|
+
@task.stop(nil)
|
348
|
+
end
|
349
|
+
|
350
|
+
alias stop terminate
|
351
|
+
|
352
|
+
# Set the host on which the various TaskScheduler methods will execute.
|
353
|
+
# This method may require administrative privileges.
|
354
|
+
#
|
355
|
+
def machine=(host)
|
356
|
+
raise TypeError unless host.is_a?(String)
|
357
|
+
|
358
|
+
begin
|
359
|
+
@service.Connect(host)
|
360
|
+
rescue WIN32OLERuntimeError => err
|
361
|
+
raise Error, ole_error('Connect', err)
|
362
|
+
end
|
363
|
+
|
364
|
+
@host = host
|
365
|
+
host
|
366
|
+
end
|
367
|
+
|
368
|
+
# Similar to the TaskScheduler#machine= method, this method also allows
|
369
|
+
# you to pass a user, domain and password as needed. This method may
|
370
|
+
# require administrative privileges.
|
371
|
+
#
|
372
|
+
def set_machine(host, user = nil, domain = nil, password = nil)
|
373
|
+
raise TypeError unless host.is_a?(String)
|
374
|
+
|
375
|
+
begin
|
376
|
+
@service.Connect(host, user, domain, password)
|
377
|
+
rescue WIN32OLERuntimeError => err
|
378
|
+
raise Error, ole_error('Connect', err)
|
379
|
+
end
|
380
|
+
|
381
|
+
@host = host
|
382
|
+
host
|
383
|
+
end
|
384
|
+
|
385
|
+
alias host= machine=
|
386
|
+
alias machine host
|
387
|
+
alias set_host set_machine
|
388
|
+
|
389
|
+
# Sets the +user+ and +password+ for the given task. If the user and
|
390
|
+
# password are set properly then true is returned.
|
391
|
+
#
|
392
|
+
def set_account_information(user, password)
|
393
|
+
raise TypeError unless user.is_a?(String)
|
394
|
+
raise TypeError unless password.is_a?(String)
|
395
|
+
check_for_active_task
|
396
|
+
|
397
|
+
@password = password
|
398
|
+
|
399
|
+
begin
|
400
|
+
@task = @root.RegisterTaskDefinition(
|
401
|
+
@task.Path,
|
402
|
+
@task.Definition,
|
403
|
+
TASK_CREATE_OR_UPDATE,
|
404
|
+
user,
|
405
|
+
password,
|
406
|
+
TASK_LOGON_PASSWORD
|
407
|
+
)
|
408
|
+
rescue WIN32OLERuntimeError => err
|
409
|
+
raise Error, ole_error('RegisterTaskDefinition', err)
|
410
|
+
end
|
411
|
+
|
412
|
+
true
|
413
|
+
end
|
414
|
+
|
415
|
+
# Returns the user associated with the task or nil if no user has yet
|
416
|
+
# been associated with the task.
|
417
|
+
#
|
418
|
+
def account_information
|
419
|
+
@task.nil? ? nil : @task.Definition.Principal.UserId
|
420
|
+
end
|
421
|
+
|
422
|
+
# Returns the name of the application associated with the task. If
|
423
|
+
# no application is associated with the task then nil is returned.
|
424
|
+
#
|
425
|
+
def application_name
|
426
|
+
check_for_active_task
|
427
|
+
|
428
|
+
app = nil
|
429
|
+
|
430
|
+
@task.Definition.Actions.each do |action|
|
431
|
+
if action.Type == 0 # TASK_ACTION_EXEC
|
432
|
+
app = action.Path
|
433
|
+
break
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
app
|
438
|
+
end
|
439
|
+
|
440
|
+
# Sets the name of the application associated with the task.
|
441
|
+
#
|
442
|
+
def application_name=(app)
|
443
|
+
raise TypeError unless app.is_a?(String)
|
444
|
+
check_for_active_task
|
445
|
+
|
446
|
+
definition = @task.Definition
|
447
|
+
|
448
|
+
definition.Actions.each do |action|
|
449
|
+
action.Path = app if action.Type == 0
|
450
|
+
end
|
451
|
+
|
452
|
+
update_task_definition(definition)
|
453
|
+
|
454
|
+
app
|
455
|
+
end
|
456
|
+
|
457
|
+
# Returns the command line parameters for the task.
|
458
|
+
#
|
459
|
+
def parameters
|
460
|
+
check_for_active_task
|
461
|
+
|
462
|
+
param = nil
|
463
|
+
|
464
|
+
@task.Definition.Actions.each do |action|
|
465
|
+
param = action.Arguments if action.Type == 0
|
466
|
+
end
|
467
|
+
|
468
|
+
param
|
469
|
+
end
|
470
|
+
|
471
|
+
# Sets the parameters for the task. These parameters are passed as command
|
472
|
+
# line arguments to the application the task will run. To clear the command
|
473
|
+
# line parameters set it to an empty string.
|
474
|
+
#--
|
475
|
+
# NOTE: Again, it seems the task must be reactivated to be picked up.
|
476
|
+
#
|
477
|
+
def parameters=(param)
|
478
|
+
raise TypeError unless param.is_a?(String)
|
479
|
+
check_for_active_task
|
480
|
+
|
481
|
+
definition = @task.Definition
|
482
|
+
|
483
|
+
definition.Actions.each do |action|
|
484
|
+
action.Arguments = param if action.Type == 0
|
485
|
+
end
|
486
|
+
|
487
|
+
update_task_definition(definition)
|
488
|
+
|
489
|
+
param
|
490
|
+
end
|
491
|
+
|
492
|
+
# Returns the working directory for the task.
|
493
|
+
#
|
494
|
+
def working_directory
|
495
|
+
check_for_active_task
|
496
|
+
|
497
|
+
dir = nil
|
498
|
+
|
499
|
+
@task.Definition.Actions.each do |action|
|
500
|
+
dir = action.WorkingDirectory if action.Type == 0
|
501
|
+
end
|
502
|
+
|
503
|
+
dir
|
504
|
+
end
|
505
|
+
|
506
|
+
# Sets the working directory for the task.
|
507
|
+
#--
|
508
|
+
# TODO: Why do I have to reactivate the task to see the change?
|
509
|
+
#
|
510
|
+
def working_directory=(dir)
|
511
|
+
raise TypeError unless dir.is_a?(String)
|
512
|
+
check_for_active_task
|
513
|
+
|
514
|
+
definition = @task.Definition
|
515
|
+
|
516
|
+
definition.Actions.each do |action|
|
517
|
+
action.WorkingDirectory = dir if action.Type == 0
|
518
|
+
end
|
519
|
+
|
520
|
+
update_task_definition(definition)
|
521
|
+
|
522
|
+
dir
|
523
|
+
end
|
524
|
+
|
525
|
+
# Returns the task's priority level. Possible values are 'idle',
|
526
|
+
# 'normal', 'high', 'realtime', 'below_normal', 'above_normal',
|
527
|
+
# and 'unknown'.
|
528
|
+
#
|
529
|
+
def priority
|
530
|
+
check_for_active_task
|
531
|
+
|
532
|
+
case @task.Definition.Settings.Priority
|
533
|
+
when 0
|
534
|
+
priority = 'critical'
|
535
|
+
when 1
|
536
|
+
priority = 'highest'
|
537
|
+
when 2
|
538
|
+
priority = 'above_normal'
|
539
|
+
when 3
|
540
|
+
priority = 'above_normal'
|
541
|
+
when 4
|
542
|
+
priority = 'normal'
|
543
|
+
when 5
|
544
|
+
priority = 'normal'
|
545
|
+
when 6
|
546
|
+
priority = 'normal'
|
547
|
+
when 7
|
548
|
+
priority = 'below_normal'
|
549
|
+
when 8
|
550
|
+
priority = 'below_normal'
|
551
|
+
when 9
|
552
|
+
priority = 'lowest'
|
553
|
+
when 10
|
554
|
+
priority = 'idle'
|
555
|
+
else
|
556
|
+
priority = 'unknown'
|
557
|
+
end
|
558
|
+
|
559
|
+
priority
|
560
|
+
end
|
561
|
+
|
562
|
+
# Sets the priority of the task. The +priority+ should be a numeric
|
563
|
+
# priority constant value.
|
564
|
+
#
|
565
|
+
def priority=(priority)
|
566
|
+
raise TypeError unless priority.is_a?(Numeric)
|
567
|
+
check_for_active_task
|
568
|
+
|
569
|
+
definition = @task.Definition
|
570
|
+
definition.Settings.Priority = priority
|
571
|
+
|
572
|
+
update_task_definition(definition)
|
573
|
+
|
574
|
+
priority
|
575
|
+
end
|
576
|
+
|
577
|
+
# Creates a new work item (scheduled job) with the given +trigger+. The
|
578
|
+
# trigger variable is a hash of options that define when the scheduled
|
579
|
+
# job should run.
|
580
|
+
#
|
581
|
+
def new_work_item(task, trigger)
|
582
|
+
raise TypeError unless task.is_a?(String)
|
583
|
+
raise TypeError unless trigger.is_a?(Hash)
|
584
|
+
|
585
|
+
validate_trigger(trigger)
|
586
|
+
|
587
|
+
taskDefinition = @service.NewTask(0)
|
588
|
+
taskDefinition.RegistrationInfo.Description = ''
|
589
|
+
taskDefinition.RegistrationInfo.Author = ''
|
590
|
+
taskDefinition.Settings.StartWhenAvailable = true
|
591
|
+
taskDefinition.Settings.Enabled = true
|
592
|
+
taskDefinition.Settings.Hidden = false
|
593
|
+
|
594
|
+
case trigger[:trigger_type]
|
595
|
+
when TASK_TIME_TRIGGER_ONCE
|
596
|
+
type = 1
|
597
|
+
when TASK_TIME_TRIGGER_DAILY
|
598
|
+
type = 2
|
599
|
+
when TASK_TIME_TRIGGER_WEEKLY
|
600
|
+
type = 3
|
601
|
+
when TASK_TIME_TRIGGER_MONTHLYDATE
|
602
|
+
type = 4
|
603
|
+
when TASK_TIME_TRIGGER_MONTHLYDOW
|
604
|
+
type = 5
|
605
|
+
when TASK_EVENT_TRIGGER_ON_IDLE
|
606
|
+
type = 6
|
607
|
+
when TASK_EVENT_TRIGGER_AT_SYSTEMSTART
|
608
|
+
type = 8
|
609
|
+
when TASK_EVENT_TRIGGER_AT_LOGON
|
610
|
+
type = 9
|
611
|
+
else
|
612
|
+
raise ArgumentError, 'Unknown trigger type'
|
613
|
+
end
|
614
|
+
|
615
|
+
startTime = "%04d-%02d-%02dT%02d:%02d:00" % [
|
616
|
+
trigger[:start_year], trigger[:start_month], trigger[:start_day],
|
617
|
+
trigger[:start_hour], trigger[:start_minute]
|
618
|
+
]
|
619
|
+
|
620
|
+
# Set defaults
|
621
|
+
trigger[:end_year] ||= 0
|
622
|
+
trigger[:end_month] ||= 0
|
623
|
+
trigger[:end_day] ||= 0
|
624
|
+
|
625
|
+
endTime = "%04d-%02d-%02dT00:00:00" % [
|
626
|
+
trigger[:end_year], trigger[:end_month], trigger[:end_day]
|
627
|
+
]
|
628
|
+
|
629
|
+
trig = taskDefinition.Triggers.Create(type)
|
630
|
+
trig.Id = "RegistrationTriggerId#{taskDefinition.Triggers.Count}"
|
631
|
+
trig.StartBoundary = startTime
|
632
|
+
trig.EndBoundary = endTime if endTime != '0000-00-00T00:00:00'
|
633
|
+
trig.Enabled = true
|
634
|
+
|
635
|
+
repetitionPattern = trig.Repetition
|
636
|
+
|
637
|
+
if trigger[:minutes_duration].to_i > 0
|
638
|
+
repetitionPattern.Duration = "PT#{trigger[:minutes_duration]||0}M"
|
639
|
+
end
|
640
|
+
|
641
|
+
if trigger[:minutes_interval].to_i > 0
|
642
|
+
repetitionPattern.Interval = "PT#{trigger[:minutes_interval]||0}M"
|
643
|
+
end
|
644
|
+
|
645
|
+
tmp = trigger[:type]
|
646
|
+
tmp = nil unless tmp.is_a?(Hash)
|
647
|
+
|
648
|
+
case trigger[:trigger_type]
|
649
|
+
when TASK_TIME_TRIGGER_DAILY
|
650
|
+
trig.DaysInterval = tmp[:days_interval] if tmp && tmp[:days_interval]
|
651
|
+
if trigger[:random_minutes_interval].to_i > 0
|
652
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]}M"
|
653
|
+
end
|
654
|
+
when TASK_TIME_TRIGGER_WEEKLY
|
655
|
+
trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
|
656
|
+
trig.WeeksInterval = tmp[:weeks_interval] if tmp && tmp[:weeks_interval]
|
657
|
+
if trigger[:random_minutes_interval].to_i > 0
|
658
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
|
659
|
+
end
|
660
|
+
when TASK_TIME_TRIGGER_MONTHLYDATE
|
661
|
+
trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
|
662
|
+
trig.DaysOfMonth = tmp[:days] if tmp && tmp[:days]
|
663
|
+
if trigger[:random_minutes_interval].to_i > 0
|
664
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
|
665
|
+
end
|
666
|
+
when TASK_TIME_TRIGGER_MONTHLYDOW
|
667
|
+
trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
|
668
|
+
trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
|
669
|
+
trig.WeeksOfMonth = tmp[:weeks] if tmp && tmp[:weeks]
|
670
|
+
if trigger[:random_minutes_interval].to_i>0
|
671
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
|
672
|
+
end
|
673
|
+
when TASK_TIME_TRIGGER_ONCE
|
674
|
+
if trigger[:random_minutes_interval].to_i > 0
|
675
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
act = taskDefinition.Actions.Create(0)
|
680
|
+
act.Path = 'cmd'
|
681
|
+
|
682
|
+
|
683
|
+
begin
|
684
|
+
@task = @root.RegisterTaskDefinition(
|
685
|
+
task,
|
686
|
+
taskDefinition,
|
687
|
+
TASK_CREATE_OR_UPDATE,
|
688
|
+
nil,
|
689
|
+
nil,
|
690
|
+
TASK_LOGON_INTERACTIVE_TOKEN
|
691
|
+
)
|
692
|
+
rescue WIN32OLERuntimeError => err
|
693
|
+
raise Error, ole_error('RegisterTaskDefinition', err)
|
694
|
+
end
|
695
|
+
|
696
|
+
@task = @root.GetTask(task)
|
697
|
+
end
|
698
|
+
|
699
|
+
alias new_task new_work_item
|
700
|
+
|
701
|
+
# Returns the number of triggers associated with the active task.
|
702
|
+
#
|
703
|
+
def trigger_count
|
704
|
+
raise Error, "No currently active task" if @task.nil?
|
705
|
+
|
706
|
+
@task.Definition.Triggers.Count
|
707
|
+
end
|
708
|
+
|
709
|
+
# Returns a string that describes the current trigger at the specified
|
710
|
+
# index for the active task.
|
711
|
+
#
|
712
|
+
# Example: "At 7:14 AM every day, starting 4/11/2015"
|
713
|
+
#
|
714
|
+
def trigger_string(index)
|
715
|
+
raise TypeError unless index.is_a?(Numeric)
|
716
|
+
check_for_active_task
|
717
|
+
index += 1 # first item index is 1
|
718
|
+
|
719
|
+
begin
|
720
|
+
trigger = @task.Definition.Triggers.Item(index)
|
721
|
+
rescue WIN32OLERuntimeError
|
722
|
+
raise Error, "No trigger found at index '#{index}'"
|
723
|
+
end
|
724
|
+
|
725
|
+
"Starting #{trigger.StartBoundary}"
|
726
|
+
end
|
727
|
+
|
728
|
+
# Deletes the trigger at the specified index.
|
729
|
+
#--
|
730
|
+
# TODO: Fix.
|
731
|
+
#
|
732
|
+
def delete_trigger(index)
|
733
|
+
raise TypeError unless index.is_a?(Numeric)
|
734
|
+
check_for_active_task
|
735
|
+
index += 1 # first item index is 1
|
736
|
+
|
737
|
+
definition = @task.Definition
|
738
|
+
definition.Triggers.Remove(index)
|
739
|
+
update_task_definition(definition)
|
740
|
+
|
741
|
+
index
|
742
|
+
end
|
743
|
+
|
744
|
+
# Returns a hash that describes the trigger at the given index for the
|
745
|
+
# current task.
|
746
|
+
#
|
747
|
+
def trigger(index)
|
748
|
+
raise TypeError unless index.is_a?(Numeric)
|
749
|
+
check_for_active_task
|
750
|
+
index += 1 # first item index is 1
|
751
|
+
|
752
|
+
begin
|
753
|
+
trig = @task.Definition.Triggers.Item(index)
|
754
|
+
rescue WIN32OLERuntimeError => err
|
755
|
+
raise Error, ole_error('Item', err)
|
756
|
+
end
|
757
|
+
|
758
|
+
trigger = {}
|
759
|
+
trigger[:start_year], trigger[:start_month],
|
760
|
+
trigger[:start_day], trigger[:start_hour],
|
761
|
+
trigger[:start_minute] = trig.StartBoundary.scan(/(\d+)-(\d+)-(\d+)T(\d+):(\d+)/).first
|
762
|
+
|
763
|
+
trigger[:end_year], trigger[:end_month],
|
764
|
+
trigger[:end_day] = trig.StartBoundary.scan(/(\d+)-(\d+)-(\d+)T/).first
|
765
|
+
|
766
|
+
if trig.Repetition.Duration != ""
|
767
|
+
trigger[:minutes_duration] = trig.Repetition.Duration.scan(/(\d+)M/)[0][0].to_i
|
768
|
+
end
|
769
|
+
|
770
|
+
if trig.Repetition.Interval != ""
|
771
|
+
trigger[:minutes_interval] = trig.Repetition.Interval.scan(/(\d+)M/)[0][0].to_i
|
772
|
+
end
|
773
|
+
|
774
|
+
if trig.RandomDelay != ""
|
775
|
+
trigger[:random_minutes_interval] = trig.RandomDelay.scan(/(\d+)M/)[0][0].to_i
|
776
|
+
end
|
777
|
+
|
778
|
+
case trig.Type
|
779
|
+
when 2
|
780
|
+
trigger[:trigger_type] = TASK_TIME_TRIGGER_DAILY
|
781
|
+
tmp = {}
|
782
|
+
tmp[:days_interval] = trig.DaysInterval
|
783
|
+
trigger[:type] = tmp
|
784
|
+
when 3
|
785
|
+
trigger[:trigger_type] = TASK_TIME_TRIGGER_WEEKLY
|
786
|
+
tmp = {}
|
787
|
+
tmp[:weeks_interval] = trig.WeeksInterval
|
788
|
+
tmp[:days_of_week] = trig.DaysOfWeek
|
789
|
+
trigger[:type] = tmp
|
790
|
+
when 4
|
791
|
+
trigger[:trigger_type] = TASK_TIME_TRIGGER_MONTHLYDATE
|
792
|
+
tmp = {}
|
793
|
+
tmp[:months] = trig.MonthsOfYear
|
794
|
+
tmp[:days] = trig.DaysOfMonth
|
795
|
+
trigger[:type] = tmp
|
796
|
+
when 5
|
797
|
+
trigger[:trigger_type] = TASK_TIME_TRIGGER_MONTHLYDOW
|
798
|
+
tmp = {}
|
799
|
+
tmp[:months] = trig.MonthsOfYear
|
800
|
+
tmp[:days_of_week] = trig.DaysOfWeek
|
801
|
+
tmp[:weeks] = trig.weeks
|
802
|
+
trigger[:type] = tmp
|
803
|
+
when 1
|
804
|
+
trigger[:trigger_type] = TASK_TIME_TRIGGER_ONCE
|
805
|
+
tmp = {}
|
806
|
+
tmp[:once] = nil
|
807
|
+
trigger[:type] = tmp
|
808
|
+
else
|
809
|
+
raise Error, 'Unknown trigger type'
|
810
|
+
end
|
811
|
+
|
812
|
+
trigger
|
813
|
+
end
|
814
|
+
|
815
|
+
# Sets the trigger for the currently active task. The +trigger+ is a hash
|
816
|
+
# with the following possible options:
|
817
|
+
#
|
818
|
+
# * days
|
819
|
+
# * days_interval
|
820
|
+
# * days_of_week
|
821
|
+
# * end_day
|
822
|
+
# * end_month
|
823
|
+
# * end_year
|
824
|
+
# * flags
|
825
|
+
# * minutes_duration
|
826
|
+
# * minutes_interval
|
827
|
+
# * months
|
828
|
+
# * random_minutes_interval
|
829
|
+
# * start_day
|
830
|
+
# * start_hour
|
831
|
+
# * start_minute
|
832
|
+
# * start_month
|
833
|
+
# * start_year
|
834
|
+
# * trigger_type
|
835
|
+
# * type
|
836
|
+
# * weeks
|
837
|
+
# * weeks_interval
|
838
|
+
#
|
839
|
+
def trigger=(trigger)
|
840
|
+
raise TypeError unless trigger.is_a?(Hash)
|
841
|
+
check_for_active_task
|
842
|
+
|
843
|
+
validate_trigger(trigger)
|
844
|
+
|
845
|
+
definition = @task.Definition
|
846
|
+
definition.Triggers.Clear()
|
847
|
+
|
848
|
+
case trigger[:trigger_type]
|
849
|
+
when TASK_TIME_TRIGGER_ONCE
|
850
|
+
type = 1
|
851
|
+
when TASK_TIME_TRIGGER_DAILY
|
852
|
+
type = 2
|
853
|
+
when TASK_TIME_TRIGGER_WEEKLY
|
854
|
+
type = 3
|
855
|
+
when TASK_TIME_TRIGGER_MONTHLYDATE
|
856
|
+
type = 4
|
857
|
+
when TASK_TIME_TRIGGER_MONTHLYDOW
|
858
|
+
type = 5
|
859
|
+
when TASK_EVENT_TRIGGER_ON_IDLE
|
860
|
+
type = 6
|
861
|
+
when TASK_EVENT_TRIGGER_AT_SYSTEM_START
|
862
|
+
type = 8
|
863
|
+
when TASK_EVENT_TRIGGER_AT_LOGON
|
864
|
+
type = 9
|
865
|
+
else
|
866
|
+
raise Error, 'Unknown trigger type'
|
867
|
+
end
|
868
|
+
|
869
|
+
startTime = "%04d-%02d-%02dT%02d:%02d:00" % [
|
870
|
+
trigger[:start_year], trigger[:start_month],
|
871
|
+
trigger[:start_day], trigger[:start_hour], trigger[:start_minute]
|
872
|
+
]
|
873
|
+
|
874
|
+
endTime = "%04d-%02d-%02dT00:00:00" % [
|
875
|
+
trigger[:end_year], trigger[:end_month], trigger[:end_day]
|
876
|
+
]
|
877
|
+
|
878
|
+
trig = definition.Triggers.Create(type)
|
879
|
+
trig.Id = "RegistrationTriggerId#{definition.Triggers.Count}"
|
880
|
+
trig.StartBoundary = startTime
|
881
|
+
trig.EndBoundary = endTime if endTime != '0000-00-00T00:00:00'
|
882
|
+
trig.Enabled = true
|
883
|
+
|
884
|
+
repetitionPattern = trig.Repetition
|
885
|
+
|
886
|
+
if trigger[:minutes_duration].to_i > 0
|
887
|
+
repetitionPattern.Duration = "PT#{trigger[:minutes_duration]||0}M"
|
888
|
+
end
|
889
|
+
|
890
|
+
if trigger[:minutes_interval].to_i > 0
|
891
|
+
repetitionPattern.Interval = "PT#{trigger[:minutes_interval]||0}M"
|
892
|
+
end
|
893
|
+
|
894
|
+
tmp = trigger[:type]
|
895
|
+
tmp = nil unless tmp.is_a?(Hash)
|
896
|
+
|
897
|
+
case trigger[:trigger_type]
|
898
|
+
when TASK_TIME_TRIGGER_DAILY
|
899
|
+
trig.DaysInterval = tmp[:days_interval] if tmp && tmp[:days_interval]
|
900
|
+
if trigger[:random_minutes_interval].to_i > 0
|
901
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]}M"
|
902
|
+
end
|
903
|
+
when TASK_TIME_TRIGGER_WEEKLY
|
904
|
+
trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
|
905
|
+
trig.WeeksInterval = tmp[:weeks_interval] if tmp && tmp[:weeks_interval]
|
906
|
+
if trigger[:random_minutes_interval].to_i > 0
|
907
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
|
908
|
+
end
|
909
|
+
when TASK_TIME_TRIGGER_MONTHLYDATE
|
910
|
+
trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
|
911
|
+
trig.DaysOfMonth = tmp[:days] if tmp && tmp[:days]
|
912
|
+
if trigger[:random_minutes_interval].to_i > 0
|
913
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
|
914
|
+
end
|
915
|
+
when TASK_TIME_TRIGGER_MONTHLYDOW
|
916
|
+
trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
|
917
|
+
trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
|
918
|
+
trig.WeeksOfMonth = tmp[:weeks] if tmp && tmp[:weeks]
|
919
|
+
if trigger[:random_minutes_interval].to_i > 0
|
920
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
|
921
|
+
end
|
922
|
+
when TASK_TIME_TRIGGER_ONCE
|
923
|
+
if trigger[:random_minutes_interval].to_i > 0
|
924
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
|
925
|
+
end
|
926
|
+
end
|
927
|
+
|
928
|
+
update_task_definition(definition)
|
929
|
+
|
930
|
+
trigger
|
931
|
+
end
|
932
|
+
|
933
|
+
# Adds a trigger at the specified index.
|
934
|
+
#
|
935
|
+
def add_trigger(index, trigger)
|
936
|
+
raise TypeError unless index.is_a?(Numeric)
|
937
|
+
raise TypeError unless trigger.is_a?(Hash)
|
938
|
+
check_for_active_task
|
939
|
+
|
940
|
+
definition = @task.Definition
|
941
|
+
case trigger[:trigger_type]
|
942
|
+
when TASK_TIME_TRIGGER_DAILY
|
943
|
+
type = 2
|
944
|
+
when TASK_TIME_TRIGGER_WEEKLY
|
945
|
+
type = 3
|
946
|
+
when TASK_TIME_TRIGGER_MONTHLYDATE
|
947
|
+
type = 4
|
948
|
+
when TASK_TIME_TRIGGER_MONTHLYDOW
|
949
|
+
type = 5
|
950
|
+
when TASK_TIME_TRIGGER_ONCE
|
951
|
+
type = 1
|
952
|
+
else
|
953
|
+
raise Error, 'Unknown trigger type'
|
954
|
+
end
|
955
|
+
|
956
|
+
startTime = "%04d-%02d-%02dT%02d:%02d:00" % [
|
957
|
+
trigger[:start_year], trigger[:start_month], trigger[:start_day],
|
958
|
+
trigger[:start_hour], trigger[:start_minute]
|
959
|
+
]
|
960
|
+
|
961
|
+
# Set defaults
|
962
|
+
trigger[:end_year] ||= 0
|
963
|
+
trigger[:end_month] ||= 0
|
964
|
+
trigger[:end_day] ||= 0
|
965
|
+
|
966
|
+
endTime = "%04d-%02d-%02dT00:00:00" % [
|
967
|
+
trigger[:end_year], trigger[:end_month], trigger[:end_day]
|
968
|
+
]
|
969
|
+
|
970
|
+
trig = definition.Triggers.Create(type)
|
971
|
+
trig.Id = "RegistrationTriggerId#{definition.Triggers.Count}"
|
972
|
+
trig.StartBoundary = startTime
|
973
|
+
trig.EndBoundary = endTime if endTime != '0000-00-00T00:00:00'
|
974
|
+
trig.Enabled = true
|
975
|
+
|
976
|
+
repetitionPattern = trig.Repetition
|
977
|
+
|
978
|
+
if trigger[:minutes_duration].to_i > 0
|
979
|
+
repetitionPattern.Duration = "PT#{trigger[:minutes_duration]||0}M"
|
980
|
+
end
|
981
|
+
|
982
|
+
if trigger[:minutes_interval].to_i > 0
|
983
|
+
repetitionPattern.Interval = "PT#{trigger[:minutes_interval]||0}M"
|
984
|
+
end
|
985
|
+
|
986
|
+
tmp = trigger[:type]
|
987
|
+
tmp = nil unless tmp.is_a?(Hash)
|
988
|
+
|
989
|
+
case trigger[:trigger_type]
|
990
|
+
when TASK_TIME_TRIGGER_DAILY
|
991
|
+
trig.DaysInterval = tmp[:days_interval] if tmp && tmp[:days_interval]
|
992
|
+
if trigger[:random_minutes_interval].to_i > 0
|
993
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]}M"
|
994
|
+
end
|
995
|
+
when TASK_TIME_TRIGGER_WEEKLY
|
996
|
+
trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
|
997
|
+
trig.WeeksInterval = tmp[:weeks_interval] if tmp && tmp[:weeks_interval]
|
998
|
+
if trigger[:random_minutes_interval].to_i > 0
|
999
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
|
1000
|
+
end
|
1001
|
+
when TASK_TIME_TRIGGER_MONTHLYDATE
|
1002
|
+
trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
|
1003
|
+
trig.DaysOfMonth = tmp[:days] if tmp && tmp[:days]
|
1004
|
+
if trigger[:random_minutes_interval].to_i > 0
|
1005
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
|
1006
|
+
end
|
1007
|
+
when TASK_TIME_TRIGGER_MONTHLYDOW
|
1008
|
+
trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
|
1009
|
+
trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
|
1010
|
+
trig.WeeksOfMonth = tmp[:weeks] if tmp && tmp[:weeks]
|
1011
|
+
if trigger[:random_minutes_interval].to_i > 0
|
1012
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
|
1013
|
+
end
|
1014
|
+
when TASK_TIME_TRIGGER_ONCE
|
1015
|
+
if trigger[:random_minutes_interval].to_i > 0
|
1016
|
+
trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
update_task_definition(definition)
|
1021
|
+
|
1022
|
+
true
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
# Returns the status of the currently active task. Possible values are
|
1026
|
+
# 'ready', 'running', 'not scheduled' or 'unknown'.
|
1027
|
+
#
|
1028
|
+
def status
|
1029
|
+
check_for_active_task
|
1030
|
+
|
1031
|
+
case @task.State
|
1032
|
+
when 3
|
1033
|
+
status = 'ready'
|
1034
|
+
when 4
|
1035
|
+
status = 'running'
|
1036
|
+
when 1
|
1037
|
+
status = 'not scheduled'
|
1038
|
+
else
|
1039
|
+
status = 'unknown'
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
status
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
# Returns the exit code from the last scheduled run.
|
1046
|
+
#
|
1047
|
+
def exit_code
|
1048
|
+
check_for_active_task
|
1049
|
+
@task.LastTaskResult
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
# Returns the comment associated with the task, if any.
|
1053
|
+
#
|
1054
|
+
def comment
|
1055
|
+
check_for_active_task
|
1056
|
+
@task.Definition.RegistrationInfo.Description
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
alias description comment
|
1060
|
+
|
1061
|
+
# Sets the comment for the task.
|
1062
|
+
#
|
1063
|
+
def comment=(comment)
|
1064
|
+
raise TypeError unless comment.is_a?(String)
|
1065
|
+
check_for_active_task
|
1066
|
+
|
1067
|
+
definition = @task.Definition
|
1068
|
+
definition.RegistrationInfo.Description = comment
|
1069
|
+
update_task_definition(definition)
|
1070
|
+
|
1071
|
+
comment
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
alias description= comment=
|
1075
|
+
|
1076
|
+
# Returns the name of the user who created the task.
|
1077
|
+
#
|
1078
|
+
def creator
|
1079
|
+
check_for_active_task
|
1080
|
+
@task.Definition.RegistrationInfo.Author
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
alias author creator
|
1084
|
+
|
1085
|
+
# Sets the creator for the task.
|
1086
|
+
#
|
1087
|
+
def creator=(creator)
|
1088
|
+
raise TypeError unless creator.is_a?(String)
|
1089
|
+
check_for_active_task
|
1090
|
+
|
1091
|
+
definition = @task.Definition
|
1092
|
+
definition.RegistrationInfo.Author = creator
|
1093
|
+
update_task_definition(definition)
|
1094
|
+
|
1095
|
+
creator
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
alias author= creator=
|
1099
|
+
|
1100
|
+
# Returns a Time object that indicates the next time the task will run.
|
1101
|
+
#
|
1102
|
+
def next_run_time
|
1103
|
+
check_for_active_task
|
1104
|
+
@task.NextRunTime
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
# Returns a Time object indicating the most recent time the task ran or
|
1108
|
+
# nil if the task has never run.
|
1109
|
+
#
|
1110
|
+
def most_recent_run_time
|
1111
|
+
check_for_active_task
|
1112
|
+
|
1113
|
+
time = nil
|
1114
|
+
|
1115
|
+
begin
|
1116
|
+
time = Time.parse(@task.LastRunTime)
|
1117
|
+
rescue
|
1118
|
+
# Ignore
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
time
|
1122
|
+
end
|
1123
|
+
|
1124
|
+
# Returns the maximum length of time, in milliseconds, that the task
|
1125
|
+
# will run before terminating.
|
1126
|
+
#
|
1127
|
+
def max_run_time
|
1128
|
+
check_for_active_task
|
1129
|
+
|
1130
|
+
t = @task.Definition.Settings.ExecutionTimeLimit
|
1131
|
+
year = t.scan(/(\d+?)Y/).flatten.first
|
1132
|
+
month = t.scan(/(\d+?)M/).flatten.first
|
1133
|
+
day = t.scan(/(\d+?)D/).flatten.first
|
1134
|
+
hour = t.scan(/(\d+?)H/).flatten.first
|
1135
|
+
min = t.scan(/T.*(\d+?)M/).flatten.first
|
1136
|
+
sec = t.scan(/(\d+?)S/).flatten.first
|
1137
|
+
|
1138
|
+
time = 0
|
1139
|
+
time += year.to_i * 365 if year
|
1140
|
+
time += month.to_i * 30 if month
|
1141
|
+
time += day.to_i if day
|
1142
|
+
time *= 24
|
1143
|
+
time += hour.to_i if hour
|
1144
|
+
time *= 60
|
1145
|
+
time += min.to_i if min
|
1146
|
+
time *= 60
|
1147
|
+
time += sec.to_i if sec
|
1148
|
+
time *= 1000
|
1149
|
+
|
1150
|
+
time
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
# Sets the maximum length of time, in milliseconds, that the task can run
|
1154
|
+
# before terminating. Returns the value you specified if successful.
|
1155
|
+
#
|
1156
|
+
def max_run_time=(max_run_time)
|
1157
|
+
raise TypeError unless max_run_time.is_a?(Numeric)
|
1158
|
+
check_for_active_task
|
1159
|
+
|
1160
|
+
t = max_run_time
|
1161
|
+
t /= 1000
|
1162
|
+
limit ="PT#{t}S"
|
1163
|
+
|
1164
|
+
definition = @task.Definition
|
1165
|
+
definition.Settings.ExecutionTimeLimit = limit
|
1166
|
+
update_task_definition(definition)
|
1167
|
+
|
1168
|
+
max_run_time
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
# Accepts a hash that lets you configure various task definition settings.
|
1172
|
+
# The possible options are:
|
1173
|
+
#
|
1174
|
+
# * allow_demand_start
|
1175
|
+
# * allow_hard_terminate
|
1176
|
+
# * compatibility
|
1177
|
+
# * delete_expired_task_after
|
1178
|
+
# * disallowed_start_if_on_batteries
|
1179
|
+
# * enabled
|
1180
|
+
# * execution_time_limit (or max_run_time)
|
1181
|
+
# * hidden
|
1182
|
+
# * idle_settings
|
1183
|
+
# * network_settings
|
1184
|
+
# * priority
|
1185
|
+
# * restart_count
|
1186
|
+
# * restart_interval
|
1187
|
+
# * run_only_if_idle
|
1188
|
+
# * run_only_if_network_available
|
1189
|
+
# * start_when_available
|
1190
|
+
# * stop_if_going_on_batteries
|
1191
|
+
# * wake_to_run
|
1192
|
+
# * xml_text (or xml)
|
1193
|
+
#
|
1194
|
+
def configure_settings(hash)
|
1195
|
+
raise TypeError unless hash.is_a?(Hash)
|
1196
|
+
check_for_active_task
|
1197
|
+
|
1198
|
+
definition = @task.Definition
|
1199
|
+
|
1200
|
+
allow_demand_start = hash[:allow_demand_start]
|
1201
|
+
allow_hard_terminate = hash[:allow_hard_terminate]
|
1202
|
+
compatibility = hash[:compatibility]
|
1203
|
+
delete_expired_task_after = hash[:delete_expired_task_after]
|
1204
|
+
disallow_start_if_on_batteries = hash[:disallow_start_if_on_batteries]
|
1205
|
+
enabled = hash[:enabled]
|
1206
|
+
execution_time_limit = hash[:execution_time_limit] || hash[:max_run_time]
|
1207
|
+
hidden = hash[:hidden]
|
1208
|
+
idle_settings = hash[:idle_settings]
|
1209
|
+
network_settings = hash[:network_settings]
|
1210
|
+
priority = hash[:priority]
|
1211
|
+
restart_count = hash[:restart_count]
|
1212
|
+
restart_interval = hash[:restart_interval]
|
1213
|
+
run_only_if_idle = hash[:run_only_if_idle]
|
1214
|
+
run_only_if_network_available = hash[:run_only_if_network_available]
|
1215
|
+
start_when_available = hash[:start_when_available]
|
1216
|
+
stop_if_going_on_batteries = hash[:stop_if_going_on_batteries]
|
1217
|
+
wake_to_run = hash[:wake_to_run]
|
1218
|
+
xml_text = hash[:xml_text] || hash[:xml]
|
1219
|
+
|
1220
|
+
definition.Settings.AllowDemandStart = allow_demand_start if allow_demand_start
|
1221
|
+
definition.Settings.AllowHardTerminate = allow_hard_terminate if allow_hard_terminate
|
1222
|
+
definition.Settings.Compatibility = compatibility if compatibility
|
1223
|
+
definition.Settings.DeleteExpiredTaskAfter = delete_expired_task_after if delete_expired_task_after
|
1224
|
+
definition.Settings.DisallowStartIfOnBatteries = disallow_start_if_on_batteries if disallow_start_if_on_batteries
|
1225
|
+
definition.Settings.Enabled = enabled if enabled
|
1226
|
+
definition.Settings.ExecutionTimeLimit = execution_time_limit if execution_time_limit
|
1227
|
+
definition.Settings.Hidden = hidden if hidden
|
1228
|
+
definition.Settings.IdleSettings = idle_settings if idle_settings
|
1229
|
+
definition.Settings.NetworkSettings = network_settings if network_settings
|
1230
|
+
definition.Settings.Priority = priority if priority
|
1231
|
+
definition.Settings.RestartCount = restart_count if restart_count
|
1232
|
+
definition.Settings.RestartInterval = restart_interval if restart_interval
|
1233
|
+
definition.Settings.RunOnlyIfIdle = run_only_if_idle if run_only_if_idle
|
1234
|
+
definition.Settings.RunOnlyIfNetworkAvailable = run_only_if_network_available if run_only_if_network_available
|
1235
|
+
definition.Settings.StartWhenAvailable = start_when_available if start_when_available
|
1236
|
+
definition.Settings.StopIfGoingOnBatteries = stop_if_going_on_batteries if stop_if_going_on_batteries
|
1237
|
+
definition.Settings.WakeToRun = wake_to_run if wake_to_run
|
1238
|
+
definition.Settings.XmlText = xml_text if xml_text
|
1239
|
+
|
1240
|
+
update_task_definition(definition)
|
1241
|
+
|
1242
|
+
hash
|
1243
|
+
end
|
1244
|
+
|
1245
|
+
# Set registration information options. The possible options are:
|
1246
|
+
#
|
1247
|
+
# * author
|
1248
|
+
# * date
|
1249
|
+
# * description (or comment)
|
1250
|
+
# * documentation
|
1251
|
+
# * security_descriptor (should be a Win32::Security::SID)
|
1252
|
+
# * source
|
1253
|
+
# * uri
|
1254
|
+
# * version
|
1255
|
+
# * xml_text (or xml)
|
1256
|
+
#
|
1257
|
+
# Note that most of these options have standalone methods as well,
|
1258
|
+
# e.g. calling ts.configure_registration_info(:author => 'Dan') is
|
1259
|
+
# the same as calling ts.author = 'Dan'.
|
1260
|
+
#
|
1261
|
+
def configure_registration_info(hash)
|
1262
|
+
raise TypeError unless hash.is_a?(Hash)
|
1263
|
+
check_for_active_task
|
1264
|
+
|
1265
|
+
definition = @task.Definition
|
1266
|
+
|
1267
|
+
author = hash[:author]
|
1268
|
+
date = hash[:date]
|
1269
|
+
description = hash[:description] || hash[:comment]
|
1270
|
+
documentation = hash[:documentation]
|
1271
|
+
security_descriptor = hash[:security_descriptor]
|
1272
|
+
source = hash[:source]
|
1273
|
+
uri = hash[:uri]
|
1274
|
+
version = hash[:version]
|
1275
|
+
xml_text = hash[:xml_text] || hash[:xml]
|
1276
|
+
|
1277
|
+
definition.RegistrationInfo.Author = author if author
|
1278
|
+
definition.RegistrationInfo.Date = date if date
|
1279
|
+
definition.RegistrationInfo.Description = description if description
|
1280
|
+
definition.RegistrationInfo.Documentation = documentation if documentation
|
1281
|
+
definition.RegistrationInfo.SecurityDescriptor = security_descriptor if security_descriptor
|
1282
|
+
definition.RegistrationInfo.Source = source if source
|
1283
|
+
definition.RegistrationInfo.URI = uri if uri
|
1284
|
+
definition.RegistrationInfo.Version = version if version
|
1285
|
+
definition.RegistrationInfo.XmlText = xml_text if xml_text
|
1286
|
+
|
1287
|
+
update_task_definition(definition)
|
1288
|
+
|
1289
|
+
hash
|
1290
|
+
end
|
1291
|
+
|
1292
|
+
# Shorthand constants
|
1293
|
+
|
1294
|
+
IDLE = IDLE_PRIORITY_CLASS
|
1295
|
+
NORMAL = NORMAL_PRIORITY_CLASS
|
1296
|
+
HIGH = HIGH_PRIORITY_CLASS
|
1297
|
+
REALTIME = REALTIME_PRIORITY_CLASS
|
1298
|
+
BELOW_NORMAL = BELOW_NORMAL_PRIORITY_CLASS
|
1299
|
+
ABOVE_NORMAL = ABOVE_NORMAL_PRIORITY_CLASS
|
1300
|
+
|
1301
|
+
ONCE = TASK_TIME_TRIGGER_ONCE
|
1302
|
+
DAILY = TASK_TIME_TRIGGER_DAILY
|
1303
|
+
WEEKLY = TASK_TIME_TRIGGER_WEEKLY
|
1304
|
+
MONTHLYDATE = TASK_TIME_TRIGGER_MONTHLYDATE
|
1305
|
+
MONTHLYDOW = TASK_TIME_TRIGGER_MONTHLYDOW
|
1306
|
+
|
1307
|
+
ON_IDLE = TASK_EVENT_TRIGGER_ON_IDLE
|
1308
|
+
AT_SYSTEMSTART = TASK_EVENT_TRIGGER_AT_SYSTEMSTART
|
1309
|
+
AT_LOGON = TASK_EVENT_TRIGGER_AT_LOGON
|
1310
|
+
FIRST_WEEK = TASK_FIRST_WEEK
|
1311
|
+
SECOND_WEEK = TASK_SECOND_WEEK
|
1312
|
+
THIRD_WEEK = TASK_THIRD_WEEK
|
1313
|
+
FOURTH_WEEK = TASK_FOURTH_WEEK
|
1314
|
+
LAST_WEEK = TASK_LAST_WEEK
|
1315
|
+
SUNDAY = TASK_SUNDAY
|
1316
|
+
MONDAY = TASK_MONDAY
|
1317
|
+
TUESDAY = TASK_TUESDAY
|
1318
|
+
WEDNESDAY = TASK_WEDNESDAY
|
1319
|
+
THURSDAY = TASK_THURSDAY
|
1320
|
+
FRIDAY = TASK_FRIDAY
|
1321
|
+
SATURDAY = TASK_SATURDAY
|
1322
|
+
JANUARY = TASK_JANUARY
|
1323
|
+
FEBRUARY = TASK_FEBRUARY
|
1324
|
+
MARCH = TASK_MARCH
|
1325
|
+
APRIL = TASK_APRIL
|
1326
|
+
MAY = TASK_MAY
|
1327
|
+
JUNE = TASK_JUNE
|
1328
|
+
JULY = TASK_JULY
|
1329
|
+
AUGUST = TASK_AUGUST
|
1330
|
+
SEPTEMBER = TASK_SEPTEMBER
|
1331
|
+
OCTOBER = TASK_OCTOBER
|
1332
|
+
NOVEMBER = TASK_NOVEMBER
|
1333
|
+
DECEMBER = TASK_DECEMBER
|
1334
|
+
|
1335
|
+
INTERACTIVE = TASK_FLAG_INTERACTIVE
|
1336
|
+
DELETE_WHEN_DONE = TASK_FLAG_DELETE_WHEN_DONE
|
1337
|
+
DISABLED = TASK_FLAG_DISABLED
|
1338
|
+
START_ONLY_IF_IDLE = TASK_FLAG_START_ONLY_IF_IDLE
|
1339
|
+
KILL_ON_IDLE_END = TASK_FLAG_KILL_ON_IDLE_END
|
1340
|
+
DONT_START_IF_ON_BATTERIES = TASK_FLAG_DONT_START_IF_ON_BATTERIES
|
1341
|
+
KILL_IF_GOING_ON_BATTERIES = TASK_FLAG_KILL_IF_GOING_ON_BATTERIES
|
1342
|
+
RUN_ONLY_IF_DOCKED = TASK_FLAG_RUN_ONLY_IF_DOCKED
|
1343
|
+
HIDDEN = TASK_FLAG_HIDDEN
|
1344
|
+
RUN_IF_CONNECTED_TO_INTERNET = TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET
|
1345
|
+
RESTART_ON_IDLE_RESUME = TASK_FLAG_RESTART_ON_IDLE_RESUME
|
1346
|
+
SYSTEM_REQUIRED = TASK_FLAG_SYSTEM_REQUIRED
|
1347
|
+
RUN_ONLY_IF_LOGGED_ON = TASK_FLAG_RUN_ONLY_IF_LOGGED_ON
|
1348
|
+
|
1349
|
+
FLAG_HAS_END_DATE = TASK_TRIGGER_FLAG_HAS_END_DATE
|
1350
|
+
FLAG_KILL_AT_DURATION_END = TASK_TRIGGER_FLAG_KILL_AT_DURATION_END
|
1351
|
+
FLAG_DISABLED = TASK_TRIGGER_FLAG_DISABLED
|
1352
|
+
|
1353
|
+
MAX_RUN_TIMES = TASK_MAX_RUN_TIMES
|
1354
|
+
|
1355
|
+
private
|
1356
|
+
|
1357
|
+
def validate_trigger(hash)
|
1358
|
+
[:start_year, :start_month, :start_day].each{ |key|
|
1359
|
+
raise ArgumentError, "#{key} must be set" unless hash[key]
|
1360
|
+
}
|
1361
|
+
end
|
1362
|
+
|
1363
|
+
def check_for_active_task
|
1364
|
+
raise Error, 'No currently active task' if @task.nil?
|
1365
|
+
end
|
1366
|
+
|
1367
|
+
def update_task_definition(definition)
|
1368
|
+
user = definition.Principal.UserId
|
1369
|
+
|
1370
|
+
@task = @root.RegisterTaskDefinition(
|
1371
|
+
@task.Path,
|
1372
|
+
definition,
|
1373
|
+
TASK_CREATE_OR_UPDATE,
|
1374
|
+
user,
|
1375
|
+
@password,
|
1376
|
+
@password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
|
1377
|
+
)
|
1378
|
+
rescue WIN32OLERuntimeError => err
|
1379
|
+
method_name = caller_locations(1,1)[0].label
|
1380
|
+
raise Error, ole_error(method_name, err)
|
1381
|
+
end
|
1382
|
+
end
|
1383
|
+
end
|