The TaskScheduler class encapsulates taskscheduler settings and behavior
Shorthand constants
Returns the user associated with the task or nil if no user has yet been associated with the task.
# File lib/puppet/util/windows/taskscheduler.rb, line 342 def account_information raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? # default under certain failures user = nil begin FFI::MemoryPointer.new(:pointer) do |ptr| @pITask.GetAccountInformation(ptr) ptr.read_com_memory_pointer do |str_ptr| user = str_ptr.read_arbitrary_wide_string_up_to(256) if ! str_ptr.null? end end rescue Puppet::Util::Windows::Error => e raise e unless e.code == SCHED_E_ACCOUNT_INFORMATION_NOT_SET || e.code == SCHED_E_NO_SECURITY_SERVICES || e.code == ERROR_NONE_MAPPED end user end
Activate the specified task.
# File lib/puppet/util/windows/taskscheduler.rb, line 231 def activate(task) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise TypeError unless task.is_a?(String) FFI::MemoryPointer.new(:pointer) do |ptr| @pITS.Activate(wide_string(task), IID_ITask, ptr) reset_current_task @pITask = COM::Task.new(ptr.read_pointer) end @pITask end
Adds a trigger at the specified index.
# File lib/puppet/util/windows/taskscheduler.rb, line 630 def add_trigger(index, trigger) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? raise TypeError unless trigger.is_a?(Hash) @pITask.UseInstance(COM::TaskTrigger, :GetTrigger, index) do |pITaskTrigger| populate_trigger(pITaskTrigger, trigger) end end
Returns the name of the application associated with the task.
# File lib/puppet/util/windows/taskscheduler.rb, line 367 def application_name raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? app = nil FFI::MemoryPointer.new(:pointer) do |ptr| @pITask.GetApplicationName(ptr) ptr.read_com_memory_pointer do |str_ptr| app = str_ptr.read_arbitrary_wide_string_up_to(256) if ! str_ptr.null? end end app end
Sets the application name associated with the task.
# File lib/puppet/util/windows/taskscheduler.rb, line 386 def application_name=(app) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? raise TypeError unless app.is_a?(String) @pITask.SetApplicationName(wide_string(app)) app end
Returns the comment associated with the task, if any.
# File lib/puppet/util/windows/taskscheduler.rb, line 714 def comment raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? comment = nil FFI::MemoryPointer.new(:pointer) do |ptr| @pITask.GetComment(ptr) ptr.read_com_memory_pointer do |str_ptr| comment = str_ptr.read_arbitrary_wide_string_up_to(256) if ! str_ptr.null? end end comment end
Sets the comment for the task.
# File lib/puppet/util/windows/taskscheduler.rb, line 732 def comment=(comment) raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? raise TypeError unless comment.is_a?(String) @pITask.SetComment(wide_string(comment)) comment end
Returns the name of the user who created the task.
# File lib/puppet/util/windows/taskscheduler.rb, line 742 def creator raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? creator = nil FFI::MemoryPointer.new(:pointer) do |ptr| @pITask.GetCreator(ptr) ptr.read_com_memory_pointer do |str_ptr| creator = str_ptr.read_arbitrary_wide_string_up_to(256) if ! str_ptr.null? end end creator end
Sets the creator for the task.
# File lib/puppet/util/windows/taskscheduler.rb, line 760 def creator=(creator) raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? raise TypeError unless creator.is_a?(String) @pITask.SetCreator(wide_string(creator)) creator end
Delete the specified task name.
# File lib/puppet/util/windows/taskscheduler.rb, line 247 def delete(task) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise TypeError unless task.is_a?(String) @pITS.Delete(wide_string(task)) true end
Deletes the trigger at the specified index.
# File lib/puppet/util/windows/taskscheduler.rb, line 581 def delete_trigger(index) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? @pITask.DeleteTrigger(index) index end
Returns an array of scheduled task names.
# File lib/puppet/util/windows/taskscheduler.rb, line 198 def enum raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? array = [] @pITS.UseInstance(COM::EnumWorkItems, :Enum) do |pIEnum| FFI::MemoryPointer.new(:pointer) do |names_array_ptr_ptr| FFI::MemoryPointer.new(:win32_ulong) do |fetched_count_ptr| # awkward usage, if number requested is available, returns S_OK (0), or if less were returned returns S_FALSE (1) while (pIEnum.Next(TASKS_TO_RETRIEVE, names_array_ptr_ptr, fetched_count_ptr) >= Puppet::Util::Windows::COM::S_OK) count = fetched_count_ptr.read_win32_ulong break if count == 0 names_array_ptr_ptr.read_com_memory_pointer do |names_array_ptr| # iterate over the array of pointers name_ptr_ptr = FFI::Pointer.new(:pointer, names_array_ptr) for i in 0 ... count name_ptr_ptr[i].read_com_memory_pointer do |name_ptr| array << name_ptr.read_arbitrary_wide_string_up_to(256) end end end end end end end array end
Returns whether or not the scheduled task exists.
# File lib/puppet/util/windows/taskscheduler.rb, line 831 def exists?(job_name) bool = false Dir.foreach('C:/Windows/Tasks'){ |file| if File.basename(file, '.job') == job_name bool = true break end } bool end
Returns the exit code from the last scheduled run.
# File lib/puppet/util/windows/taskscheduler.rb, line 695 def exit_code raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? status = 0 begin FFI::MemoryPointer.new(:dword, 1) do |ptr| @pITask.GetExitCode(ptr) status = ptr.read_dword end rescue Puppet::Util::Windows::Error => e raise e unless e.code == SCHED_S_TASK_HAS_NOT_RUN end status end
Returns the flags (integer) that modify the behavior of the work item. You must OR the return value to determine the flags yourself.
# File lib/puppet/util/windows/taskscheduler.rb, line 643 def flags raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? flags = 0 FFI::MemoryPointer.new(:dword, 1) do |ptr| @pITask.GetFlags(ptr) flags = ptr.read_dword end flags end
Sets an OR’d value of flags that modify the behavior of the work item.
# File lib/puppet/util/windows/taskscheduler.rb, line 658 def flags=(flags) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? @pITask.SetFlags(flags) flags end
Set the host on which the various TaskScheduler methods will execute.
# File lib/puppet/util/windows/taskscheduler.rb, line 296 def machine=(host) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise TypeError unless host.is_a?(String) @pITS.SetTargetComputer(wide_string(host)) host end
Returns the maximum length of time, in milliseconds, that the task will run before terminating.
# File lib/puppet/util/windows/taskscheduler.rb, line 806 def max_run_time raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? max_run_time = nil FFI::MemoryPointer.new(:dword, 1) do |ptr| @pITask.GetMaxRunTime(ptr) max_run_time = ptr.read_dword end max_run_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/puppet/util/windows/taskscheduler.rb, line 822 def max_run_time=(max_run_time) raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? raise TypeError unless max_run_time.is_a?(Numeric) @pITask.SetMaxRunTime(max_run_time) 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/puppet/util/windows/taskscheduler.rb, line 786 def most_recent_run_time raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? time = nil begin FFI::MemoryPointer.new(WIN32::SYSTEMTIME.size) do |ptr| @pITask.GetMostRecentRunTime(ptr) time = WIN32::SYSTEMTIME.new(ptr).to_local_time end rescue Puppet::Util::Windows::Error => e raise e unless e.code == SCHED_S_TASK_HAS_NOT_RUN end time 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/puppet/util/windows/taskscheduler.rb, line 509 def new_work_item(task, trigger) raise TypeError unless trigger.is_a?(Hash) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? # I'm working around github issue #1 here. enum.each{ |name| if name.downcase == task.downcase + '.job' raise Error.new("task '#{task}' already exists") end } FFI::MemoryPointer.new(:pointer) do |ptr| @pITS.NewWorkItem(wide_string(task), CLSID_CTask, IID_ITask, ptr) reset_current_task @pITask = COM::Task.new(ptr.read_pointer) FFI::MemoryPointer.new(:word, 1) do |trigger_index_ptr| # Without the 'enum.include?' check above the code segfaults here if the # task already exists. This should probably be handled properly instead # of simply avoiding the issue. @pITask.UseInstance(COM::TaskTrigger, :CreateTrigger, trigger_index_ptr) do |pITaskTrigger| populate_trigger(pITaskTrigger, trigger) end end end @pITask end
Returns a Time object that indicates the next time the task will run.
# File lib/puppet/util/windows/taskscheduler.rb, line 770 def next_run_time raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? time = nil FFI::MemoryPointer.new(WIN32::SYSTEMTIME.size) do |ptr| @pITask.GetNextRunTime(ptr) time = WIN32::SYSTEMTIME.new(ptr).to_local_time end time end
Returns the command line parameters for the task.
# File lib/puppet/util/windows/taskscheduler.rb, line 398 def parameters raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? param = nil FFI::MemoryPointer.new(:pointer) do |ptr| @pITask.GetParameters(ptr) ptr.read_com_memory_pointer do |str_ptr| param = str_ptr.read_arbitrary_wide_string_up_to(256) if ! str_ptr.null? end 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/puppet/util/windows/taskscheduler.rb, line 419 def parameters=(param) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? raise TypeError unless param.is_a?(String) @pITask.SetParameters(wide_string(param)) param end
Returns the task’s priority level. Possible values are ‘idle’, ‘normal’, ‘high’, ‘realtime’, ‘below_normal’, ‘above_normal’, and ‘unknown’.
# File lib/puppet/util/windows/taskscheduler.rb, line 464 def priority raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? FFI::MemoryPointer.new(:dword, 1) do |ptr| @pITask.GetPriority(ptr) pri = ptr.read_dword if (pri & IDLE) != 0 priority = 'idle' elsif (pri & NORMAL) != 0 priority = 'normal' elsif (pri & HIGH) != 0 priority = 'high' elsif (pri & REALTIME) != 0 priority = 'realtime' elsif (pri & BELOW_NORMAL) != 0 priority = 'below_normal' elsif (pri & ABOVE_NORMAL) != 0 priority = 'above_normal' else priority = 'unknown' end end priority end
Sets the priority of the task. The priority should be a
numeric priority constant value.
# File lib/puppet/util/windows/taskscheduler.rb, line 495 def priority=(priority) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? raise TypeError unless priority.is_a?(Numeric) @pITask.SetPriority(priority) priority end
Execute the current task.
# File lib/puppet/util/windows/taskscheduler.rb, line 258 def run raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? @pITask.Run end
Saves the current task. Tasks must be saved before they can be activated. The .job file itself is typically stored in the C:WINDOWSTasks folder.
If file (an absolute path) is specified then the job is saved
to that file instead. A ‘.job’ extension is recommended but not
enforced.
# File lib/puppet/util/windows/taskscheduler.rb, line 270 def save(file = nil) raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? reset = true begin @pITask.QueryInstance(COM::PersistFile) do |pIPersistFile| pIPersistFile.Save(wide_string(file), 1) end rescue reset = false ensure reset_current_task if reset end end
Sets the user and password for the given task. If
the user and password are set properly then true is returned.
In some cases the job may be created, but the account information was bad. In this case the task is created but a warning is generated and false is returned.
# File lib/puppet/util/windows/taskscheduler.rb, line 314 def set_account_information(user, password) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? bool = false begin if (user.nil? || user=="") && (password.nil? || password=="") @pITask.SetAccountInformation(wide_string(""), FFI::Pointer::NULL) else user = wide_string(user) password = wide_string(password) @pITask.SetAccountInformation(user, password) end bool = true rescue Puppet::Util::Windows::Error => e raise e unless e.code == SCHED_E_ACCOUNT_INFORMATION_NOT_SET warn 'job created, but password was invalid' end bool end
Returns the status of the currently active task. Possible values are ‘ready’, ‘running’, ‘not scheduled’ or ‘unknown’.
# File lib/puppet/util/windows/taskscheduler.rb, line 669 def status raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? st = nil FFI::MemoryPointer.new(:hresult, 1) do |ptr| @pITask.GetStatus(ptr) st = ptr.read_hresult end case st when SCHED_S_TASK_READY status = 'ready' when SCHED_S_TASK_RUNNING status = 'running' when SCHED_S_TASK_NOT_SCHEDULED status = 'not scheduled' else status = 'unknown' end status end
Terminate the current task.
# File lib/puppet/util/windows/taskscheduler.rb, line 288 def terminate raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? @pITask.Terminate end
Returns a hash that describes the trigger at the given index for the current task.
# File lib/puppet/util/windows/taskscheduler.rb, line 592 def trigger(index) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? trigger = {} @pITask.UseInstance(COM::TaskTrigger, :GetTrigger, index) do |pITaskTrigger| FFI::MemoryPointer.new(COM::TASK_TRIGGER.size) do |task_trigger_ptr| pITaskTrigger.GetTrigger(task_trigger_ptr) trigger = populate_hash_from_trigger(COM::TASK_TRIGGER.new(task_trigger_ptr)) end end trigger end
Sets the trigger for the currently active task.
# File lib/puppet/util/windows/taskscheduler.rb, line 610 def trigger=(trigger) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? raise TypeError unless trigger.is_a?(Hash) FFI::MemoryPointer.new(:word, 1) do |trigger_index_ptr| # Without the 'enum.include?' check above the code segfaults here if the # task already exists. This should probably be handled properly instead # of simply avoiding the issue. @pITask.UseInstance(COM::TaskTrigger, :CreateTrigger, trigger_index_ptr) do |pITaskTrigger| populate_trigger(pITaskTrigger, trigger) end end trigger end
Returns the number of triggers associated with the active task.
# File lib/puppet/util/windows/taskscheduler.rb, line 544 def trigger_count raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? count = 0 FFI::MemoryPointer.new(:word, 1) do |ptr| @pITask.GetTriggerCount(ptr) count = ptr.read_word end 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/2009”
# File lib/puppet/util/windows/taskscheduler.rb, line 563 def trigger_string(index) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? raise TypeError unless index.is_a?(Numeric) FFI::MemoryPointer.new(:pointer) do |ptr| @pITask.GetTriggerString(index, ptr) ptr.read_com_memory_pointer do |str_ptr| trigger = str_ptr.read_arbitrary_wide_string_up_to(256) end end trigger end
Returns the working directory for the task.
# File lib/puppet/util/windows/taskscheduler.rb, line 431 def working_directory raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? dir = nil FFI::MemoryPointer.new(:pointer) do |ptr| @pITask.GetWorkingDirectory(ptr) ptr.read_com_memory_pointer do |str_ptr| dir = str_ptr.read_arbitrary_wide_string_up_to(256) if ! str_ptr.null? end end dir end
Sets the working directory for the task.
# File lib/puppet/util/windows/taskscheduler.rb, line 450 def working_directory=(dir) raise Error.new('No current task scheduler. ITaskScheduler is NULL.') if @pITS.nil? raise Error.new('No currently active task. ITask is NULL.') if @pITask.nil? raise TypeError unless dir.is_a?(String) @pITask.SetWorkingDirectory(wide_string(dir)) dir end
Returns a new TaskScheduler object. If a work_item (and possibly the the trigger) are passed as arguments then a new work item is created and associated with that trigger, although you can still activate other tasks with the same handle.
This is really just a bit of convenience. Passing arguments to the constructor is the same as calling ::new plus #new_work_item.
# File lib/puppet/util/windows/taskscheduler.rb, line 170 def initialize(work_item=nil, trigger=nil) @pITS = nil @pITask = nil if ! self.class.com_initialized Puppet::Util::Windows::COM.InitializeCom() self.class.com_initialized = true end @pITS = COM::TaskScheduler.new at_exit do begin @pITS.Release if @pITS && !@pITS.null? @pITS = nil rescue end end if work_item if trigger raise TypeError unless trigger.is_a?(Hash) new_work_item(work_item, trigger) end end end