Windows 使用 C# 更新 API 未找到任何已安装的更新

Windows Update API with C# not finding any installed updates

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

在 Virtual PC(Windows 7 Professional Hyper-v 客户端)上进行测试时,我遇到了与目标 PC(Windows 7 Embedded)类似的情况,其中以下代码 returns (非常快,没有任何例外)0 次更新。我知道这是错误的。事实上,它甚至 returns 在我安装 .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 更新并单击 'Check for updates',它会关闭一段时间然后返回并安装一堆更新。此时,如果我 运行 上面的代码,它会按预期工作并报告超过 200 个已安装的更新。

似乎是搜索更新的手动过程 starts/restarts 一些服务 and/or 其他过程,但是,我正在努力弄清楚我需要对系统做些什么才能得到它进入正确的状态。我希望答案是启动服务 x 或使用一组参数处理 y 的简单情况,但是哪个?

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

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

机器处于代码 运行s 正确的状态(after 我 运行 WU 手动),我注意到过程 wuauclt.exe出现在上面代码为运行时开始。当它处于目标状态时(在我手动 运行 WU 之前), wuauclt.exe 没有启动,我无法手动启动它,我怀疑这是一个很大的线索。

另一条线索是 Windows 在我手动 运行 更新之前的状态。在控制面板中 windows 更新如下所示:

在 运行ning WU 并通过该方法安装更新后,机器处于代码 运行s 的状态,如预期的 WU 看起来像:

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

由于这个问题目前没有答案(虽然综合评论大多给出了答案),这里发生了什么:

这是一种非常常见的检查方法"Do I have the patches I need in order for my program to run successfully?",它有一个短期问题和一个长期问题。

短期问题:

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

因此,如果您想尝试通过执行离线扫描来加快速度,检查 IAutomaticResults::LastSearchSuccessDate 是一个很好的编码习惯,它会告诉您上次自动更新执行扫描的时间。由于自动更新扫描是联机的,因此您知道当时发生了联机扫描。如果日期超过几天,您应该进行在线扫描。

长期问题:

此代码假定更新 KB123456 存在并且与计算机相关。但这本质上是一个有时间限制的假设,而现在的时间限制通常很短。如果 KB123456 中的补丁被纳入更新的累积更新 KB234567,那么 KB123456 可能会在某个时候从 Windows 更新中过期。届时您的搜索将始终 return "not installed",即使修补代码实际上在 PC 上也是如此。

与其尝试检查 "Is KB X installed?",更好的方法是测试 "Is the fix/feature I need installed?"

  • 如果可能,请直接检查 fix/feature。例如,如果您需要一个特定的新 Windows API,那么如果 OS 支持它,您可以使用 API 集,或者只使用 LoadLibrary 和 GetProcAddress 来查看是否您要查找的 DLL 包含您需要的功能。

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

  • 具体取决于您正在测试的内容和您进行测试的环境(脚本等),DISM 命令也可能有用——如果您需要特定的Windows 包出现,您可以使用 DISM /ONLINE /GET-PACKAGES 并查看您的包是否出现在输出中。