可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
We have an MSI based installer that recently stopped working on a Windows 2008 R2 environment. The installer is copied over to the target computer using the \\servername\c$\
admin UNC shares and then is remotely executed using the create method on the WMI Win32_Process class. The remote execution now fails with the following error message in the Event Viewer:
The description for Event ID 10837 from source MsiInstaller cannot be
found. Either the component that raises this event is not installed on
your local computer or the installation is corrupted. You can install
or repair the component on the local computer.
If the event originated on another computer, the display information
had to be saved with the event.
The following information was included with the event:
Product: OUR PRODUCT NAME -- The requested operation cannot
be completed. The computer must be trusted for delegation and the
current user account must be configured to allow delegation.
After searching it looks like this is caused by a recently released security patch for Windows Installer. When I uninstall KB2918614 the installer starts working again, and if I reinstall KB2918614 the MSI stops working again.
The error message indicates that to solve the issue we would have to have a Domain Administrator edit the target computer using Active Directory Users and Computers to allow delegation, however the MSI is NOT using any remote resources, so I don't see why this is required. The same MSI and remote execution process works fine on Windows Server 2012, so I wonder if this is an issue with the patch for 2008 R2.
Are there any other ways to get around this error message?
UPDATE: This doesnt appear to be an issue with the WMI remote execution, as it also occurs when we try to install the MSI remotely using Powershell, WinRM, and the Invoke-Commmand -ComputerName TargetComputer ...
cmdlet. There is a change in the way the Windows Installer on 2008 R2 works after installing KB2918614 that now prevents the custom action from completing it's task.
回答1:
From what I understand,
With KB2918614, MS have apparently tried to fix something in the Windows Installer Service.
New stuff:
- They are creating a file by name "SourceHash{PRODUCT-GUID}" under
%windir%\Windows\Installer. This is done for every product installed
on the machine(with KB2918614 already installed).
- SECREPAIR- They are computing 'Stored Hash Value' and 'Current Hash' for a given MSI.
Error:
And, in this comparison, for some reason, these mismatch! (Found these in the MSI verbose logs).
Once this fails, it looks for
Machine policy value 'AlwaysInstallElevated'
User policy value 'AlwaysInstallElevated'
Now, if you are running a silent install "qn", this error is thrown: MSI_LUA: Elevation prompt disabled for silent installs.
- Removing silent install cmdline option for msiexec- ex., "qr" or "qb", will throw a UAC prompt. (which most likely will not be the expected behavior).
Additional Info:
My MSI is ivkoded through a bootstrapper exe. But, it doesn't really matter. Even a manual call to msiexec through cmd line behaves the same way.
Any inputs/solutions, anyone?
回答2:
This is the word from the MS Enterprise Support folks.
Apparently they are not aware of any fix to this. At-least as of now.
All they are saying that this KB is to fix a security loophole.
I don't understand what kind of a security fix this is- one that allows a Fresh Install without an UAC prompt, but throws an UAC prompt only for the Upgrade.
Workaround 1: Distributing hash.
Capture the Hash file* in one machine and distribute them to other machines.
Hash files are created under “%windir%\installer” directory. The naming convention is as follows: “SourceHash
* This file is created only when a Product is installed with KB2918614 installed on the machine.This directory is hidden. Open cmd prompt using 'run as administrator'. Traverse to this path and open the folder using "explorer ." command.
[I couldn't solve the issue using this approach- may be because accessing this directory requires administrator privileges which the Windows Installer itself might not have]
Workaround 2: Whitelisting.
Only if you trust the application that it is always digitally signed and doesn't contain anything malicious(even in the future).
Step 1: Enable Whitelisting
Under Key “HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer”, create a DWORD: “SecureRepairPolicy” and set its Value to 2.
Step 2: Add the application to the whitelist
Create a new key “SecureRepairWhitelist” under "HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer” and create StringValues with the product codes(Including flower brackets {}) of the product.
... Sadly though, both these workarounds need admin privileges!
回答3:
Here is my automatic way of utilizing the registry whitelist work around mentioned on Microsoft's site.
Now, before I run my install command against a remote machine, I look at the MSI and extract the product code with Get-ProductCodeFromMSI, and then use Add-GuidToWhitelist to add each GUID to the list on that computer. Here's an example:
$guids = Get-ChildItem -Path D:\somefolder -filter "*.msi" -recurse | % {Get-ProductCodefromMSI $_.FullName}
Add-GUIDtoWhiteList -computername "SomeServer" -GUIDs $guids
Before doing that, each machine can be tested and repaired for the workaround using Test-SecureRepairPolicy and Repair-SecureRepairPolicy, respectively.
Get-ProductCodeFromMSI will require the DLL referenced to be placed somewhere and unblocked - this DLL can be retrieved from the Wix toolset.
Code for the functions I reference is here:
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'")
}
回答4:
I also encounter the issue. I got powershell script to install MSI on remote machines (using Invoke-Command cmdlet and provide the credential along with the script), but suddenly it failed to install MSI which I suppose also from this security patch.
After run the MSI installation file manually on target machine using the domain account (from remote desktop), suddenly the powershell script can run the MSI installation using domain account, but still failed to install if I used target machine local admin account.
I prefer to add this as a comment, but I don't have enough rep to do that. If the other has any solution or explanation for this I'd love to know that too. Thanks.
回答5:
This is to be to do with the SourceHash{product-code} files under \windows\installer directory.
This file can be opened with Orca you can read the contents. It contains a file name, hash algorithm specifier, and hash. On Windows 2k3 this hash is a base64ed sha256 hash with the last byte changed.
If you rename the SourceHash file for your product out of the way, I found the upgrade worked and after that a new SourceHash file is generated. You can then diff the two source hash files. In the case I am investigating, when you diff the two files only the hash listed for the original msi is different.
After a successful upgrade the hash of the new msi listed in the source hash file will match that of installation source. The broken sourcehash file was obviously generated from a modified/different source MSI, although I have as yet been unable to identify which.
回答6:
I have the same problem. MSIs failed to be installed with Invoke-Command PoSH. I've found that if I install any MSI on the server locally under the same account which is used for Invoke-Command the issue is fixed and Invoke-Command starts to work as usual.
回答7:
Response from Microsoft:
This security update resolves a privately disclosed vulnerability in Microsoft Windows. The vulnerability could allow elevation of privilege if an attacker runs a specially crafted application that attempts to repair a previously-installed application. An attacker must have valid logon credentials and be able to log on locally to exploit this vulnerability.
Workaround if you have problems with repairing application:
Uninstall the application and reinstall it with the security update installed. (sourcehash file generated with security update)
Manually copy the sourcehash file to c:\windows\installer folder. As the sourcehash file is generated based on the application files, the sourcehash file generated on computer A can be used on computer B.
http://happysccm.com/kb2918614-uac-gate/ - commands to uninstall it.
回答8:
I had this as well on different servers. After a few hours of digging I discovered that they could not reach the domain controllers. Check your DNS settings and ensure they can reach the AD. After fixing this this error disappeared.
回答9:
If you are executing through psexec, just adding the -s argument also resolves the error. Then it is ran as the remote system user and UAC is not required.