如何修复无法卸载的拙劣MSI安装程序

时间:2009-04-15 20:36:10

标签: windows-installer

作为this question的后续内容,在阅读了blog post提到的Rob Mensching this answer之后,似乎我尝试使用msizap进行操作的方式是一个坏主意我在测试中看到了一些问题。

在他以不同的方式做的事情中,他说:

  

利用数据构建解决方案。一世   期望建立一个新的MSI   解决问题。然后你发送   所有的修复和指示   那些有问题的人。它会   可能是类似的东西   recache / reinstall(msiexec / fv,a   支持开关)顶部   有问题的安装然后卸载。   这样机器就知道了   状态和设置递增   提高。

如何构建这样的MSI?我正在使用WiX,问题是卸载过程试图在删除之后运行exe,因为它是在InstallFinalize之后安排的。 (忘了指定它应该只在安装而不是卸载时运行)

2 个答案:

答案 0 :(得分:2)

根据您在卸载时遇到的问题类型以及如何部署它,完全可以编写脚本并对其进行部署以编辑计算机上的缓存MSI以解决问题。您可以遍历C:\ Windows \ Installer \文件夹中的MSI来查找产品的MSI(打开所有内容并阅读摘要信息)

一旦找到了你需要的那个,你可以直接修改表来修复你引入的任何问题(即在卸载时禁用自定义操作等),下次调用卸载时不会发生问题。

资源:
Windows Installer SQL Reference
Windows Installer Automation Interface Reference

包括一个示例脚本,我应该指出,这主要是因为内部部署的应用程序并不是真正可以作为修复程序发送给客户的东西,但它可以创建一个二进制文件来执行相同的操作并将其包含在内说一个setup.exe,其中二进制文件首先开始清理并删除以前的卸载然后放下新的卸载,或者只是发送二进制文件来修复卸载问题。

Option Explicit

Dim objFS, objShell
Dim objFolder, objFiles, objFile
Dim objInstaller
Dim installerPath, titleToFind
Dim queries

Const msiOpenDatabaseReadOnly = 0
Const msiOpenDatabaseTransact = 1

Set objInstaller = CreateObject("WindowsInstaller.Installer")

Set objShell = CreateObject("WScript.Shell")
installerPath = objShell.ExpandEnvironmentStrings("%SystemRoot%") & "\Installer\"

'Set the title you want to use for comparison
titleToFind = "Sample"
' Define the queries you wish to run against the database if found
queries = Array(    "UPDATE `InstallExecuteSequence` SET `Condition` = 'NOT Installed' WHERE `Action` = 'SampleAction'", _
                    "DELETE FROM `InstallExecuteSequence` WHERE `Action` = 'SampleAction'")

Set objFS = CreateObject("Scripting.FileSystemObject")
On Error Resume Next
If ( objFS.FolderExists(installerPath)) Then
    Set objFolder = objFS.GetFolder(installerPath) 
    Set objFiles = objFolder.Files

    For Each objFile in objFiles
        If ( StrComp ( Right(objFile.Name, 4), ".msi") = 0 ) Then
            If ( CheckMSI (installerPath & objFile.Name, titleToFind) ) Then
                UpdateMSI ( installerPath & objFile.name)
                Exit For
            End If
        End If
    Next
End If

Set objFS = Nothing
Set objShell = Nothing
Set objFile = Nothing
Set objFiles = Nothing
Set objFolder = Nothing
Set objInstaller = Nothing

' Check if the title in the MSI matches the one you are looking for
Function CheckMSI ( msiPath, title)
    Dim objDatabase, objSummary
    Dim msiTitle
    Set objDatabase = objInstaller.OpenDatabase ( msiPath, msiOpenDatabaseReadOnly ) : CheckError
    Set objSummary = objDatabase.SummaryInformation(0)

    msiTitle = objSummary.Property(2)

    If ( StrComp ( msiTitle, title) = 0 ) Then
        CheckMSI = true
    Else
        CheckMSI = false
    End If

    Set objSummary = Nothing
    Set objDatabase = Nothing
End Function

' Loop though the queries specified above and execute them against the MSI
Function UpdateMSI (msiPath)
    Dim objDatabase
    Dim objView
    Dim query

    Set objDatabase = objInstaller.OpenDatabase(msiPath, msiOpenDatabaseTransact) : CheckError
    For Each query in queries
        Set objView = objDatabase.OpenView (query) : CheckError
        objView.Execute : CheckError
    Next
    objDatabase.Commit

    Set objView = Nothing
    Set objDatabase = Nothing
End Function 

Sub CheckError
      Dim message, errRec
      If Err = 0 Then Exit Sub
      message = Err.Source & " " & Hex(Err) & ": " & Err.Description
      If Not installer Is Nothing Then
            Set errRec = installer.LastErrorRecord
            If Not errRec Is Nothing Then message = message & vbLf & errRec.FormatText
      End If
      Fail message
End Sub

Sub Fail ( message )
    WScript.Echo message
    WScript.Quit 2
End Sub

答案 1 :(得分:0)

如果MSI不会卸载你可能只需要使用MSI zap。它不会删除任何文件,但您可以使用Orca查看MSI中所有文件的列表并手动删除它们。