通过浏览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)。
有关更新的这些适用性规则的文档似乎太少。有什么好的消息来源吗?
参考文献:
答案 0 :(得分:6)
现在,给定一个.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)适用性测试。 没有必要检查registry / wmi等,以确定升级是否会通过规则,如果它不适用于OS和SP 。
要查看ApplicabilityInfo,请运行展开命令行实用程序:
expand -f:* "C:\temp\msu\Windows6.1-KB2973201-x64.msu" "C:\temp\msu"
这将创建以下文件:
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参考:Description of the Windows Update Standalone Installer in Windows
答案 1 :(得分:2)
您可以使用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公开的。