Search code examples
c#.netwindowstaskscheduler

How to set “run only if logged in” and “run as” with TaskScheduler in C#?


I am trying to use the c# Task Scheduler Managed Wrapper to programmatically generate scheduled tasks on a windows system. I can generate tasks, but i cannot get it to run only when the account is logged on:

enter image description here

I have been looking around and I found another SO question that was asked last year, but either there are other relevant settings that aren't mentioned, or something in the code base has changed since then:

How to set "run only if logged in" and "run as" with TaskScheduler in C#?

I think this approach is probably correct, but when I try it I get a confusing error message:

Task Scheduler 2.0 (1.2) does not support setting this property. You must use an InteractiveToken in order to have the task run in the current user session.

The code I am using is as follows:

    public static void ScheduleTask(string machineName, string taskName, string taskAccount, string password)
    {
        using (TaskService ts = new TaskService(machineName))
        {
            TaskDefinition td = ts.NewTask();

            td.Principal.RunLevel = TaskRunLevel.Highest;
            td.Principal.UserId = WindowsIdentity.GetCurrent().Name;
            td.Principal.LogonType = TaskLogonType.InteractiveToken;

            td.Settings.MultipleInstances = TaskInstancesPolicy.IgnoreNew;
            td.Settings.DisallowStartIfOnBatteries = false;
            td.Settings.StopIfGoingOnBatteries = false;
            td.Settings.StartWhenAvailable = true;
            //td.Settings.RunOnlyIfLoggedOn = true;
            td.Settings.Enabled = true;
            td.Settings.Hidden = false;
            td.Settings.AllowHardTerminate = true;
            td.Settings.ExecutionTimeLimit = new TimeSpan();

            var tt = new SessionStateChangeTrigger();
            tt.StartBoundary = DateTime.Now.AddMinutes(1);
            tt.UserId = taskAccount;
            tt.StateChange = TaskSessionStateChangeType.RemoteConnect;
            tt.Repetition.Interval = TimeSpan.FromMinutes(1);
            tt.Repetition.StopAtDurationEnd = false;
            td.Triggers.Add(tt);

            td.Actions.Add("notepad.exe", "c:\\test.log");

            ts.RootFolder.RegisterTaskDefinition(taskName, td, TaskCreation.CreateOrUpdate, taskAccount, password, TaskLogonType.Password, null);
        }
    }

If I run this code with a valid server,user, etc. it generates a task w/o a problem. If I comment in the 'RunOnlyIfLoggedOn' parameter, it generates the error I previously mentioned. Note that I am setting the LogonType property to TaskLogonType.InteractiveToken, so there must be something else that I am missing.


Solution

  • Ok there is the solution:

    The register task definition call needs to have its TaskLogonType set to Interactive Token. Just setting the TaskDefinition Principal Logon type to use an interactive Token will not work.

    RunOnlyIfLoggedOn appears to only work for earlier versions of the task scheduler (v1, on systems like w2k3, etc)