0
votes

I am creating an application that creates a scheduled task for every user on first logon. I am using NuGet package Task Scheduler Managed Wrapper 2.5.21. When the exe run on logon, the Access Denied error occurs. When manually run the exe as Administrator, the Scheduled Task is created. How can I overcome this issue?

string installPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);

using (TaskService ts = new TaskService())
{
    TaskDefinition td = ts.NewTask();

    td.Actions.Add(new ExecAction("MyExe.exe", null, installPath));
    td.Triggers.Add(new SessionStateChangeTrigger
    {
        StateChange = TaskSessionStateChangeType.SessionUnlock,
        UserId = Environment.UserName
    });

    td.Principal.RunLevel = TaskRunLevel.Highest;
    td.Principal.LogonType = TaskLogonType.InteractiveToken;
    ts.RootFolder.RegisterTaskDefinition("task_" + Environment.UserName, td);
}
1
Im guessing your user account isnt an admin or power user or has UAC on max?BugFinder
even a user has admin privilege, the error occurs. Stack traceNelson T Joseph
Explicitly documented here, second Note. So either the program must run with UAC elevation (can't happen at login) or an admin need to change the ACL of c:\windows\tasksHans Passant
There is no need in admin privileges to create a task for yourself, for interactive token. I also experiencing similar issue... Just can't create task using TaskService in unprivileged account...Dmitry Gusarov

1 Answers

3
votes

For non-administrative or non-elevated user every trigger type have a set of restrictions. E.g. you can not add OnLogon trigger for somebody else, only for yourself. Looks like you also cannot add a SessionStateChangeTrigger at all.

This is working example based on author's answer to my issue: https://github.com/dahall/TaskScheduler/issues/58

var td = ts.NewTask();
td.Actions.Add("notepad", null, null);
td.Triggers.Add(new LogonTrigger { UserId = WindowsIdentity.GetCurrent().Name });
ts.RootFolder.RegisterTaskDefinition("Test", td);

Note: if you are creating task with TaskRunLevel.Highest for administrator under UAC this is only possible after elevation (otherwise that would be a huge vulnerability that makes UAC useless)

Note: if you are creating task for each user that launches application - you have to include User SID in a task name. This is guaranteed to be unique even if users will be renamed. Otherwise there would be access denied because same task already created by other user (and he have more rights on it than you). Consider DropBox, OneDrive, GoogleDrive - thery are all adding SID to the task name.

This is how I did it in the end (including different task name for Highest version and normal one:

private static void CreateTask(string path, string taskFolder, bool highest)
{
    var sid = WindowsIdentity.GetCurrent().User.Value;
    var userId = WindowsIdentity.GetCurrent().Name;
    using (var ts = new TaskService())
    {
        var td = ts.NewTask();
        if (highest)
        {
            td.Principal.RunLevel = TaskRunLevel.Highest;
        }
        td.Actions.Add(path, "/a", null);
        td.Triggers.Add(new LogonTrigger { UserId = userId, });
        ts.RootFolder.RegisterTaskDefinition(taskFolder + "MyApp Task-" + sid + (highest ? "h" : ""), td);
    }
}