class Win32::TaskScheduler
The TaskScheduler
class encapsulates a Windows scheduled task
Constants
- ABOVE_NORMAL
- APRIL
- AT_LOGON
- AT_SYSTEMSTART
- AUGUST
- Arguments
- Author
- BELOW_NORMAL
- DAILY
- DECEMBER
- DELETE_WHEN_DONE
- DISABLED
- DONT_START_IF_ON_BATTERIES
- Date
- DaysInterval
- DaysOfMonth
- DaysOfWeek
- Delay
- Description
- DisplayName
- Documentation
- Duration
- EIGHTEENTH
- EIGHTH
- ELEVENTH
- Enabled
- EndBoundary
- ExecutionTimeLimit
- FEBRUARY
- FIFTEENTH
- FIFTH
- FIRST
- FIRST_WEEK
- FLAG_DISABLED
- FLAG_HAS_END_DATE
- FLAG_KILL_AT_DURATION_END
- FOURTEENTH
- FOURTH
- FOURTH_WEEK
- FRIDAY
- GroupId
- HIDDEN
- HIGH
- Hidden
- IDLE
Shorthand constants
- INTERACTIVE
- Id
- IdleSettings
The Idle settings of a task
@see docs.microsoft.com/en-us/windows/desktop/TaskSchd/idlesettings#properties
- Interval
- JANUARY
- JULY
- JUNE
- KILL_IF_GOING_ON_BATTERIES
- KILL_ON_IDLE_END
- LAST
- LAST_WEEK
- LogonType
- MARCH
- MAX_RUN_TIMES
- MAY
- MONDAY
- MONTHLYDATE
- MONTHLYDOW
- MonthsOfYear
- NINETEENTH
- NINETH
- NORMAL
- NOVEMBER
- OCTOBER
- ONCE
- ON_IDLE
- Path
- Priority
- REALTIME
- RESTART_ON_IDLE_RESUME
- RUN_IF_CONNECTED_TO_INTERNET
- RUN_ONLY_IF_DOCKED
- RUN_ONLY_IF_LOGGED_ON
- RandomDelay
- RunLevel
- RunOnLastDayOfMonth
- RunOnLastWeekOfMonth
- SATURDAY
- SECOND
- SECOND_WEEK
- SEPTEMBER
- SEVENTEENTH
- SEVENTH
- SIXTEENTH
- SIXTH
- START_ONLY_IF_IDLE
- SUNDAY
- SYSTEM_REQUIRED
- SecurityDescriptor
- Source
- StartBoundary
- StartWhenAvailable
- TENTH
- THIRD
- THIRD_WEEK
- THIRTEENTH
- THIRTYETH
- THIRTY_FIRST
- THURSDAY
- TUESDAY
- TWELFTH
- TWENTIETH
- TWENTY_EIGHTH
- TWENTY_FIFTH
- TWENTY_FIRST
- TWENTY_FOURTH
- TWENTY_NINTH
- TWENTY_SECOND
- TWENTY_SEVENTH
- TWENTY_SIXTH
- TWENTY_THIRD
- URI
- UserId
- VERSION
The version of the win32-taskscheduler library
- Version
- WEDNESDAY
- WEEKLY
- WeeksInterval
- WeeksOfMonth
- WorkingDirectory
- XmlText
Attributes
Public Class Methods
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
.
# File lib/win32/taskscheduler.rb, line 136 def initialize(task = nil, trigger = nil, folder = root_path, 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 != root_path begin @root = @service.GetFolder(folder) rescue WIN32OLERuntimeError => err if force @root = @service.GetFolder(root_path) @root = @root.CreateFolder(folder) else raise ArgumentError, "folder '#{folder}' not found" end end else @root = @service.GetFolder(folder) end new_work_item(task, trigger) if task && trigger end
Public Instance Methods
Returns the user or group associated with the task or nil if no one has been associated with the task yet
@return [String] user or group associated with the task
# File lib/win32/taskscheduler.rb, line 342 def account_information if @task.nil? nil elsif !@task.Definition.Principal.UserId.empty? @task.Definition.Principal.UserId else @task.Definition.Principal.GroupId end end
Activate the specified task.
# File lib/win32/taskscheduler.rb, line 240 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
Adds a trigger at the specified index.
# File lib/win32/taskscheduler.rb, line 832 def add_trigger(index, trigger) raise TypeError unless index.is_a?(Numeric) raise TypeError unless trigger.is_a?(Hash) raise ArgumentError, "Unknown trigger type" unless valid_trigger_option(trigger[:trigger_type]) check_for_active_task definition = @task.Definition startTime = format("%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 = format("%04d-%02d-%02dT00:00:00", trigger[:end_year], trigger[:end_month], trigger[:end_day]) trig = definition.Triggers.Create(trigger[:trigger_type].to_i) trig.Id = "RegistrationTriggerId#{definition.Triggers.Count}" trig.StartBoundary = startTime if startTime != "0000-00-00T00:00:00" 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 trig.RunOnLastDayOfMonth = trigger[:run_on_last_day_of_month] if trigger[:run_on_last_day_of_month] 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_of_month] if tmp && tmp[:weeks_of_month] if trigger[:random_minutes_interval].to_i > 0 trig.RandomDelay = "PT#{trigger[:random_minutes_interval] || 0}M" end trig.RunOnLastWeekOfMonth = trigger[:run_on_last_week_of_month] if trigger[:run_on_last_week_of_month] when TASK_TIME_TRIGGER_ONCE if trigger[:random_minutes_interval].to_i > 0 trig.RandomDelay = "PT#{trigger[:random_minutes_interval] || 0}M" end when TASK_EVENT_TRIGGER_AT_SYSTEMSTART trig.Delay = "PT#{trigger[:delay_duration] || 0}M" when TASK_EVENT_TRIGGER_AT_LOGON trig.UserId = trigger[:user_id] if trigger[:user_id] trig.Delay = "PT#{trigger[:delay_duration] || 0}M" end register_task_definition(definition) true end
Returns the name of the application associated with the task. If no application is associated with the task then nil is returned.
# File lib/win32/taskscheduler.rb, line 355 def application_name check_for_active_task app = nil @task.Definition.Actions.each do |action| if action.Type == 0 # TASK_ACTION_EXEC app = action.Path break end end app end
Sets the name of the application associated with the task.
# File lib/win32/taskscheduler.rb, line 372 def application_name=(app) raise TypeError unless app.is_a?(String) check_for_active_task definition = @task.Definition definition.Actions.each do |action| action.Path = app if action.Type == 0 end register_task_definition(definition) app end
Returns the comment associated with the task, if any.
# File lib/win32/taskscheduler.rb, line 949 def comment check_for_active_task @task.Definition.RegistrationInfo.Description end
Sets the comment for the task.
# File lib/win32/taskscheduler.rb, line 958 def comment=(comment) raise TypeError unless comment.is_a?(String) check_for_active_task definition = @task.Definition definition.RegistrationInfo.Description = comment register_task_definition(definition) comment end
Sets the principals for current active task. The principal is hash with following possible options. Expected principal hash: { id: STRING, display_name: STRING, user_id: STRING, logon_type
: INTEGER, group_id: STRING, run_level: INTEGER }
# File lib/win32/taskscheduler.rb, line 1207 def configure_principals(principals) raise TypeError unless principals.is_a?(Hash) check_for_active_task definition = @task.Definition definition.Principal.Id = principals[:id] if principals[:id].to_s != "" definition.Principal.DisplayName = principals[:display_name] if principals[:display_name].to_s != "" definition.Principal.UserId = principals[:user_id] if principals[:user_id].to_s != "" definition.Principal.LogonType = principals[:logon_type] if principals[:logon_type].to_s != "" definition.Principal.GroupId = principals[:group_id] if principals[:group_id].to_s != "" definition.Principal.RunLevel = principals[:run_level] if principals[:run_level].to_s != "" @interactive = true if principals[:logon_type] == TASK_LOGON_INTERACTIVE_TOKEN register_task_definition(definition) principals end
Set registration information options. The possible options are:
-
author
-
date
-
description (or comment)
-
documentation
-
security_descriptor (should be a Win32::Security::SID)
-
source
-
uri
-
version
-
xml_text (or xml)
Note that most of these options have standalone methods as well, e.g. calling ts.configure_registration_info(:author => 'Dan') is the same as calling ts.author = 'Dan'.
# File lib/win32/taskscheduler.rb, line 1172 def configure_registration_info(hash) raise TypeError unless hash.is_a?(Hash) check_for_active_task definition = @task.Definition author = hash[:author] date = hash[:date] description = hash[:description] || hash[:comment] documentation = hash[:documentation] security_descriptor = hash[:security_descriptor] source = hash[:source] uri = hash[:uri] version = hash[:version] xml_text = hash[:xml_text] || hash[:xml] definition.RegistrationInfo.Author = author if author definition.RegistrationInfo.Date = date if date definition.RegistrationInfo.Description = description if description definition.RegistrationInfo.Documentation = documentation if documentation definition.RegistrationInfo.SecurityDescriptor = security_descriptor if security_descriptor definition.RegistrationInfo.Source = source if source definition.RegistrationInfo.URI = uri if uri definition.RegistrationInfo.Version = version if version definition.RegistrationInfo.XmlText = xml_text if xml_text register_task_definition(definition) hash end
Configures tasks settings
@param [Hash] settings_hash The settings to configure a task @option settings_hash [Boolean] :allow_demand_start The subject @option settings_hash [Boolean] :allow_hard_terminate @option settings_hash [Boolean] :disallow_start_if_on_batteries @option settings_hash [Boolean] :disallow_start_on_remote_app_session @option settings_hash [Boolean] :enabled @option settings_hash [Boolean] :hidden @option settings_hash [Boolean] :run_only_if_idle @option settings_hash [Boolean] :run_only_if_network_available @option settings_hash [Boolean] :start_when_available @option settings_hash [Boolean] :stop_if_going_on_batteries @option settings_hash [Boolean] :use_unified_scheduling_engine @option settings_hash [Boolean] :volatile @option settings_hash [Boolean] :wake_to_run @option settings_hash [Boolean] :restart_on_idle The Idle Setting @option settings_hash [Boolean] :stop_on_idle_end The Idle Setting @option settings_hash [Integer] :compatibility @option settings_hash [Integer] :multiple_instances @option settings_hash [Integer] :priority @option settings_hash [Integer] :restart_count @option settings_hash [String] :delete_expired_task_after @option settings_hash [String] :execution_time_limit @option settings_hash [String] :restart_interval @option settings_hash [String] :idle_duration The Idle Setting @option settings_hash [String] :wait_timeout The Idle Setting
@return [Hash] User input
@see msdn.microsoft.com/en-us/library/windows/desktop/aa383480(v=vs.85).aspx#properties
# File lib/win32/taskscheduler.rb, line 1111 def configure_settings(settings_hash) raise TypeError, "User input settings are required in hash" unless settings_hash.is_a?(Hash) check_for_active_task definition = @task.Definition # Check for invalid setting invalid_settings = settings_hash.keys - valid_settings_options raise TypeError, "Invalid setting passed: #{invalid_settings.join(', ')}" unless invalid_settings.empty? # Some modification is required in user input hash = settings_hash.dup # Conversion of few settings hash[:execution_time_limit] = hash[:max_run_time] unless hash[:max_run_time].nil? %i{execution_time_limit idle_duration restart_interval wait_timeout}.each do |setting| hash[setting] = "PT#{hash[setting]}M" unless hash[setting].nil? end task_settings = definition.Settings # Some Idle setting needs to be configured if IdleSettings.any? { |setting| hash.key?(setting) } idle_settings = task_settings.IdleSettings IdleSettings.each do |setting| next if hash[setting].nil? idle_settings.setproperty(camelize(setting.to_s), hash[setting]) # This setting is not required to be configured now hash.delete(setting) end end # XML settings are not to be configured %i{xml_text xml}.map { |x| hash.delete(x) } hash.each do |setting, value| setting = camelize(setting.to_s) definition.Settings.setproperty(setting, value) end register_task_definition(definition) settings_hash end
Returns the name of the user who created the task.
# File lib/win32/taskscheduler.rb, line 973 def creator check_for_active_task @task.Definition.RegistrationInfo.Author end
Sets the creator for the task.
# File lib/win32/taskscheduler.rb, line 982 def creator=(creator) raise TypeError unless creator.is_a?(String) check_for_active_task definition = @task.Definition definition.RegistrationInfo.Author = creator register_task_definition(definition) creator end
Delete the specified task name.
# File lib/win32/taskscheduler.rb, line 254 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
Deletes the trigger at the specified index.
# File lib/win32/taskscheduler.rb, line 640 def delete_trigger(index) raise TypeError unless index.is_a?(Numeric) check_for_active_task index += 1 # first item index is 1 definition = @task.Definition definition.Triggers.Remove(index) register_task_definition(definition) index end
Returns true if current task is enabled
# File lib/win32/taskscheduler.rb, line 935 def enabled? check_for_active_task @task.enabled end
Returns an array of scheduled task names.
# File lib/win32/taskscheduler.rb, line 178 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
Returns the execution time limit for current active task
# File lib/win32/taskscheduler.rb, line 1021 def execution_time_limit check_for_active_task @task.Definition.Settings.ExecutionTimeLimit end
Returns whether or not the specified task exists.
# File lib/win32/taskscheduler.rb, line 195 def exists?(full_task_path) path = nil task_name = nil if full_task_path.include?('\\') *path, task_name = full_task_path.split('\\') else task_name = full_task_path end folder = path.nil? ? root_path : path.join('\\') begin root = @service.GetFolder(folder) rescue WIN32OLERuntimeError => err return false end if root.nil? return false else begin task = root.GetTask(task_name) return task && task.Name == task_name rescue WIN32OLERuntimeError => err return false end end end
Returns the exit code from the last scheduled run.
# File lib/win32/taskscheduler.rb, line 942 def exit_code check_for_active_task @task.LastTaskResult end
Return the sepcified task if exist
# File lib/win32/taskscheduler.rb, line 227 def get_task(task) raise TypeError unless task.is_a?(String) begin registeredTask = @root.GetTask(task) @task = registeredTask rescue WIN32OLERuntimeError => err raise Error, ole_error("activate", err) end end
Returns a hash of idle settings of the current task
# File lib/win32/taskscheduler.rb, line 1247 def idle_settings check_for_active_task settings_hash = {} @task.Definition.Settings.IdleSettings.ole_get_methods.each do |setting| settings_hash[setting.name] = @task.Definition.Settings.IdleSettings._getproperty(setting.dispid, [], []) end symbolize_keys(settings_hash) end
Set the host on which the various TaskScheduler
methods will execute. This method may require administrative privileges.
# File lib/win32/taskscheduler.rb, line 292 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
Returns the maximum length of time, in milliseconds, that the task will run before terminating.
# File lib/win32/taskscheduler.rb, line 1029 def max_run_time check_for_active_task 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
Sets the maximum length of time, in milliseconds, that the task can run before terminating. Returns the value you specified if successful.
# File lib/win32/taskscheduler.rb, line 1058 def max_run_time=(max_run_time) raise TypeError unless max_run_time.is_a?(Numeric) check_for_active_task t = max_run_time t /= 1000 limit = "PT#{t}S" definition = @task.Definition definition.Settings.ExecutionTimeLimit = limit register_task_definition(definition) max_run_time end
Returns a Time object indicating the most recent time the task ran or nil if the task has never run.
# File lib/win32/taskscheduler.rb, line 1005 def most_recent_run_time check_for_active_task time = nil begin time = Time.parse(@task.LastRunTime) rescue StandardError # Ignore end time end
Returns a hash of network settings of the current task
# File lib/win32/taskscheduler.rb, line 1257 def network_settings check_for_active_task settings_hash = {} @task.Definition.Settings.NetworkSettings.ole_get_methods.each do |setting| settings_hash[setting.name] = @task.Definition.Settings.NetworkSettings._getproperty(setting.dispid, [], []) end symbolize_keys(settings_hash) end
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.
# File lib/win32/taskscheduler.rb, line 511 def new_work_item(task, trigger, userinfo = { user: nil, password: nil, interactive: false }) raise TypeError unless userinfo.is_a?(Hash) && task.is_a?(String) && trigger.is_a?(Hash) # If user ID is not given, consider it as a 'SYSTEM' user userinfo[:user] = SERVICE_ACCOUNT_USERS.first if userinfo[:user].to_s.empty? @password = userinfo[:password] @interactive = userinfo[:interactive] check_credential_requirements(userinfo[:user], userinfo[:password]) taskDefinition = @service.NewTask(0) taskDefinition.RegistrationInfo.Description = "" taskDefinition.RegistrationInfo.Author = "" taskDefinition.Settings.StartWhenAvailable = false taskDefinition.Settings.Enabled = true taskDefinition.Settings.Hidden = false unless trigger.empty? raise ArgumentError, "Unknown trigger type" unless valid_trigger_option(trigger[:trigger_type]) validate_trigger(trigger) startTime = format("%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 = format("%04d-%02d-%02dT00:00:00", trigger[:end_year], trigger[:end_month], trigger[:end_day]) trig = taskDefinition.Triggers.Create(trigger[:trigger_type].to_i) trig.Id = "RegistrationTriggerId#{taskDefinition.Triggers.Count}" trig.StartBoundary = startTime if startTime != "0000-00-00T00:00:00" 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 trig.RunOnLastDayOfMonth = trigger[:run_on_last_day_of_month] if trigger[:run_on_last_day_of_month] 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_of_month] if tmp && tmp[:weeks_of_month] if trigger[:random_minutes_interval].to_i > 0 trig.RandomDelay = "PT#{trigger[:random_minutes_interval] || 0}M" end trig.RunOnLastWeekOfMonth = trigger[:run_on_last_week_of_month] if trigger[:run_on_last_week_of_month] when TASK_TIME_TRIGGER_ONCE if trigger[:random_minutes_interval].to_i > 0 trig.RandomDelay = "PT#{trigger[:random_minutes_interval] || 0}M" end when TASK_EVENT_TRIGGER_AT_SYSTEMSTART trig.Delay = "PT#{trigger[:delay_duration] || 0}M" when TASK_EVENT_TRIGGER_AT_LOGON trig.UserId = trigger[:user_id] if trigger[:user_id] trig.Delay = "PT#{trigger[:delay_duration] || 0}M" end end act = taskDefinition.Actions.Create(0) act.Path = "cmd" register_task_definition(taskDefinition, task, userinfo[:user], userinfo[:password]) @task = @root.GetTask(task) end
Returns a Time object that indicates the next time the task will run.
# File lib/win32/taskscheduler.rb, line 997 def next_run_time check_for_active_task @task.NextRunTime end
Returns the command line parameters for the task.
# File lib/win32/taskscheduler.rb, line 389 def parameters check_for_active_task param = nil @task.Definition.Actions.each do |action| param = action.Arguments if action.Type == 0 end param end
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.
# File lib/win32/taskscheduler.rb, line 407 def parameters=(param) raise TypeError unless param.is_a?(String) check_for_active_task definition = @task.Definition definition.Actions.each do |action| action.Arguments = param if action.Type == 0 end register_task_definition(definition) param end
Returns a hash containing all the principal information of the current task
# File lib/win32/taskscheduler.rb, line 1223 def principals check_for_active_task principals_hash = {} @task.Definition.Principal.ole_get_methods.each do |principal| principals_hash[principal.name] = @task.Definition.Principal._getproperty(principal.dispid, [], []) end symbolize_keys(principals_hash) end
Returns the task's priority level. Possible values are 'idle', 'lowest'. 'below_normal_8', 'below_normal_7', 'normal_6', 'normal_5', 'normal_4', 'above_normal_3', 'above_normal_2', 'highest', 'critical' and 'unknown'.
# File lib/win32/taskscheduler.rb, line 459 def priority check_for_active_task priority = case @task.Definition.Settings.Priority when 0 "critical" when 1 "highest" when 2 "above_normal_2" when 3 "above_normal_3" when 4 "normal_4" when 5 "normal_5" when 6 "normal_6" when 7 "below_normal_7" when 8 "below_normal_8" when 9 "lowest" when 10 "idle" else "unknown" end priority end
Sets the priority of the task. The priority
should be a numeric priority constant value.
# File lib/win32/taskscheduler.rb, line 495 def priority=(priority) raise TypeError unless priority.is_a?(Numeric) check_for_active_task definition = @task.Definition definition.Settings.Priority = priority register_task_definition(definition) priority end
# File lib/win32/taskscheduler.rb, line 124 def root_path(path = '\\') path end
Execute the current task.
# File lib/win32/taskscheduler.rb, line 266 def run check_for_active_task @task.run(nil) end
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.
# File lib/win32/taskscheduler.rb, line 274 def save(_file = nil) warn DeprecatedMethodWarning, "this method is no longer necessary" check_for_active_task # Do nothing, deprecated. end
Sets the user
and password
for the given task. If the user and password are set properly then true is returned. throws TypeError if password is not provided for other than system users
# File lib/win32/taskscheduler.rb, line 329 def set_account_information(user_id, password, interactive) @interactive ||= interactive check_credential_requirements(user_id, password) check_for_active_task @password = password register_task_definition(@task.Definition, @task.Path, user_id, password) true end
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.
# File lib/win32/taskscheduler.rb, line 309 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
Returns a hash containing all settings of the current task
# File lib/win32/taskscheduler.rb, line 1233 def settings check_for_active_task settings_hash = {} @task.Definition.Settings.ole_get_methods.each do |setting| next if setting.name == "XmlText" # not needed settings_hash[setting.name] = @task.Definition.Settings._getproperty(setting.dispid, [], []) end settings_hash["IdleSettings"] = idle_settings settings_hash["NetworkSettings"] = network_settings symbolize_keys(settings_hash) end
Returns the status of the currently active task. Possible values are 'ready', 'running', 'not scheduled' or 'unknown'.
# File lib/win32/taskscheduler.rb, line 915 def status check_for_active_task status = case @task.State when 3 "ready" when 4 "running" when 2 "queued" when 1 "not scheduled" else "unknown" end status end
Returns the user or group associated with the task. If no one is associated, it returns the default user i.e., 'SYSTEM'
@param [WIN32OLE] definition
@return [String] user_id
# File lib/win32/taskscheduler.rb, line 1272 def task_user_id(definition) user_id = definition.Principal.UserId.to_s user_id = definition.Principal.GroupId.to_s if user_id.empty? user_id = SERVICE_ACCOUNT_USERS.first if user_id.empty? user_id end
Terminate (stop) the current task.
# File lib/win32/taskscheduler.rb, line 282 def terminate check_for_active_task @task.stop(nil) end
Returns a hash that describes the trigger at the given index for the current task.
# File lib/win32/taskscheduler.rb, line 655 def trigger(index) raise TypeError unless index.is_a?(Numeric) check_for_active_task 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 = {} case trig.Type when TASK_TIME_TRIGGER_DAILY tmp = {} tmp[:days_interval] = trig.DaysInterval trigger[:type] = tmp trigger[:random_minutes_interval] = time_in_minutes(trig.RandomDelay) when TASK_TIME_TRIGGER_WEEKLY tmp = {} tmp[:weeks_interval] = trig.WeeksInterval tmp[:days_of_week] = trig.DaysOfWeek trigger[:type] = tmp trigger[:random_minutes_interval] = time_in_minutes(trig.RandomDelay) when TASK_TIME_TRIGGER_MONTHLYDATE tmp = {} tmp[:months] = trig.MonthsOfYear tmp[:days] = trig.DaysOfMonth trigger[:type] = tmp trigger[:random_minutes_interval] = time_in_minutes(trig.RandomDelay) trigger[:run_on_last_day_of_month] = trig.RunOnLastDayOfMonth when TASK_TIME_TRIGGER_MONTHLYDOW tmp = {} tmp[:months] = trig.MonthsOfYear tmp[:days_of_week] = trig.DaysOfWeek tmp[:weeks_of_month] = trig.WeeksOfMonth trigger[:type] = tmp trigger[:random_minutes_interval] = time_in_minutes(trig.RandomDelay) trigger[:run_on_last_week_of_month] = trig.RunOnLastWeekOfMonth when TASK_TIME_TRIGGER_ONCE tmp = {} tmp[:once] = nil trigger[:type] = tmp trigger[:random_minutes_interval] = time_in_minutes(trig.RandomDelay) when TASK_EVENT_TRIGGER_AT_SYSTEMSTART trigger[:delay_duration] = time_in_minutes(trig.Delay) when TASK_EVENT_TRIGGER_AT_LOGON trigger[:user_id] = trig.UserId if trig.UserId.to_s != "" trigger[:delay_duration] = time_in_minutes(trig.Delay) when TASK_EVENT_TRIGGER_ON_IDLE trigger[:execution_time_limit] = time_in_minutes(trig.ExecutionTimeLimit) else raise Error, "Unknown trigger type" end 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.EndBoundary.scan(/(\d+)-(\d+)-(\d+)T/).first trigger[:minutes_duration] = time_in_minutes(trig.Repetition.Duration) trigger[:minutes_interval] = time_in_minutes(trig.Repetition.Interval) trigger[:trigger_type] = trig.Type trigger end
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
# File lib/win32/taskscheduler.rb, line 748 def trigger=(trigger) raise TypeError unless trigger.is_a?(Hash) raise ArgumentError, "Unknown trigger type" unless valid_trigger_option(trigger[:trigger_type]) check_for_active_task validate_trigger(trigger) definition = @task.Definition definition.Triggers.Clear() startTime = format("%04d-%02d-%02dT%02d:%02d:00", trigger[:start_year], trigger[:start_month], trigger[:start_day], trigger[:start_hour], trigger[:start_minute]) endTime = format("%04d-%02d-%02dT00:00:00", trigger[:end_year], trigger[:end_month], trigger[:end_day]) trig = definition.Triggers.Create(trigger[:trigger_type].to_i) trig.Id = "RegistrationTriggerId#{definition.Triggers.Count}" trig.StartBoundary = startTime if startTime != "0000-00-00T00:00:00" 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 trig.RunOnLastDayOfMonth = trigger[:run_on_last_day_of_month] if trigger[:run_on_last_day_of_month] 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_of_month] if tmp && tmp[:weeks_of_month] if trigger[:random_minutes_interval].to_i > 0 trig.RandomDelay = "PT#{trigger[:random_minutes_interval] || 0}M" end trig.RunOnLastWeekOfMonth = trigger[:run_on_last_week_of_month] if trigger[:run_on_last_week_of_month] when TASK_TIME_TRIGGER_ONCE if trigger[:random_minutes_interval].to_i > 0 trig.RandomDelay = "PT#{trigger[:random_minutes_interval] || 0}M" end when TASK_EVENT_TRIGGER_AT_SYSTEMSTART trig.Delay = "PT#{trigger[:delay_duration] || 0}M" when TASK_EVENT_TRIGGER_AT_LOGON trig.UserId = trigger[:user_id] if trigger[:user_id] trig.Delay = "PT#{trigger[:delay_duration] || 0}M" when TASK_EVENT_TRIGGER_ON_IDLE # for setting execution time limit Ref : https://msdn.microsoft.com/en-us/library/windows/desktop/aa380724(v=vs.85).aspx if trigger[:execution_time_limit].to_i > 0 trig.ExecutionTimeLimit = "PT#{trigger[:execution_time_limit] || 0}M" end end register_task_definition(definition) trigger end
Returns the number of triggers associated with the active task.
# File lib/win32/taskscheduler.rb, line 611 def trigger_count raise Error, "No currently active task" if @task.nil? @task.Definition.Triggers.Count end
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”
# File lib/win32/taskscheduler.rb, line 622 def trigger_string(index) raise TypeError unless index.is_a?(Numeric) check_for_active_task 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
Returns the working directory for the task.
# File lib/win32/taskscheduler.rb, line 424 def working_directory check_for_active_task dir = nil @task.Definition.Actions.each do |action| dir = action.WorkingDirectory if action.Type == 0 end dir end
Sets the working directory for the task.
# File lib/win32/taskscheduler.rb, line 440 def working_directory=(dir) raise TypeError unless dir.is_a?(String) check_for_active_task definition = @task.Definition definition.Actions.each do |action| action.WorkingDirectory = dir if action.Type == 0 end register_task_definition(definition) dir end
Private Instance Methods
Converts a snake-case string to camel-case format
@param [String] str
@return [String] In camel case format
# File lib/win32/taskscheduler.rb, line 1292 def camelize(str) str.split("_").map(&:capitalize).join end
System users will not require a password Other users will require a password if the task is non-interactive.
@param [String] user_id @param [String] password
# File lib/win32/taskscheduler.rb, line 1368 def check_credential_requirements(user_id, password) user_id = user_id.to_s password = password.to_s if password.empty? unless system_user?(user_id) || @interactive raise ArgumentError, "Password is required for non-system users" end else if system_user?(user_id) raise ArgumentError, "Password is not required for system users" end end end
# File lib/win32/taskscheduler.rb, line 1334 def check_for_active_task raise Error, "No currently active task" if @task.nil? end
Checks if the user belongs to group accounts category
@return [Boolean] True or False
# File lib/win32/taskscheduler.rb, line 1350 def group_user?(user) BUILT_IN_GROUPS.include?(user.to_s.upcase) end
Returns the applicable flag as per the given users and groups which is used while RegisterTaskDefinition
@param [String] user_id @param [String] password
@return [Integer] Logon Types
# File lib/win32/taskscheduler.rb, line 1391 def logon_type(user_id, password) if service_account_user?(user_id) TASK_LOGON_SERVICE_ACCOUNT elsif group_user?(user_id) TASK_LOGON_GROUP elsif !user_id.to_s.empty? && !password.to_s.empty? if @interactive TASK_LOGON_INTERACTIVE_TOKEN else TASK_LOGON_PASSWORD end else TASK_LOGON_INTERACTIVE_TOKEN end end
Uses RegisterTaskDefinition and creates or updates the task
@param [WIN32OLE] definition @param [String] path @param [String] user_id @param [String] password
@return [Integer] Logon Types
# File lib/win32/taskscheduler.rb, line 1416 def register_task_definition(definition, path = nil, user_id = nil, password = nil) user_id ||= task_user_id(definition) password ||= @password path ||= @task.Path @task = @root.RegisterTaskDefinition( path, # Path (name) of the task definition, # definition of the task TASK_CREATE_OR_UPDATE, # Equivalent to TASK_CREATE | TASK_UPDATE user_id, password, logon_type(user_id, password) ) rescue WIN32OLERuntimeError => err method_name = caller_locations(1, 1)[0].label raise Error, ole_error(method_name, err) end
Checks if the user belongs to service accounts category
@return [Boolean] True or False
# File lib/win32/taskscheduler.rb, line 1342 def service_account_user?(user) SERVICE_ACCOUNT_USERS.include?(user.to_s.upcase) end
Converts all the keys of a hash to underscored-symbol format
# File lib/win32/taskscheduler.rb, line 1297 def symbolize_keys(hash) hash.each_with_object({}) do |(k, v), h| h[underscore(k.to_s).to_sym] = v.is_a?(Hash) ? symbolize_keys(v) : v end end
Checks if the user belongs to system users category
@return [Boolean] True or False
# File lib/win32/taskscheduler.rb, line 1358 def system_user?(user) SYSTEM_USERS.include?(user.to_s.upcase) end
Returns a camle-case string to its underscore format
# File lib/win32/taskscheduler.rb, line 1282 def underscore(string) string.gsub(/([a-z\d])([A-Z])/, '\1_\2'.freeze).downcase end
Configurable settings options
@note Logically, this is summation of
* Settings * IdleSettings - [:idle_settings] * :max_run_time, :xml
@return [Array]
# File lib/win32/taskscheduler.rb, line 1324 def valid_settings_options %i{allow_demand_start allow_hard_terminate compatibility delete_expired_task_after disallow_start_if_on_batteries disallow_start_on_remote_app_session enabled execution_time_limit hidden idle_duration maintenance_settings max_run_time multiple_instances network_settings priority restart_count restart_interval restart_on_idle run_only_if_idle run_only_if_network_available start_when_available stop_if_going_on_batteries stop_on_idle_end use_unified_scheduling_engine volatile wait_timeout wake_to_run xml xml_text} end
# File lib/win32/taskscheduler.rb, line 1303 def valid_trigger_option(trigger_type) [TASK_TIME_TRIGGER_ONCE, TASK_TIME_TRIGGER_DAILY, TASK_TIME_TRIGGER_WEEKLY, TASK_TIME_TRIGGER_MONTHLYDATE, TASK_TIME_TRIGGER_MONTHLYDOW, TASK_EVENT_TRIGGER_ON_IDLE, TASK_EVENT_TRIGGER_AT_SYSTEMSTART, TASK_EVENT_TRIGGER_AT_LOGON].include?(trigger_type.to_i) end
# File lib/win32/taskscheduler.rb, line 1309 def validate_trigger(hash) %i{start_year start_month start_day}.each do |key| raise ArgumentError, "#{key} must be set" unless hash[key] end end