12

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

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

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

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

从合并模块中提取文件

Orca 支持三种不同的方法来提取包含在合并模块中的文件。Orca 可以提取单个 CAB 文件,将文件提取到模块树中,并在将文件合并到目标数据库后将文件提取到源图像中......

提取文件

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

... -x ... 命令行上的选项,其中是新目录树的所需路径。

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

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

orca -x theDirectory theModule.msm

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

然后我尝试了 msidb,我做了几次尝试,如下所示:

msidb -d theModule.msm -w {存储}

msidb -d theModule.msm -x MergeModule.CABinet

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

有人可以解释我在命令行选项上做错了什么吗?有没有其他工具可以做到这一点?

4

5 回答 5

14

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

dark.exe myMergeModule.msm -x "path_to_extracted_files"

这些文件将被提取到 -x 参数中指定的路径。

注意:将使用安装数据库的文件表中指定的名称提取文件,这实际上可能不是实际安装文件时使用的文件名。如果您需要使用实际文件名提取文件,请参阅我对此问题的其他答案:从合并模块中提取文件

于 2012-07-27T15:08:39.273 回答
5

为此,我只需要创建一个空白 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
    

文件将被提取到 -x 参数指定的目录(在本例中为.\xdir)。

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

于 2012-07-27T14:59:01.357 回答
1

WiX中的 DeploymentToolsFoundation 类库有一个带有 ExtractFiles() 方法的 InstallPackage 类,该方法应该可以满足您的需求,但合并模块失败。这似乎是一个错误

以下 PowerShell 脚本使用 DTF 访问合并模块中的 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()
}
于 2010-12-16T09:32:55.243 回答
1

我遇到了类似的问题,但我从不同的方向着手。

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

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

于 2012-05-10T09:08:06.587 回答
0

MSI2XML

于 2010-04-23T21:36:42.027 回答