ManageIQ/manageiq-gems-pending

View on GitHub
lib/gems/pending/util/win32/miq-wmi-mswin.rb

Summary

Maintainability
A
1 hr
Test Coverage
F
20%
module WmiMswin
  require 'win32ole'

  def connectServer
    # Connect to WMI
    WIN32OLE.ole_initialize
    objLocator = WIN32OLE.new("WbemScripting.SWbemLocator")
    begin
      @objWMI = objLocator.ConnectServer(@server, @namespace, logon_username, @password)
    rescue
      # Win2008 and Vista throw an error if you specify credentials
      if $!.to_s.include?('User credentials cannot be used for local connections')
        @objWMI = objLocator.ConnectServer(@server, @namespace, nil, nil)
      else
        raise
      end
    end
    @objWMI.Security_.ImpersonationLevel = 3 # Impersonate
  end

  def logon_username
    return nil if @username.nil?

    # Check for usernames that supplied the domain as well
    # Example manageiq\user1 or just user1
    return @username if @username.include?("\\")

    # If we just have a username append the server name to it.  Otherwise
    # connecting will fail when running in SYSTEM context.
    "#{@server}\\#{@username}"
  end

  def release
    unless @objWMI.nil?
      @objWMI.ole_free rescue nil
    end
  end

  def verify_credentials
    connectServer
    true
  rescue WIN32OLERuntimeError
    raise_win32ole_error($!)
  end

  # Return a better, single line, error message for logging
  def raise_win32ole_error(err)
    err = err.to_s.split("\n")
    err.delete_at(-1)
    err.each(&:strip!)
    raise(WIN32OLERuntimeError, err.join(" - "))
  end

  def runProcess(command, async = true, startup = {})
    startup = {:ShowWindow => 1, :Title => "MIQ - #{Time.now.utc.iso8601}"}.merge(startup)
    objStartup = @objWMI.Get("Win32_ProcessStartup").SpawnInstance_
    startup.each_pair { |k, v| objStartup.send("#{k}=", v) }

    # Obtain the Win32_Process class of object.
    strShell = exec_method(@objWMI.Get("Win32_Process"), "Create", :CommandLine => command, :ProcessStartupInformation => objStartup)

    raise "Failed to create process [#{command}]" if strShell.ProcessID.nil?
    return strShell.ProcessID if async

    if strShell.ReturnValue.zero?
      loop do
        break if @objWMI.ExecQuery("select * from Win32_Process where ProcessID = #{strShell.ProcessID}").count == 0
        if $log
          $log.debug "waiting for remote process [#{strShell.ProcessID}] to end."
        else
          puts "waiting for process [#{strShell.ProcessID}] to end."
        end

        sleep(1)
      end
    end

    strShell.ReturnValue
  end

  def getWin32Service(svcName)
    wmi_object = run_query("select * from Win32_Service where Name = '#{svcName}'")
    wmi_object.each { |s| yield s } if block_given?
    wmi_object
    # Example calls against the service object.
    #  puts s.started
    #  s.StartService
  end

  def getObject(klassName)
    wmi_object = @objWMI.InstancesOf(klassName)
    wmi_object.each { |w| yield(w) } if block_given?
    wmi_object
  end

  def run_query(wmiQuery)
    wmi_object = @objWMI.ExecQuery(wmiQuery)
    wmi_object.each { |s| yield s } if block_given?
    wmi_object
  end

  def get_instance(wmiQuery)
    wmi_object = nil
    run_query(wmiQuery) { |w| wmi_object = w; break }
    wmi_object
  end

  def exec_method(wmi_obj, method_name, *input_hash)
    input_hash = input_hash.first || {}
    inParams = wmi_obj.Methods_(method_name.to_s).InParameters.SpawnInstance_
    input_hash.each_pair { |k, v| inParams.send("#{k}=", v) }
    wmi_obj.ExecMethod_(method_name.to_s, inParams)
  end

  # Call the 'Get' method when you have a __RELPATH or __PATH string to an object
  # Example: \\DEV008-HYPERV\root\CIMV2:Win32_ComputerSystem.Name="DEV008-HYPERV"
  #       or Win32_ComputerSystem.Name="DEV008-HYPERV"
  def get(path)
    @objWMI.Get(path)
  end

  def associators_of(obj, options = {})
    wql = "ASSOCIATORS OF {#{obj.Path_.Path}}"
    wql += " WHERE AssocClass = #{options[:assocClass]}" unless options[:assocClass].nil?
    wql += " WHERE ResultClass = #{options[:resultClass]}" unless options[:resultClass].nil?
    wmi_object = @objWMI.ExecQuery(wql)
    wmi_object.each { |s| yield s } if block_given?
    wmi_object
  end

  def references_of(obj, options = {})
    wql = "REFERENCES OF {#{obj.Path_.Path}}"
    wql += " WHERE ResultClass = #{options[:resultClass]}" unless options[:resultClass].nil?
    wmi_object = @objWMI.ExecQuery(wql)
    wmi_object.each { |s| yield s } if block_given?
    wmi_object
  end

  def props_to_hash(wmi_obj)
    h = {}
    wmi_obj.Properties_.each { |p| h[p.name] = p.value }
    h
  end

  def to_h(instance, nh = {}, paths = {}, level = -2)
    level += 2
    i = 0
    # puts "\n\n%0*s[#{level}]======================" % [level,'']
    instance.Properties_.each do |p|
      nh[p.name] = p.value
      # puts "%0*s[#{p.name}] = [#{p.value}]" % [level,'']
    end
    instance.SystemProperties_.each do |p|
      nh[p.name] = p.value
      # puts "%0*s[#{p.name}] = [#{p.value}]" % [level,'']
      paths[p.value] = true if p.name == "__PATH"
    end

    #    instance.Associators_.each do |a|
    #      klass_name = a.SystemProperties_.each {|p| break(p.value) if p.name == "__CLASS"}
    #      next if klass_name == "Msvm_ComputerSystem"
    #      next if paths.has_key?(a.Path_.path)
    #
    #      x = nh["Associator_#{i}"] = {}
    #      self.to_h(a, x, paths, level)
    #      i += 1
    #    end
    nh
  end
end