/// <summary>
        /// Method called in the background to actually install the downloaded updates.
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="updatesToInstall"></param>
        /// <returns></returns>
        private SofOperation Install(SofOperation operation, UpdateCollection updatesToInstall)
        {
            AgentSettings.Log("Installing...");
            foreach (IUpdate update in updatesToInstall)
            {
                // TODO Need a way to send back to server for approval of EULA...
                if (update.IsDownloaded)
                {
                    if (update.EulaAccepted == false)
                    {
                        update.AcceptEula();
                    }
                }
            }

            IUpdateInstaller2 installer = (IUpdateInstaller2)session.CreateUpdateInstaller();
            installer.ForceQuiet = true;
            installer.Updates = updatesToInstall;

            IInstallationResult installationRes = installer.Install();

            for (int i = 0; i < updatesToInstall.Count; i++)
            {
                // Find the Update that corresponds to updatesToInstall[i] by matching UpdateIds.
                Update update = FindUpdateByVendorId(operation, updatesToInstall[i].Identity.UpdateID);

                SofResult results;
                results.TopPatchId = update.TopPatchId;

                if (installationRes.GetUpdateResult(i).HResult == 0)
                {   // Success!
                    results.Successful = true;
                    results.Restart = installationRes.GetUpdateResult(i).RebootRequired;
                    results.SpecificMessage = null;

                    // Update SQLiteDB
                    SQLiteHelper.UpdateToggle(SQLiteHelper.WindowsUpdateColumn.Installed, true, results.TopPatchId);
                    SQLiteHelper.UpdateDate(SQLiteHelper.WindowsUpdateColumn.DateInstalled, DateTime.Now.ToShortDateString(), results.TopPatchId);
                }
                else
                {
                    // Failed...
                    results.Successful = false;
                    results.Restart = false;
                    results.SpecificMessage = installationRes.GetUpdateResult(i).HResult.ToString();

                    // Update SQLiteDB
                    SQLiteHelper.UpdateToggle(SQLiteHelper.WindowsUpdateColumn.Installed, false, results.TopPatchId);
                }
                operation.SetResult(results);
            }
            return operation;
        }
        public void UninstallUpdates(SofOperation operation)
        {
            // Can't use IUpdateInstaller.Uninstall() because it will fail if it does not go through WSUS.
            // Work around by using hacks provided in the nested Uninstaller class

            AgentSettings.Log("Uninstalling...");
            UninstallerResults uninstallerResults;

            SofResult results;
            foreach (Update update in operation.UpdateList)
            {
                // Make sure to set all results properties or the previous value will roll over
                // to the next update's results!!
                results.TopPatchId = update.TopPatchId;

                uninstallerResults = windowsUninstaller.Uninstall(update);
                if (uninstallerResults.Sucess)
                {   // Success!
                    results.Successful = true;
                    results.Restart = uninstallerResults.Restart;
                    results.SpecificMessage = uninstallerResults.Message;

                    // Update SQLiteDB
                    SQLiteHelper.UpdateToggle(SQLiteHelper.WindowsUpdateColumn.Installed, false, results.TopPatchId);
                }
                else
                {   // Fail...
                    results.Successful = false;
                    results.Restart = uninstallerResults.Restart;
                    results.SpecificMessage = uninstallerResults.Message;
                }
                operation.SetResult(results);
            }

            SQLiteHelper.RecreateUpdatesTable();
            CheckForInstalledUpdates();
            GetPendingUpdates();

            if (UninstallOperationCompleted != null)
                UninstallOperationCompleted(operation);
        }
        /// <summary>
        /// Determines whether to perform a system restore or send data back to the server. It use WMI.
        /// </summary>
        /// <param name="operation"></param>
        /// <returns></returns>
        public SofOperation WindowsRestore(SofOperation operation)
        {
            SofResult results;
            ManagementClass restoreClass = new ManagementClass("\\\\.\\root\\default", "systemrestore", new System.Management.ObjectGetOptions());
            ManagementObjectCollection restoreCollection = restoreClass.GetInstances();

            foreach (ManagementObject restoreItem in restoreCollection)
            {
                // Possible properties. See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa378925(v=vs.85).aspx
                //(string)restoreItem["Description"]
                //(uint)restoreItem["RestorePointType"]).ToString()
                //(uint)restoreItem["EventType"]).ToString()
                //(uint)restoreItem["SequenceNumber"]).ToString()
                //(string)restoreItem["CreationTime"]

                // Crazy way to call a method for a WMI class through System.Management.
                // See: http://msdn.microsoft.com/en-us/library/ms257364(v=vs.80).aspx
                if (((uint)restoreItem["SequenceNumber"]) == operation.WindowsRestoreSequence)
                {
                    ManagementBaseObject inputParameters = restoreClass.GetMethodParameters("Restore");
                    inputParameters["SequenceNumber"] = operation.WindowsRestoreSequence;

                    try
                    {
                        ManagementBaseObject outputParameters = restoreClass.InvokeMethod("Restore", inputParameters, null);
                        if (Convert.ToInt32(outputParameters["returnValue"]) == 0)
                        {
                            // Success! Restart system for restore point can take affect.
                            RestartSystem();
                            return null;
                        }
                        else
                        {
                            // Failed...
                            results.TopPatchId = null;
                            results.Successful = false;
                            results.Restart = false;

                            // Ummmm from the docs: "If the method succeeds, the return value is S_OK (0).
                            // Otherwise, the method returns one of the COM error codes defined in WinError.h."
                            // Yayyyyy.... (/s + April face)
                            int exitCode = Convert.ToInt32(outputParameters["returnValue"]);
                            results.SpecificMessage = "Win32 Error: " + new Win32Exception(exitCode).Message;

                            operation.SetResult(results);
                        }
                    }
                    catch (ManagementException e)
                    {
                        AgentSettings.Log("Exception: {0}", AgentLogLevel.Error, e.Message);
                        if (e.InnerException != null)
                        {
                            AgentSettings.Log("Inner exception: {0}", AgentLogLevel.Error, e.InnerException.Message);
                        }
                        AgentSettings.Log("Failed to perform a system restore.", AgentLogLevel.Error);
                        results.TopPatchId = null;
                        results.Successful = false;
                        results.Restart = false;
                        results.SpecificMessage = String.Format("ManagementException Error: ", e);
                    }
                    operation.SetResult(results);
                    return operation;
                }
            }

            results.TopPatchId = null;
            results.Successful = false;
            results.Restart = false;
            results.SpecificMessage = String.Format("No restore point with sequence number {0} was found.", operation.WindowsRestoreSequence);

            operation.SetResult(results);
            return operation;
        }
        /// <summary>
        /// "Un-hides" updates that are hidden and/or ignored.
        /// </summary>
        /// <param name="operation"></param>
        public void ShowUpdates(SofOperation operation)
        {
            UpdateCollection updateCollection = RetrieveUpdates(operation.UpdateList, OperationValue.Show);
            Update tpUpdate;
            foreach (IUpdate iUpdate in updateCollection)
            {
                // This is all it takes...
                iUpdate.IsHidden = false;

                tpUpdate = FindUpdateByVendorId(operation, iUpdate.Identity.UpdateID);

                // Seems like a lot for a simple operation.
                SofResult results;
                results.TopPatchId = tpUpdate.TopPatchId;
                results.Successful = true;
                results.Restart = false;
                results.SpecificMessage = null;
                operation.SetResult(results);

                // Update SQLiteDB
                SQLiteHelper.UpdateToggle(SQLiteHelper.WindowsUpdateColumn.Hidden, false, results.TopPatchId);
            }

            if (ShowOperationCompleted != null)
                ShowOperationCompleted(operation);
        }