capnspacehook / taskmaster

Windows Task Scheduler Library for Go
MIT License
142 stars 29 forks source link

Problem setting RepetitionInterval #15

Open wh1te909 opened 3 years ago

wh1te909 commented 3 years ago

Hi, I'm trying to create a scheduled task that runs daily and repeats every hour indefinitely, the below code works only when I comment out the line RepetitionInterval: period.NewHMS(1, 0, 0), otherwise it throws this error: error creating registered task \TacticalRMM_fixmesh: error registering task: The task XML contains a value which is incorrectly formatted or out of range.

Am I doing something wrong or this is bug?

Thanks!

func CreateSchedTask() bool {
    conn, err := taskmaster.Connect()
    if err != nil {
        panic(err)
    }
    defer conn.Disconnect()

    def := conn.NewTaskDefinition()

    dailyTrigger := taskmaster.DailyTrigger{
        TaskTrigger: taskmaster.TaskTrigger{
            Enabled:       true,
            StartBoundary: time.Now().Add(5 * time.Minute),
            RepetitionPattern: taskmaster.RepetitionPattern{
                RepetitionDuration: period.NewYMD(100, 0, 0),
                RepetitionInterval: period.NewHMS(1, 0, 0), // this is the problem line
                StopAtDurationEnd:  false,
            },
        },
        DayInterval: taskmaster.EveryDay,
    }

    def.AddTrigger(dailyTrigger)

    action := taskmaster.ExecAction{
        Path:       "tacticalrmm.exe",
        WorkingDir: `C:\Program Files\TacticalAgent`,
        Args:       "-m fixmesh",
    }
    def.AddAction(action)

    def.Principal.RunLevel = taskmaster.TASK_RUNLEVEL_HIGHEST
    def.Principal.LogonType = taskmaster.TASK_LOGON_SERVICE_ACCOUNT
    def.Principal.UserID = "SYSTEM"
    def.Settings.AllowDemandStart = true
    def.Settings.AllowHardTerminate = true
    def.Settings.DontStartOnBatteries = false
    def.Settings.Enabled = true
    def.Settings.MultipleInstances = taskmaster.TASK_INSTANCES_IGNORE_NEW
    def.Settings.StopIfGoingOnBatteries = false
    def.Settings.WakeToRun = true

    _, success, err := conn.CreateTask("\\TacticalRMM_fixmesh", def, true)
    if err != nil {
        panic(err)
    }
    return success
}
capnspacehook commented 3 years ago

I imagine what is happening is that the RepititionDuration of period.NewYMD(100, 0, 0) is causing the errors, but I'm not sure. It would be better not to specify a RepitionDuration at all, as the docs state that 'if no value is specified for the duration, then the pattern is repeated indefinitely'.

I don't understand how your code works when you omit the RepititionInterval, as the docs state that if you specify a duration, you must also specify an interval. But as I said before, the inverse is not true.

I just created a scheduled task with Taskmaster last week that had a RepititionInterval similar to yours, so I'm honestly not sure what the issue is. This shouldn't matter, but since you are registering a task that is running as SYSTEM, you should need to run this code from an elevated prompt, see if that helps.

wh1te909 commented 3 years ago

Thanks for your swift reply!

Yea I tried actually without the RepetitionDuration but same issue. Am running it from elevated cmd as well, no luck. I've stripped down the code to just use defaults in the function below but still getting same error. Tried on multiple computers as well different OS (win 10, server 2019, server 2016) always the same error about invalid XML. Also tried creating the task without setting any RepetitionPattern which works, and then after created calling another function to just update it with UpdateTask() but same xml error. Can you send me the code for task you created with an interval so I can try that maybe?

func CreateSchedTask() bool {
    conn, err := taskmaster.Connect()
    if err != nil {
        panic(err)
    }
    defer conn.Disconnect()

    def := conn.NewTaskDefinition()

    dailyTrigger := taskmaster.DailyTrigger{
        TaskTrigger: taskmaster.TaskTrigger{
            Enabled:       true,
            StartBoundary: time.Now().Add(30 * time.Minute),
            RepetitionPattern: taskmaster.RepetitionPattern{
                RepetitionInterval: period.NewHMS(1, 0, 0),
            },
        },
        DayInterval: taskmaster.EveryDay,
    }

    def.AddTrigger(dailyTrigger)

    action := taskmaster.ExecAction{
        Path: `C:\Windows\System32\notepad.exe`,
    }
    def.AddAction(action)

    _, success, err := conn.CreateTask("\\Testingtask", def, true)
    if err != nil {
        panic(err)
    }
    return success
}
joshuasprow commented 3 years ago

I started looking at using taskmaster for a project and am hitting the same error. I tried a few different configurations and it seems like there's an issue with how the period.Period is getting parsed. However, I also saw the error when I tried to use taskmaster.TASK_LOGON_SERVICE_ACCOUNT as the LogonType.

The tricky part is that the majority of the work is happening in the go-ole package, making clues hard to find. Drilling down into the method calls, the error is first returned here. Here's a "stack trace" following that error from my code to the source:

I'm not sure where to start as far as debugging the problem since the error originates so far away from the caller. I was eventually able to get a working configuration, but let me know if there's anything I can help with.

service, err := taskmaster.Connect()
if err != nil {
    log.Fatal(err)
}
defer service.Disconnect()

exe, err := filepath.Abs("./dummy.exe")
if err != nil {
    log.Fatal(err)
}

def := service.NewTaskDefinition()

def.AddAction(taskmaster.ExecAction{Path: exe})

trigger := taskmaster.DailyTrigger{}

trigger.StartBoundary = time.Now()
trigger.DayInterval = taskmaster.EveryDay
trigger.Enabled = true

def.AddTrigger(trigger)

def.Principal.LogonType = taskmaster.TASK_LOGON_SERVICE_ACCOUNT // XML error
def.Principal.RunLevel = taskmaster.TASK_RUNLEVEL_HIGHEST

def.Settings.Enabled = true
def.Settings.RestartInterval = period.NewHMS(0, 20, 0) // XML error
def.Settings.MultipleInstances = taskmaster.TASK_INSTANCES_STOP_EXISTING
def.Settings.WakeToRun = true

path := "\\Test\\Dummy"

task, success, err := service.CreateTask(path, def, true)
if err != nil {
    log.Fatal(err)
}
if !success {
    log.Fatal("task not registered successfully")
}

fmt.Printf("created %q\n", task.Name)

err = service.DeleteTask(path)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("deleted %q\n", task.Name)
SkewwG commented 3 years ago

Hi, I'm trying to create a scheduled task that runs daily and repeats every hour indefinitely, the below code works only when I comment out the line RepetitionInterval: period.NewHMS(1, 0, 0), otherwise it throws this error: error creating registered task \TacticalRMM_fixmesh: error registering task: The task XML contains a value which is incorrectly formatted or out of range.

Am I doing something wrong or this is bug?

Thanks!

func CreateSchedTask() bool {
  conn, err := taskmaster.Connect()
  if err != nil {
      panic(err)
  }
  defer conn.Disconnect()

  def := conn.NewTaskDefinition()

  dailyTrigger := taskmaster.DailyTrigger{
      TaskTrigger: taskmaster.TaskTrigger{
          Enabled:       true,
          StartBoundary: time.Now().Add(5 * time.Minute),
          RepetitionPattern: taskmaster.RepetitionPattern{
              RepetitionDuration: period.NewYMD(100, 0, 0),
              RepetitionInterval: period.NewHMS(1, 0, 0), // this is the problem line
              StopAtDurationEnd:  false,
          },
      },
      DayInterval: taskmaster.EveryDay,
  }

  def.AddTrigger(dailyTrigger)

  action := taskmaster.ExecAction{
      Path:       "tacticalrmm.exe",
      WorkingDir: `C:\Program Files\TacticalAgent`,
      Args:       "-m fixmesh",
  }
  def.AddAction(action)

  def.Principal.RunLevel = taskmaster.TASK_RUNLEVEL_HIGHEST
  def.Principal.LogonType = taskmaster.TASK_LOGON_SERVICE_ACCOUNT
  def.Principal.UserID = "SYSTEM"
  def.Settings.AllowDemandStart = true
  def.Settings.AllowHardTerminate = true
  def.Settings.DontStartOnBatteries = false
  def.Settings.Enabled = true
  def.Settings.MultipleInstances = taskmaster.TASK_INSTANCES_IGNORE_NEW
  def.Settings.StopIfGoingOnBatteries = false
  def.Settings.WakeToRun = true

  _, success, err := conn.CreateTask("\\TacticalRMM_fixmesh", def, true)
  if err != nil {
      panic(err)
  }
  return success
}

使用 RepetitionDuration: period.New(0,0,100,0,0,0), 可以解决你的问题。

你的错误我猜测是因为你用了RepetitionDuration: period.NewHMS(1000, 40, 0),,因为windows的计划任务里会转换为分钟,而你设置的值过大,会导致值超出范围。可以看我下面的截图。

image

image

而使用了 period.New 则不会,当你设置持续时间100天,在windows计划任务里显示的是100天,而不是转换为分钟,那么值就不会超出范围,继续看图

image

image

所以你可以使用period.New解决你的问题。

maja42 commented 3 years ago

I have the same issue. It's supported by windows, but taskmaster generates an invalid XML. Right now, I'm setting the duration to 365 days as a workaround.

jasonm128 commented 2 years ago

I think this is a bug that was introduced by https://github.com/capnspacehook/taskmaster/commit/b5a801333f75908bc3f079563804ada1f6e3839e on line 161. When the call to PeriodToString was removed, it became impossible to create a task that will repeat indefinitely. If you don't specify a RepetitionDuration (because you want to to run indefinitely) you get the zero value which becomes P0D. This is apparently an illegal value for this field. The correct fix is to put the call to PeriodToString back. A workaround is that you must specify a RepetitionDuration in every RepetitionPattern. The largest value I've found that's legal is period.NewYMD(0, 0, 3256) which is about 10 years.