Как программно проверить правила применения обновления Windows?

Изучая содержимое файла .msu для обновления Windows (например, используя такой инструмент, как 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 для этой цели? Или есть инструмент / script?

То, что я на самом деле хочу, - это точно знать, какое условие заставил компьютер отклонить определенное обновление Windows (KB2973201) с сообщением. Обновление не применимо к вашему компьютеру (код ошибки позади этого - WU_E_NOT_APPLICABLE).

Кажется, что слишком мало документации относительно этих правил применимости обновления. Есть ли хорошие источники?

Литература:

Ответы

Ответ 1

Теперь, учитывая определенный .msu файл и мой локальный компьютер, есть ли способ перебрать эти правила и выяснить, не удовлетворен ли он - и какой?
Могу ли я использовать библиотеку классов WSUS 3.0 для этой цели? Или есть инструмент / script?

Вы можете Обновить правила применимости через библиотеку классов WSUS 3.0, хотя она не предлагает функциональности, чтобы проверить, пройдут ли правила, если ( Я полагаю), вы запускаете установщик, но это не говорит вам, какой из них не удалось.

Саймон упомянул, что библиотека WUAPI не раскрывает внутренние правила, и (afaik) нет способа сопоставить WUAPI ResultCodes с ApplicabilityRules, которые терпят неудачу.

И, к сожалению, библиотеки, такие как Microsoft.Deployment.WindowsInstaller.dll, не работают с файлами MSU, поэтому нам не повезло с "готовыми" вариантами. Поэтому вам нужно сделать это вручную с кодом и XML файлом (msu.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;
}
}

Прежде чем запускать Правила применимости, лучше всего проверить, будет ли обновление проходить тест применимости операционной системы (ОС) и пакета обновления SP (SP). Нет никакого смысла проверять реестр /wmi и т.д., Чтобы определить, будет ли обновление проходить правила, если оно не применимо к ОС и SP.

Чтобы просмотреть приложение 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 Embedded SP1, Windows 7.0 Server SP1, Windows 7.0 WinPE 3.1;"

MSDN Ref: Описание автономного установщика Windows Update в Windows

Ответ 2

Вы можете использовать API агента Windows Update для запроса установленных обновлений (на самом деле у него много информации), что-то вроде этого:

  // 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 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"));
      }
  }

Однако это не скажет вам, какие внутренние правила (реестр/wmi и т.д.) используются для определения того, были ли установлены обновления. Это не распространяется на WUAPI.