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.21k stars 191 forks source link

FindTask returns null when connected as specific user but not another #866

Closed Rolf-Herbert closed 3 years ago

Rolf-Herbert commented 3 years ago

I use tasksrvc.FindTask(taskName) to attempt to find a task and then run it

FindTask always returns null

I have enumerated through the task list and the task appears there (I have created an empty task called 'test'), but I cant find it. I have tried with and without the path/folder info (this task is in the root folder).

When enumerating I can test the task.Name property and extract the correct task using the same string as when I am searching.

Thanks

dahall commented 3 years ago

Will you share your code? I have used this function many times without problems and just confirmed its unit tests are still working. For some examples, see TestTaskService project.

dahall commented 3 years ago

@TeamKinetic Please provide the code or close this issue if you have it resolved.

Rolf-Herbert commented 3 years ago

Sorry haven't been back to this...will get teh code sample up tomorrow

Rolf-Herbert commented 3 years ago

sorry for the delay here is the code...I iterating through all the tasks as a sanity check...once I find a task called 'test' I then try to create a new task using FindTask using the name that has been matched.

Thanks for the help

    using (TaskService tasksrvc = new TaskService(servername, username, domain, password, true))
    {
      void EnumAllTasks()
        {
            EnumFolderTasks(TaskService.Instance.RootFolder);
        }

        void EnumFolderTasks(TaskFolder fld)
        {
            foreach (Task task in fld.Tasks)
            {
                if (task.Name == "test")
                {
                    Task mytask = task;

        //this outputs the folder name and the task.Name successfully
                    Response.Write(task.Folder + " - " + task.Name + "<br>");

        //this raises no error or exception
        Task foundTask = tasksrvc.FindTask(task.Name);

        //this gives Object reference not set to an instance of an object 
        Response.Write (foundTask.Name);
                }

            }

            foreach (TaskFolder sfld in fld.SubFolders)
                EnumFolderTasks(sfld);
        }

        EnumAllTasks();

    }`
dahall commented 3 years ago

In your call to EnumFolderTasks, you use one instance of TaskService and then another within that method to call FindTask. Either use tasksrvc or TaskService.Instance, but not both. I'd write your code as follows, assuming you are connecting to either a non-local instance or from a different account:

// Recursively enumerate all tasks in root folder of connected system's tasks where the name equals "test".
using var tasksrvc = new TaskService(servername, username, domain, password, false);
foreach (var task in tasksrvc.RootFolder.EnumerateTasks(t => t.Name == "test", true))
{
   // Write out full path and name of this task
   Response.Write(task.Path + "<br>");
   // See if this same task is found using FindTask
   var foundTask = tasksrvc.FindTask(task.Name);
   // Write out name if found or indicate the result was null
   Response.Write(foundTask?.Name ?? "(not found)");
}
dahall commented 3 years ago

TaskService.Instance is the same as new TaskService(null, null, null, null, false) -- it is the local instance using the current user's permissions/credentials.

Rolf-Herbert commented 3 years ago

Hi there,

I wasn't interested in iterating through the tasks really, it was just to check I wasn't going mad and the task actually existed. So to keep it simple

So I know the task 'test' exists and I know its in the root directory "\" so if I use;

    using (TaskService tasksrvc = new TaskService(servername, username, domain, password, true))
        {
            Task foundTask = tasksrvc.FindTask("test");
            Response.Write (foundTask.Name);
        }

It should work but it doesnt object reference not set to an instance of an object

dahall commented 3 years ago

I'm curious, does iterating through find it?

bool found = tasksrvc.RootFolder.EnumerateTasks(t => t.Name == "test", true).Any();

If not, then it is likely a permission problem, i.e. whatever credentials you've used when constructing TaskService do not have the right to see that task.

Rolf-Herbert commented 3 years ago
bool found = TaskService.Instance.RootFolder.EnumerateTasks(t => t.Name == "test", true).Any(); = True
bool found = tasksrvc.RootFolder.EnumerateTasks(t => t.Name == "test", true).Any(); = False

ok so it looks like a permissions issues but the user I am logging in with as a test is a member of administrators (so that I could eliminate permissions issues!)

Thanks

PS I also altered the password to check and got a password error, so I know the username and password is good

dahall commented 3 years ago

Visibility depends on more than group. There are task specific permissions (just like with files) and I have seen task ownership, especially if the owner is also an admin, cause a task to not be visible for other users. This issue is not directly related to this library, it is permissions and the Windows Task Scheduler itself causing your problem.

zibakwa commented 3 years ago

@TeamKinetic

Your code is good as is and you just need to enable the Remote Scheduled Tasks Management firewall exception on the remote computer. To allow this exception click Start , Control Panel , Security , Allow a program through Windows Firewall , and then select the Remote Scheduled Tasks Management check box. Then click the Ok button in the Windows Firewall Settings dialog box.

You may also need to change the boolean value in your TaskService instance from true to false so that you don't force the remote server to use version 1.0

Below is Sample method reading remote server Scheduled Tasks names, author and status---

public static void GetTaskStatus(string servername, string username, string domain, string password)
{
    string TaskNamex = "";
    string Author = "";
    string Status = "";

    using (TaskService tasksrvc = new TaskService(servername, username, domain, password, false))
    {
        // Output all the tasks in the root folder with their properties
        //TaskFolder tf = TaskService.Instance.RootFolder;
        TaskFolder tf = tasksrvc.RootFolder;

        foreach (Task t in tf.Tasks)
        {
            try
            {
                TaskNamex = t.Name;
                Author = t.Definition.RegistrationInfo.Author;
                Status = t.State.ToString();

            }
            catch
            {

            }
        }

    }
}
dahall commented 3 years ago

Thanks for the update!