dahall / TaskScheduler

Provides a .NET wrapper for the Windows Task Scheduler. It aggregates the multiple versions, provides an editor and allows for localization.
MIT License
1.22k stars 193 forks source link

Is there a way to find the logged in user's "domain\name" when creating a task in code running as SYSTEM? #722

Closed dahall closed 6 years ago

dahall commented 6 years ago

I have scoured the internet and there are suggestions that work for certain scenarios, but none work for me. I'm creating a task in a custom action inside the installer. The installer runs as SYSTEM, so instead of my domain\username I get SYSTEM. And, I'm installing a service, which also runs as SYSTEM. Is there a way of getting the actual current user's name, short of asking the user to enter manually? Here's my code:

//Works, I get "Bob-PC\Bob" if I run the code as a user. If it's run as a system
// I get "WORKGROUP\SYSTEM"
string user = Environment.UserDomainName + "\\"+ Environment.UserName;
// doesn't work, returns "NT AUTHORITY\SYSTEM"
string user2 = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
// doesn't work at all, this is not ASP.NET 
string user3 = "";//Request.LogonUserIdentity.Name;
// doesn't work, my thread is unnamed
string user4 = System.Threading.Thread.CurrentPrincipal.Identity.Name;

MessageBox.Show("user " + user + "\nuser2 " + user2 + "\nuser3 " + user3 + "\nuser4 " + user4);
tf.RegisterTaskDefinition("MyTask", td,
    TaskCreation.CreateOrUpdate,
    user,
    null,
    TaskLogonType.InteractiveToken,
    null);

Originally posted: 2016-08-27T14:11:14

dahall commented 6 years ago

Thanks I have found the answer on this board!
Just use:

  ts.RootFolder.RegisterTaskDefinition("MyTask", td,
                    TaskCreation.CreateOrUpdate, "SYSTEM", null,
                    TaskLogonType.ServiceAccount);

or rather, in my case:

 tf.RegisterTaskDefinition("MyTask", td,
                    TaskCreation.CreateOrUpdate, "SYSTEM", null,
                    TaskLogonType.ServiceAccount);

Originally posted: 2016-08-27T15:08:13

dahall commented 6 years ago

That did create the task but then ran the process launched by the task as SYSTEM, not user. So I was back to square 1! Here's the way to get the username during install as a SYSTEM:

ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem");
ManagementObjectCollection collection = searcher.Get();
string username = (string)collection.Cast<ManagementBaseObject>().First()["UserName"];
 MessageBox.Show(username);

Not sure what happens when you have multiple users on the machine..

Originally posted: 2016-08-27T18:17:07

dahall commented 6 years ago

Here's what works for one user and many users (hopefully for the latter) :D

       private static void CreateSheduledTask1(string targetPathDir)
        {
            try
            {
                // Get the service on the local machine
                using (TaskService ts = new TaskService())
                {
                    string folder = "Luna Sleep Tasks";
                    if (!ts.RootFolder.SubFolders.Exists("\\" + folder))
                    {
                        ts.RootFolder.CreateFolder(folder);
                    }
                    TaskFolder tf = ts.GetFolder(folder);
                    // Create a new task definition and assign properties
                    TaskDefinition td = ts.NewTask();
                    td.Settings.AllowDemandStart = true;
                    td.Settings.Compatibility = TaskCompatibility.V2;
                    td.Settings.Enabled = true;
                    td.Settings.RunOnlyIfIdle = false;
                    td.Settings.IdleSettings.StopOnIdleEnd = true;
                    td.Settings.IdleSettings.RestartOnIdle = false;
                    td.Settings.DisallowStartIfOnBatteries = false;
                    td.Settings.DisallowStartOnRemoteAppSession = false;
                    td.Settings.UseUnifiedSchedulingEngine = true;
                    td.Settings.WakeToRun = false;
                    td.Settings.MultipleInstances = TaskInstancesPolicy.IgnoreNew;
                    td.Settings.RunOnlyIfNetworkAvailable = false;
                    td.Settings.ExecutionTimeLimit = new TimeSpan(72, 0, 0);
                    td.Settings.Priority = ProcessPriorityClass.Normal;

                    td.RegistrationInfo.Description = "Created by Luna Sleep Service installer.";

                    DailyTrigger dt = new DailyTrigger();
                    dt.Enabled = false;
                    dt.StartBoundary = System.DateTime.Now;
                    td.Triggers.Add(dt);

                    td.Principal.RunLevel = TaskRunLevel.Highest;

                    td.Actions.Add(new ExecAction(targetPathDir + "\\LunaSleep.exe", null, null));

                    ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem");
                    ManagementObjectCollection collection = searcher.Get();
                    string username = (string)collection.Cast<ManagementBaseObject>().First()["UserName"];

                    MessageBox.Show("moc user:" + username);

                    tf.RegisterTaskDefinition("Luna Sleep Task", td,
                        TaskCreation.CreateOrUpdate,
                        username,
                        null,
                        TaskLogonType.InteractiveToken,
                        null);

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private static void CreateSheduledTaskManyUsers(string targetPathDir)
        {
            try
            {
                // Get the service on the local machine
                using (TaskService ts = new TaskService())
                {
                    string folder = "Luna Sleep Tasks";
                    if (!ts.RootFolder.SubFolders.Exists("\\" + folder))
                    {
                        ts.RootFolder.CreateFolder(folder);
                    }
                    TaskFolder tf = ts.GetFolder(folder);
                    // Create a new task definition and assign properties
                    TaskDefinition td = ts.NewTask();
                    td.Settings.AllowDemandStart = true;
                    td.Settings.Compatibility = TaskCompatibility.V2;
                    td.Settings.Enabled = true;
                    td.Settings.RunOnlyIfIdle = false;
                    td.Settings.IdleSettings.StopOnIdleEnd = true;
                    td.Settings.IdleSettings.RestartOnIdle = false;
                    td.Settings.DisallowStartIfOnBatteries = false;
                    td.Settings.DisallowStartOnRemoteAppSession = false;
                    td.Settings.UseUnifiedSchedulingEngine = true;
                    td.Settings.WakeToRun = false;
                    td.Settings.MultipleInstances = TaskInstancesPolicy.IgnoreNew;
                    td.Settings.RunOnlyIfNetworkAvailable = false;
                    td.Settings.ExecutionTimeLimit = new TimeSpan(72, 0, 0);
                    td.Settings.Priority = ProcessPriorityClass.Normal;

                    td.RegistrationInfo.Description = "Created by Luna Sleep Service installer.";

                    DailyTrigger dt = new DailyTrigger();
                    dt.Enabled = false;
                    dt.StartBoundary = System.DateTime.Now;
                    td.Triggers.Add(dt);

                    td.Principal.RunLevel = TaskRunLevel.Highest;

                    td.Actions.Add(new ExecAction(targetPathDir + "\\LunaSleep.exe", null, null));

                    ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT UserName FROM Win32_ComputerSystem");
                    ManagementObjectCollection collection = searcher.Get();

                    foreach(ManagementObject o in collection)
                    {

                        try
                        {
                            username = (string)o["UserName"];

                            MessageBox.Show("moc user:" + username);

                            tf.RegisterTaskDefinition("Luna Sleep Task", td,
                                TaskCreation.CreateOrUpdate,
                                username,
                                null,
                                TaskLogonType.InteractiveToken,
                                null);
                        }
                        catch
                        {
                            MessageBox.Show(username + " didn't work");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
        static string username;

Originally posted: 2016-08-27T18:41:00

dahall commented 6 years ago

Glad you figured it out. Just some thoughts on code optimizations:

// If just creating a default TaskService (new TaskService()), use TaskService.Instance instead. // You can then avoid the "using" clause. TaskService ts = TaskService.Instance;

// Use this statement to get a folder that may have not been created.
TaskFolder tf = ts.RootFolder.GetFolder(folderName) ?? ts.RootFolder.CreateFolder(folderName);

// All triggers set StartBoundary to DateTime.Now in the constructor so you could write:
td.Triggers.Add(new DailyTrigger { Enabled = false });

// You don't need to explicitly add ExecAction. Instead you can write:
td.Actions.Add(targetPathDir + "\\LunaSleep.exe");

Originally posted: 2016-08-30T15:43:30

dahall commented 6 years ago

Thank you! And I want to thank you for creating this C# COM wrapper! Great Job!!!!

Originally posted: 2016-08-30T23:42:32