我们有一个基于MSI的安装程序,最近停止在Windows 2008 R2环境中工作。使用\\servername\c$\
admin UNC共享将安装程序复制到目标计算机,然后使用WMI Win32_Process class上的create方法远程执行。远程执行现在失败,并在事件查看器中显示以下错误消息:
来自源MsiInstaller的事件ID 10837的描述不可能 找到。未安装引发此事件的组件 您的本地计算机或安装已损坏。你可以安装 或修复本地计算机上的组件。
如果事件源自另一台计算机,则显示信息 不得不与事件一起得救。
活动中包含以下信息:
产品:我们的产品名称 - 请求的操作不能 完成。必须信任计算机才能授权和使用 必须将当前用户帐户配置为允许委派。
搜索后,看起来这是由最近发布的security patch for Windows Installer引起的。当我卸载KB2918614时,安装程序再次开始工作,如果我重新安装KB2918614,MSI将再次停止工作。
错误消息表明要解决此问题,我们必须让域管理员使用Active Directory Users and Computers编辑目标计算机以允许委派,但MSI不使用任何远程资源,因此我不会这样做。看看为什么这是必需的。相同的MSI和远程执行过程在Windows Server 2012上运行正常,所以我想知道这是否是2008 R2补丁的问题。
还有其他方法可以解决此错误消息吗?
UPDATE :这似乎不是WMI远程执行的问题,因为当我们尝试使用Powershell,WinRM和Invoke-Commmand -ComputerName TargetComputer ...
cmdlet远程安装MSI时也会出现这种情况。 。安装KB2918614后,2008 R2上的Windows Installer的工作方式发生了变化,现在阻止自定义操作完成它的任务。
答案 0 :(得分:5)
据我了解,
对于KB2918614,MS显然已尝试在Windows Installer服务中修复某些内容。
而且,在这种比较中,出于某种原因,这些不匹配! (在MSI详细日志中找到这些)。
一旦失败,它会寻找 机器政策价值' AlwaysInstallElevated' 用户政策值' AlwaysInstallElevated'
现在,如果您正在运行静默安装" qn",则会抛出此错误:MSI_LUA:已禁用静默安装的提升提示。
我的MSI通过bootstrapper exe进行了ivk。但是,它并不重要。即使通过cmd行手动调用msiexec的行为也是一样的。
任何输入/解决方案,任何人?
答案 1 :(得分:3)
这是来自MS Enterprise支持人员的话。
显然他们不知道对此有任何解决方法。至少截至目前。 他们只是说这个KB是为了修复安全漏洞。 我不明白这是什么类型的安全修复程序 - 允许在没有UAC提示的情况下进行全新安装,但仅为升级引发UAC提示。
解决方法1: 分发哈希。
在一台计算机中捕获哈希文件*并将其分发到其他计算机。 散列文件在“%windir%\ installer”目录下创建。命名约定如下:“SourceHash *仅当在计算机上安装了KB2918614安装了产品时才会创建此文件。此目录已隐藏。使用“以管理员身份运行”打开cmd提示符。遍历此路径并使用“资源管理器”打开文件夹。命令。 [我无法使用此方法解决问题 - 可能是因为访问此目录需要Windows安装程序本身可能没有的管理员权限]
解决方法2: 白名单。
只有当您信任该应用程序时,它始终经过数字签名并且不包含任何恶意内容(即使将来)。
第1步:启用白名单
在Key“HKLM \ SOFTWARE \ Policies \ Microsoft \ Windows \ Installer”下,创建一个DWORD:“SecureRepairPolicy”并将其值设置为2.
第2步:将应用程序添加到白名单
在“HKLM \ SOFTWARE \ Policies \ Microsoft \ Windows \ Installer”下创建一个新密钥“SecureRepairWhitelist”,并使用产品的产品代码(包括花括号{})创建StringValues。
......可悲的是,这两种解决方法都需要管理员权限!
答案 2 :(得分:3)
这是我在微软网站上提到的利用注册表白名单工作的自动方式。
现在,在我对远程计算机运行安装命令之前,我查看MSI并使用Get-ProductCodeFromMSI提取产品代码,然后使用Add-GuidToWhitelist将每个GUID添加到该计算机上的列表中。这是一个例子:
$guids = Get-ChildItem -Path D:\somefolder -filter "*.msi" -recurse | % {Get-ProductCodefromMSI $_.FullName}
Add-GUIDtoWhiteList -computername "SomeServer" -GUIDs $guids
在此之前,可以分别使用Test-SecureRepairPolicy和Repair-SecureRepairPolicy对每台计算机进行测试和修复以解决此问题。
Get-ProductCodeFromMSI将要求引用的DLL放在和unblocked 的某个位置 - 可以从Wix工具集中检索此DLL。
我参考的函数代码在这里:
Function Test-SecureRepairPolicy{
param (
[Parameter(mandatory=$true,ValueFromPipelineByPropertyName=$true)][string[]]
# Specifies the computer name to connect to
$ComputerName
)
Process {
foreach ($Computer in $ComputerName)
{
#Open Remote Base
$reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$Computer)
#Get Windows key
$subkey = $reg.OpenSubKey("SOFTWARE\Policies\Microsoft\Windows")
$subkeynames = $subkey.GetSubKeyNames()
if (($subkeynames | Measure-Object).Count -lt 1){
return New-Object -type PSObject -Property @{
Success = $False
Note = "Can not open base key"
ComputerName = $Computer
}
}
if ($subkeynames -notcontains "Installer"){
return New-Object -type PSObject -Property @{
Success = $False
Note = "Can not locate installer subkey"
}
}
$subkey.Close();$subkey = $null
$subkey = $reg.OpenSubKey("SOFTWARE\Policies\Microsoft\Windows\Installer")
$subkeynames = $subkey.GetSubKeyNames()
if ($subkeynames -notcontains "SecureRepairWhitelist"){
return New-Object -type PSObject -Property @{
Success = $False
Note = "Can not locate repairlist subkey"
ComputerName = $Computer
}
}
$repairvalue = $subkey.GetValue("SecureRepairPolicy")
if ($repairvalue -ne 2){
return New-Object -type PSObject -Property @{
Success = $False
Note = "SecureRepairPolicy is incorrect"
ComputerName = $Computer
}
}
$subkey.Close();$subkey = $null;$reg.Close();$reg = $null
return New-Object -type PSObject -Property @{
Success = $True
Note = "SecureRepairPolicy structure is in place"
ComputerName = $Computer
}
}
}
}
Function Repair-SecureRepairPolicy{
param (
[Parameter(mandatory=$true,ValueFromPipelineByPropertyName=$true)][string[]]
# Specifies the computer name to connect to
$ComputerName
)
Begin{
Function Add-RemoteRegistryKey($Computer,$Parent,$Name){
$reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$Computer)
$subkey = $reg.OpenSubKey($Parent, $true)
$subkey.CreateSubKey($Name)
$subkey.Close();$subkey = $null;$reg.Close();$reg = $null
}
Function Add-InstallerKey($Computer){
Add-RemoteRegistryKey $Computer "SOFTWARE\Policies\Microsoft\Windows" "Installer"
}
Function Add-RepairPolicy($Computer){
$reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$Computer)
$subkey = $reg.OpenSubKey("SOFTWARE\Policies\Microsoft\Windows\Installer", $true)
$subkey.SetValue("SecureRepairPolicy",2, "DWORD")
$subkey.Close();$subkey = $null;$reg.Close();$reg = $null
}
Function Add-WhitelistKey($Computer){
Add-RemoteRegistryKey $Computer "SOFTWARE\Policies\Microsoft\Windows\Installer" "SecureRepairWhitelist"
}
}
Process {
foreach ($Computer in $ComputerName)
{
$audit = Test-SecureRepairPolicy $computer
if ($audit.Success){
Write-Output "Repair whitelist keys setup. No repair being performed."
}
else{
Write-Output "Repair whitelist keys not setup. Attempting to resolve"
if ($audit.Note -match "Can not open base key"){
Write-Error "Unable to open computer's registry key"
return
}
if ($audit.Note -match "Can not locate installer subkey"){
Add-Installerkey $Computer
Add-RepairPolicy $Computer
Add-WhitelistKey $Computer
}
if ($audit.Note -match "Can not locate repairlist subkey"){
Add-RepairPolicy $Computer
Add-WhitelistKey $Computer
}
if ($audit.Note -match "Can not locate repairlist subkey"){
Add-RepairPolicy $Computer
}
Write-Output "Showing new audit"
Test-SecureRepairPolicy $computer
}
}
}
}
Function Add-GUIDtoWhiteList{
param (
[Parameter(mandatory=$true,ValueFromPipelineByPropertyName=$true)][string[]]
# Specifies the computer name to connect to
$ComputerName,
[Parameter(mandatory=$true)][string[]]
# Specifies the GUID(s) to add.
$GUIDs
)
Process {
foreach ($Computer in $ComputerName)
{
#Open Remote Base
$reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$Computer)
$subkey = $reg.OpenSubKey("SOFTWARE\Policies\Microsoft\Windows\Installer\SecureRepairWhitelist", $true)
foreach($GUID in $GUIDs){
$subkey.SetValue($GUID,"", "String")
}
$subkey.Close();$subkey = $null;$reg.Close();$reg = $null
}
}
}
Function Get-ProductCodefromMSI ($msi){
[Reflection.Assembly]::LoadFrom("D:\scripts\lib\Microsoft.Deployment.WindowsInstaller.dll") | out-null
(New-Object -TypeName Microsoft.Deployment.WindowsInstaller.Database -ArgumentList $msi).ExecuteQuery("SELECT Value FROM Property WHERE Property = 'ProductCode'")
}
答案 3 :(得分:1)
我也遇到了这个问题。我有PowerShell脚本在远程机器上安装MSI(使用Invoke-Command cmdlet并提供凭证和脚本),但突然无法安装MSI,我想也是从这个安全补丁。
使用域帐户(从远程桌面)在目标计算机上手动运行MSI安装文件后,powershell脚本突然可以使用域帐户运行MSI安装,但如果我使用目标计算机本地管理员帐户仍然无法安装。
我更喜欢将其添加为评论,但我没有足够的代表来做到这一点。如果对方有任何解决方案或解释,我也很想知道。感谢。
答案 4 :(得分:1)
这与\ windows \ installer目录下的SourceHash {product-code}文件有关。 这个文件可以用Orca打开,你可以阅读内容。它包含文件名,哈希算法说明符和哈希。在Windows 2k3上,此哈希是base64ed sha256哈希,最后一个字节已更改。
如果您重命名产品的SourceHash文件,我发现升级工作正常,之后会生成新的SourceHash文件。然后,您可以区分两个源哈希文件。在我正在研究的情况下,当您对两个文件进行区分时,只有原始msi列出的哈希值不同。 成功升级后,源哈希文件中列出的新msi的哈希值将与安装源的哈希值相匹配。破碎的sourcehash文件显然是从修改后的/不同的源MSI生成的,尽管我还是无法识别哪个。
答案 5 :(得分:1)
我有同样的问题。无法使用Invoke-Command PoSH安装MSI。我发现如果我在本地服务器上在用于Invoke-Command的同一帐户下安装任何MSI,问题就解决了,Invoke-Command开始像往常一样工作。
答案 6 :(得分:0)
微软的回应: 此安全更新可解决Microsoft Windows中一个秘密披露的漏洞。如果攻击者运行试图修复以前安装的应用程序的特制应用程序,则该漏洞可能允许特权提升。攻击者必须拥有有效的登录凭据,并且能够在本地登录才能利用此漏洞。
卸载应用程序并在安装了安全更新的情况下重新安装。 (使用安全更新生成的sourcehash文件)
将sourcehash文件手动复制到c:\ windows \ installer文件夹。由于sourcehash文件是基于应用程序文件生成的,因此计算机A上生成的sourcehash文件可以在计算机B上使用。
http://happysccm.com/kb2918614-uac-gate/ - 卸载它的命令。
答案 7 :(得分:0)
我在不同的服务器上也有这个。经过几个小时的挖掘后,我发现他们无法访问域控制器。检查您的DNS设置,确保他们可以访问AD。修好后,此错误消失了。
答案 8 :(得分:0)
如果您正在执行psexec,只需添加-s参数也可以解决错误。然后它作为远程系统用户运行,不需要UAC。