public void DoAddTasks(bool abStartup)
        {
            // Do this at most once per minute to avoid running the same task twice in rapid succession.
            if ( !abStartup && (!moProfile.ContainsKey("-AddTasks") || DateTime.Now < mdtPreviousAddTasksStarted.AddMinutes(1)) )
                return;

            mdtPreviousAddTasksStarted = DateTime.Now;

            try
            {
                if ( null == moAddTasksProfile )
                {
                    moAddTasksProfile = moProfile.oProfile("-AddTasks").oOneKeyProfile("-Task");
                    moAddTasksProcessArray = new Process[moAddTasksProfile.Count];
                }
                
                for (int i=0; i < moAddTasksProfile.Count; ++i)
                {
                    // Convert the current task from a command-line string to a profile oject.
                    tvProfile loAddTask = new tvProfile(moAddTasksProfile[i].ToString());

                    bool lbDoTask = false;

                    if ( abStartup )
                    {
                        lbDoTask = loAddTask.bValue("-OnStartup", false);

                        // Reset pause timer to allow other tasks to run without delay after startup.
                        mdtPreviousAddTasksStarted = DateTime.Now.AddMinutes(-1);
                    }
                    else
                    {
                        DateTime    ldtTaskStartTime = loAddTask.dtValue("-StartTime", DateTime.MinValue);
                        string      lsTaskDaysOfWeek = loAddTask.sValue("-StartDays", "");

                        // If -StartTime is within the current minute, start the task.
                        // If -StartDays is specified, run the task on those days only.
                        lbDoTask = DateTime.MinValue != ldtTaskStartTime && (int)mdtPreviousAddTasksStarted.TimeOfDay.TotalMinutes == (int)ldtTaskStartTime.TimeOfDay.TotalMinutes
                                && ("" == lsTaskDaysOfWeek || this.bListIncludesDay(lsTaskDaysOfWeek, mdtPreviousAddTasksStarted));
                    }

                    if ( lbDoTask )
                    {
                        string  lsCommandEXE = loAddTask.sValue("-CommandEXE", "add task -CommandEXE missing");

                        Process loProcess = new Process();
                                loProcess.ErrorDataReceived += new DataReceivedEventHandler(this.BackupProcessOutputHandler);
                                loProcess.OutputDataReceived += new DataReceivedEventHandler(this.BackupProcessOutputHandler);
                                loProcess.StartInfo.FileName = lsCommandEXE;
                                loProcess.StartInfo.Arguments = loAddTask.sValue("-CommandArgs", "");
                                loAddTask.bValue("-UnloadOnExit", false);

                                // The following subset of parameters are overridden when -TimeoutMinutes is set. This is
                                // necessary to guarantee IO redirection is handled properly (ie. output goes to the log).
                        bool    lbWaitForExitOverride = (loAddTask.iValue("-TimeoutMinutes", 0) > 0);
                                loProcess.StartInfo.CreateNoWindow          =  lbWaitForExitOverride | loAddTask.bValue("-CreateNoWindow", false);
                                loProcess.StartInfo.UseShellExecute         = !lbWaitForExitOverride & loAddTask.bValue("-UseShellExecute", true);
                                loProcess.StartInfo.RedirectStandardInput   =  lbWaitForExitOverride | loAddTask.bValue("-RedirectStandardInput", false);
                                loProcess.StartInfo.RedirectStandardError   =  lbWaitForExitOverride | loAddTask.bValue("-RedirectStandardError", false);
                                loProcess.StartInfo.RedirectStandardOutput  =  lbWaitForExitOverride | loAddTask.bValue("-RedirectStandardOutput", false);

                                moAddTasksProcessArray[i] = loProcess;

                        try
                        {
                            if ( !loAddTask.bValue("-OnStartup", false) )
                            {
                                this.LogIt(String.Format("Starting Task: {0}", loAddTask.sCommandLine()));

                                loProcess.Start();

                                // Start output to console also.
                                if ( loProcess.StartInfo.RedirectStandardError )
                                    loProcess.BeginErrorReadLine();
                                if ( loProcess.StartInfo.RedirectStandardOutput )
                                    loProcess.BeginOutputReadLine();

                                if ( lbWaitForExitOverride )
                                {
                                    // Wait the timeout period, then call "WaitForExit()" to flush the output steams.
                                    if ( loProcess.WaitForExit(60000 * loAddTask.iValue("-TimeoutMinutes", 0)) )
                                        loProcess.WaitForExit();

                                    // Stop output to console.
                                    if ( loProcess.StartInfo.RedirectStandardError )
                                        loProcess.CancelErrorRead();
                                    if ( loProcess.StartInfo.RedirectStandardOutput )
                                        loProcess.CancelOutputRead();

                                    loProcess.Close();
                                }
                            }
                            else
                            {
                                bool        lbFound = false;
                                string      lsWindowTitle = loAddTask.sValue("-CommandWindowTitle", "");
                                Process[]   loProcessesArray = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(loProcess.StartInfo.FileName));
                                            // If there's exactly one matching process and no given window title to compare, we're done.
                                            lbFound = (1 == loProcessesArray.Length && "" == lsWindowTitle );

                                            // If no window title has been given to compare, there's nothing else to do.
                                            if ( !lbFound && "" != lsWindowTitle )
                                            {
                                                // If no matching processes have been found so far, get them all to compare.
                                                if ( 0 == loProcessesArray.Length )
                                                    loProcessesArray = Process.GetProcesses();

                                                // Since a window title has been provided, it must be compared to the process(es) found.
                                                // Wildcards are permitted, but only at the end of titles. We stop at the first match.
                                                foreach (Process loProcessEntry in loProcessesArray)
                                                    if ( loProcessEntry.MainWindowTitle.StartsWith(lsWindowTitle.Replace("*", "")) )
                                                    {
                                                        lbFound = true;
                                                        break;
                                                    }
                                            }

                                // Don't start -OnStartup processes that have already been started.
                                if ( lbFound )
                                {
                                    // The process has "already started" if there is only one with the
                                    // same EXE or multiple EXEs with one having the same window title.
                                    this.LogIt(String.Format("Already running, task not started: {0}", loAddTask.sCommandLine()));
                                }
                                else
                                {
                                    this.LogIt(String.Format("Starting Task: {0}", loAddTask.sCommandLine()));

                                    loProcess.Start();

                                    // Start output to console also.
                                    if ( loProcess.StartInfo.RedirectStandardError )
                                        loProcess.BeginErrorReadLine();
                                    if ( loProcess.StartInfo.RedirectStandardOutput )
                                        loProcess.BeginOutputReadLine();

                                    if ( lbWaitForExitOverride )
                                    {
                                        // Wait the timeout period, then call "WaitForExit()" to flush the output steams.
                                        if ( loProcess.WaitForExit(60000 * loAddTask.iValue("-TimeoutMinutes", 0)) )
                                            loProcess.WaitForExit();

                                        // Stop output to console.
                                        if ( loProcess.StartInfo.RedirectStandardError )
                                            loProcess.CancelErrorRead();
                                        if ( loProcess.StartInfo.RedirectStandardOutput )
                                            loProcess.CancelOutputRead();

                                        loProcess.Close();
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            this.ShowError(ex.Message, String.Format("Failed starting task: {0}", lsCommandEXE));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                this.ShowError(ex.Message, "Add Tasks Failed");
            }
        }