【问题标题】:How to programmatically check the applicability rules of a Windows update?如何以编程方式检查 Windows 更新的适用性规则?
【发布时间】:2015-07-02 20:24:20
【问题描述】:

通过探索 Windows 更新 .msu 文件的内容(例如,使用 7zip 等工具),您可能会发现一系列文件,其中包括定义先决条件和 适用性规则。例如:

<UpdateIdentity UpdateID="E6CF1350-C01B-414D-A61F-263D14D133B4" RevisionNumber="1" /><Properties UpdateType="Category" /><ApplicabilityRules><IsInstalled><True /></IsInstalled></ApplicabilityRules>
....
<UpdateIdentity UpdateID="2bf7ed9c-6f43-493a-b156-db20f08c44c4" RevisionNumber="101" /><Properties UpdateType="Detectoid" /><Relationships /><ApplicabilityRules><IsInstalled><b.RegSz Key="HKEY_LOCAL_MACHINE" Subkey="SYSTEM\CurrentControlSet\Control\Nls\Language" Value="InstallLanguage" Comparison="EqualTo" Data="0409" /></IsInstalled></ApplicabilityRules>
....
<UpdateIdentity UpdateID="6AECE9A4-19E3-4BC7-A20C-070A5E31AFF4" RevisionNumber="100" /><Properties UpdateType="Detectoid" /><Relationships>
...
<UpdateIdentity UpdateID="3B4B8621-726E-43A6-B43B-37D07EC7019F" /><ApplicabilityRules><IsInstalled><b.WmiQuery Namespace="root\cimv2" WqlQuery="SELECT Manufacturer FROM Win32_ComputerSystem WHERE Manufacturer = 'Samsung Electronics' or Manufacturer = 'Hewlett-Packard' or Manufacturer = 'Gateway'" /></IsInstalled></ApplicabilityRules>
...

现在,给定一个特定的 .msu 文件和我的本地计算机,有没有办法遍历这些规则并找出是否不满意 - 以及哪一个?

我可以为此目的使用 WSUS 3.0 类库吗?或者有没有工具/脚本?

我真正想要的是确切知道是什么条件使计算机拒绝某个 Windows 更新 (KB2973201) 并显示消息更新不适用于您的计算机(这背后的错误代码是WU_E_NOT_APPLICABLE)。

关于这些更新的适用性规则的文档似乎太少了。有什么好的资源吗?

参考资料:

【问题讨论】:

    标签: c# windows powershell windows-update


    【解决方案1】:

    您可以使用Windows Update Agent API 来查询已安装的更新(实际上它有很多信息),如下所示:

      // in .NET, you need to add a reference
      // to the WUAPI COM component located in \windows\system32\wuapi.dll
      // to be able to access the WUAPI object model
      UpdateSearcher searcher = new UpdateSearcher();
      searcher.Online = false; // you can remove this line if you allow the API to get online to search
      var res = searcher.Search("IsInstalled=0"); // search not installed update
      foreach (IUpdate update in res.Updates)
      {
          Console.WriteLine("update:" + update.Title);
    
          // get history information
          // this can return nothing for example it it was hidden by end user
          // note we use update's identity and rev number here for matching a specific update
          var histories = searcher.QueryHistory(0, searcher.GetTotalHistoryCount()).OfType<IUpdateHistoryEntry>().Where(
              h => h.UpdateIdentity.UpdateID == update.Identity.UpdateID && h.UpdateIdentity.RevisionNumber == update.Identity.RevisionNumber);
          foreach (var history in histories)
          {
              Console.WriteLine(" code:" + history.ResultCode);
              Console.WriteLine(" hr:0x" + history.HResult.ToString("X8"));
          }
      }
    

    但是,这不会告诉您用于确定是否安装了 updagres 的内部规则(注册表/wmi 等)是什么。这不是 WUAPI 公开的。

    【讨论】:

      【解决方案2】:

      现在,给定一个特定的 .msu 文件和我的本地计算机,有没有办法迭代这些规则并找出是否不满意 - 以及哪一个?
      我可以为此目的使用 WSUS 3.0 类库吗?或者有没有工具/脚本?

      您可以通过 WSUS 3.0 类库Update Applicability Rules,尽管它不提供检查规则是否通过的功能,除非(我猜)您运行安装程序,但不会告诉您哪个失败。

      Simon 提到 WUAPI 库没有公开内部规则,并且 (afaik) 无法将 WUAPI ResultCodes 与失败的 ApplicabilityRules 匹配。

      不幸的是,像Microsoft.Deployment.WindowsInstaller.dll 这样的库不能处理 MSU 文件,所以我们对“现成”选项不走运。因此,您必须手动使用代码和 (msu.xml) XML 文件:

      <Updates>
        <UpdateIdentity UpdateID="E6CF1350-C01B-414D-A61F-263D14D133B4" RevisionNumber="1" />
        <Properties UpdateType="Category" />
        <ApplicabilityRules>
          <IsInstalled>
            <True />
          </IsInstalled>
        </ApplicabilityRules>
        <UpdateIdentity UpdateID="2bf7ed9c-6f43-493a-b156-db20f08c44c4" RevisionNumber="101" />
        <Properties UpdateType="Detectoid" />
        <Relationships />
        <ApplicabilityRules>
          <IsInstalled>
            <b.RegSz Key="HKEY_LOCAL_MACHINE" Subkey="SYSTEM\CurrentControlSet\Control\Nls\Language" Value="InstallLanguage" Comparison="EqualTo" Data="0409" />
          </IsInstalled>
        </ApplicabilityRules>
        <UpdateIdentity UpdateID="6AECE9A4-19E3-4BC7-A20C-070A5E31AFF4" RevisionNumber="100" />
        <Properties UpdateType="Detectoid" />
        <Relationships></Relationships>
        <UpdateIdentity UpdateID="3B4B8621-726E-43A6-B43B-37D07EC7019F" />
        <ApplicabilityRules>
          <IsInstalled>
            <b.WmiQuery Namespace="root\cimv2" WqlQuery="SELECT Manufacturer FROM Win32_ComputerSystem WHERE Manufacturer = 'Dell Inc.' or Manufacturer = 'Samsung Electronics' or Manufacturer = 'Hewlett-Packard' or Manufacturer = 'Gateway'" />
          </IsInstalled>
        </ApplicabilityRules>
      </Updates>
      

      使用此代码查看哪些 ApplicabilityRules 失败:

      private void btnWillPassApplicabilityRules_Click(object sender, EventArgs e)
      {
          XDocument doc = XDocument.Load("msu.xml");
          var elements = doc.Element("Updates").Elements("ApplicabilityRules").Elements("IsInstalled").Elements();
      
          foreach (var element in elements) {
              if (element.ToString().StartsWith("<b.RegSz")) {
                  string subKeyName = element.Attribute("Subkey").Value;
                  string keyName = element.Attribute("Value").Value;
                  string keyValue = element.Attribute("Data").Value;
      
                  //TODO: Leave the Registry Hive "Switch()" upto reader to fully implement
                  if (!ValueExistsInRegistry(Registry.LocalMachine, subKeyName, keyName, keyValue)) {
                      Console.WriteLine("Install is not applicable as Applicability Rule failed: " + element.ToString());
                  }
              }
              else if (element.ToString().StartsWith("<b.WmiQuery")) {
                  string nameSpace = element.Attribute("Namespace").Value;
                  string wqlQuery = element.Attribute("WqlQuery").Value;
                  if (!ValueExistsInWMI(nameSpace, wqlQuery)) {
                      Console.WriteLine("Install is not applicable as Applicability Rule failed: " + element.ToString());
                  }
              }
          }
      }
      
      private bool ValueExistsInRegistry(RegistryKey root, string subKeyName, string keyName, string keyValue)
      {
          using (RegistryKey key = root.OpenSubKey(subKeyName)) {
              if (key != null) return keyValue == key.GetValue(keyName).ToString();
          }
          return false;
      }
      
      private bool ValueExistsInWMI(string nameSpace, string wqlQuery)
      {
          ManagementScope scope = new ManagementScope(String.Format("\\\\{0}\\" + nameSpace, "."), null);  //The "." is for your local PC
          scope.Connect();
          ObjectQuery query = new ObjectQuery(wqlQuery);
          ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
          if (searcher.Get().Count == 0) {
              return false;
          }
          else {
              return true;
          }
          return false;
      }
      }
      

      在运行适用性规则之前,最好先检查更新是否会通过操作系统 (OS) 和 Service Pack (SP) 适用性测试。 如果升级不适用于操作系统和 SP,则没有必要检查注册表/wmi 等来确定升级是否通过规则

      要查看 ApplicabilityInfo,请运行 expand 命令行实用程序:

      expand -f:* "C:\temp\msu\Windows6.1-KB2973201-x64.msu" "C:\temp\msu"
      

      这将创建以下文件:

      • WSUSSCAN.cab
      • Windows6.1-KB2973201-x64.cab
      • Windows6.1-KB2973201-x64.xml
      • Windows6.1-KB2973201-x64-pkgProperties.txt

      创建 xml 和 txt 文件大约需要 5 秒。打开 pkgProperties.txt 文件,第一行有信息:

      ApplicabilityInfo="Windows 7.0 Client SP1;Windows 7.0 Server Core SP1;Windows 7.0 嵌入式 SP1;Windows 7.0 服务器 SP1;Windows 7.0 WinPE 3.1;"

      MSDN 参考:Description of the Windows Update Standalone Installer in Windows

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-31
        • 2012-01-04
        • 1970-01-01
        • 1970-01-01
        • 2019-08-01
        • 2014-10-01
        • 2010-12-09
        相关资源
        最近更新 更多