Extract MSI Installer
Problem
You need to extract files from an MSI installer to analyze its contents or access specific files without running the installer.
Solution
Use Excavate with recursive extraction to handle the nested CAB archives:
require 'excavate'
# Create archive instance
archive = Excavate::Archive.new('installer.msi')
# Extract with recursive option to get all files
archive.extract(recursive_packages: true)Complete Example
require 'excavate'
require 'fileutils'
class MsiExtractor
def initialize(msi_path)
@msi_path = msi_path
@archive = Excavate::Archive.new(msi_path)
end
def extract_all(target = nil)
target ||= default_target
# Remove existing target if any
FileUtils.rm_rf(target) if File.exist?(target)
# Extract with recursive option
@archive.extract(target, recursive_packages: true)
puts "Extracted to: #{target}"
target
end
def extract_files(file_patterns, target = nil)
target ||= default_target
# Extract specific files
extracted = @archive.extract(
target,
recursive_packages: true,
files: file_patterns
)
puts "Extracted #{extracted.size} files"
extracted
end
def extract_by_filter(pattern, target = nil)
target ||= default_target
# Extract matching files
extracted = @archive.extract(
target,
recursive_packages: true,
filter: pattern
)
puts "Extracted #{extracted.size} files matching #{pattern}"
extracted
end
def list_contents
files = []
@archive.files(recursive_packages: true) do |path|
files << path
end
files.sort
end
private
def default_target
File.basename(@msi_path, '.msi')
end
end
# Usage
extractor = MsiExtractor.new('installer.msi')
# List contents
puts "Contents:"
extractor.list_contents.each { |f| puts " #{f}" }
# Extract everything
extractor.extract_all
# Extract only DLLs
extractor.extract_by_filter('**/*.dll')
# Extract specific files
extractor.extract_files(['data1.cab/config.ini', 'data1.cab/README.txt'])