class Chef::Resource::WindowsTask

Constants

DAYS_OF_MONTH
DAYS_OF_WEEK
MONTHS
PRIORITY
VALID_DAYS_OF_MONTH
VALID_MONTHS
VALID_WEEKS
VALID_WEEK_DAYS
WEEKS_OF_MONTH

Attributes

command_arguments[RW]
exists[RW]
task[RW]

Public Instance Methods

after_created() click to toggle source
# File lib/chef/resource/windows_task.rb, line 251
def after_created
  if random_delay
    validate_random_delay(random_delay, frequency)
    random_delay(sec_to_min(random_delay))
  end

  if execution_time_limit
    execution_time_limit(259200) if execution_time_limit == "PT72H"
    raise ArgumentError, "Invalid value passed for `execution_time_limit`. Please pass seconds as an Integer (e.g. 60) or a String with numeric values only (e.g. '60')." unless numeric_value_in_string?(execution_time_limit)

    execution_time_limit(sec_to_min(execution_time_limit))
  end

  validate_frequency(frequency) if action.include?(:create) || action.include?(:change)
  validate_start_time(start_time, frequency)
  validate_start_day(start_day, frequency) if start_day
  validate_user_and_password(user, password)
  validate_create_frequency_modifier(frequency, frequency_modifier) if frequency_modifier
  validate_create_day(day, frequency, frequency_modifier) if day
  validate_create_months(months, frequency) if months
  validate_frequency_monthly(frequency_modifier, months, day) if frequency == :monthly
  validate_idle_time(idle_time, frequency)
  idempotency_warning_for_frequency_weekly(day, start_day) if frequency == :weekly
end

Private Instance Methods

basic_validation() click to toggle source

This method checks if task and command properties exist since those two are mandatory properties to create a schedules task.

# File lib/chef/resource/windows_task.rb, line 926
def basic_validation
  validate = []
  validate << "Command" if new_resource.command.nil? || new_resource.command.empty?
  validate << "Task Name" if new_resource.task_name.nil? || new_resource.task_name.empty?
  return true if validate.empty?

  raise Chef::Exceptions::ValidationFailed.new "Value for '#{validate.join(", ")}' option cannot be empty"
end
config_settings() click to toggle source

TODO: while creating the configuration settings win32-taskscheduler it accepts execution time limit values in ISO8601 format

# File lib/chef/resource/windows_task.rb, line 880
def config_settings
  settings = {
    execution_time_limit: new_resource.execution_time_limit,
    enabled: true,
  }
  settings[:idle_duration] = new_resource.idle_time if new_resource.idle_time
  settings[:run_only_if_idle] = true if new_resource.idle_time
  settings[:priority] = new_resource.priority
  settings[:disallow_start_if_on_batteries] = new_resource.disallow_start_if_on_batteries
  settings[:stop_if_going_on_batteries] = new_resource.stop_if_going_on_batteries
  settings[:start_when_available] = new_resource.start_when_available
  settings
end
convert_hours_in_minutes(hours) click to toggle source
# File lib/chef/resource/windows_task.rb, line 646
def convert_hours_in_minutes(hours)
  hours.to_i * 60 if hours
end
day_includes_last_or_lastday?(day) click to toggle source
# File lib/chef/resource/windows_task.rb, line 640
def day_includes_last_or_lastday?(day)
  day = day.to_s.split(",")
  day.map! { |value| value.strip.upcase }
  day.include?("LAST") || day.include?("LASTDAY")
end
days_includes_days_of_months?(days) click to toggle source

This method returns true if day has values from 1-31 which is a days of moths and used with frequency :monthly

# File lib/chef/resource/windows_task.rb, line 441
def days_includes_days_of_months?(days)
  days.map! { |day| day.to_s.strip.downcase }
  (days - VALID_DAYS_OF_MONTH).empty?
end
days_of_month() click to toggle source

Deleting the “LAST” and “LASTDAY” from days since last day is handled in :run_on_last_day_of_month parameter.

# File lib/chef/resource/windows_task.rb, line 771
def days_of_month
  days_of_month = []
  if new_resource.day
    days = new_resource.day.to_s.split(",")
    days.map! { |day| day.to_s.strip.upcase }
    days.delete("LAST") if days.include?("LAST")
    days.delete("LASTDAY") if days.include?("LASTDAY")
    if days - (1..31).to_a
      days.each do |day|
        days_of_month << DAYS_OF_MONTH[day.to_i]
      end
      days_of_month = days_of_month.size > 1 ? days_of_month.inject(:|) : days_of_month[0]
    end
  else
    days_of_month = DAYS_OF_MONTH[1]
  end
  days_of_month
end
days_of_week() click to toggle source
# File lib/chef/resource/windows_task.rb, line 790
def days_of_week
  if new_resource.day
    # this line of code is just to support backward compatibility of wild card *
    new_resource.day = "mon, tue, wed, thu, fri, sat, sun" if new_resource.day == "*" && new_resource.frequency == :weekly
    days = new_resource.day.to_s.split(",")
    days.map! { |day| day.to_s.strip.upcase }
    weeks_days = get_binary_values_from_constants(days, DAYS_OF_WEEK)
  else
    # following condition will make the frequency :weekly idempotent if start_day is not provided by user setting day as the current_resource day
    if (current_resource) && (current_resource.task) && (current_resource.task.trigger(0)[:type][:days_of_week]) && (new_resource.start_day.nil?)
      weeks_days = current_resource.task.trigger(0)[:type][:days_of_week]
    else
      day = get_day(new_resource.start_day).to_sym if new_resource.start_day
      DAYS_OF_WEEK[day]
    end
  end
end
description_needs_update?(task) click to toggle source
# File lib/chef/resource/windows_task.rb, line 901
def description_needs_update?(task)
  task.description != new_resource.description unless new_resource.description.nil?
end
do_backup() click to toggle source
# File lib/chef/resource/windows_task.rb, line 958
def do_backup
  file = "C:/Windows/System32/Tasks/#{new_resource.task_name}"
  Chef::Util::Backup.new(new_resource, file).backup!
end
frequency_modifier_contains_last_week?(frequency_modifier) click to toggle source
# File lib/chef/resource/windows_task.rb, line 634
def frequency_modifier_contains_last_week?(frequency_modifier)
  frequency_modifier = frequency_modifier.to_s.split(",")
  frequency_modifier.map! { |value| value.strip.upcase }
  frequency_modifier.include?("LAST")
end
frequency_modifier_includes_days_of_weeks?(frequency_modifier) click to toggle source

returns true if frequency_modifier has values First, second, third, fourth, last, lastday

# File lib/chef/resource/windows_task.rb, line 314
def frequency_modifier_includes_days_of_weeks?(frequency_modifier)
  frequency_modifier = frequency_modifier.to_s.split(",")
  frequency_modifier.map! { |value| value.strip.upcase }
  (frequency_modifier - VALID_WEEKS).empty?
end
get_binary_values_from_constants(array_values, constant) click to toggle source
# File lib/chef/resource/windows_task.rb, line 861
def get_binary_values_from_constants(array_values, constant)
  data = []
  array_values.each do |value|
    value = value.to_sym
    data << constant[value]
  end
  data.size > 1 ? data.inject(:|) : data[0]
end
get_day(date) click to toggle source

rubocop:enable Style/StringLiteralsInInterpolation

# File lib/chef/resource/windows_task.rb, line 954
def get_day(date)
  Date.strptime(date, "%m/%d/%Y").strftime("%a").upcase
end
idempotency_warning_for_frequency_weekly(day, start_day) click to toggle source

Resource is not idempotent when day, start_day is not provided with frequency :weekly we set start_day when not given by user as current date based on which we set the day property for current current date day is monday .. we set the monday as the day so at next run when new_resource.day is nil and current_resource day is monday due to which update gets called

# File lib/chef/resource/windows_task.rb, line 281
def idempotency_warning_for_frequency_weekly(day, start_day)
  if start_day.nil? && day.nil?
    logger.warn "To maintain idempotency for frequency :weekly provide start_day, start_time and day."
  end
end
load_current_resource() click to toggle source
# File lib/chef/resource/windows_task.rb, line 545
def load_current_resource
  @current_resource = Chef::Resource::WindowsTask.new(new_resource.name)
  task = ::Win32::TaskScheduler.new(new_resource.task_name, nil, "\\", false)
  @current_resource.exists = task.exists?(new_resource.task_name)
  if @current_resource.exists
    task.get_task(new_resource.task_name)
    @current_resource.task = task
    pathed_task_name = new_resource.task_name.start_with?("\\") ? new_resource.task_name : "\\#{new_resource.task_name}"
    @current_resource.task_name(pathed_task_name)
  end
  @current_resource
end
logon_type() click to toggle source
# File lib/chef/resource/windows_task.rb, line 905
def logon_type
  # Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383566(v=vs.85).aspx
  # if nothing is passed as logon_type the TASK_LOGON_SERVICE_ACCOUNT is getting set as default so using that for comparison.
  user_id = new_resource.user.to_s
  password = new_resource.password.to_s
  if Chef::ReservedNames::Win32::Security::SID.service_account_user?(user_id)
    ::Win32::TaskScheduler::TASK_LOGON_SERVICE_ACCOUNT
  elsif Chef::ReservedNames::Win32::Security::SID.group_user?(user_id)
    ::Win32::TaskScheduler::TASK_LOGON_GROUP
  elsif !user_id.empty? && !password.empty?
    if new_resource.interactive_enabled
      ::Win32::TaskScheduler::TASK_LOGON_INTERACTIVE_TOKEN
    else
      ::Win32::TaskScheduler::TASK_LOGON_PASSWORD
    end
  else
    ::Win32::TaskScheduler::TASK_LOGON_INTERACTIVE_TOKEN
  end
end
months_of_year() click to toggle source
# File lib/chef/resource/windows_task.rb, line 808
def months_of_year
  months_of_year = []
  if new_resource.frequency_modifier.to_i.between?(1, 12) && !(new_resource.months)
    new_resource.months = set_months(new_resource.frequency_modifier.to_i)
  end

  if new_resource.months
    # this line of code is just to support backward compatibility of wild card *
    new_resource.months = "jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec" if new_resource.months == "*" && new_resource.frequency == :monthly
    months = new_resource.months.split(",")
    months.map! { |month| month.to_s.strip.upcase }
    months_of_year = get_binary_values_from_constants(months, MONTHS)
  else
    MONTHS.each do |key, value|
      months_of_year << MONTHS[key]
    end
    months_of_year = months_of_year.inject(:|)
  end
  months_of_year
end
non_system_user?(user)
Alias for: password_required?
numeric_value_in_string?(val) click to toggle source

Validate the passed value is numeric values only if it is a string

# File lib/chef/resource/windows_task.rb, line 288
def numeric_value_in_string?(val)
  return true if Integer(val)
rescue ArgumentError
  false
end
password_required?(user) click to toggle source

Password is not required for system user and required for non-system user.

# File lib/chef/resource/windows_task.rb, line 369
def password_required?(user)
  @password_required ||= (!user.nil? && !Chef::ReservedNames::Win32::Security::SID.system_user?(user))
end
Also aliased as: non_system_user?
principal_settings() click to toggle source
# File lib/chef/resource/windows_task.rb, line 894
def principal_settings
  settings = {}
  settings[:run_level] = run_level
  settings[:logon_type] = logon_type
  settings
end
run_level() click to toggle source
# File lib/chef/resource/windows_task.rb, line 870
def run_level
  case new_resource.run_level
  when :highest
    ::Win32::TaskScheduler::TASK_RUNLEVEL_HIGHEST
  when :limited
    ::Win32::TaskScheduler::TASK_RUNLEVEL_LUA
  end
end
run_schtasks(task_action, options = {}) click to toggle source

rubocop:disable Style/StringLiteralsInInterpolation

# File lib/chef/resource/windows_task.rb, line 936
def run_schtasks(task_action, options = {})
  cmd = "schtasks /#{task_action} /TN \"#{new_resource.task_name}\" "
  options.each_key do |option|
    unless option == "TR"
      cmd += "/#{option} "
      cmd += "\"#{options[option].to_s.gsub('"', "\\\"")}\" " unless options[option] == ""
    end
  end
  # Appending Task Run [TR] option at the end since appending causing sometimes to append other options in option["TR"] value
  if options["TR"]
    cmd += "/TR \"#{options["TR"]} \" " unless task_action == "DELETE"
  end
  logger.trace("running: ")
  logger.trace("    #{cmd}")
  shell_out!(cmd, returns: [0])
end
sec_to_dur(seconds) click to toggle source

Converts the number of seconds to an ISO8601 duration format and returns it. Ref : github.com/arnau/ISO8601/blob/master/lib/iso8601/duration.rb#L18-L23 e.g. ISO8601::Duration.new(65707200).to_s returns 'PT65707200S'

# File lib/chef/resource/windows_task.rb, line 463
def sec_to_dur(seconds)
  ISO8601::Duration.new(seconds.to_i).to_s
end
sec_to_min(seconds) click to toggle source
# File lib/chef/resource/windows_task.rb, line 467
def sec_to_min(seconds)
  seconds.to_i / 60
end
set_command_and_arguments() click to toggle source

separated command arguments from :command property

# File lib/chef/resource/windows_task.rb, line 559
def set_command_and_arguments
  cmd, *args = Chef::Util::PathHelper.split_args(new_resource.command)
  new_resource.command = cmd
  new_resource.command_arguments = args.join(" ")
end
set_months(frequency_modifier) click to toggle source

This values are set for frequency_modifier set as 1-12 This is to give backward compatibility validated this values with earlier code and running schtask.exe Used this as reference docs.microsoft.com/en-us/windows-server/administration/windows-commands/schtasks#d-dayday

# File lib/chef/resource/windows_task.rb, line 832
def set_months(frequency_modifier)
  case frequency_modifier
  when 1
    "jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec"
  when 2
    "feb, apr, jun, aug, oct, dec"
  when 3
    "mar, jun, sep, dec"
  when 4
    "apr, aug, dec"
  when 5
    "may, oct"
  when 6
    "jun, dec"
  when 7
    "jul"
  when 8
    "aug"
  when 9
    "sep"
  when 10
    "oct"
  when 11
    "nov"
  when 12
    "dec"
  end
end
set_start_day_and_time() click to toggle source
# File lib/chef/resource/windows_task.rb, line 565
def set_start_day_and_time
  new_resource.start_day = Time.now.strftime("%m/%d/%Y") unless new_resource.start_day
  new_resource.start_time = Time.now.strftime("%H:%M") unless new_resource.start_time
end
start_day_updated?(current_task_trigger, new_task_trigger) click to toggle source
# File lib/chef/resource/windows_task.rb, line 703
def start_day_updated?(current_task_trigger, new_task_trigger)
  ( new_resource.start_day && (current_task_trigger[:start_year].to_i != new_task_trigger[:start_year] ||
                               current_task_trigger[:start_month].to_i != new_task_trigger[:start_month] ||
                               current_task_trigger[:start_day].to_i != new_task_trigger[:start_day]) )
end
start_time_updated?(current_task_trigger, new_task_trigger) click to toggle source
# File lib/chef/resource/windows_task.rb, line 709
def start_time_updated?(current_task_trigger, new_task_trigger)
  ( new_resource.start_time && ( current_task_trigger[:start_hour].to_i != new_task_trigger[:start_hour] ||
                                current_task_trigger[:start_minute].to_i != new_task_trigger[:start_minute] ) )
end
task_needs_update?(task) click to toggle source

TODO : Try to optimize this method known issue : Since start_day and time is not mandatory while updating weekly frequency for which start_day is not mentioned by user idempotency is not getting maintained as new_resource.start_day is nil and we fetch the day of week from start_day to set and its currently coming as nil and don't match with current_task

# File lib/chef/resource/windows_task.rb, line 653
def task_needs_update?(task)
  flag = false
  if new_resource.frequency == :none
    flag = (task.author != new_resource.user ||
            task.application_name != new_resource.command ||
            description_needs_update?(task) ||
            task.parameters != new_resource.command_arguments.to_s ||
            task.principals[:run_level] != run_level ||
            task.settings[:disallow_start_if_on_batteries] != new_resource.disallow_start_if_on_batteries ||
            task.settings[:stop_if_going_on_batteries] != new_resource.stop_if_going_on_batteries ||
            task.settings[:start_when_available] != new_resource.start_when_available)
  else
    current_task_trigger = task.trigger(0)
    new_task_trigger = trigger
    flag = (ISO8601::Duration.new(task.idle_settings[:idle_duration])) != (ISO8601::Duration.new(new_resource.idle_time * 60)) if new_resource.frequency == :on_idle
    flag = (ISO8601::Duration.new(task.execution_time_limit)) != (ISO8601::Duration.new(new_resource.execution_time_limit * 60)) unless new_resource.execution_time_limit.nil?

    # if trigger not found updating the task to add the trigger
    if current_task_trigger.nil?
      flag = true
    else
      flag = true if start_day_updated?(current_task_trigger, new_task_trigger) == true ||
        start_time_updated?(current_task_trigger, new_task_trigger) == true ||
        current_task_trigger[:trigger_type] != new_task_trigger[:trigger_type] ||
        current_task_trigger[:type] != new_task_trigger[:type] ||
        current_task_trigger[:random_minutes_interval].to_i != new_task_trigger[:random_minutes_interval].to_i ||
        current_task_trigger[:minutes_interval].to_i != new_task_trigger[:minutes_interval].to_i ||
        task.author.to_s.casecmp(new_resource.user.to_s) != 0 ||
        task.application_name != new_resource.command ||
        description_needs_update?(task) ||
        task.parameters != new_resource.command_arguments.to_s ||
        task.working_directory != new_resource.cwd.to_s ||
        task.principals[:logon_type] != logon_type ||
        task.principals[:run_level] != run_level ||
        PRIORITY[task.priority] != new_resource.priority ||
        task.settings[:disallow_start_if_on_batteries] != new_resource.disallow_start_if_on_batteries ||
        task.settings[:stop_if_going_on_batteries] != new_resource.stop_if_going_on_batteries ||
        task.settings[:start_when_available] != new_resource.start_when_available
      if trigger_type == ::Win32::TaskScheduler::MONTHLYDATE
        flag = true if current_task_trigger[:run_on_last_day_of_month] != new_task_trigger[:run_on_last_day_of_month]
      end

      if trigger_type == ::Win32::TaskScheduler::MONTHLYDOW
        flag = true if current_task_trigger[:run_on_last_week_of_month] != new_task_trigger[:run_on_last_week_of_month]
      end
    end
  end
  flag
end
trigger() click to toggle source
# File lib/chef/resource/windows_task.rb, line 585
def trigger
  start_month, start_day, start_year = new_resource.start_day.to_s.split("/")
  start_hour, start_minute = new_resource.start_time.to_s.split(":")
  # TODO currently end_month, end_year and end_year needs to be set to 0. If not set win32-taskscheduler throwing nil into integer error.
  trigger_hash = {
    start_year: start_year.to_i,
    start_month: start_month.to_i,
    start_day: start_day.to_i,
    start_hour: start_hour.to_i,
    start_minute: start_minute.to_i,
    end_month: 0,
    end_day: 0,
    end_year: 0,
    trigger_type: trigger_type,
    type: type,
    random_minutes_interval: new_resource.random_delay,
  }

  if new_resource.frequency == :minute
    trigger_hash[:minutes_interval] = new_resource.frequency_modifier
  end

  if new_resource.frequency == :hourly
    minutes = convert_hours_in_minutes(new_resource.frequency_modifier.to_i)
    trigger_hash[:minutes_interval] = minutes
  end

  if new_resource.minutes_interval
    trigger_hash[:minutes_interval] = new_resource.minutes_interval
  end

  if new_resource.minutes_duration
    trigger_hash[:minutes_duration] = new_resource.minutes_duration
  end

  if trigger_type == ::Win32::TaskScheduler::MONTHLYDOW && frequency_modifier_contains_last_week?(new_resource.frequency_modifier)
    trigger_hash[:run_on_last_week_of_month] = true
  else
    trigger_hash[:run_on_last_week_of_month] = false
  end

  if trigger_type == ::Win32::TaskScheduler::MONTHLYDATE && day_includes_last_or_lastday?(new_resource.day)
    trigger_hash[:run_on_last_day_of_month] = true
  else
    trigger_hash[:run_on_last_day_of_month] = false
  end
  trigger_hash
end
trigger_type() click to toggle source
# File lib/chef/resource/windows_task.rb, line 714
def trigger_type
  case new_resource.frequency
  when :once, :minute, :hourly
    ::Win32::TaskScheduler::ONCE
  when :daily
    ::Win32::TaskScheduler::DAILY
  when :weekly
    ::Win32::TaskScheduler::WEEKLY
  when :monthly
    # If frequency modifier is set with frequency :monthly we are setting taskscheduler as monthlydow
    # Ref https://msdn.microsoft.com/en-us/library/windows/desktop/aa382061(v=vs.85).aspx
    new_resource.frequency_modifier.to_i.between?(1, 12) ? ::Win32::TaskScheduler::MONTHLYDATE : ::Win32::TaskScheduler::MONTHLYDOW
  when :on_idle
    ::Win32::TaskScheduler::ON_IDLE
  when :onstart
    ::Win32::TaskScheduler::AT_SYSTEMSTART
  when :on_logon
    ::Win32::TaskScheduler::AT_LOGON
  else
    raise ArgumentError, "Please set frequency"
  end
end
type() click to toggle source
# File lib/chef/resource/windows_task.rb, line 737
def type
  case trigger_type
  when ::Win32::TaskScheduler::ONCE
    { once: nil }
  when ::Win32::TaskScheduler::DAILY
    { days_interval: new_resource.frequency_modifier.to_i }
  when ::Win32::TaskScheduler::WEEKLY
    { weeks_interval: new_resource.frequency_modifier.to_i, days_of_week: days_of_week.to_i }
  when ::Win32::TaskScheduler::MONTHLYDATE
    { months: months_of_year.to_i, days: days_of_month.to_i }
  when ::Win32::TaskScheduler::MONTHLYDOW
    { months: months_of_year.to_i, days_of_week: days_of_week.to_i, weeks_of_month: weeks_of_month.to_i }
  when ::Win32::TaskScheduler::ON_IDLE
    # TODO: handle option for this trigger
  when ::Win32::TaskScheduler::AT_LOGON
    # TODO: handle option for this trigger
  when ::Win32::TaskScheduler::AT_SYSTEMSTART
    # TODO: handle option for this trigger
  end
end
update_task(task) click to toggle source
# File lib/chef/resource/windows_task.rb, line 570
def update_task(task)
  converge_by("#{new_resource} task updated") do
    do_backup
    task.set_account_information(new_resource.user, new_resource.password, new_resource.interactive_enabled)
    task.application_name = new_resource.command if new_resource.command
    task.parameters = new_resource.command_arguments if new_resource.command_arguments
    task.working_directory = new_resource.cwd if new_resource.cwd
    task.trigger = trigger unless new_resource.frequency == :none
    task.configure_settings(config_settings)
    task.creator = new_resource.user
    task.description = new_resource.description unless new_resource.description.nil?
    task.configure_principals(principal_settings)
  end
end
validate_create_day(day, frequency, frequency_modifier) click to toggle source
# File lib/chef/resource/windows_task.rb, line 407
def validate_create_day(day, frequency, frequency_modifier)
  raise ArgumentError, "day property is only valid for tasks that run monthly or weekly" unless %i{weekly monthly}.include?(frequency)

  # This has been verified with schtask.exe https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/schtasks#d-dayday--
  # verified with earlier code if day "*" is given with frequency it raised exception Invalid value for /D option
  raise ArgumentError, "day wild card (*) is only valid with frequency :weekly" if frequency == :monthly && day == "*"

  if day.is_a?(String) && day.to_i.to_s != day
    days = day.split(",")
    if days_includes_days_of_months?(days)
      # Following error will be raise if day is set as 1-31 and frequency is selected as :weekly since those values are valid with only frequency :monthly
      raise ArgumentError, "day values 1-31 or last is only valid with frequency :monthly" if frequency == :weekly
    else
      days.map! { |day| day.to_s.strip.downcase }
      unless (days - VALID_WEEK_DAYS).empty?
        raise ArgumentError, "day property invalid. Only valid values are: #{VALID_WEEK_DAYS.map(&:upcase).join(", ")}. Multiple values must be separated by a comma."
      end
    end
  end
end
validate_create_frequency_modifier(frequency, frequency_modifier) click to toggle source
# File lib/chef/resource/windows_task.rb, line 375
def validate_create_frequency_modifier(frequency, frequency_modifier)
  if (%i{on_logon onstart on_idle none}.include?(frequency)) && ( frequency_modifier != 1)
    raise ArgumentError, "frequency_modifier property not supported with frequency :#{frequency}"
  end

  if frequency == :monthly
    unless (1..12).cover?(frequency_modifier.to_i) || frequency_modifier_includes_days_of_weeks?(frequency_modifier)
      raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :monthly frequency are 1 - 12, 'FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST'."
    end
  else
    unless frequency.nil? || frequency_modifier.nil?
      frequency_modifier = frequency_modifier.to_i
      min = 1
      max = case frequency
            when :minute
              1439
            when :hourly
              23
            when :daily
              365
            when :weekly
              52
            else
              min
            end
      unless frequency_modifier.between?(min, max)
        raise ArgumentError, "frequency_modifier value #{frequency_modifier} is invalid. Valid values for :#{frequency} frequency are #{min} - #{max}."
      end
    end
  end
end
validate_create_months(months, frequency) click to toggle source
# File lib/chef/resource/windows_task.rb, line 428
def validate_create_months(months, frequency)
  raise ArgumentError, "months property is only valid for tasks that run monthly" if frequency != :monthly

  if months.is_a?(String)
    months = months.split(",")
    months.map! { |month| month.strip.upcase }
    unless (months - VALID_MONTHS).empty?
      raise ArgumentError, "months property invalid. Only valid values are: #{VALID_MONTHS.join(", ")}. Multiple values must be separated by a comma."
    end
  end
end
validate_frequency(frequency) click to toggle source
# File lib/chef/resource/windows_task.rb, line 294
def validate_frequency(frequency)
  if frequency.nil? || !(%i{minute hourly daily weekly monthly once on_logon onstart on_idle none}.include?(frequency))
    raise ArgumentError, "Frequency needs to be provided. Valid frequencies are :minute, :hourly, :daily, :weekly, :monthly, :once, :on_logon, :onstart, :on_idle, :none."
  end
end
validate_frequency_monthly(frequency_modifier, months, day) click to toggle source
# File lib/chef/resource/windows_task.rb, line 300
def validate_frequency_monthly(frequency_modifier, months, day)
  # validates the frequency :monthly and raises error if frequency_modifier is first, second, third etc and day is not provided
  if (frequency_modifier != 1) && (frequency_modifier_includes_days_of_weeks?(frequency_modifier)) && !(day)
    raise ArgumentError, "Please select day on which you want to run the task e.g. 'Mon, Tue'. Multiple values must be separated by comma."
  end

  # frequency_modifier 2-12 is used to set every (n) months, so using :months property with frequency_modifier is not valid since they both used to set months.
  # Not checking value 1 here for frequency_modifier since we are setting that as default value it won't break anything since preference is given to months property
  if (frequency_modifier.to_i.between?(2, 12)) && !(months.nil?)
    raise ArgumentError, "For frequency :monthly either use property months or frequency_modifier to set months."
  end
end
validate_idle_time(idle_time, frequency) click to toggle source
# File lib/chef/resource/windows_task.rb, line 446
def validate_idle_time(idle_time, frequency)
  if !idle_time.nil? && frequency != :on_idle
    raise ArgumentError, "idle_time property is only valid for tasks that run on_idle"
  end
  if idle_time.nil? && frequency == :on_idle
    raise ArgumentError, "idle_time value should be set for :on_idle frequency."
  end
  unless idle_time.nil? || idle_time > 0 && idle_time <= 999
    raise ArgumentError, "idle_time value #{idle_time} is invalid. Valid values for :on_idle frequency are 1 - 999."
  end
end
validate_random_delay(random_delay, frequency) click to toggle source
# File lib/chef/resource/windows_task.rb, line 320
def validate_random_delay(random_delay, frequency)
  if %i{on_logon onstart on_idle none}.include? frequency
    raise ArgumentError, "`random_delay` property is supported only for frequency :once, :minute, :hourly, :daily, :weekly and :monthly"
  end

  raise ArgumentError, "Invalid value passed for `random_delay`. Please pass seconds as an Integer (e.g. 60) or a String with numeric values only (e.g. '60')." unless numeric_value_in_string?(random_delay)
end
validate_start_day(start_day, frequency) click to toggle source

@todo when we drop ruby 2.3 support this should be converted to .match?() instead of =~f

# File lib/chef/resource/windows_task.rb, line 329
def validate_start_day(start_day, frequency)
  if start_day && frequency == :none
    raise ArgumentError, "`start_day` property is not supported with frequency: #{frequency}"
  end

  # make sure the start_day is in MM/DD/YYYY format: http://rubular.com/r/cgjHemtWl5
  if start_day
    raise ArgumentError, "`start_day` property must be in the MM/DD/YYYY format." unless %r{^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\d\d$}.match?(start_day)
  end
end
validate_start_time(start_time, frequency) click to toggle source

@todo when we drop ruby 2.3 support this should be converted to .match?() instead of =~

# File lib/chef/resource/windows_task.rb, line 341
def validate_start_time(start_time, frequency)
  if start_time
    raise ArgumentError, "`start_time` property is not supported with `frequency :none`" if frequency == :none
    raise ArgumentError, "`start_time` property must be in the HH:mm format (e.g. 6:20pm -> 18:20)." unless /^[0-2][0-9]:[0-5][0-9]$/.match?(start_time)
  else
    raise ArgumentError, "`start_time` needs to be provided with `frequency :once`" if frequency == :once
  end
end
validate_user_and_password(user, password) click to toggle source

System users will not require a password Other users will require a password if the task is non-interactive.

@param [String] user @param [String] password

# File lib/chef/resource/windows_task.rb, line 356
def validate_user_and_password(user, password)
  if non_system_user?(user)
    if password.nil? && !interactive_enabled
      raise ArgumentError, "Please provide a password or check if this task needs to be interactive! Valid passwordless users are: '#{Chef::ReservedNames::Win32::Security::SID::SYSTEM_USER.join("', '")}'"
    end
  else
    unless password.nil?
      raise ArgumentError, "Password is not required for system users."
    end
  end
end
weeks_of_month() click to toggle source

Deleting last from the array of weeks of month since last week is handled in :run_on_last_week_of_month parameter.

# File lib/chef/resource/windows_task.rb, line 759
def weeks_of_month
  weeks_of_month = []
  if new_resource.frequency_modifier
    weeks = new_resource.frequency_modifier.split(",")
    weeks.map! { |week| week.to_s.strip.upcase }
    weeks.delete("LAST") if weeks.include?("LAST")
    weeks_of_month = get_binary_values_from_constants(weeks, WEEKS_OF_MONTH)
  end
  weeks_of_month
end