从合并模块中提取文件

时间:2010-04-23 18:00:19

标签: installer windows-installer extract merge-module orca

我想要的只是一个命令行工具,可以将合并模块(.msm)中的文件提取到磁盘上。换句话说,我想要一个MSI可能的“管理安装”功能:

msiexec / a myProduct.msi TARGETDIR =“C:\ myInstallation”/ qn

以上只适用于msi(我可以告诉你)。因此,为了获得合并模块的相同效果,我正在尝试msidb.exe和orca.exe orca的文档说明:

  

许多合并模块选项都可以   从命令行指定...

     

从合并模块中提取文件

     

Orca支持三种不同的方法   用于提取包含在文件中的文件   合并模块。逆戟鲸可以提取出来   单个CAB文件,解压缩文件   进入模块树并提取   文件一旦进入源图像   已合并到目标数据库......

     

提取文件

     

从a中提取单个文件   合并模块,使用

     

... -x ...选项   命令行,在哪里   新目录的所需路径   树。

     

指定的路径用作根   提取文件的路径。所有   文件从CAB文件中提取   嵌入模块并放入   指定的路径。目录   提取文件的布局是   基于目录树   合并模块。

这听起来像我需要的。但是当我尝试它时,orca只是打开一个编辑器(在我指定的msm上有信息)然后什么都不做。我尝试了各种命令行,通常从这开始:

orca -x theDirectory theModule.msm

我使用“theDirectory”作为我想要的任何空文件夹。就像我说的 - 它没有做任何事情。

然后我尝试了msidb,我做了几次尝试:

msidb -d theModule.msm -w {storage}

msidb -d theModule.msm -x MergeModule.CABinet

在第一种情况下,我不知道要为{storage}放什么。在第二种情况下,事实证明文字字符串“MergeModule.CABinet”是必要的(它是保留名称)。但是,提取的机柜不保留文件层次结构或“正常”文件名;所以我不能将它用于我的目的。

有人可以用命令行选项解释我的错误吗?有没有其他工具可以做到这一点?

5 个答案:

答案 0 :(得分:9)

您可以使用WiX附带的反编译工具(称为Dark)来反编译合并模块并提取文件:

dark.exe myMergeModule.msm -x "path_to_extracted_files"

文件将被引用到-x参数中指定的路径。

注意:将使用安装数据库的File表中指定的名称提取文件,这些名称实际上可能不是实际安装文件时使用的文件名。如果您需要使用实际文件名提取文件,请参阅此问题的其他答案:Extracting files from merge module

答案 1 :(得分:2)

我必须通过创建一个空白msi然后使用Orca尝试将模块合并到我的msi中然后提取文件来完成此操作。

  1. 创建一个空白.msi。我使用WiX 3.6来创建.msi,而下面是最小的来源。我把它命名为“blank.msi”。

    <?xml version="1.0" encoding="UTF-8"?>
    <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
        <Product Id="*" Name="blank" Language="1033" Version="1.0.0.0" Manufacturer="blank" UpgradeCode="298878d0-5e7b-4b2e-84f9-45bb66541b10">
            <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
    
            <MediaTemplate />
    
            <Directory Id="TARGETDIR" Name="SourceDir">
                <Directory Id="ProgramFilesFolder"/>
            </Directory>
    
            <ComponentGroup Id="ProductComponents" Directory="ProgramFilesFolder" />
    
            <Feature Id="ProductFeature" Title="blank" Level="1">
                <ComponentGroupRef Id="ProductComponents" />
            </Feature>
         </Product>
    </Wix>
    
  2. 使用Orca从合并模块中提取文件。

    orca -m "myModule.msm" -f ProductFeature -x .\xdir blank.msi
    
  3. 文件将被解压缩到-x参数指定的目录(在本例中为。\ xdir )。

    请注意,-f参数“ ProductFeature ”的值与上面msi文件中指定的要素的名称相匹配。

答案 2 :(得分:1)

WiX中的DeploymentToolsFoundation类库有一个带有ExtractFiles()方法的InstallPackage类,该方法应该只是你想要的,但是对于Merge Modules来说是失败的。这似乎是bug

以下PowerShell脚本(使用DTF访问mergemodule中的CAB)应该可以执行您想要的操作。如果脚本有点不稳定,我很抱歉,我是PowerShell的新手。

[Reflection.Assembly]::LoadFrom("[InsertPath]\Microsoft.Deployment.WindowsInstaller.dll")

function ExtractMSM([string]$file, [string]$targetDir)
{
    write-host "Extracting files from merge module: "$file

    if(![IO.Directory]::Exists($targetDir)) { new-item -type directory -path $targetDir }

    $cabFile = join-path $targetDir "temp.cab"
    if([IO.File]::Exists($cabFile)) { remove-item $cabFile }

    $db = new-object Microsoft.Deployment.WindowsInstaller.DataBase($file, [Microsoft.Deployment.WindowsInstaller.DataBaseOpenMode]::ReadOnly)
    $view = $db.OpenView("SELECT `Name`,`Data` FROM _Streams WHERE `Name`= 'MergeModule.CABinet'")
    $view.Execute()
    $record = $view.Fetch()
    $record.GetStream(2, $cabFile)
    $view.Dispose()

    expand -F:* $cabFile $targetDir

    remove-item $cabFile

    $extractedFiles = get-childitem $targetDir
    $hashFiles = @{}
    foreach($extracted in $extractedFiles)
    {
        try
        {
            $longName = $db.ExecuteScalar("SELECT `FileName` FROM `File` WHERE `File`='{0}'", $extracted.Name) 
        }
        catch 
        {
            write-host "$($extracted.Name) is not in the MSM file"
        }

        if($longName)
        {
            $longName = $LongName.SubString($LongName.IndexOf("|") + 1)
            Write-host $longName

            #There are duplicates in the 
            if($hashFiles.Contains($longName))
            {
                write-host "Removing duplicate of $longName"
                remove-item $extracted.FullName
            }
            else
            {
                write-host "Rename $($extracted.Name) to $longName"
                $hashFiles[$longName] = $extracted
                $targetFilePath = join-path $targetDir $longName
                if([IO.File]::Exists($targetFilePath)) {remove-item $targetFilePath}
                rename-item $extracted.FullName -NewName $longName    
            }
        }
    }
    $db.Dispose()
}

答案 3 :(得分:1)

我遇到了类似的问题,但我从另一个方向开始。

我安装了早期版本的Visual Studio附带的InstallSheild Express,创建了一个新项目,但我只添加了我需要的MSM文件。

编译并运行我的新安装后,我能够检索MSM文件包含的文件。

答案 4 :(得分:0)