#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;
}
}