public bool ParseAutomationTasks()
        {
            Logging.Info(Logfiles.AutomationRunner, LogOptions.MethodName, "Getting list and parsing of automation tasks");
            Logging.Debug("Getting xml node results of TaskDefinitions");
            XPathNavigator result = XmlUtils.GetXNodeFromXpath(TasksDocument, AutomationSequenceTaskDefinitionsXpath);

            if (result == null)
            {
                Logging.Error("The xml document was valid xml and loaded, but has incorrect task definition formatting for the application (missing the TaskDefinitions root?)");
                return(false);
            }

            XElement automationTaskHolder = XElement.Parse(result.OuterXml);

            Logging.Debug("Getting property of automationTasks and setting list entries");
            AutomationTasks.Clear();
            PropertyInfo listPropertyInfo = this.GetType().GetProperty(nameof(AutomationTasks));

            try
            {
                bool setListEntriesResult = CommonUtils.SetListEntries(this, listPropertyInfo, automationTaskHolder.Elements(), AutomationTask.AttributeNameForMapping, AutomationTask.TaskTypeMapper);
                if (!setListEntriesResult)
                {
                    return(false);
                }
            }
            catch (Exception ex)
            {
                Logging.AutomationRunner(ex.ToString(), LogLevel.Exception);
                return(false);
            }

            Logging.Debug(Logfiles.AutomationRunner, LogOptions.MethodName, "Configuration of any additional properties for each task");
            foreach (AutomationTask task in AutomationTasks)
            {
                task.AutomationSequence = this;
                task.PreProcessingHook();
                Logging.Info("Processed task {0}", task.ID);
            }

            Logging.Debug(Logfiles.AutomationRunner, LogOptions.MethodName, "Finish parsing of tasks");
            return(true);
        }
        public async Task <bool> RunTasksAsync()
        {
            ExecutionTimeStopwatch.Restart();
            RunningTask = null;
            ExitCode    = SequencerExitCode.NotRun;
            if (Package == null || AutomationSequencer == null || AutomationRunnerSettings == null)
            {
                throw new NullReferenceException();
            }

            Logging.Debug(Logfiles.AutomationRunner, "Setting up macro list before task run");
            AllMacros.Clear();
            AllMacros.AddRange(ApplicationMacros);
            foreach (AutomationMacro macro in GlobalMacros)
            {
                AllMacros.Add(AutomationMacro.Copy(macro));
            }

            //process local macros in case they were added with macros inside them
            foreach (AutomationMacro macro in SequenceMacros)
            {
                macro.Value = AutomationTask.ProcessMacro(macro.Name, macro.Value, SequenceMacros);
                AllMacros.Add(AutomationMacro.Copy(macro));
            }

            Logging.Debug(Logfiles.AutomationRunner, "Setting up working directory");
            string workingDirectory = Path.Combine(ApplicationConstants.RelhaxTempFolderPath, Package.PackageName);

            if (Directory.Exists(workingDirectory))
            {
                Logging.Debug("Directory exits, delete");
                if (!await FileUtils.DirectoryDeleteAsync(workingDirectory, true, true))
                {
                    Logging.Error(LogOptions.ClassName, "Failed to clear the working directory");
                    return(false);
                }
            }
            Directory.CreateDirectory(workingDirectory);

            bool taskReturnGood = true;

            for (int index = 0; index < AutomationTasks.Count; index++)
            {
                AutomationTask task = AutomationTasks[index];
                RunningTask = task;
                bool breakLoop = false;
                Logging.Info(Logfiles.AutomationRunner, LogOptions.MethodName, "Running task: {0}", task.ID);
                try
                {
                    await task.Execute();
                }
                catch (Exception ex)
                {
                    if (task is ICancelOperation taskThatNeedsCancel)
                    {
                        taskThatNeedsCancel.Cancel();
                    }

                    if (!(ex is OperationCanceledException))
                    {
                        Logging.Exception(ex.ToString());
                    }
                }

                switch (task.ExitCode)
                {
                case AutomationExitCode.None:
                    breakLoop      = false;
                    taskReturnGood = true;
                    ExitCode       = SequencerExitCode.NoErrors;
                    break;

                case AutomationExitCode.Cancel:
                    breakLoop      = true;
                    taskReturnGood = true;
                    ExitCode       = SequencerExitCode.Cancel;
                    break;

                case AutomationExitCode.ComparisonNoFilesToUpdate:
                    breakLoop      = true;
                    taskReturnGood = true;
                    ExitCode       = SequencerExitCode.NoErrors;
                    break;

                case AutomationExitCode.ComparisonManualFilesToUpdate:
                    breakLoop      = true;
                    taskReturnGood = true;
                    ExitCode       = SequencerExitCode.NoErrors;
                    break;

                default:
                    Logging.Error(Logfiles.AutomationRunner, LogOptions.MethodName, "The task, '{0}', failed to execute. Check the task error output above for more details. You may want to enable verbose logging.", task.ID);
                    breakLoop      = true;
                    taskReturnGood = false;
                    ExitCode       = SequencerExitCode.Errors;
                    break;
                }

                if (CancellationToken.IsCancellationRequested)
                {
                    breakLoop      = true;
                    taskReturnGood = true;
                    ExitCode       = SequencerExitCode.Cancel;
                }

                if (breakLoop)
                {
                    break;
                }
            }

            //dispose/cleanup the tasks
            AutomationTasks.Clear();
            RunningTask = null;
            Logging.Info("Sequence {0} completed in {1} ms", PackageName, ExecutionTimeStopwatch.ElapsedMilliseconds);
            Dispose();
            return(taskReturnGood);
        }