class WindowsInstaller
Public Class Methods
default_options(hash)
click to toggle source
# File lib/WindowsInstaller.rb, line 15 def self.default_options(hash) hash.each { |key,value| @@default_options[key] = value } end
new(options = {})
click to toggle source
# File lib/WindowsInstaller.rb, line 8 def initialize(options = {}) @@default_options.each { |key, value| self[key] = value } options.each { |key, value| self[key] = value} @installer = WIN32OLE.new('WindowsInstaller.Installer') end
Public Instance Methods
install_msi(msi_file)
click to toggle source
# File lib/WindowsInstaller.rb, line 36 def install_msi(msi_file) raise "#{msi_file} does not exist!" unless(File.exists?(msi_file)) msi_file = File.absolute_path(msi_file).gsub(/\//, '\\') cmd = "msiexec.exe" cmd = "#{cmd} #{self[:mode]}" if(has_key?(:mode)) cmd = "#{cmd} /i #{msi_file}" msiexec(cmd) raise "Failed to install msi_file: #{msi_file}" unless(msi_installed?(msi_file)) end
installation_properties(product_name_or_product_code)
click to toggle source
# File lib/WindowsInstaller.rb, line 98 def installation_properties(product_name_or_product_code) product_code = product_name_or_product_code properties = installed_properties(product_code) if(properties.nil?) product_name = product_name_or_product_code product_code = installed_get_product_code(product_name) return nil if(product_code == '') properties = installed_properties(product_code) end return nil if(properties.nil?) upgrade_code = get_upgrade_code(product_code) properties['UpgradeCode'] = upgrade_code unless(upgrade_code.nil?) return properties end
installed_products()
click to toggle source
# File lib/WindowsInstaller.rb, line 117 def installed_products products = [] @installer.Products.each { |installed_product_code| products << installed_product_code } return products end
msi_installed?(msi_file)
click to toggle source
# File lib/WindowsInstaller.rb, line 19 def msi_installed?(msi_file) info = msi_properties(msi_file) return product_code_installed?(info['ProductCode']) end
msi_properties(msi_file)
click to toggle source
# File lib/WindowsInstaller.rb, line 74 def msi_properties(msi_file) raise "#{msi_file} does not exist!" unless(File.exists?(msi_file)) properties = {} sql_query = "SELECT * FROM `Property`" db = @installer.OpenDatabase(msi_file, 0) view = db.OpenView(sql_query) view.Execute(nil) record = view.Fetch() return nil if(record == nil) while(!record.nil?) properties[record.StringData(1)] = record.StringData(2) record = view.Fetch() end db.ole_free db = nil return properties end
product_code_installed?(product_code)
click to toggle source
# File lib/WindowsInstaller.rb, line 31 def product_code_installed?(product_code) @installer.Products.each { |installed_product_code| return true if (product_code == installed_product_code) } return false end
product_codes(upgrade_code)
click to toggle source
# File lib/WindowsInstaller.rb, line 123 def product_codes(upgrade_code) upgrade_codes = get_upgrade_codes return (upgrade_codes.key?(upgrade_code)) ? upgrade_codes[upgrade_code] : [] end
product_installed?(product_name)
click to toggle source
# File lib/WindowsInstaller.rb, line 24 def product_installed?(product_name) product_code = installed_get_product_code(product_name) return false if(product_code.empty?) return product_code_installed?(product_code) end
uninstall_msi(msi_file)
click to toggle source
# File lib/WindowsInstaller.rb, line 49 def uninstall_msi(msi_file) raise "#{msi_file} does not exist!" unless(File.exists?(msi_file)) info = msi_properties(msi_file) uninstall_product_code(info['ProductCode']) end
uninstall_product(product_name)
click to toggle source
# File lib/WindowsInstaller.rb, line 55 def uninstall_product(product_name) raise StandardError.new("Product '#{product_name}' is not installed") unless(product_installed?(product_name)) product_code = installed_get_product_code(product_name) uninstall_product_code(product_code) end
uninstall_product_code(product_code)
click to toggle source
# File lib/WindowsInstaller.rb, line 61 def uninstall_product_code(product_code) raise "#{product_code} is not installed" unless(product_code_installed?(product_code)) cmd = "msiexec.exe" cmd = "#{cmd} #{self[:mode]}" if(has_key?(:mode)) cmd = "#{cmd} /x #{product_code}" msiexec(cmd) if(product_code_installed?(product_code)) properties = installed_properties(product_code) raise "Failed to uninstall #{properties['InstalledProductName']} #{properties['VersionString']}" end end
Private Instance Methods
get_upgrade_code(product_code)
click to toggle source
# File lib/WindowsInstaller.rb, line 182 def get_upgrade_code(product_code) return nil if(!product_code_installed?(product_code)) upgrade_codes = get_upgrade_codes upgrade_codes.each do |upgrade_code, product_codes| product_codes.each { |pc| return upgrade_code if(pc == product_code) } end return nil end
get_upgrade_codes()
click to toggle source
# File lib/WindowsInstaller.rb, line 155 def get_upgrade_codes upgrade_codes = {} property_value = @installer.ProductsEx('','',7).each do |prod| begin local_pkg = prod.InstallProperty('LocalPackage') db = @installer.OpenDataBase(local_pkg, 0) query = 'SELECT `Value` FROM `Property` WHERE `Property` = \'UpgradeCode\'' view = db.OpenView(query) view.Execute record = view.Fetch unless(record.nil?) upgrade_code = record.StringData(1) upgrade_codes[upgrade_code] ||= [] upgrade_codes[upgrade_code] << prod.ProductCode end rescue next end end return upgrade_codes end
installed_get_product_code(product_name)
click to toggle source
# File lib/WindowsInstaller.rb, line 129 def installed_get_product_code(product_name) return '' if(product_name.empty?) @installer.Products.each do |product_code| name = @installer.ProductInfo(product_code, "ProductName") return product_code if (product_name == name) end return '' end
installed_properties(product_code)
click to toggle source
# File lib/WindowsInstaller.rb, line 140 def installed_properties(product_code) return nil if(!product_code_installed?(product_code)) hash = Hash.new # known product keywords found on internet. Would be nice to generate. %w[Language PackageCode Transforms AssignmentType PackageName InstalledProductName VersionString RegCompany RegOwner ProductID ProductIcon InstallLocation InstallSource InstallDate Publisher LocalPackage HelpLink HelpTelephone URLInfoAbout URLUpdateInfo InstanceType].sort.each do |prop| value = @installer.ProductInfo(product_code, prop) hash[prop] = value unless(value.nil? || value == '') end hash['ProductCode'] = product_code return hash end
msiexec(cmd)
click to toggle source
# File lib/WindowsInstaller.rb, line 191 def msiexec(cmd) cmd_options = { echo_command: false, echo_output: false} unless(self[:debug]) if(self.has_key?(:administrative_user)) msiexec_admin(cmd, cmd_options) else command = Execute.new(cmd, cmd_options) command.execute end end
msiexec_admin(cmd, options)
click to toggle source
# File lib/WindowsInstaller.rb, line 201 def msiexec_admin(cmd, options) cmd = "runas /noprofile /savecred /user:#{self[:administrative_user]} \"#{cmd}\"" command = Execute.new(cmd, options) wait_on_spawned(cmd) { cmd.execute } end
wait_on_spawned_process(cmd) { || ... }
click to toggle source
# File lib/WindowsInstaller.rb, line 207 def wait_on_spawned_process(cmd) pre_execute = Sys::ProcTable.ps pre_pids = [] pre_execute.each { |ps| pre_pids << ps.pid } yield exe = cmd[:command].match(/\\(?<path>.+\.exe)/i).named_captures['path'] exe = File.basename(exe) #puts "Exe: #{exe}" msiexe_pid = 0 post_execute = Sys::ProcTable.ps post_execute.each do |ps| msiexe_pid = ps.pid if((ps.name.downcase == exe.downcase) && pre_pids.index(ps.pid).nil?) end if(msiexe_pid != 0) loop do s = Sys::ProcTable.ps(msiexe_pid) break if(s.nil?) sleep(1) end end end