我有一个.msi,其中包含一些开发文件(gstreamer开发文件(,我想将.msi中的一些功能提取到某个文件夹中,而无需从命令行安装。
我知道如何使用msiexec的ADDLOCAL属性安装一些功能:
msiexec /i gstreamer.msi /qb TARGETDIR=somefolder ADDLOCAL=_gstreamer_1.0_system,_gstreamer_1.0_libav
但当我尝试在不使用管理安装的情况下提取文件时,ADDLOCAL属性似乎不起作用,它提取包中的所有文件:
msiexec /a gstreamer.msi /qb TARGETDIR=somefolder ADDLOCAL=_gstreamer_1.0_system,_gstreamer_1.0_libav
有人知道如何只从.msi中提取选定的功能而不将其安装到系统中吗?
简短回答 :进行转换,为要从文件提取中排除的功能设置
Feature Table => Level Column to 0
。按如下方式运行管理安装:msiexec.exe /a MySetup.msi TRANSFORMS=MyTransform.mst TARGETDIR=C:MyExtractPath
转换 :可能还有其他我目前想不出来的方法,但您可以尝试的一种方法是将转换应用于管理安装。根据MSI中功能的数量,这可能需要大量工作,也可能根本不需要太多工作(如果要排除的功能很少(。
功能级别
:MSI有一个特殊之处,即功能级别设置为0
的特性将不会在管理安装期间提取。对我来说,这似乎是一个bug(不过是设计出来的(,但你可以在这里用它来实现你想要的——我认为——但它并不漂亮。
- 变换 :对所有不想提取的特征进行变换,将"特征"表中的"级别"列设置为0
-
msiexec.exe :通过以下命令行将转换应用于MSI:
msiexec.exe /a MySetup.msi TRANSFORMS=MyTransform.mst TARGETDIR=C:MyExtractPath
工具
:您需要一个工具来帮助您进行此转换。你可能已经有了,但对于其他人:我推荐Orca.exe-微软自己的SDK工具。但是,您可以免费使用许多工具。这里描述了大多数(我认为(:如何比较两个(或多个(MSI文件的内容?(向下滚动到列表底部-dark.exe
是一个反编译器,而不是MSI查看器-链接描述了比较MSI文件,而不是更改它们(。
如果安装了Visual Studio,Orca.exe将已在磁盘上(很可能(。尝试在Program Files (x86)
下搜索Orca-x86_en-us.msi
。只需安装它并在开始菜单中找到奥卡(或搜索它(。
高级
:在上述"比较MSI"答案中链接了VBScript(widiffdb.vbs
(。它允许比较两个MSI文件。还有另一个VBScript,它允许您通过SQL语句更新MSI。请参阅此处:WiRunSQL.vbs。如果您安装了SDK,您可以在磁盘上找到这些脚本,也可以在github.com上找到它们。请参阅此答案底部的脚本使用示例如果有大量功能级别要设置为0,请尝试此操作。显然,将所有功能设置为0,然后通过将它们设置回正常(1或更高-取决于MSI(手动打开所需的功能。
实体模型
:将所有Feature levels
设置为0
的示例VBScript代码:
注意 请勿在主源MSI文件上运行此操作复制
此脚本中没有错误处理。要生成转换,请参阅此处的示例(根据原始和修改后的MSI文件之间的差异生成转换(。
Const msiOpenDatabaseModeTransact = 1
Const msiViewModifyReplace = 4
Set installer = CreateObject("WindowsInstaller.Installer")
Set database = installer.OpenDatabase("Test.msi", msiOpenDatabaseModeTransact)
' Allow user to cancel operation
If MsgBox ("Only run this on a COPY of your MSI!" & vbNewLine & vbNewLine & "Continue?", vbYesNo + vbInformation, "Warning!") = vbNo Then
MsgBox "Update Aborted.", vbOKOnly + vbInformation, "Aborted"
WScript.Quit(0)
End If
sql = "SELECT * FROM `Feature`"
Set view = database.OpenView(sql)
view.Execute()
Do
Set record = view.Fetch()
If record Is Nothing Then Exit Do
record.IntegerData(6) = 0
view.Modify msiViewModifyReplace, record
Loop
view.Close()
database.Commit()
MsgBox "Update Complete.", vbOKOnly + vbInformation, "Completed"