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.
@@ -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'
@@ -1,1368 +1,1383 @@
1
- require File.join(File.dirname(__FILE__), '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::Helper
13
-
14
- # The version of the win32-taskscheduler library
15
- VERSION = '0.3.1'
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
- raise Error, 'null task' if @task.nil?
331
-
332
- @task.run(nil)
333
- end
334
-
335
- # This method no longer has any effect. It is a no-op that remains for
336
- # backwards compatibility. It will be removed in 0.4.0.
337
- #
338
- def save(file = nil)
339
- warn DeprecatedMethodWarning, "this method is no longer necessary"
340
- raise Error, 'null task' if @task.nil?
341
- # Do nothing, deprecated.
342
- end
343
-
344
- # Terminate (stop) the current task.
345
- #
346
- def terminate
347
- raise Error, 'null task' if @task.nil?
348
- @task.stop(nil)
349
- end
350
-
351
- alias stop terminate
352
-
353
- # Set the host on which the various TaskScheduler methods will execute.
354
- # This method may require administrative privileges.
355
- #
356
- def machine=(host)
357
- raise TypeError unless host.is_a?(String)
358
-
359
- begin
360
- @service.Connect(host)
361
- rescue WIN32OLERuntimeError => err
362
- raise Error, ole_error('Connect', err)
363
- end
364
-
365
- @host = host
366
- host
367
- end
368
-
369
- # Similar to the TaskScheduler#machine= method, this method also allows
370
- # you to pass a user, domain and password as needed. This method may
371
- # require administrative privileges.
372
- #
373
- def set_machine(host, user = nil, domain = nil, password = nil)
374
- raise TypeError unless host.is_a?(String)
375
-
376
- begin
377
- @service.Connect(host, user, domain, password)
378
- rescue WIN32OLERuntimeError => err
379
- raise Error, ole_error('Connect', err)
380
- end
381
-
382
- @host = host
383
- host
384
- end
385
-
386
- alias host= machine=
387
- alias machine host
388
- alias set_host set_machine
389
-
390
- # Sets the +user+ and +password+ for the given task. If the user and
391
- # password are set properly then true is returned.
392
- #
393
- def set_account_information(user, password)
394
- raise Error, 'No currently active task' if @task.nil?
395
-
396
- raise TypeError unless user.is_a?(String)
397
- raise TypeError unless password.is_a?(String)
398
-
399
- @password = password
400
-
401
- begin
402
- @task = @root.RegisterTaskDefinition(
403
- @task.Path,
404
- @task.Definition,
405
- TASK_CREATE_OR_UPDATE,
406
- user,
407
- password,
408
- TASK_LOGON_PASSWORD
409
- )
410
- rescue WIN32OLERuntimeError => err
411
- raise Error, ole_error('RegisterTaskDefinition', err)
412
- end
413
-
414
- true
415
- end
416
-
417
- # Returns the user associated with the task or nil if no user has yet
418
- # been associated with the task.
419
- #
420
- def account_information
421
- @task.nil? ? nil : @task.Definition.Principal.UserId
422
- end
423
-
424
- # Returns the name of the application associated with the task. If
425
- # no application is associated with the task then nil is returned.
426
- #
427
- def application_name
428
- raise Error, 'No currently active task' if @task.nil?
429
-
430
- app = nil
431
-
432
- @task.Definition.Actions.each do |action|
433
- if action.Type == 0 # TASK_ACTION_EXEC
434
- app = action.Path
435
- break
436
- end
437
- end
438
-
439
- app
440
- end
441
-
442
- # Sets the name of the application associated with the task.
443
- #
444
- def application_name=(app)
445
- raise TypeError unless app.is_a?(String)
446
- raise Error, 'No currently active task' if @task.nil?
447
-
448
- definition = @task.Definition
449
-
450
- definition.Actions.each do |action|
451
- action.Path = app if action.Type == 0
452
- end
453
-
454
- user = definition.Principal.UserId
455
-
456
- @task = @root.RegisterTaskDefinition(
457
- @task.Path,
458
- definition,
459
- TASK_CREATE_OR_UPDATE,
460
- user,
461
- @password,
462
- @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
463
- )
464
-
465
- app
466
- end
467
-
468
- # Returns the command line parameters for the task.
469
- #
470
- def parameters
471
- raise Error, 'No currently active task' if @task.nil?
472
-
473
- param = nil
474
-
475
- @task.Definition.Actions.each do |action|
476
- param = action.Arguments if action.Type == 0
477
- end
478
-
479
- param
480
- end
481
-
482
- # Sets the parameters for the task. These parameters are passed as command
483
- # line arguments to the application the task will run. To clear the command
484
- # line parameters set it to an empty string.
485
- #--
486
- # NOTE: Again, it seems the task must be reactivated to be picked up.
487
- #
488
- def parameters=(param)
489
- raise TypeError unless param.is_a?(String)
490
- raise Error, 'No currently active task' if @task.nil?
491
-
492
- definition = @task.Definition
493
- definition.Actions.each do |action|
494
- action.Arguments = param if action.Type == 0
495
- end
496
- user = definition.Principal.UserId
497
-
498
- @task = @root.RegisterTaskDefinition(
499
- @task.Path,
500
- definition,
501
- TASK_CREATE_OR_UPDATE,
502
- user,
503
- @password,
504
- @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
505
- )
506
-
507
- param
508
- end
509
-
510
- # Returns the working directory for the task.
511
- #
512
- def working_directory
513
- raise Error,"No currently active task" if @task.nil?
514
-
515
- dir = nil
516
-
517
- @task.Definition.Actions.each do |action|
518
- dir = action.WorkingDirectory if action.Type == 0
519
- end
520
-
521
- dir
522
- end
523
-
524
- # Sets the working directory for the task.
525
- #--
526
- # TODO: Why do I have to reactivate the task to see the change?
527
- #
528
- def working_directory=(dir)
529
- raise Error, 'No currently active task' if @task.nil?
530
- raise TypeError unless dir.is_a?(String)
531
-
532
- definition = @task.Definition
533
-
534
- definition.Actions.each do |action|
535
- action.WorkingDirectory = dir if action.Type == 0
536
- end
537
-
538
- user = definition.Principal.UserId
539
-
540
- @task = @root.RegisterTaskDefinition(
541
- @task.Path,
542
- definition,
543
- TASK_CREATE_OR_UPDATE,
544
- user,
545
- @password,
546
- @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
547
- )
548
-
549
- dir
550
- end
551
-
552
- # Returns the task's priority level. Possible values are 'idle',
553
- # 'normal', 'high', 'realtime', 'below_normal', 'above_normal',
554
- # and 'unknown'.
555
- #
556
- def priority
557
- raise Error, 'No currently active task' if @task.nil?
558
-
559
- case @task.Definition.Settings.Priority
560
- when 0
561
- priority = 'critical'
562
- when 1
563
- priority = 'highest'
564
- when 2
565
- priority = 'above_normal'
566
- when 3
567
- priority = 'above_normal'
568
- when 4
569
- priority = 'normal'
570
- when 5
571
- priority = 'normal'
572
- when 6
573
- priority = 'normal'
574
- when 7
575
- priority = 'below_normal'
576
- when 8
577
- priority = 'below_normal'
578
- when 9
579
- priority = 'lowest'
580
- when 10
581
- priority = 'idle'
582
- else
583
- priority = 'unknown'
584
- end
585
-
586
- priority
587
- end
588
-
589
- # Sets the priority of the task. The +priority+ should be a numeric
590
- # priority constant value.
591
- #
592
- def priority=(priority)
593
- raise TypeError unless priority.is_a?(Numeric)
594
- raise Error, 'No currently active task' if @task.nil?
595
-
596
- definition = @task.Definition
597
-
598
- begin
599
- definition.Settings.Priority = priority
600
- user = definition.Principal.UserId
601
- rescue WIN32OLERuntimeError => err
602
- raise Error, ole_error('Priority', err)
603
- end
604
-
605
- @task = @root.RegisterTaskDefinition(
606
- @task.Path,
607
- definition,
608
- TASK_CREATE_OR_UPDATE,
609
- user,
610
- @password,
611
- @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
612
- )
613
-
614
- priority
615
- end
616
-
617
- # Creates a new work item (scheduled job) with the given +trigger+. The
618
- # trigger variable is a hash of options that define when the scheduled
619
- # job should run.
620
- #
621
- def new_work_item(task, trigger)
622
- raise TypeError unless task.is_a?(String)
623
- raise TypeError unless trigger.is_a?(Hash)
624
-
625
- validate_trigger(trigger)
626
-
627
- taskDefinition = @service.NewTask(0)
628
- taskDefinition.RegistrationInfo.Description = ''
629
- taskDefinition.RegistrationInfo.Author = ''
630
- taskDefinition.Settings.StartWhenAvailable = true
631
- taskDefinition.Settings.Enabled = true
632
- taskDefinition.Settings.Hidden = false
633
-
634
- case trigger[:trigger_type]
635
- when TASK_TIME_TRIGGER_ONCE
636
- type = 1
637
- when TASK_TIME_TRIGGER_DAILY
638
- type = 2
639
- when TASK_TIME_TRIGGER_WEEKLY
640
- type = 3
641
- when TASK_TIME_TRIGGER_MONTHLYDATE
642
- type = 4
643
- when TASK_TIME_TRIGGER_MONTHLYDOW
644
- type = 5
645
- when TASK_EVENT_TRIGGER_ON_IDLE
646
- type = 6
647
- when TASK_EVENT_TRIGGER_AT_SYSTEMSTART
648
- type = 8
649
- when TASK_EVENT_TRIGGER_AT_LOGON
650
- type = 9
651
- else
652
- raise ArgumentError, 'Unknown trigger type'
653
- end
654
-
655
- startTime = "%04d-%02d-%02dT%02d:%02d:00" % [
656
- trigger[:start_year], trigger[:start_month], trigger[:start_day],
657
- trigger[:start_hour], trigger[:start_minute]
658
- ]
659
-
660
- # Set defaults
661
- trigger[:end_year] ||= 0
662
- trigger[:end_month] ||= 0
663
- trigger[:end_day] ||= 0
664
-
665
- endTime = "%04d-%02d-%02dT00:00:00" % [
666
- trigger[:end_year], trigger[:end_month], trigger[:end_day]
667
- ]
668
-
669
- trig = taskDefinition.Triggers.Create(type)
670
- trig.Id = "RegistrationTriggerId#{taskDefinition.Triggers.Count}"
671
- trig.StartBoundary = startTime
672
- trig.EndBoundary = endTime if endTime != '0000-00-00T00:00:00'
673
- trig.Enabled = true
674
-
675
- repetitionPattern = trig.Repetition
676
-
677
- if trigger[:minutes_duration].to_i > 0
678
- repetitionPattern.Duration = "PT#{trigger[:minutes_duration]||0}M"
679
- end
680
-
681
- if trigger[:minutes_interval].to_i > 0
682
- repetitionPattern.Interval = "PT#{trigger[:minutes_interval]||0}M"
683
- end
684
-
685
- tmp = trigger[:type]
686
- tmp = nil unless tmp.is_a?(Hash)
687
-
688
- case trigger[:trigger_type]
689
- when TASK_TIME_TRIGGER_DAILY
690
- trig.DaysInterval = tmp[:days_interval] if tmp && tmp[:days_interval]
691
- if trigger[:random_minutes_interval].to_i > 0
692
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]}M"
693
- end
694
- when TASK_TIME_TRIGGER_WEEKLY
695
- trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
696
- trig.WeeksInterval = tmp[:weeks_interval] if tmp && tmp[:weeks_interval]
697
- if trigger[:random_minutes_interval].to_i > 0
698
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
699
- end
700
- when TASK_TIME_TRIGGER_MONTHLYDATE
701
- trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
702
- trig.DaysOfMonth = tmp[:days] if tmp && tmp[:days]
703
- if trigger[:random_minutes_interval].to_i > 0
704
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
705
- end
706
- when TASK_TIME_TRIGGER_MONTHLYDOW
707
- trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
708
- trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
709
- trig.WeeksOfMonth = tmp[:weeks] if tmp && tmp[:weeks]
710
- if trigger[:random_minutes_interval].to_i>0
711
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
712
- end
713
- when TASK_TIME_TRIGGER_ONCE
714
- if trigger[:random_minutes_interval].to_i > 0
715
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
716
- end
717
- end
718
-
719
- act = taskDefinition.Actions.Create(0)
720
- act.Path = 'cmd'
721
-
722
- begin
723
- @task = @root.RegisterTaskDefinition(
724
- task,
725
- taskDefinition,
726
- TASK_CREATE_OR_UPDATE,
727
- nil,
728
- nil,
729
- TASK_LOGON_INTERACTIVE_TOKEN
730
- )
731
- rescue WIN32OLERuntimeError => err
732
- raise Error, ole_error('RegisterTaskDefinition', err)
733
- end
734
-
735
- @task = @root.GetTask(task)
736
- end
737
-
738
- alias new_task new_work_item
739
-
740
- # Returns the number of triggers associated with the active task.
741
- #
742
- def trigger_count
743
- raise Error, "No currently active task" if @task.nil?
744
-
745
- @task.Definition.Triggers.Count
746
- end
747
-
748
- # Returns a string that describes the current trigger at the specified
749
- # index for the active task.
750
- #
751
- # Example: "At 7:14 AM every day, starting 4/11/2015"
752
- #
753
- def trigger_string(index)
754
- raise TypeError unless index.is_a?(Numeric)
755
- raise Error, 'No currently active task' if @task.nil?
756
- index += 1 # first item index is 1
757
-
758
- begin
759
- trigger = @task.Definition.Triggers.Item(index)
760
- rescue WIN32OLERuntimeError
761
- raise Error, "No trigger found at index '#{index}'"
762
- end
763
-
764
- "Starting #{trigger.StartBoundary}"
765
- end
766
-
767
- # Deletes the trigger at the specified index.
768
- #--
769
- # TODO: Fix.
770
- #
771
- def delete_trigger(index)
772
- raise TypeError unless index.is_a?(Numeric)
773
- raise Error, 'No currently active task' if @task.nil?
774
- index += 1 # first item index is 1
775
-
776
- definition = @task.Definition
777
- definition.Triggers.Remove(index)
778
- user = definition.Principal.UserId
779
-
780
- @task = @root.RegisterTaskDefinition(
781
- @task.Path,
782
- definition,
783
- TASK_CREATE_OR_UPDATE,
784
- user,
785
- @password,
786
- @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
787
- )
788
-
789
- index
790
- end
791
-
792
- # Returns a hash that describes the trigger at the given index for the
793
- # current task.
794
- #
795
- def trigger(index)
796
- raise TypeError unless index.is_a?(Numeric)
797
- raise Error, 'No currently active task' if @task.nil?
798
- index += 1 # first item index is 1
799
-
800
- begin
801
- trig = @task.Definition.Triggers.Item(index)
802
- rescue WIN32OLERuntimeError => err
803
- raise Error, ole_error('Item', err)
804
- end
805
-
806
- trigger = {}
807
- trigger[:start_year], trigger[:start_month],
808
- trigger[:start_day], trigger[:start_hour],
809
- trigger[:start_minute] = trig.StartBoundary.scan(/(\d+)-(\d+)-(\d+)T(\d+):(\d+)/).first
810
-
811
- trigger[:end_year], trigger[:end_month],
812
- trigger[:end_day] = trig.StartBoundary.scan(/(\d+)-(\d+)-(\d+)T/).first
813
-
814
- if trig.Repetition.Duration != ""
815
- trigger[:minutes_duration] = trig.Repetition.Duration.scan(/(\d+)M/)[0][0].to_i
816
- end
817
-
818
- if trig.Repetition.Interval != ""
819
- trigger[:minutes_interval] = trig.Repetition.Interval.scan(/(\d+)M/)[0][0].to_i
820
- end
821
-
822
- if trig.RandomDelay != ""
823
- trigger[:random_minutes_interval] = trig.RandomDelay.scan(/(\d+)M/)[0][0].to_i
824
- end
825
-
826
- case trig.Type
827
- when 2
828
- trigger[:trigger_type] = TASK_TIME_TRIGGER_DAILY
829
- tmp = {}
830
- tmp[:days_interval] = trig.DaysInterval
831
- trigger[:type] = tmp
832
- when 3
833
- trigger[:trigger_type] = TASK_TIME_TRIGGER_WEEKLY
834
- tmp = {}
835
- tmp[:weeks_interval] = trig.WeeksInterval
836
- tmp[:days_of_week] = trig.DaysOfWeek
837
- trigger[:type] = tmp
838
- when 4
839
- trigger[:trigger_type] = TASK_TIME_TRIGGER_MONTHLYDATE
840
- tmp = {}
841
- tmp[:months] = trig.MonthsOfYear
842
- tmp[:days] = trig.DaysOfMonth
843
- trigger[:type] = tmp
844
- when 5
845
- trigger[:trigger_type] = TASK_TIME_TRIGGER_MONTHLYDOW
846
- tmp = {}
847
- tmp[:months] = trig.MonthsOfYear
848
- tmp[:days_of_week] = trig.DaysOfWeek
849
- tmp[:weeks] = trig.weeks
850
- trigger[:type] = tmp
851
- when 1
852
- trigger[:trigger_type] = TASK_TIME_TRIGGER_ONCE
853
- tmp = {}
854
- tmp[:once] = nil
855
- trigger[:type] = tmp
856
- else
857
- raise Error, 'Unknown trigger type'
858
- end
859
-
860
- trigger
861
- end
862
-
863
- # Sets the trigger for the currently active task. The +trigger+ is a hash
864
- # with the following possible options:
865
- #
866
- # * days
867
- # * days_interval
868
- # * days_of_week
869
- # * end_day
870
- # * end_month
871
- # * end_year
872
- # * flags
873
- # * minutes_duration
874
- # * minutes_interval
875
- # * months
876
- # * random_minutes_interval
877
- # * start_day
878
- # * start_hour
879
- # * start_minute
880
- # * start_month
881
- # * start_year
882
- # * trigger_type
883
- # * type
884
- # * weeks
885
- # * weeks_interval
886
- #
887
- def trigger=(trigger)
888
- raise TypeError unless trigger.is_a?(Hash)
889
- raise Error, 'No currently active task' if @task.nil?
890
-
891
- validate_trigger(trigger)
892
-
893
- definition = @task.Definition
894
- definition.Triggers.Clear()
895
-
896
- case trigger[:trigger_type]
897
- when TASK_TIME_TRIGGER_ONCE
898
- type = 1
899
- when TASK_TIME_TRIGGER_DAILY
900
- type = 2
901
- when TASK_TIME_TRIGGER_WEEKLY
902
- type = 3
903
- when TASK_TIME_TRIGGER_MONTHLYDATE
904
- type = 4
905
- when TASK_TIME_TRIGGER_MONTHLYDOW
906
- type = 5
907
- when TASK_EVENT_TRIGGER_ON_IDLE
908
- type = 6
909
- when TASK_EVENT_TRIGGER_AT_SYSTEM_START
910
- type = 8
911
- when TASK_EVENT_TRIGGER_AT_LOGON
912
- type = 9
913
- else
914
- raise Error, 'Unknown trigger type'
915
- end
916
-
917
- startTime = "%04d-%02d-%02dT%02d:%02d:00" % [
918
- trigger[:start_year], trigger[:start_month],
919
- trigger[:start_day], trigger[:start_hour], trigger[:start_minute]
920
- ]
921
-
922
- endTime = "%04d-%02d-%02dT00:00:00" % [
923
- trigger[:end_year], trigger[:end_month], trigger[:end_day]
924
- ]
925
-
926
- trig = definition.Triggers.Create(type)
927
- trig.Id = "RegistrationTriggerId#{definition.Triggers.Count}"
928
- trig.StartBoundary = startTime
929
- trig.EndBoundary = endTime if endTime != '0000-00-00T00:00:00'
930
- trig.Enabled = true
931
-
932
- repetitionPattern = trig.Repetition
933
-
934
- if trigger[:minutes_duration].to_i > 0
935
- repetitionPattern.Duration = "PT#{trigger[:minutes_duration]||0}M"
936
- end
937
-
938
- if trigger[:minutes_interval].to_i > 0
939
- repetitionPattern.Interval = "PT#{trigger[:minutes_interval]||0}M"
940
- end
941
-
942
- tmp = trigger[:type]
943
- tmp = nil unless tmp.is_a?(Hash)
944
-
945
- case trigger[:trigger_type]
946
- when TASK_TIME_TRIGGER_DAILY
947
- trig.DaysInterval = tmp[:days_interval] if tmp && tmp[:days_interval]
948
- if trigger[:random_minutes_interval].to_i > 0
949
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]}M"
950
- end
951
- when TASK_TIME_TRIGGER_WEEKLY
952
- trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
953
- trig.WeeksInterval = tmp[:weeks_interval] if tmp && tmp[:weeks_interval]
954
- if trigger[:random_minutes_interval].to_i > 0
955
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
956
- end
957
- when TASK_TIME_TRIGGER_MONTHLYDATE
958
- trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
959
- trig.DaysOfMonth = tmp[:days] if tmp && tmp[:days]
960
- if trigger[:random_minutes_interval].to_i > 0
961
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
962
- end
963
- when TASK_TIME_TRIGGER_MONTHLYDOW
964
- trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
965
- trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
966
- trig.WeeksOfMonth = tmp[:weeks] if tmp && tmp[:weeks]
967
- if trigger[:random_minutes_interval].to_i > 0
968
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
969
- end
970
- when TASK_TIME_TRIGGER_ONCE
971
- if trigger[:random_minutes_interval].to_i > 0
972
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
973
- end
974
- end
975
-
976
- user = definition.Principal.UserId
977
-
978
- @task = @root.RegisterTaskDefinition(
979
- @task.Path,
980
- definition,
981
- TASK_CREATE_OR_UPDATE,
982
- user,
983
- @password,
984
- @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
985
- )
986
-
987
- trigger
988
- end
989
-
990
- # Adds a trigger at the specified index.
991
- #
992
- def add_trigger(index, trigger)
993
- raise TypeError unless index.is_a?(Numeric)
994
- raise TypeError unless trigger.is_a?(Hash)
995
- raise Error, 'No currently active task' if @task.nil?
996
-
997
- definition = @task.Definition
998
- case trigger[:trigger_type]
999
- when TASK_TIME_TRIGGER_DAILY
1000
- type = 2
1001
- when TASK_TIME_TRIGGER_WEEKLY
1002
- type = 3
1003
- when TASK_TIME_TRIGGER_MONTHLYDATE
1004
- type = 4
1005
- when TASK_TIME_TRIGGER_MONTHLYDOW
1006
- type = 5
1007
- when TASK_TIME_TRIGGER_ONCE
1008
- type = 1
1009
- else
1010
- raise Error, 'Unknown trigger type'
1011
- end
1012
-
1013
- startTime = "%04d-%02d-%02dT%02d:%02d:00" % [
1014
- trigger[:start_year], trigger[:start_month], trigger[:start_day],
1015
- trigger[:start_hour], trigger[:start_minute]
1016
- ]
1017
-
1018
- # Set defaults
1019
- trigger[:end_year] ||= 0
1020
- trigger[:end_month] ||= 0
1021
- trigger[:end_day] ||= 0
1022
-
1023
- endTime = "%04d-%02d-%02dT00:00:00" % [
1024
- trigger[:end_year], trigger[:end_month], trigger[:end_day]
1025
- ]
1026
-
1027
- trig = definition.Triggers.Create(type)
1028
- trig.Id = "RegistrationTriggerId#{definition.Triggers.Count}"
1029
- trig.StartBoundary = startTime
1030
- trig.EndBoundary = endTime if endTime != '0000-00-00T00:00:00'
1031
- trig.Enabled = true
1032
-
1033
- repetitionPattern = trig.Repetition
1034
-
1035
- if trigger[:minutes_duration].to_i > 0
1036
- repetitionPattern.Duration = "PT#{trigger[:minutes_duration]||0}M"
1037
- end
1038
-
1039
- if trigger[:minutes_interval].to_i > 0
1040
- repetitionPattern.Interval = "PT#{trigger[:minutes_interval]||0}M"
1041
- end
1042
-
1043
- tmp = trigger[:type]
1044
- tmp = nil unless tmp.is_a?(Hash)
1045
-
1046
- case trigger[:trigger_type]
1047
- when TASK_TIME_TRIGGER_DAILY
1048
- trig.DaysInterval = tmp[:days_interval] if tmp && tmp[:days_interval]
1049
- if trigger[:random_minutes_interval].to_i > 0
1050
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]}M"
1051
- end
1052
- when TASK_TIME_TRIGGER_WEEKLY
1053
- trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
1054
- trig.WeeksInterval = tmp[:weeks_interval] if tmp && tmp[:weeks_interval]
1055
- if trigger[:random_minutes_interval].to_i > 0
1056
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
1057
- end
1058
- when TASK_TIME_TRIGGER_MONTHLYDATE
1059
- trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
1060
- trig.DaysOfMonth = tmp[:days] if tmp && tmp[:days]
1061
- if trigger[:random_minutes_interval].to_i > 0
1062
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
1063
- end
1064
- when TASK_TIME_TRIGGER_MONTHLYDOW
1065
- trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
1066
- trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
1067
- trig.WeeksOfMonth = tmp[:weeks] if tmp && tmp[:weeks]
1068
- if trigger[:random_minutes_interval].to_i > 0
1069
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
1070
- end
1071
- when TASK_TIME_TRIGGER_ONCE
1072
- if trigger[:random_minutes_interval].to_i > 0
1073
- trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
1074
- end
1075
- end
1076
-
1077
- user = definition.Principal.UserId
1078
-
1079
- begin
1080
-
1081
- @task = @root.RegisterTaskDefinition(
1082
- @task.Path,
1083
- definition,
1084
- TASK_CREATE_OR_UPDATE,
1085
- user,
1086
- @password,
1087
- @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
1088
- )
1089
- rescue WIN32OLERuntimeError => err
1090
- raise Error, ole_error('add_trigger', err)
1091
- end
1092
-
1093
- true
1094
- end
1095
-
1096
- # Returns the status of the currently active task. Possible values are
1097
- # 'ready', 'running', 'not scheduled' or 'unknown'.
1098
- #
1099
- def status
1100
- raise Error, 'No currently active task' if @task.nil?
1101
-
1102
- case @task.State
1103
- when 3
1104
- status = 'ready'
1105
- when 4
1106
- status = 'running'
1107
- when 1
1108
- status = 'not scheduled'
1109
- else
1110
- status = 'unknown'
1111
- end
1112
-
1113
- status
1114
- end
1115
-
1116
- # Returns the exit code from the last scheduled run.
1117
- #
1118
- def exit_code
1119
- raise Error, 'No currently active task' if @task.nil?
1120
-
1121
- @task.LastTaskResult
1122
- end
1123
-
1124
- # Returns the comment associated with the task, if any.
1125
- #
1126
- def comment
1127
- raise Error, 'No currently active task' if @task.nil?
1128
-
1129
- @task.Definition.RegistrationInfo.Description
1130
- end
1131
-
1132
- # Sets the comment for the task.
1133
- #
1134
- def comment=(comment)
1135
- raise TypeError unless comment.is_a?(String)
1136
- raise Error, 'No currently active task' if @task.nil?
1137
-
1138
- definition = @task.Definition
1139
- definition.RegistrationInfo.Description = comment
1140
-
1141
- user = definition.Principal.UserId
1142
-
1143
- @task = @root.RegisterTaskDefinition(
1144
- @task.Path,
1145
- definition,
1146
- TASK_CREATE_OR_UPDATE,
1147
- user,
1148
- @password,
1149
- @password ? 1 : 3
1150
- )
1151
-
1152
- comment
1153
- end
1154
-
1155
- # Returns the name of the user who created the task.
1156
- #
1157
- def creator
1158
- raise Error, 'No currently active task' if @task.nil?
1159
-
1160
- @task.Definition.RegistrationInfo.Author
1161
- end
1162
-
1163
- alias author creator
1164
-
1165
- # Sets the creator for the task.
1166
- #
1167
- def creator=(creator)
1168
- raise TypeError unless creator.is_a?(String)
1169
- raise Error, 'No currently active task' if @task.nil?
1170
-
1171
- definition = @task.Definition
1172
- definition.RegistrationInfo.Author = creator
1173
-
1174
- user = definition.Principal.UserId
1175
-
1176
- @task = @root.RegisterTaskDefinition(
1177
- @task.Path,
1178
- definition,
1179
- TASK_CREATE_OR_UPDATE,
1180
- user,
1181
- @password,
1182
- @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
1183
- )
1184
-
1185
- creator
1186
- end
1187
-
1188
- # Returns a Time object that indicates the next time the task will run.
1189
- #
1190
- def next_run_time
1191
- raise Error, 'No currently active task' if @task.nil?
1192
-
1193
- @task.NextRunTime
1194
- end
1195
-
1196
- # Returns a Time object indicating the most recent time the task ran or
1197
- # nil if the task has never run.
1198
- #
1199
- def most_recent_run_time
1200
- raise Error, 'No currently active task' if @task.nil?
1201
-
1202
- time = nil
1203
-
1204
- begin
1205
- time = Time.parse(@task.LastRunTime)
1206
- rescue
1207
- # Ignore
1208
- end
1209
-
1210
- time
1211
- end
1212
-
1213
- # Returns the maximum length of time, in milliseconds, that the task
1214
- # will run before terminating.
1215
- #
1216
- def max_run_time
1217
- raise Error, 'No currently active task' if @task.nil?
1218
-
1219
- t = @task.Definition.Settings.ExecutionTimeLimit
1220
- year = t.scan(/(\d+?)Y/).flatten.first
1221
- month = t.scan(/(\d+?)M/).flatten.first
1222
- day = t.scan(/(\d+?)D/).flatten.first
1223
- hour = t.scan(/(\d+?)H/).flatten.first
1224
- min = t.scan(/T.*(\d+?)M/).flatten.first
1225
- sec = t.scan(/(\d+?)S/).flatten.first
1226
-
1227
- time = 0
1228
- time += year.to_i * 365 if year
1229
- time += month.to_i * 30 if month
1230
- time += day.to_i if day
1231
- time *= 24
1232
- time += hour.to_i if hour
1233
- time *= 60
1234
- time += min.to_i if min
1235
- time *= 60
1236
- time += sec.to_i if sec
1237
- time *= 1000
1238
-
1239
- time
1240
- end
1241
-
1242
- # Sets the maximum length of time, in milliseconds, that the task can run
1243
- # before terminating. Returns the value you specified if successful.
1244
- #
1245
- def max_run_time=(max_run_time)
1246
- raise TypeError unless max_run_time.is_a?(Numeric)
1247
- raise Error, 'No currently active task' if @task.nil?
1248
-
1249
- t = max_run_time
1250
- t /= 1000
1251
- limit ="PT#{t}S"
1252
-
1253
- definition = @task.Definition
1254
- definition.Settings.ExecutionTimeLimit = limit
1255
- user = definition.Principal.UserId
1256
-
1257
- @task = @root.RegisterTaskDefinition(
1258
- @task.Path,
1259
- definition,
1260
- TASK_CREATE_OR_UPDATE,
1261
- user,
1262
- @password,
1263
- @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
1264
- )
1265
-
1266
- max_run_time
1267
- end
1268
-
1269
- # Shorthand constants
1270
-
1271
- IDLE = IDLE_PRIORITY_CLASS
1272
- NORMAL = NORMAL_PRIORITY_CLASS
1273
- HIGH = HIGH_PRIORITY_CLASS
1274
- REALTIME = REALTIME_PRIORITY_CLASS
1275
- BELOW_NORMAL = BELOW_NORMAL_PRIORITY_CLASS
1276
- ABOVE_NORMAL = ABOVE_NORMAL_PRIORITY_CLASS
1277
-
1278
- ONCE = TASK_TIME_TRIGGER_ONCE
1279
- DAILY = TASK_TIME_TRIGGER_DAILY
1280
- WEEKLY = TASK_TIME_TRIGGER_WEEKLY
1281
- MONTHLYDATE = TASK_TIME_TRIGGER_MONTHLYDATE
1282
- MONTHLYDOW = TASK_TIME_TRIGGER_MONTHLYDOW
1283
-
1284
- ON_IDLE = TASK_EVENT_TRIGGER_ON_IDLE
1285
- AT_SYSTEMSTART = TASK_EVENT_TRIGGER_AT_SYSTEMSTART
1286
- AT_LOGON = TASK_EVENT_TRIGGER_AT_LOGON
1287
- FIRST_WEEK = TASK_FIRST_WEEK
1288
- SECOND_WEEK = TASK_SECOND_WEEK
1289
- THIRD_WEEK = TASK_THIRD_WEEK
1290
- FOURTH_WEEK = TASK_FOURTH_WEEK
1291
- LAST_WEEK = TASK_LAST_WEEK
1292
- SUNDAY = TASK_SUNDAY
1293
- MONDAY = TASK_MONDAY
1294
- TUESDAY = TASK_TUESDAY
1295
- WEDNESDAY = TASK_WEDNESDAY
1296
- THURSDAY = TASK_THURSDAY
1297
- FRIDAY = TASK_FRIDAY
1298
- SATURDAY = TASK_SATURDAY
1299
- JANUARY = TASK_JANUARY
1300
- FEBRUARY = TASK_FEBRUARY
1301
- MARCH = TASK_MARCH
1302
- APRIL = TASK_APRIL
1303
- MAY = TASK_MAY
1304
- JUNE = TASK_JUNE
1305
- JULY = TASK_JULY
1306
- AUGUST = TASK_AUGUST
1307
- SEPTEMBER = TASK_SEPTEMBER
1308
- OCTOBER = TASK_OCTOBER
1309
- NOVEMBER = TASK_NOVEMBER
1310
- DECEMBER = TASK_DECEMBER
1311
-
1312
- INTERACTIVE = TASK_FLAG_INTERACTIVE
1313
- DELETE_WHEN_DONE = TASK_FLAG_DELETE_WHEN_DONE
1314
- DISABLED = TASK_FLAG_DISABLED
1315
- START_ONLY_IF_IDLE = TASK_FLAG_START_ONLY_IF_IDLE
1316
- KILL_ON_IDLE_END = TASK_FLAG_KILL_ON_IDLE_END
1317
- DONT_START_IF_ON_BATTERIES = TASK_FLAG_DONT_START_IF_ON_BATTERIES
1318
- KILL_IF_GOING_ON_BATTERIES = TASK_FLAG_KILL_IF_GOING_ON_BATTERIES
1319
- RUN_ONLY_IF_DOCKED = TASK_FLAG_RUN_ONLY_IF_DOCKED
1320
- HIDDEN = TASK_FLAG_HIDDEN
1321
- RUN_IF_CONNECTED_TO_INTERNET = TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET
1322
- RESTART_ON_IDLE_RESUME = TASK_FLAG_RESTART_ON_IDLE_RESUME
1323
- SYSTEM_REQUIRED = TASK_FLAG_SYSTEM_REQUIRED
1324
- RUN_ONLY_IF_LOGGED_ON = TASK_FLAG_RUN_ONLY_IF_LOGGED_ON
1325
-
1326
- FLAG_HAS_END_DATE = TASK_TRIGGER_FLAG_HAS_END_DATE
1327
- FLAG_KILL_AT_DURATION_END = TASK_TRIGGER_FLAG_KILL_AT_DURATION_END
1328
- FLAG_DISABLED = TASK_TRIGGER_FLAG_DISABLED
1329
-
1330
- MAX_RUN_TIMES = TASK_MAX_RUN_TIMES
1331
-
1332
- private
1333
-
1334
- def validate_trigger(hash)
1335
- [:start_year, :start_month, :start_day].each{ |key|
1336
- raise ArgumentError, "#{key} must be set" unless hash[key]
1337
- }
1338
- end
1339
- end
1340
- end
1341
-
1342
- if $0 == __FILE__
1343
- require 'socket'
1344
- include Win32
1345
-
1346
- task = 'foo'
1347
- ts = TaskScheduler.new
1348
-
1349
- trigger = {
1350
- :start_year => 2015,
1351
- :start_month => 4,
1352
- :start_day => 25,
1353
- :start_hour => 23,
1354
- :start_minute => 5,
1355
- :trigger_type => TaskScheduler::AT_SYSTEMSTART, # Need admin privs
1356
- :type => {
1357
- :weeks => TaskScheduler::FIRST_WEEK | TaskScheduler::LAST_WEEK,
1358
- :days_of_week => TaskScheduler::MONDAY | TaskScheduler::FRIDAY,
1359
- :months => TaskScheduler::APRIL | TaskScheduler::MAY
1360
- }
1361
- }
1362
-
1363
- ts.new_task(task, trigger)
1364
- ts.activate(task)
1365
- #p ts.account_information
1366
- #ts.save
1367
- #ts.machine = Socket.gethostname
1368
- end
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