0

我正在使用 WUAPI 搜索、下载和安装 Windows 更新(目前未使用 WSUS 服务器)。我正在使用具有特殊映像(Windows 10)的 VM 对其进行测试,该映像缺少多个更新(目前为 8 个)。我以管理员身份启动程序并提升权限以避免出现问题。它搜索更新,列出它们,下载它们并安装它们而不会出现任何错误。在我的情况下完成后,不需要重新启动。(出于测试目的,我内置_maxDownloadAndInstallSize = 1因为累积更新和功能更新需要很长时间才能安装:/) 但是当我现在打开我的 Windows 更新对话框时,它仍然显示它想要更新。此外,已安装的更新不会出现在历史记录中。我试图重新启动,但这也无济于事。当我再次执行我的程序时,它会毫无问题地安装下一个更新。情况是一样的。系统无法识别其中的任何内容。我也尝试过一次安装。它没有改变任何东西。

如果我的概念是错误的,或者我有什么有趣的许可问题,你知道吗?

对我来说,“完成”已安装的更新似乎缺少一些东西,所以一切都得到了同步。

我的代码(对不起,这只是实验性代码,因为我有问题,一些检查已经完成了好几次......)

(程序.cs)

static void Main(string[] args)
    {
      try
      {
        WindowsUpdateAPI updater = new WindowsUpdateAPI();
        IUpdateInstaller2 installer = new UpdateInstaller();
        updater.ExecuteWindowsUpdate(installer);
      }
      catch (Exception ex)
      {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine("Exception occured");
      }
    }

(WindowsUpdateAPI.cs)

 public class WindowsUpdateAPI
  {
    enum LogType
    {
      info,
      success,
      warning,
      error,
      fatalError
    }
    static int _maxDownloadAndInstallSize = 1;  // 0 => all

    public void ExecuteWindowsUpdate(IUpdateInstaller2 updateInstaller)
    {
      //IUpdateInstaller2 Installs or uninstalls updates from or onto a computer.
      updateInstaller = new UpdateInstaller();
      LogMessage("Automatic Windows Update mechanism started", LogType.info);
      LogMessage("\n-- Basic Checks --", LogType.info);
      ISystemInformation info = new SystemInformation();
      if (updateInstaller.RebootRequiredBeforeInstallation || CheckRegistriesForPendingRestart())
      {
        if (!info.RebootRequired)
        {
          LogMessage("Reboot not required by system", LogType.warning);
        }
        //TODO:Reboot PC
        LogMessage("Reboot required", LogType.warning);
        Console.ReadLine();
        return;
      }
      else
      {
        LogMessage("No reboot required", LogType.info);
      }
      if (info.RebootRequired)
      {
        LogMessage("Reboot required by system", LogType.warning);
      }

      if (updateInstaller.IsBusy)
      {
        LogMessage("Ongoing updates found", LogType.warning);
      }
      else
      {
        LogMessage("No ongoing updates found", LogType.info);
        UpdateSession updateSession = new UpdateSession();
        ISearchResult updateResult = SearchWindowsUpdates(updateSession);
        DownloadWindowsUpdates(updateSession, updateResult, false);
        bool rebootRequired = false;
        InstallWindowsUpdates(updateInstaller, updateResult, rebootRequired);
        if (rebootRequired)
        {
          LogMessage("Reboot required by update", LogType.warning);
        }
      }
      LogMessage("\n -- End --", LogType.info);
      Console.ReadLine();
    }

    private static void LogMessage(string message, LogType logType)
    {
      switch (logType)
      {
        case LogType.info:
          Console.ForegroundColor = ConsoleColor.White;
          break;
        case LogType.success:
          Console.ForegroundColor = ConsoleColor.Green;
          break;
        case LogType.warning:
          Console.ForegroundColor = ConsoleColor.Yellow;
          break;
        case LogType.error:
          Console.ForegroundColor = ConsoleColor.Red;
          break;
        case LogType.fatalError:
          Console.BackgroundColor = ConsoleColor.Red;
          Console.ForegroundColor = ConsoleColor.White;
          break;
      }
      Console.WriteLine(message);
      Console.BackgroundColor = ConsoleColor.Black;
      Console.ForegroundColor = ConsoleColor.White;
    }

    private static int GetNumberOfMaxUpdates(int updateCount)
    {
      return ( _maxDownloadAndInstallSize > 0 ? Math.Min(updateCount, _maxDownloadAndInstallSize) : updateCount);
    }

    private static ISearchResult SearchWindowsUpdates(UpdateSession updateSession)
    {
      LogMessage("\n-- Search --", LogType.info);
      IUpdateSearcher updateSearcher = updateSession.CreateUpdateSearcher();
      LogMessage("Searching for Windows Updates..", LogType.info);
      //TODO: criteria: RebootRequired, IsHidden, 
      ISearchResult
          updateSearchResult = updateSearcher.Search(
              "IsInstalled=0"); //Use operators written with capital letters as example: AND Type='Software'

      LogMessage($"Found {updateSearchResult.Updates.Count} available updates", LogType.info);

      foreach (IUpdate update in updateSearchResult.Updates)
      {
        //TODO:Implement logging (network share)
        LogMessage($"Update \"{update.Title}\" is available", LogType.info);
      }
      return updateSearchResult;
    }

    private static void DownloadWindowsUpdates(UpdateSession updateSession, ISearchResult updateSearchResult, bool forceDownloadAll)
    {
      LogMessage("\n-- Download --", LogType.info);
      UpdateDownloader updateDownloader = updateSession.CreateUpdateDownloader();
      if (updateDownloader.Updates == null)
      {
        updateDownloader.Updates = new UpdateCollection();
      }
      int updateCount = GetNumberOfMaxUpdates(updateSearchResult.Updates.Count);
      LogMessage($"Number of max Updates to download is {updateCount}", LogType.info);
      for (int i = 0; i < updateCount; i++)
      {
        IUpdate update = updateSearchResult.Updates[i];
        if (!update.IsDownloaded || forceDownloadAll)
        {
          LogMessage($"Update \"{update.Title}\" prepared for download", LogType.info);
          updateDownloader.Updates.Add(update);
        }
      }
      LogMessage($"Downloading updates..", LogType.info);
      if (updateDownloader.Updates.Count > 0)
      {
        IDownloadResult downloadResult = updateDownloader.Download();
        for (int i = 0; i < updateDownloader.Updates.Count; i++)
        {
          PrintOperationResultCode("Download of Update", updateDownloader.Updates[0].Title, downloadResult.GetUpdateResult(i).ResultCode);
        }
      }
    }

    private static void PrepareUpdatesForInstall(UpdateCollection updatesToInstall, ISearchResult updateSearchResult, bool rebootRequiredBeforeUpdate)
    {
      int updateCount = GetNumberOfMaxUpdates(updateSearchResult.Updates.Count);
      LogMessage($"Number of max Updates to install is {updateCount}", LogType.info);
      for (int i = 0; i < updateCount; i++)
      {
        IUpdate update = updateSearchResult.Updates[i];
        if (!update.IsDownloaded)
        {
          LogMessage($"Update \"{update.Title}\" cannot be prepared for install because it's not downloaded", LogType.error);
        }
        else if (update.IsInstalled)
        {
          LogMessage($"Update \"{update.Title}\" is already installed", LogType.info);
        }
        else
        {
          updatesToInstall.Add(update);
          LogMessage($"Update \"{update.Title}\" prepared for install", LogType.info);
        }
      }
    }

    private static void InstallWindowsUpdates(IUpdateInstaller2 updateInstaller, ISearchResult updateSearchResult, bool rebootRequired)
    {
      LogMessage("\n-- Install --", LogType.info);
      IInstallationResult updateInstallationResult;
      //Update collection which is used for installing
      UpdateCollection updatesToInstall = new UpdateCollection();
      bool rebootRequiredBeforeInstall = false;
      PrepareUpdatesForInstall(updatesToInstall, updateSearchResult, rebootRequiredBeforeInstall);
      if (rebootRequiredBeforeInstall)
      {
        LogMessage($"A Reboot is required before updating", LogType.warning);
        return;
      }
      //Assign updates to install
      updateInstaller.Updates = updatesToInstall;
      updateInstaller.ForceQuiet = true;
      if (updateInstaller.RebootRequiredBeforeInstallation)
      {
        LogMessage($"A Reboot is required before updating", LogType.warning);
        Console.ReadLine();
        return;
      }
      if (updatesToInstall.Count > 0)
      {
        LogMessage($"Installing updates..", LogType.info);
        updateInstallationResult = updateInstaller.Install();
        rebootRequired = false;
        for (int i = 0; i < updateInstaller.Updates.Count; i++)
        {
          if (updateInstaller.Updates[i].IsInstalled &&
            updateInstaller.Updates[i].InstallationBehavior.RebootBehavior != InstallationRebootBehavior.irbNeverReboots)
          {
            rebootRequired = true;
          }
          PrintOperationResultCode("Install of Update", updateInstaller.Updates[i].Title, updateInstallationResult.GetUpdateResult(i).ResultCode);
        }
      }
    }

    private static void PrintOperationResultCode(string messagePrefix, string updateTitle, OperationResultCode resultCode)
    {
      switch (resultCode)
      {
        case OperationResultCode.orcSucceeded:
          LogMessage($"{messagePrefix} \"{updateTitle}\" succeeded", LogType.success);
          //TODO: Implement logging (network share)
          break;

        case OperationResultCode.orcSucceededWithErrors:
          LogMessage($"{messagePrefix} \"{updateTitle}\" succeeded with errors", LogType.warning);
          //TODO: Implement logging (network share)
          break;

        case OperationResultCode.orcFailed:
          LogMessage($"{messagePrefix} \"{updateTitle}\" failed", LogType.error);
          break;
        case OperationResultCode.orcAborted:
          LogMessage($"{messagePrefix} \"{updateTitle}\" aborted", LogType.fatalError);
          break;

        case OperationResultCode.orcInProgress:
          LogMessage($"{messagePrefix}  \"{updateTitle}\" in progress", LogType.warning);
          break;
        case OperationResultCode.orcNotStarted:
          LogMessage($"{messagePrefix}  \"{updateTitle}\" not started yet", LogType.warning);
          break;
      }
    }

    private static bool CheckRegistriesForPendingRestart()
    {
      using var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);

      RegistryKey RebootRequired = hklm.OpenSubKey(
          @"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired", false);
      RegistryKey RebootPending = hklm.OpenSubKey(
          @"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending", false);
      RegistryKey PackagesPending = hklm.OpenSubKey(
          @"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\PackagesPending", false);
      RegistryKey Pending = hklm.OpenSubKey(
          @"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Services\Pending", false);

      //Here we are searching for a keys in the HKLM registry that are created when pending reboot
      bool rebootNeededBecauseOfRegistryKey = false;
      if (RebootRequired != null || RebootRequired != null || PackagesPending != null)
      {
        rebootNeededBecauseOfRegistryKey = true;
      }
      if (RebootRequired != null)
      {
        RebootRequired.Close();
      }
      if (RebootPending != null)
      {
        RebootPending.Close();
      }
      if (PackagesPending != null)
      {
        PackagesPending.Close();
      }
      if (rebootNeededBecauseOfRegistryKey)
      {
        return true;
      }
      //Key SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Services\Pending exists always but it is empty if no pending reboot , if key contains any sub keys, only then reboot is needed.
      if (Pending != null)
      {
        foreach (RegistryKey subkey in Pending.GetSubKeyNames()
            .Select(keyName => Pending.OpenSubKey(keyName)))
        {
          Pending.Close();
          return true;
        }
        Pending.Close();
      }
      Pending.Close();
      return false;
    }
  }
4

0 回答 0