После установки обновлений с помощью WUAPI Windows их вообще не распознает

#c# #wuapi

Вопрос:

Я использую WUAPI для поиска, загрузки и установки обновлений Windows (пока без использования сервера WSUS). Я тестирую это с помощью виртуальной машины со специальным образом (Windows 10), в котором отсутствует несколько обновлений (на данный момент 8). Я запускаю программу как администратор и повышен, чтобы избежать проблем. Он ищет обновления, перечисляет их, загружает и устанавливает без каких-либо ошибок. После завершения в моем случае перезагрузка не потребуется. (Для целей тестирования я встроил _maxDownloadAndInstallSize = 1 , потому что установка накопительных обновлений и обновлений функций занимает довольно много времени :/) Но когда я сейчас открываю диалоговое окно центра обновления Windows, оно по-прежнему показывает, что оно хочет обновиться. Кроме того, установленные обновления не отображаются в истории. Я попытался перезагрузиться, но это тоже не помогло. Когда я снова запускаю свою программу, она устанавливает следующее обновление без проблем. И ситуация та же самая. Система ничего из этого не распознает. Я также попытался установить все сразу. Это ничего не меняет.

У вас есть идея, если моя концепция неверна или у меня есть какие-то забавные проблемы с разрешениями?

Для меня это выглядит так, как будто чего-то не хватает, чтобы «завершить» установленные обновления, чтобы все синхронизировалось.

Мой код (извините, это просто экспериментальный код, и, поскольку у меня есть проблемы, некоторые проверки выполняются несколько раз…)

(Program.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 updateSearchResu<
    }

    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 updateInstallationResu<
      //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 amp;amp;
            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(
          @"SOFTWAREMicrosoftWindowsCurrentVersionWindowsUpdateAuto UpdateRebootRequired", false);
      RegistryKey RebootPending = hklm.OpenSubKey(
          @"SOFTWAREMicrosoftWindowsCurrentVersionComponent Based ServicingRebootPending", false);
      RegistryKey PackagesPending = hklm.OpenSubKey(
          @"SOFTWAREMicrosoftWindowsCurrentVersionComponent Based ServicingPackagesPending", false);
      RegistryKey Pending = hklm.OpenSubKey(
          @"SOFTWAREMicrosoftWindowsCurrentVersionWindowsUpdateServicesPending", 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 SOFTWAREMicrosoftWindowsCurrentVersionWindowsUpdateServicesPending 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;
    }
  }