2009-04-15 325 views
1

作为随访至this question和阅读后罗布Mensching的blog post一个从this answer提及,似乎我试图用的MSIZap做到这一点的方式是一个坏主意我在测试中遇到了一些问题。如何解决一个拙劣的MSI安装程序,将无法卸载

在他之下,他会做什么不同的岗位上,他说:

与数据建立一个解决方案。 I 期望可以构建新的MSI以解决这些问题 。然后你发送 的修复和说明出来的所有 与问题。它会 可能类似 recache /重新安装(msiexec/fv, 支持的交换机)顶部 有问题的安装,然后卸载。 通过这种方式,机器保持已知的 状态,并且增量设置 得到改善。

如何构建这样一个MSI?我使用WiX的,问题是卸载过程试图后,因为它InstallFinalize后安排它被移除运行exe文件。 (忘了指定,它只能运行在安装无法卸载)

回答

0

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

2

根据卸载时的问题类型以及如何部署它,完全可以编写脚本并部署它以编辑机器上缓存的MSI以解决问题。您可以遍历C:\ Windows \ Installer \文件夹中的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 
+0

任何链接或资源如何做到这一点? – Davy8 2009-05-01 15:10:05