修复导致错误 2908 和"UNKNOWNComponents"注册表项的 MSI 卸载失败的答案



问题与失败的MSI包卸载导致进一步的安装尝试返回错误2908在MSI日志(msiexec返回1603)已经出现在很多不同的论坛,所以我只是想给我的解决方案,因为我们已经出现了它现在和然后多年来,我从来没有见过一个程序化的解决方案。

一般原因是MSI卸载程序在SOFTWAREMicrosoftWindowsCurrentVersionInstallerUserDataS-1-5-18Components下的LOCALMACHINE hive的注册表中创建了"孤立键"

典型的MSIEXEC日志错误如下所示:

MSI (s) (2C:0C)[14:52:21:49]:注:1:14 01 2:UNKNOWNComponentsB44598ECC622C01BD780AEC8E234E3E1 3:5调试:错误2908:无法注册组件{CE89544B-226C-B10C-7D08-EA8C2E433E1E}。MSI (s) (2C:0C) [14:52:21:523]: Product: Some software 3.7——安装程序在安装此软件包时遇到意外错误。这可能表明这个包有问题。错误码为2908。参数为:{CE89544B-226C-B10C-7D08-EA8C2E433E1E},,

正如其他帖子所指出的,您可以从MSI日志文件中找到密钥并使用Regedit编辑它们,执行"属性"one_answers"高级",将其所有者从"无法显示当前所有者"(或类似文本)更改为"管理员",并最终设置其访问权限,如此链接所示:

https://kb.acronis.com/content/33458

然而,这很麻烦,你可以得到数百个破碎的物品。更糟糕的是,上面的手动过程似乎在Windows 10中有问题,并且没有更多的"Windows修复"工具可用。

那么如何自动修复这个呢?这些"损坏"的注册表项很难更改,即使作为高级管理员导致各种错误,因此为了确保成功,我在SYSTEM帐户中将其作为服务运行。

因此,我在visual studio中创建了一个windows服务项目,运行为SYSTEM (SID S-1-5-18),然后我们打开违规条目的父键:

RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey regParent = hklm.OpenSubKey(
   "SOFTWAREMicrosoftWindowsCurrentVersionInstallerUserDataS-1-5-18Components",
   RegistryKeyPermissionCheck.ReadWriteSubTree,
   RegistryRights.FullControl);

当使用

打开每个子密钥时,可以通过安全异常检测损坏的密钥。
regKey = regParent.OpenSubKey(
   registryKeyName,
   RegistryKeyPermissionCheck.Default,
   RegistryRights.TakeOwnership | RegistryRights.ReadPermissions | RegistryRights.ReadKey))

对我来说,msiexec似乎已经添加了一个"管理用户"的问题,更糟糕的是,规则继承已经完全停止工作,出于某种原因,我认为这是这regedit不能显示密钥的所有者,这实际上仍然是系统,所以密钥并不是真正孤儿在第一位。它也不能帮助删除这个奇怪的Admin用户条目的RegistryAccessRule。解决方案是在regParent中为用户重新应用规则,因为这似乎也会更新和"治愈"所有子节点。

这样做就足够了:

   security = regParent.GetAccessControl(AccessControlSections.All);
    security.AddAccessRule(new RegistryAccessRule(
        new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null),
        RegistryRights.FullControl,
        InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
        PropagationFlags.None, // Self+Children
        AccessControlType.Allow));
    security.AddAccessRule(new RegistryAccessRule(
        new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null),
        RegistryRights.FullControl,
        InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
        PropagationFlags.None, // Self+Children
        AccessControlType.Allow));
    security.AddAccessRule(new RegistryAccessRule(
        new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null),
        RegistryRights.ReadPermissions | RegistryRights.ReadKey | RegistryRights.EnumerateSubKeys | RegistryRights.QueryValues,
        InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
        PropagationFlags.None, // Self+Children
        AccessControlType.Allow));
    regParent.SetAccessControl(security);

这应该足以使Regedit工作,并且Msiexec再次更改其键。你现在可以修复/删除你的失败的卸载。

此外,我还创建了一个简单的包装器应用程序,它在SYSTEM帐户中安装并启动服务,然后在清理过程结束时卸载它。

希望这能帮助那些和我们有同样问题的人!

最新更新