Class: Win32::TaskScheduler

Inherits:
Object
  • Object
show all
Includes:
Windows::Helper
Defined in:
lib/win32/taskscheduler.rb

Overview

The TaskScheduler class encapsulates a Windows scheduled task

Defined Under Namespace

Classes: Error

Constant Summary collapse

VERSION =

The version of the win32-taskscheduler library

'0.3.1'
TASK_TIME_TRIGGER_ONCE =

Trigger is set to run the task a single tim

0
TASK_TIME_TRIGGER_DAILY =

Trigger is set to run the task on a daily interval

1
TASK_TIME_TRIGGER_WEEKLY =

Trigger is set to run the task on specific days of a specific week & month

2
TASK_TIME_TRIGGER_MONTHLYDATE =

Trigger is set to run the task on specific day(s) of the month

3
TASK_TIME_TRIGGER_MONTHLYDOW =

Trigger is set to run the task on specific day(s) of the month

4
TASK_EVENT_TRIGGER_ON_IDLE =

Trigger is set to run the task if the system remains idle for the amount of time specified by the idle wait time of the task

5
TASK_EVENT_TRIGGER_AT_SYSTEMSTART =

Trigger is set to run the task at system startup

6
TASK_EVENT_TRIGGER_AT_LOGON =

Trigger is set to run the task when a user logs on

7
TASK_SUNDAY =

The task will run on Sunday

0x1
TASK_MONDAY =

The task will run on Monday

0x2
TASK_TUESDAY =

The task will run on Tuesday

0x4
TASK_WEDNESDAY =

The task will run on Wednesday

0x8
TASK_THURSDAY =

The task will run on Thursday

0x10
TASK_FRIDAY =

The task will run on Friday

0x20
TASK_SATURDAY =

The task will run on Saturday

0x40
TASK_FIRST_WEEK =

The task will run between the 1st and 7th day of the month

1
TASK_SECOND_WEEK =

The task will run between the 8th and 14th day of the month

2
TASK_THIRD_WEEK =

The task will run between the 15th and 21st day of the month

3
TASK_FOURTH_WEEK =

The task will run between the 22nd and 28th day of the month

4
TASK_LAST_WEEK =

The task will run the last seven days of the month

5
TASK_JANUARY =

The task will run in January

0x1
TASK_FEBRUARY =

The task will run in February

0x2
TASK_MARCH =

The task will run in March

0x4
TASK_APRIL =

The task will run in April

0x8
TASK_MAY =

The task will run in May

0x10
TASK_JUNE =

The task will run in June

0x20
TASK_JULY =

The task will run in July

0x40
TASK_AUGUST =

The task will run in August

0x80
TASK_SEPTEMBER =

The task will run in September

0x100
TASK_OCTOBER =

The task will run in October

0x200
TASK_NOVEMBER =

The task will run in November

0x400
TASK_DECEMBER =

The task will run in December

0x800
TASK_FLAG_INTERACTIVE =

Used when converting AT service jobs into work items

0x1
TASK_FLAG_DELETE_WHEN_DONE =

The work item will be deleted when there are no more scheduled run times

0x2
TASK_FLAG_DISABLED =

The work item is disabled. Useful for temporarily disabling a task

0x4
TASK_FLAG_START_ONLY_IF_IDLE =

The work item begins only if the computer is not in use at the scheduled start time

0x10
TASK_FLAG_KILL_ON_IDLE_END =

The work item terminates if the computer makes an idle to non-idle transition while the work item is running

0x20
TASK_FLAG_DONT_START_IF_ON_BATTERIES =

The work item does not start if the computer is running on battery power

0x40
TASK_FLAG_KILL_IF_GOING_ON_BATTERIES =

The work item ends, and the associated application quits, if the computer switches to battery power

0x80
TASK_FLAG_RUN_ONLY_IF_DOCKED =

The work item starts only if the computer is in a docking station

0x100
TASK_FLAG_HIDDEN =

The work item created will be hidden

0x200
TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET =

The work item runs only if there is a valid internet connection

0x400
TASK_FLAG_RESTART_ON_IDLE_RESUME =

The work item starts again if the computer makes a non-idle to idle transition

0x800
TASK_FLAG_SYSTEM_REQUIRED =

The work item causes the system to be resumed, or awakened, if the system is running on batter power

0x1000
TASK_FLAG_RUN_ONLY_IF_LOGGED_ON =

The work item runs only if a specified account is logged on interactively

0x2000
TASK_TRIGGER_FLAG_HAS_END_DATE =

The task will stop at some point in time

0x1
TASK_TRIGGER_FLAG_KILL_AT_DURATION_END =

The task can be stopped at the end of the repetition period

0x2
TASK_TRIGGER_FLAG_DISABLED =

The task trigger is disabled

0x4
TASK_MAX_RUN_TIMES =

:stopdoc:

1440
TASKS_TO_RETRIEVE =
5
TASK_VALIDATE_ONLY =

Task creation

0x1
TASK_CREATE =
0x2
TASK_UPDATE =
0x4
TASK_CREATE_OR_UPDATE =
0x6
TASK_DISABLE =
0x8
TASK_DONT_ADD_PRINCIPAL_ACE =
0x10
TASK_IGNORE_REGISTRATION_TRIGGERS =
0x20
TASK_LOGON_NONE =

Task logon types

0
TASK_LOGON_PASSWORD =
1
TASK_LOGON_S4U =
2
TASK_LOGON_INTERACTIVE_TOKEN =
3
TASK_LOGON_GROUP =
4
TASK_LOGON_SERVICE_ACCOUNT =
5
TASK_LOGON_INTERACTIVE_TOKEN_OR_PASSWORD =
6
REALTIME_PRIORITY_CLASS =

Priority classes

0
HIGH_PRIORITY_CLASS =
1
ABOVE_NORMAL_PRIORITY_CLASS =

Or 3

2
NORMAL_PRIORITY_CLASS =

Or 5, 6

4
BELOW_NORMAL_PRIORITY_CLASS =

Or 8

7
IDLE_PRIORITY_CLASS =

Or 10

9
CLSCTX_INPROC_SERVER =
0x1
CLSID_CTask =
[0x148BD520,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
CLSID_CTaskScheduler =
[0x148BD52A,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
IID_ITaskScheduler =
[0x148BD527,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
IID_ITask =
[0x148BD524,0xA2AB,0x11CE,0xB1,0x1F,0x00,0xAA,0x00,0x53,0x05,0x03].pack('LSSC8')
IID_IPersistFile =
[0x0000010b,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46].pack('LSSC8')
IDLE =

Shorthand constants

IDLE_PRIORITY_CLASS
NORMAL =
NORMAL_PRIORITY_CLASS
HIGH =
HIGH_PRIORITY_CLASS
REALTIME =
REALTIME_PRIORITY_CLASS
BELOW_NORMAL =
BELOW_NORMAL_PRIORITY_CLASS
ABOVE_NORMAL =
ABOVE_NORMAL_PRIORITY_CLASS
ONCE =
TASK_TIME_TRIGGER_ONCE
DAILY =
TASK_TIME_TRIGGER_DAILY
WEEKLY =
TASK_TIME_TRIGGER_WEEKLY
MONTHLYDATE =
TASK_TIME_TRIGGER_MONTHLYDATE
MONTHLYDOW =
TASK_TIME_TRIGGER_MONTHLYDOW
ON_IDLE =
TASK_EVENT_TRIGGER_ON_IDLE
AT_SYSTEMSTART =
TASK_EVENT_TRIGGER_AT_SYSTEMSTART
AT_LOGON =
TASK_EVENT_TRIGGER_AT_LOGON
FIRST_WEEK =
TASK_FIRST_WEEK
SECOND_WEEK =
TASK_SECOND_WEEK
THIRD_WEEK =
TASK_THIRD_WEEK
FOURTH_WEEK =
TASK_FOURTH_WEEK
LAST_WEEK =
TASK_LAST_WEEK
SUNDAY =
TASK_SUNDAY
MONDAY =
TASK_MONDAY
TUESDAY =
TASK_TUESDAY
WEDNESDAY =
TASK_WEDNESDAY
THURSDAY =
TASK_THURSDAY
FRIDAY =
TASK_FRIDAY
SATURDAY =
TASK_SATURDAY
JANUARY =
TASK_JANUARY
FEBRUARY =
TASK_FEBRUARY
MARCH =
TASK_MARCH
APRIL =
TASK_APRIL
MAY =
TASK_MAY
JUNE =
TASK_JUNE
JULY =
TASK_JULY
AUGUST =
TASK_AUGUST
SEPTEMBER =
TASK_SEPTEMBER
OCTOBER =
TASK_OCTOBER
NOVEMBER =
TASK_NOVEMBER
DECEMBER =
TASK_DECEMBER
INTERACTIVE =
TASK_FLAG_INTERACTIVE
DELETE_WHEN_DONE =
TASK_FLAG_DELETE_WHEN_DONE
DISABLED =
TASK_FLAG_DISABLED
START_ONLY_IF_IDLE =
TASK_FLAG_START_ONLY_IF_IDLE
KILL_ON_IDLE_END =
TASK_FLAG_KILL_ON_IDLE_END
DONT_START_IF_ON_BATTERIES =
TASK_FLAG_DONT_START_IF_ON_BATTERIES
KILL_IF_GOING_ON_BATTERIES =
TASK_FLAG_KILL_IF_GOING_ON_BATTERIES
RUN_ONLY_IF_DOCKED =
TASK_FLAG_RUN_ONLY_IF_DOCKED
HIDDEN =
TASK_FLAG_HIDDEN
RUN_IF_CONNECTED_TO_INTERNET =
TASK_FLAG_RUN_IF_CONNECTED_TO_INTERNET
RESTART_ON_IDLE_RESUME =
TASK_FLAG_RESTART_ON_IDLE_RESUME
SYSTEM_REQUIRED =
TASK_FLAG_SYSTEM_REQUIRED
RUN_ONLY_IF_LOGGED_ON =
TASK_FLAG_RUN_ONLY_IF_LOGGED_ON
FLAG_HAS_END_DATE =
TASK_TRIGGER_FLAG_HAS_END_DATE
FLAG_KILL_AT_DURATION_END =
TASK_TRIGGER_FLAG_KILL_AT_DURATION_END
FLAG_DISABLED =
TASK_TRIGGER_FLAG_DISABLED
MAX_RUN_TIMES =
TASK_MAX_RUN_TIMES

Constants included from Windows::Helper

Windows::Helper::FORMAT_MESSAGE_FROM_SYSTEM, Windows::Helper::FORMAT_MESSAGE_IGNORE_INSERTS, Windows::Helper::FORMAT_MESSAGE_MAX_WIDTH_MASK

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Windows::Helper

#ole_error, #win_error

Constructor Details

#initialize(task = nil, trigger = nil, folder = "\\", force = false) ⇒ TaskScheduler

Returns a new TaskScheduler object, attached to folder. If that folder does not exist, but the force option is set to true, then it will be created. Otherwise an error will be raised. The default is to use the root folder.

If task and trigger are present, then a new task is generated as well. This is effectively the same as .new + #new_work_item.

Raises:

  • (ArgumentError)


236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/win32/taskscheduler.rb', line 236

def initialize(task = nil, trigger = nil, folder = "\\", force = false)
  @folder = folder
  @force  = force

  @host     = Socket.gethostname
  @task     = nil
  @password = nil

  raise ArgumentError, "invalid folder" unless folder.include?("\\")

  unless [TrueClass, FalseClass].include?(force.class)
    raise TypeError, "invalid force value"
  end

  begin
    @service = WIN32OLE.new('Schedule.Service')
  rescue WIN32OLERuntimeError => err
    raise Error, err.inspect
  end

  @service.Connect

  if folder != "\\"
    begin
      @root = @service.GetFolder(folder)
    rescue WIN32OLERuntimeError => err
      if force
        @root.CreateFolder(folder)
        @root = @service.GetFolder(folder)
      else
        raise ArgumentError, "folder '#{folder}' not found"
      end
    end
  else
    @root = @service.GetFolder(folder)
  end

  if task && trigger
    new_work_item(task, trigger)
  end
end

Instance Attribute Details

#hostObject (readonly) Also known as: machine

Returns the value of attribute host



226
227
228
# File 'lib/win32/taskscheduler.rb', line 226

def host
  @host
end

#passwordObject

:startdoc:



225
226
227
# File 'lib/win32/taskscheduler.rb', line 225

def password
  @password
end

Instance Method Details

#account_informationObject

Returns the user associated with the task or nil if no user has yet been associated with the task.



420
421
422
# File 'lib/win32/taskscheduler.rb', line 420

def 
  @task.nil? ? nil : @task.Definition.Principal.UserId
end

#activate(task) ⇒ Object

Activate the specified task.

Raises:

  • (TypeError)


303
304
305
306
307
308
309
310
311
312
313
# File 'lib/win32/taskscheduler.rb', line 303

def activate(task)
  raise TypeError unless task.is_a?(String)

  begin
    registeredTask = @root.GetTask(task)
    registeredTask.Enabled = 1
    @task = registeredTask
  rescue WIN32OLERuntimeError => err
    raise Error, ole_error('activate', err)
  end
end

#add_trigger(index, trigger) ⇒ Object

Adds a trigger at the specified index.

Raises:

  • (TypeError)


992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
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
# File 'lib/win32/taskscheduler.rb', line 992

def add_trigger(index, trigger)
  raise TypeError unless index.is_a?(Numeric)
  raise TypeError unless trigger.is_a?(Hash)
  raise Error, 'No currently active task' if @task.nil?

  definition = @task.Definition
  case trigger[:trigger_type]
    when TASK_TIME_TRIGGER_DAILY
      type = 2
    when TASK_TIME_TRIGGER_WEEKLY
      type = 3
    when TASK_TIME_TRIGGER_MONTHLYDATE
      type = 4
    when TASK_TIME_TRIGGER_MONTHLYDOW
      type = 5
    when TASK_TIME_TRIGGER_ONCE
      type = 1
    else
      raise Error, 'Unknown trigger type'
  end

  startTime = "%04d-%02d-%02dT%02d:%02d:00" % [
    trigger[:start_year], trigger[:start_month], trigger[:start_day],
    trigger[:start_hour], trigger[:start_minute]
  ]

  # Set defaults
  trigger[:end_year]  ||= 0
  trigger[:end_month] ||= 0
  trigger[:end_day]   ||= 0

  endTime = "%04d-%02d-%02dT00:00:00" % [
    trigger[:end_year], trigger[:end_month], trigger[:end_day]
  ]

  trig = definition.Triggers.Create(type)
  trig.Id = "RegistrationTriggerId#{definition.Triggers.Count}"
  trig.StartBoundary = startTime
  trig.EndBoundary = endTime if endTime != '0000-00-00T00:00:00'
  trig.Enabled = true

  repetitionPattern = trig.Repetition

  if trigger[:minutes_duration].to_i > 0
    repetitionPattern.Duration = "PT#{trigger[:minutes_duration]||0}M"
  end

  if trigger[:minutes_interval].to_i > 0
    repetitionPattern.Interval  = "PT#{trigger[:minutes_interval]||0}M"
  end

  tmp = trigger[:type]
  tmp = nil unless tmp.is_a?(Hash)

  case trigger[:trigger_type]
    when TASK_TIME_TRIGGER_DAILY
      trig.DaysInterval = tmp[:days_interval] if tmp && tmp[:days_interval]
      if trigger[:random_minutes_interval].to_i > 0
      trig.RandomDelay = "PT#{trigger[:random_minutes_interval]}M"
      end
    when TASK_TIME_TRIGGER_WEEKLY
      trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
      trig.WeeksInterval = tmp[:weeks_interval] if tmp && tmp[:weeks_interval]
      if trigger[:random_minutes_interval].to_i > 0
      trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
      end
    when TASK_TIME_TRIGGER_MONTHLYDATE
      trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
      trig.DaysOfMonth = tmp[:days] if tmp && tmp[:days]
      if trigger[:random_minutes_interval].to_i > 0
      trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
      end
    when TASK_TIME_TRIGGER_MONTHLYDOW
      trig.MonthsOfYear  = tmp[:months] if tmp && tmp[:months]
      trig.DaysOfWeek  = tmp[:days_of_week] if tmp && tmp[:days_of_week]
      trig.WeeksOfMonth  = tmp[:weeks] if tmp && tmp[:weeks]
      if trigger[:random_minutes_interval].to_i > 0
      trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
      end
    when TASK_TIME_TRIGGER_ONCE
      if trigger[:random_minutes_interval].to_i > 0
      trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
      end
  end

  user = definition.Principal.UserId

  begin

    @task = @root.RegisterTaskDefinition(
      @task.Path,
      definition,
      TASK_CREATE_OR_UPDATE,
      user,
      @password,
      @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
    )
  rescue WIN32OLERuntimeError => err
    raise Error, ole_error('add_trigger', err)
  end

  true
end

#application_nameObject

Returns the name of the application associated with the task. If no application is associated with the task then nil is returned.

Raises:



427
428
429
430
431
432
433
434
435
436
437
438
439
440
# File 'lib/win32/taskscheduler.rb', line 427

def application_name
  raise Error, 'No currently active task' if @task.nil?

  app = nil

  @task.Definition.Actions.each do |action|
    if action.Type == 0 # TASK_ACTION_EXEC
      app = action.Path
      break
    end
  end

  app
end

#application_name=(app) ⇒ Object

Sets the name of the application associated with the task.

Raises:

  • (TypeError)


444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
# File 'lib/win32/taskscheduler.rb', line 444

def application_name=(app)
  raise TypeError unless app.is_a?(String)
  raise Error, 'No currently active task' if @task.nil?

  definition = @task.Definition

  definition.Actions.each do |action|
    action.Path = app if action.Type == 0
  end

  user = definition.Principal.UserId

  @task = @root.RegisterTaskDefinition(
    @task.Path,
    definition,
    TASK_CREATE_OR_UPDATE,
    user,
    @password,
    @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
  )

  app
end

#commentObject

Returns the comment associated with the task, if any.

Raises:



1126
1127
1128
1129
1130
# File 'lib/win32/taskscheduler.rb', line 1126

def comment
  raise Error, 'No currently active task' if @task.nil?

  @task.Definition.RegistrationInfo.Description
end

#comment=(comment) ⇒ Object

Sets the comment for the task.

Raises:

  • (TypeError)


1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
# File 'lib/win32/taskscheduler.rb', line 1134

def comment=(comment)
  raise TypeError unless comment.is_a?(String)
  raise Error, 'No currently active task' if @task.nil?

  definition = @task.Definition
  definition.RegistrationInfo.Description = comment

  user = definition.Principal.UserId

  @task = @root.RegisterTaskDefinition(
    @task.Path,
    definition,
    TASK_CREATE_OR_UPDATE,
    user,
    @password,
    @password ? 1 : 3
  )

  comment
end

#creatorObject Also known as: author

Returns the name of the user who created the task.

Raises:



1157
1158
1159
1160
1161
# File 'lib/win32/taskscheduler.rb', line 1157

def creator
  raise Error, 'No currently active task' if @task.nil?

  @task.Definition.RegistrationInfo.Author
end

#creator=(creator) ⇒ Object

Sets the creator for the task.

Raises:

  • (TypeError)


1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
# File 'lib/win32/taskscheduler.rb', line 1167

def creator=(creator)
  raise TypeError unless creator.is_a?(String)
  raise Error, 'No currently active task' if @task.nil?

  definition = @task.Definition
  definition.RegistrationInfo.Author = creator

  user = definition.Principal.UserId

  @task = @root.RegisterTaskDefinition(
    @task.Path,
    definition,
    TASK_CREATE_OR_UPDATE,
    user,
    @password,
    @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
  )

  creator
end

#delete(task) ⇒ Object

Delete the specified task name.

Raises:

  • (TypeError)


317
318
319
320
321
322
323
324
325
# File 'lib/win32/taskscheduler.rb', line 317

def delete(task)
  raise TypeError unless task.is_a?(String)

  begin
    @root.DeleteTask(task, 0)
  rescue WIN32OLERuntimeError => err
    raise Error, ole_error('DeleteTask', err)
  end
end

#delete_trigger(index) ⇒ Object

Deletes the trigger at the specified index. – TODO: Fix.

Raises:

  • (TypeError)


771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
# File 'lib/win32/taskscheduler.rb', line 771

def delete_trigger(index)
  raise TypeError unless index.is_a?(Numeric)
  raise Error, 'No currently active task' if @task.nil?
  index += 1  # first item index is 1

  definition = @task.Definition
  definition.Triggers.Remove(index)
  user = definition.Principal.UserId

  @task = @root.RegisterTaskDefinition(
    @task.Path,
    definition,
    TASK_CREATE_OR_UPDATE,
    user,
    @password,
    @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
  )

  index
end

#enumObject Also known as: tasks

Returns an array of scheduled task names.



280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/win32/taskscheduler.rb', line 280

def enum
  # Get the task folder that contains the tasks.
  taskCollection = @root.GetTasks(0)

  array = []

  taskCollection.each do |registeredTask|
    array << registeredTask.Name
  end

  array
end

#exists?(task) ⇒ Boolean

Returns whether or not the specified task exists.

Returns:

  • (Boolean)


297
298
299
# File 'lib/win32/taskscheduler.rb', line 297

def exists?(task)
  enum.include?(task)
end

#exit_codeObject

Returns the exit code from the last scheduled run.

Raises:



1118
1119
1120
1121
1122
# File 'lib/win32/taskscheduler.rb', line 1118

def exit_code
  raise Error, 'No currently active task' if @task.nil?

  @task.LastTaskResult
end

#machine=(host) ⇒ Object Also known as: host=

Set the host on which the various TaskScheduler methods will execute. This method may require administrative privileges.

Raises:

  • (TypeError)


356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/win32/taskscheduler.rb', line 356

def machine=(host)
  raise TypeError unless host.is_a?(String)

  begin
    @service.Connect(host)
  rescue WIN32OLERuntimeError => err
    raise Error, ole_error('Connect', err)
  end

  @host = host
  host
end

#max_run_timeObject

Returns the maximum length of time, in milliseconds, that the task will run before terminating.

Raises:



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
# File 'lib/win32/taskscheduler.rb', line 1216

def max_run_time
  raise Error, 'No currently active task' if @task.nil?

  t = @task.Definition.Settings.ExecutionTimeLimit
  year = t.scan(/(\d+?)Y/).flatten.first
  month = t.scan(/(\d+?)M/).flatten.first
  day = t.scan(/(\d+?)D/).flatten.first
  hour = t.scan(/(\d+?)H/).flatten.first
  min = t.scan(/T.*(\d+?)M/).flatten.first
  sec = t.scan(/(\d+?)S/).flatten.first

  time = 0
  time += year.to_i * 365 if year
  time += month.to_i * 30 if month
  time += day.to_i if day
  time *= 24
  time += hour.to_i if hour
  time *= 60
  time += min.to_i if min
  time *= 60
  time += sec.to_i if sec
  time *= 1000

  time
end

#max_run_time=(max_run_time) ⇒ Object

Sets the maximum length of time, in milliseconds, that the task can run before terminating. Returns the value you specified if successful.

Raises:

  • (TypeError)


1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
# File 'lib/win32/taskscheduler.rb', line 1245

def max_run_time=(max_run_time)
  raise TypeError unless max_run_time.is_a?(Numeric)
  raise Error, 'No currently active task' if @task.nil?

  t = max_run_time
  t /= 1000
  limit ="PT#{t}S"

  definition = @task.Definition
  definition.Settings.ExecutionTimeLimit = limit
  user = definition.Principal.UserId

  @task = @root.RegisterTaskDefinition(
    @task.Path,
    definition,
    TASK_CREATE_OR_UPDATE,
    user,
    @password,
    @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
  )

  max_run_time
end

#most_recent_run_timeObject

Returns a Time object indicating the most recent time the task ran or nil if the task has never run.

Raises:



1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
# File 'lib/win32/taskscheduler.rb', line 1199

def most_recent_run_time
  raise Error, 'No currently active task' if @task.nil?

  time = nil

  begin
    time = Time.parse(@task.LastRunTime)
  rescue
    # Ignore
  end

  time
end

#new_work_item(task, trigger) ⇒ Object Also known as: new_task

Creates a new work item (scheduled job) with the given trigger. The trigger variable is a hash of options that define when the scheduled job should run.

Raises:

  • (TypeError)


621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
# File 'lib/win32/taskscheduler.rb', line 621

def new_work_item(task, trigger)
  raise TypeError unless task.is_a?(String)
  raise TypeError unless trigger.is_a?(Hash)

  validate_trigger(trigger)

  taskDefinition = @service.NewTask(0)
  taskDefinition.RegistrationInfo.Description = ''
  taskDefinition.RegistrationInfo.Author = ''
  taskDefinition.Settings.StartWhenAvailable = true
  taskDefinition.Settings.Enabled  = true
  taskDefinition.Settings.Hidden = false

  case trigger[:trigger_type]
    when TASK_TIME_TRIGGER_ONCE
      type = 1
    when TASK_TIME_TRIGGER_DAILY
      type = 2
    when TASK_TIME_TRIGGER_WEEKLY
      type = 3
    when TASK_TIME_TRIGGER_MONTHLYDATE
      type = 4
    when TASK_TIME_TRIGGER_MONTHLYDOW
      type = 5
    when TASK_EVENT_TRIGGER_ON_IDLE
      type = 6
    when TASK_EVENT_TRIGGER_AT_SYSTEMSTART
      type = 8
    when TASK_EVENT_TRIGGER_AT_LOGON
      type = 9
    else
      raise ArgumentError, 'Unknown trigger type'
  end

  startTime = "%04d-%02d-%02dT%02d:%02d:00" % [
    trigger[:start_year], trigger[:start_month], trigger[:start_day],
    trigger[:start_hour], trigger[:start_minute]
  ]

  # Set defaults
  trigger[:end_year]  ||= 0
  trigger[:end_month] ||= 0
  trigger[:end_day]   ||= 0

  endTime = "%04d-%02d-%02dT00:00:00" % [
    trigger[:end_year], trigger[:end_month], trigger[:end_day]
  ]

  trig = taskDefinition.Triggers.Create(type)
  trig.Id = "RegistrationTriggerId#{taskDefinition.Triggers.Count}"
  trig.StartBoundary = startTime
  trig.EndBoundary = endTime if endTime != '0000-00-00T00:00:00'
  trig.Enabled = true

  repetitionPattern = trig.Repetition

  if trigger[:minutes_duration].to_i > 0
    repetitionPattern.Duration = "PT#{trigger[:minutes_duration]||0}M"
  end

  if trigger[:minutes_interval].to_i > 0
    repetitionPattern.Interval = "PT#{trigger[:minutes_interval]||0}M"
  end

  tmp = trigger[:type]
  tmp = nil unless tmp.is_a?(Hash)

  case trigger[:trigger_type]
    when TASK_TIME_TRIGGER_DAILY
      trig.DaysInterval = tmp[:days_interval] if tmp && tmp[:days_interval]
      if trigger[:random_minutes_interval].to_i > 0
        trig.RandomDelay = "PT#{trigger[:random_minutes_interval]}M"
      end
    when TASK_TIME_TRIGGER_WEEKLY
      trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
      trig.WeeksInterval = tmp[:weeks_interval] if tmp && tmp[:weeks_interval]
      if trigger[:random_minutes_interval].to_i > 0
        trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
      end
    when TASK_TIME_TRIGGER_MONTHLYDATE
      trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
      trig.DaysOfMonth = tmp[:days] if tmp && tmp[:days]
      if trigger[:random_minutes_interval].to_i > 0
        trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
      end
    when TASK_TIME_TRIGGER_MONTHLYDOW
      trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
      trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
      trig.WeeksOfMonth = tmp[:weeks] if tmp && tmp[:weeks]
      if trigger[:random_minutes_interval].to_i>0
        trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
      end
    when TASK_TIME_TRIGGER_ONCE
      if trigger[:random_minutes_interval].to_i > 0
        trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
      end
  end

  act = taskDefinition.Actions.Create(0)
  act.Path = 'cmd'

  begin
    @task = @root.RegisterTaskDefinition(
      task,
      taskDefinition,
      TASK_CREATE_OR_UPDATE,
      nil,
      nil,
      TASK_LOGON_INTERACTIVE_TOKEN
    )
  rescue WIN32OLERuntimeError => err
    raise Error, ole_error('RegisterTaskDefinition', err)
  end

  @task = @root.GetTask(task)
end

#next_run_timeObject

Returns a Time object that indicates the next time the task will run.

Raises:



1190
1191
1192
1193
1194
# File 'lib/win32/taskscheduler.rb', line 1190

def next_run_time
  raise Error, 'No currently active task' if @task.nil?

  @task.NextRunTime
end

#parametersObject

Returns the command line parameters for the task.

Raises:



470
471
472
473
474
475
476
477
478
479
480
# File 'lib/win32/taskscheduler.rb', line 470

def parameters
  raise Error, 'No currently active task' if @task.nil?

  param = nil

  @task.Definition.Actions.each do |action|
    param = action.Arguments if action.Type == 0
  end

  param
end

#parameters=(param) ⇒ Object

Sets the parameters for the task. These parameters are passed as command line arguments to the application the task will run. To clear the command line parameters set it to an empty string. – NOTE: Again, it seems the task must be reactivated to be picked up.

Raises:

  • (TypeError)


488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
# File 'lib/win32/taskscheduler.rb', line 488

def parameters=(param)
  raise TypeError unless param.is_a?(String)
  raise Error, 'No currently active task' if @task.nil?

  definition = @task.Definition
  definition.Actions.each do |action|
    action.Arguments = param if action.Type == 0
  end
  user = definition.Principal.UserId

  @task = @root.RegisterTaskDefinition(
    @task.Path,
    definition,
    TASK_CREATE_OR_UPDATE,
    user,
    @password,
    @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
  )

  param
end

#priorityObject

Returns the task's priority level. Possible values are 'idle', 'normal', 'high', 'realtime', 'below_normal', 'above_normal', and 'unknown'.

Raises:



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
# File 'lib/win32/taskscheduler.rb', line 556

def priority
  raise Error, 'No currently active task' if @task.nil?

  case @task.Definition.Settings.Priority
    when 0
      priority = 'critical'
    when 1
      priority = 'highest'
    when 2
      priority = 'above_normal'
    when 3
      priority = 'above_normal'
    when 4
      priority = 'normal'
    when 5
      priority = 'normal'
    when 6
      priority = 'normal'
    when 7
      priority = 'below_normal'
    when 8
      priority = 'below_normal'
    when 9
      priority = 'lowest'
    when 10
      priority = 'idle'
    else
      priority = 'unknown'
  end

  priority
end

#priority=(priority) ⇒ Object

Sets the priority of the task. The priority should be a numeric priority constant value.

Raises:

  • (TypeError)


592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
# File 'lib/win32/taskscheduler.rb', line 592

def priority=(priority)
  raise TypeError unless priority.is_a?(Numeric)
  raise Error, 'No currently active task' if @task.nil?

  definition = @task.Definition

  begin
    definition.Settings.Priority = priority
    user = definition.Principal.UserId
  rescue WIN32OLERuntimeError => err
    raise Error, ole_error('Priority', err)
  end

  @task = @root.RegisterTaskDefinition(
    @task.Path,
    definition,
    TASK_CREATE_OR_UPDATE,
    user,
    @password,
    @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
  )

  priority
end

#runObject

Execute the current task.

Raises:



329
330
331
332
333
# File 'lib/win32/taskscheduler.rb', line 329

def run
  raise Error, 'null task' if @task.nil?

  @task.run(nil)
end

#save(file = nil) ⇒ Object

This method no longer has any effect. It is a no-op that remains for backwards compatibility. It will be removed in 0.4.0.

Raises:



338
339
340
341
342
# File 'lib/win32/taskscheduler.rb', line 338

def save(file = nil)
  warn DeprecatedMethodWarning, "this method is no longer necessary"
  raise Error, 'null task' if @task.nil?
  # Do nothing, deprecated.
end

#set_account_information(user, password) ⇒ Object

Sets the user and password for the given task. If the user and password are set properly then true is returned.

Raises:



393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
# File 'lib/win32/taskscheduler.rb', line 393

def (user, password)
  raise Error, 'No currently active task' if @task.nil?

  raise TypeError unless user.is_a?(String)
  raise TypeError unless password.is_a?(String)

  @password = password

  begin
    @task = @root.RegisterTaskDefinition(
      @task.Path,
      @task.Definition,
      TASK_CREATE_OR_UPDATE,
      user,
      password,
      TASK_LOGON_PASSWORD
    )
  rescue WIN32OLERuntimeError => err
    raise Error, ole_error('RegisterTaskDefinition', err)
  end

  true
end

#set_machine(host, user = nil, domain = nil, password = nil) ⇒ Object Also known as: set_host

Similar to the TaskScheduler#machine= method, this method also allows you to pass a user, domain and password as needed. This method may require administrative privileges.

Raises:

  • (TypeError)


373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/win32/taskscheduler.rb', line 373

def set_machine(host, user = nil, domain = nil, password = nil)
  raise TypeError unless host.is_a?(String)

  begin
    @service.Connect(host, user, domain, password)
  rescue WIN32OLERuntimeError => err
    raise Error, ole_error('Connect', err)
  end

  @host = host
  host
end

#statusObject

Returns the status of the currently active task. Possible values are 'ready', 'running', 'not scheduled' or 'unknown'.

Raises:



1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
# File 'lib/win32/taskscheduler.rb', line 1099

def status
  raise Error, 'No currently active task' if @task.nil?

  case @task.State
    when 3
      status = 'ready'
    when 4
      status = 'running'
    when 1
      status = 'not scheduled'
    else
      status = 'unknown'
  end

  status
end

#terminateObject Also known as: stop

Terminate (stop) the current task.

Raises:



346
347
348
349
# File 'lib/win32/taskscheduler.rb', line 346

def terminate
  raise Error, 'null task' if @task.nil?
  @task.stop(nil)
end

#trigger(index) ⇒ Object

Returns a hash that describes the trigger at the given index for the current task.

Raises:

  • (TypeError)


795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
# File 'lib/win32/taskscheduler.rb', line 795

def trigger(index)
  raise TypeError unless index.is_a?(Numeric)
  raise Error, 'No currently active task' if @task.nil?
  index += 1  # first item index is 1

  begin
    trig = @task.Definition.Triggers.Item(index)
  rescue WIN32OLERuntimeError => err
    raise Error, ole_error('Item', err)
  end

  trigger = {}
  trigger[:start_year], trigger[:start_month],
  trigger[:start_day],  trigger[:start_hour],
  trigger[:start_minute] = trig.StartBoundary.scan(/(\d+)-(\d+)-(\d+)T(\d+):(\d+)/).first

  trigger[:end_year], trigger[:end_month],
  trigger[:end_day] = trig.StartBoundary.scan(/(\d+)-(\d+)-(\d+)T/).first

  if trig.Repetition.Duration != ""
    trigger[:minutes_duration] = trig.Repetition.Duration.scan(/(\d+)M/)[0][0].to_i
  end

  if trig.Repetition.Interval != ""
    trigger[:minutes_interval] = trig.Repetition.Interval.scan(/(\d+)M/)[0][0].to_i
  end

  if trig.RandomDelay != ""
    trigger[:random_minutes_interval] = trig.RandomDelay.scan(/(\d+)M/)[0][0].to_i
  end

  case trig.Type
    when 2
      trigger[:trigger_type] = TASK_TIME_TRIGGER_DAILY
      tmp = {}
      tmp[:days_interval] = trig.DaysInterval
      trigger[:type] = tmp
    when 3
      trigger[:trigger_type] = TASK_TIME_TRIGGER_WEEKLY
      tmp = {}
      tmp[:weeks_interval] = trig.WeeksInterval
      tmp[:days_of_week] = trig.DaysOfWeek
      trigger[:type] = tmp
    when 4
      trigger[:trigger_type] = TASK_TIME_TRIGGER_MONTHLYDATE
      tmp = {}
      tmp[:months] = trig.MonthsOfYear
      tmp[:days] = trig.DaysOfMonth
      trigger[:type] = tmp
    when 5
      trigger[:trigger_type] = TASK_TIME_TRIGGER_MONTHLYDOW
      tmp = {}
      tmp[:months] = trig.MonthsOfYear
      tmp[:days_of_week] = trig.DaysOfWeek
      tmp[:weeks] = trig.weeks
      trigger[:type] = tmp
    when 1
      trigger[:trigger_type] = TASK_TIME_TRIGGER_ONCE
      tmp = {}
      tmp[:once] = nil
      trigger[:type] = tmp
    else
      raise Error, 'Unknown trigger type'
  end

  trigger
end

#trigger=(trigger) ⇒ Object

Sets the trigger for the currently active task. The trigger is a hash with the following possible options:

  • days

  • days_interval

  • days_of_week

  • end_day

  • end_month

  • end_year

  • flags

  • minutes_duration

  • minutes_interval

  • months

  • random_minutes_interval

  • start_day

  • start_hour

  • start_minute

  • start_month

  • start_year

  • trigger_type

  • type

  • weeks

  • weeks_interval

Raises:

  • (TypeError)


887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
# File 'lib/win32/taskscheduler.rb', line 887

def trigger=(trigger)
  raise TypeError unless trigger.is_a?(Hash)
  raise Error, 'No currently active task' if @task.nil?

  validate_trigger(trigger)

  definition = @task.Definition
  definition.Triggers.Clear()

  case trigger[:trigger_type]
    when TASK_TIME_TRIGGER_ONCE
      type = 1
    when TASK_TIME_TRIGGER_DAILY
      type = 2
    when TASK_TIME_TRIGGER_WEEKLY
      type = 3
    when TASK_TIME_TRIGGER_MONTHLYDATE
      type = 4
    when TASK_TIME_TRIGGER_MONTHLYDOW
      type = 5
    when TASK_EVENT_TRIGGER_ON_IDLE
      type = 6
    when TASK_EVENT_TRIGGER_AT_SYSTEM_START
      type = 8
    when TASK_EVENT_TRIGGER_AT_LOGON
      type = 9
    else
      raise Error, 'Unknown trigger type'
  end

  startTime = "%04d-%02d-%02dT%02d:%02d:00" % [
    trigger[:start_year], trigger[:start_month],
    trigger[:start_day], trigger[:start_hour], trigger[:start_minute]
  ]

  endTime = "%04d-%02d-%02dT00:00:00" % [
    trigger[:end_year], trigger[:end_month], trigger[:end_day]
  ]

  trig = definition.Triggers.Create(type)
  trig.Id = "RegistrationTriggerId#{definition.Triggers.Count}"
  trig.StartBoundary = startTime
  trig.EndBoundary = endTime if endTime != '0000-00-00T00:00:00'
  trig.Enabled = true

  repetitionPattern = trig.Repetition

  if trigger[:minutes_duration].to_i > 0
    repetitionPattern.Duration = "PT#{trigger[:minutes_duration]||0}M"
  end

  if trigger[:minutes_interval].to_i > 0
    repetitionPattern.Interval  = "PT#{trigger[:minutes_interval]||0}M"
  end

  tmp = trigger[:type]
  tmp = nil unless tmp.is_a?(Hash)

  case trigger[:trigger_type]
    when TASK_TIME_TRIGGER_DAILY
      trig.DaysInterval = tmp[:days_interval] if tmp && tmp[:days_interval]
      if trigger[:random_minutes_interval].to_i > 0
        trig.RandomDelay = "PT#{trigger[:random_minutes_interval]}M"
      end
    when TASK_TIME_TRIGGER_WEEKLY
      trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
      trig.WeeksInterval = tmp[:weeks_interval] if tmp && tmp[:weeks_interval]
      if trigger[:random_minutes_interval].to_i > 0
        trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
      end
    when TASK_TIME_TRIGGER_MONTHLYDATE
      trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
      trig.DaysOfMonth = tmp[:days] if tmp && tmp[:days]
      if trigger[:random_minutes_interval].to_i > 0
        trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
      end
    when TASK_TIME_TRIGGER_MONTHLYDOW
      trig.MonthsOfYear = tmp[:months] if tmp && tmp[:months]
      trig.DaysOfWeek = tmp[:days_of_week] if tmp && tmp[:days_of_week]
      trig.WeeksOfMonth = tmp[:weeks] if tmp && tmp[:weeks]
      if trigger[:random_minutes_interval].to_i > 0
        trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
      end
    when TASK_TIME_TRIGGER_ONCE
      if trigger[:random_minutes_interval].to_i > 0
        trig.RandomDelay = "PT#{trigger[:random_minutes_interval]||0}M"
      end
  end

  user = definition.Principal.UserId

  @task = @root.RegisterTaskDefinition(
    @task.Path,
    definition,
    TASK_CREATE_OR_UPDATE,
    user,
    @password,
    @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
  )

  trigger
end

#trigger_countObject

Returns the number of triggers associated with the active task.

Raises:



742
743
744
745
746
# File 'lib/win32/taskscheduler.rb', line 742

def trigger_count
  raise Error, "No currently active task" if @task.nil?

  @task.Definition.Triggers.Count
end

#trigger_string(index) ⇒ Object

Returns a string that describes the current trigger at the specified index for the active task.

Example: “At 7:14 AM every day, starting 4/11/2015”

Raises:

  • (TypeError)


753
754
755
756
757
758
759
760
761
762
763
764
765
# File 'lib/win32/taskscheduler.rb', line 753

def trigger_string(index)
  raise TypeError unless index.is_a?(Numeric)
  raise Error, 'No currently active task' if @task.nil?
  index += 1  # first item index is 1

  begin
    trigger = @task.Definition.Triggers.Item(index)
  rescue WIN32OLERuntimeError
    raise Error, "No trigger found at index '#{index}'"
  end

  "Starting #{trigger.StartBoundary}"
end

#working_directoryObject

Returns the working directory for the task.

Raises:



512
513
514
515
516
517
518
519
520
521
522
# File 'lib/win32/taskscheduler.rb', line 512

def working_directory
  raise Error,"No currently active task" if @task.nil?

  dir = nil

  @task.Definition.Actions.each do |action|
    dir = action.WorkingDirectory if action.Type == 0
  end

  dir
end

#working_directory=(dir) ⇒ Object

Sets the working directory for the task. – TODO: Why do I have to reactivate the task to see the change?

Raises:



528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
# File 'lib/win32/taskscheduler.rb', line 528

def working_directory=(dir)
  raise Error, 'No currently active task' if @task.nil?
  raise TypeError unless dir.is_a?(String)

  definition = @task.Definition

  definition.Actions.each do |action|
    action.WorkingDirectory = dir if action.Type == 0
  end

  user = definition.Principal.UserId

  @task = @root.RegisterTaskDefinition(
    @task.Path,
    definition,
    TASK_CREATE_OR_UPDATE,
    user,
    @password,
    @password ? TASK_LOGON_PASSWORD : TASK_LOGON_INTERACTIVE_TOKEN
  )

  dir
end