【问题标题】:Windows Update API with C# not finding any installed updates使用 C# 的 Windows 更新 API 未找到任何已安装的更新
【发布时间】:2017-12-08 22:58:00
【问题描述】:

我有许多 Windows 7 PC 需要使用 C# 控制台应用程序中的 Windows Update API 进行特定 Windows 更新的修补。 API 需要搜索已安装的更新并报告是否已安装,如果未安装则执行安装。

在虚拟 PC(Windows 7 Professional Hyper-v 客户端)上进行测试时,我遇到了与目标 PC(Windows 7 Embedded)类似的情况,其中以下代码返回(非常快速且无任何异常)0 更新。我知道这是错的。事实上,它甚至会在我安装 .msu 更新后返回。

代码:

 UpdateSession uSession = new UpdateSession();
 IUpdateSearcher uSearcher = uSession.CreateUpdateSearcher();
 uSearcher.Online = false;
 try
 {
    ISearchResult sResult = uSearcher.Search("IsInstalled=1 And IsHidden=0");
    Console.WriteLine("Found " + sResult.Updates.Count + " updates");
    foreach (IUpdate update in sResult.Updates)
    {
       Console.WriteLine(update.Title);
       if (update.Title.ToLower().Contains("kb123456")) {
        //Update is not required
        ReportInstalled();
        return;
       }
     }
     //If we get here, the update is not installed
     InstallUpdate();
  }
  catch (Exception ex)
  {
    Console.WriteLine("Something went wrong: " + ex.Message);
  }

现在是有趣的部分。如果我从控制面板打开 Windows 更新并单击“检查更新”,它会关闭一段时间,然后回来安装一堆更新。此时,如果我运行上述代码,它会按预期工作并报告已安装的更新超过 200 个。

似乎搜索更新的手动过程会启动/重新启动某些服务和/或其他进程,但是,我正在努力弄清楚我需要对系统做什么才能使其进入正确状态。我希望答案是使用一组参数启动服务 x 或进程 y 的简单案例,但是哪个?

我尝试了一些(不是全部)但没有改变行为的事情:

  1. 启动 BITS 服务,重新启动 Windows 更新服务
  2. 尝试使用各种开关启动 wuauclt.exe(记录在 here 在 cmets 中)

当机器处于代码正确运行的状态时(我手动运行 WU),我注意到运行上述代码时进程 wuauclt.exe 似乎启动了。当它处于目标状态时(在我手动运行 WU 之前), wuauclt.exe 无法启动,并且我无法手动启动它,我怀疑这是一个很大的线索。

另一个线索是我手动运行 Windows 更新之前的状态。在控制面板窗口更新看起来是这样的:

通过该方法运行 WU 并安装更新后,机器处于代码按预期运行的状态,WU 如下所示:

总而言之,我需要这个过程来自动安装更新。如果我检测到 0 个已安装的更新,我知道机器处于特定状态,所以我需要启动/重新启动一些进程和服务(以编程方式)以使机器在运行我的代码之前进入正确的状态。知道要运行/重启什么是这个问题的本质。

【问题讨论】:

  • 检查 KB 编号是不好的,因为更新会被取代,稍后将被删除以清理 WinSXS 文件夹。更好:检查 System32 文件夹中 DLL/exe 文件的 Fileversion
  • 检查 KB 编号并不是这个问题的一部分。它正在从 API 获取已安装更新的列表。
  • 不,您遇到了 XY 问题,您需要确保您的 Windows 是最新的,以进行特定修复以阻止当前在野外出现的 Randomware。现在您的“解决方案”是检查是否安装了特定的 KB,但这失败了。同样,最好检查文件版本。
  • 我明白你的意思,尽管目前我有一个解决方法(WMI 查询)正在返回已安装的 KB 项目,而不管我的目标上的 Windows 更新的状态如何机器。不过,我仍然希望将 WU API 用于未来的更新。毕竟,WU 不就是为了执行您所说的那种文件版本检查而设计的吗?
  • 通过指定uSearcher.Online = false;,您正在进行离线搜索,即仅使用上次在线搜索的缓存信息;如果没有,则不会产生任何更新。

标签: c# windows-7 windows-services windows-update wuapi


【解决方案1】:

由于这个问题目前没有答案(尽管合并后的 cmets 大多给出了答案),所以这里发生了什么:

这是一种非常常见的方法来检查“我是否有我需要的补丁才能让我的程序成功运行?”,它有短期和长期的问题。

短期问题:

搜索代码正在进行离线扫描(它将 IUpdateSearcher::Online 设置为 false)。这是加快搜索速度的常用策略。问题是它只处理在以前的在线扫描期间可用的更新。如果计算机很久没有进行在线扫描,那么结果将是陈旧的。如果计算机自上次在线扫描后发生了显着的硬件或软件配置更改,则结果将不完整。如果计算机从未进行过在线扫描,则 IUpdateSearcher::Search 不会返回错误——它只会立即报告没有适用的更新。

因此,如果您想尝试通过离线扫描来加快速度,最好检查IAutomaticResults::LastSearchSuccessDate,它会告诉您自动更新上次进行扫描的时间。由于自动更新扫描处于联机状态,因此您知道当时发生了联机扫描。如果日期超过几天,则应改为在线扫描。

长期问题:

此代码假设存在更新 KB123456 并且与计算机相关。但这本质上是一个有时间限制的假设,而现在的时间限制通常很短。如果 KB123456 中的补丁被滚动到更新的累积更新 KB234567 中,那么 KB123456 可能会在某个时候从 Windows 更新中过期。此时,您的搜索将始终返回“未安装”,即使修补后的代码实际上在 PC 上。

与其尝试检查“是否安装了 KB X?”,更好的方法是测试“是否安装了我需要的修复程序/功能?”

  • 如果可能,请直接检查修复程序/功能。例如,如果您需要特定的新 Windows API,那么如果操作系统支持,您可以使用 API Sets,或者只使用 LoadLibrary 和 GetProcAddress 来查看您所追求的 DLL 是否包含您需要的功能。

  • 如果无法直接测试修复/功能,则测试 Windows 本身的状态,看看它是否是您需要的。在 Windows 10 中,您通常只需要检查内部版本号。在旧版本的操作系统上,您可以查看 KB 的补丁说明,而不是硬编码 KB 编号,找出它更新的 DLL 以及将它们更新到的版本号,然后将这些 DLL 名称和版本用于您的运行时查看。

  • 根据您正在测试的具体内容以及您正在执行测试的上下文(脚本等),DISM 命令也可能会有所帮助 - 如果您需要特定的 Windows 包目前,您可以使用 DISM /ONLINE /GET-PACKAGES 并查看您的包是否显示在输出中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-08
    • 1970-01-01
    • 2023-03-15
    • 2018-02-23
    相关资源
    最近更新 更多