# winenum.rb # enumerate any WMI class in any namespace # # Usage # winenum [--debug] [--namespace ] [ ... ] # # Example # (-> http://www.codeproject.com/Articles/46390/WMI-Query-Language-by-Example) # 1. Enumerate namespaces (call recursively!) # ruby winenum.rb -n root __NAMESPACE # 2. Enumerate classnames # ruby winenum.rb -n root/cimv2 -q "select * from meta_class" # 3. Get class properties # ruby winenum.rb -n root/cimv2 -q "select * from meta_class where __Class = \"Win32_LogicalDisk\"" # 4. Get all base classes # ruby winenum.rb -n root/cimv2 -q "select * from meta_class where __SuperClass Is Null" # 5. Get immediate children of a class # ruby winenum.rb -n root/cimv2 -q "select * from meta_class where __SuperClass = \"CIM_Setting\"" # 6. Get the dynasty of children starting at a class # ruby winenum.rb -n root/cimv2 -q "select * from meta_class where __Dynasty = \"CIM_Setting\"" # # Additional WQL parameters # - limit to specific names # Where __Class Like "Win32%" # - limit to specific origins ("is a") # Where __This Isa "__Event" # # # Associations # winrm enumerate wmicimv2/* -dialect:association -associations -filter:{object=win32_service?name=winrm;resultclassname=win32_dependentservice;role=dependent} # (a: addressing, b: cimbinding, w: dmtf wsman, p: microsoft wsman) # # # 32000 # # # # http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous # # http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/win32_service # # winrm # # # # win32_dependentservice # dependent # # # # # winrm enumerate wmicimv2/* -dialect:association -associations -filter:{object=win32_service?name=winrm} # # # 32000 # # # # http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous # # http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/win32_service # # winrm # # # # # # require 'rexml/document' require File.expand_path(File.join(File.dirname(__FILE__),'_loadpath')) require 'openwsman' require '_client' require 'getoptlong' WIDTH = 25 # # parse classname and selectors from string # # ?key=value&key=value... # def parse_classname str raise "Classname required" unless str classname, args = str.split "?" return [classname] unless args selectors = {} args.split("&").each do |kv| key,value = kv.split "=" selectors[key] = value end [classname,selectors] end # # extract reference information from a node # # returns a [ , ] pair # def get_reference_from node uri = node.ReferenceParameters.ResourceURI selectors = {} node.ReferenceParameters.SelectorSet.each do |s| name = s.attr_find(nil, "Name") selectors[name] = s.text end [uri,selectors] end # # Extract filter arguments # --{associators,references} ,[,] # e.g. Win32_DependentService,dependent # e.g. Win32_Service,dependent,antecedent # # @returns [AssociationClassName, result_class, role, result_role ] # def extract_filter_arguments arg if arg.nil? || arg.empty? return nil end a,b,c,d = arg.split "," a = nil if a && a.empty? b = nil if b && b.empty? c = nil if c && c.empty? d = nil if d && d.empty? [a,b,c,d] end def print_item indent, item, properties = [] indentation = " "*indent if properties.empty? # puts node.string item.each do |c| if c.size == 0 attrs = "" c.each_attr { |a| attrs << " #{a.name}=#{a.value}" } attrs = "<"+attrs+">" unless attrs.empty? puts "#{indentation}#{c.name}#{attrs}: #{c.text}" else print_item indent+1, c end end else values = [] properties.each do |p| values << item.send(p) end printf "#{indentation}%-#{WIDTH}s\n" * values.size, *values end end # # Enumerate # # Enumerates instances of a class # parms[:epr] - end point references only (aka 'names') # parms[:associators] - enumerate associators # parms[:references] - enumerate references # def enum_properties client, parms, *properties options = Openwsman::ClientOptions.new namespace = parms[:namespace] || "root/cimv2" classname = parms[:classname] limit = parms[:limit].to_i rescue 0 faults = 0 filter = nil if parms[:query] q = parms[:query] filter = Openwsman::Filter.new filter.wql q classname = "*" if q =~ /.*from(\s+)(([\w_])+)/i uri = Openwsman.epr_prefix_for $2, namespace uri << "/*" end end start_time = Time.new # Openwsman::debug = -1 # Openwsman.debug = -1 # options.max_envelope_size = 1024 * 1024 * 1024 # puts "max_envelope_size #{options.max_envelope_size}" options.set_dump_request if parms[:debug] # timeout if parms[:timeout] options.timeout = parms[:timeout].to_i * 1000 # parms is in sec, timeout in msec end # locale if parms[:locale] options.locale = parms[:locale] end options.flags = Openwsman::FLAG_ENUMERATION_OPTIMIZATION options.max_elements = 999 # return endpoint references (instead of instances) options.flags = Openwsman::FLAG_ENUMERATION_ENUM_EPR if parms[:epr] uri ||= Openwsman.epr_uri_for namespace, classname # enumerate Associators if parms[:associators] || parms[:references] # options.flags = Openwsman::FLAG_ENUMERATION_ENUM_OBJ_AND_EPR filter = Openwsman::Filter.new selectors = parms[:selectors] epr = Openwsman::EndPointReference.new(uri, nil, selectors) if parms[:associators] assoc_class, result_class, role, result_role = extract_filter_arguments parms[:associators] filter.associators(epr, assoc_class, result_class, role, result_role) elsif parms[:references] assoc_class, result_class, role, result_role = extract_filter_arguments parms[:references] filter.references(epr, assoc_class, result_class, role, result_role) end classname = "*" # accept any result classname uri = Openwsman.epr_uri_for "", classname end # enumerate References # STDERR.puts "URI <#{uri}>" result = client.enumerate( options, filter, uri ) unless properties.empty? printf "%-#{WIDTH}s" * properties.size, *properties puts puts "-" * WIDTH * properties.size end results = 0 context = nil loop do break if fault? client, result puts "result #{result.to_xml}" if parms[:debug] items = result.Items break unless items items.each do |item| if parms[:epr] epr = Openwsman::EndPointReference.new(item) puts epr results += 1 else # puts items.to_xml if parms[:debug] puts "-------" if results > 0 unless classname == "*" next unless item.name == classname end puts item.name results += 1 print_item 1, item, properties end end # Items.each limit -= 1 break if limit == 0 context = result.context break unless context result = client.pull( options, nil, uri, context ) puts end client.release( options, uri, context ) if context duration = Time.new - start_time printf "%d results, %d faults in %3.2f seconds\n" % [results, faults, duration] end def usage msg=nil STDERR.puts msg if msg STDERR.puts "Usage:" STDERR.puts "winenum [-n ] [-q ] [-l ] [-d] " STDERR.puts "\twith -q , is discarded" STDERR.puts "\nand remember to set WSMANCLIENT" exit 1 end # # --- main --- # # client = Client.open parms = {} begin opts = GetoptLong.new( [ "--associators", "-a", GetoptLong::REQUIRED_ARGUMENT ], [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], [ "--epr", "-e", GetoptLong::NO_ARGUMENT ], [ "--limit", "-l", GetoptLong::REQUIRED_ARGUMENT ], [ "--namespace", "-n", GetoptLong::REQUIRED_ARGUMENT ], [ "--query", "-q", GetoptLong::REQUIRED_ARGUMENT ], [ "--references", "-r", GetoptLong::REQUIRED_ARGUMENT ], [ "--timeout", "-t", GetoptLong::REQUIRED_ARGUMENT ], [ "--locale", "-L", GetoptLong::REQUIRED_ARGUMENT ] ) opts.each do |opt,arg| case opt when "--query" then parms[:query] = arg when "--limit" then parms[:limit] = arg when "--namespace" then parms[:namespace] = arg when "--debug" then parms[:debug] = true when "--epr" then parms[:epr] = true when "--associators" then parms[:associators] = arg when "--references" then parms[:references] = arg when "--timeout" then parms[:timeout] = arg when "--locale" then parms[:locale] = arg end end rescue GetoptLong::InvalidOption usage "invalid option passed" end if parms[:associators] && parms[:references] usage "Enumeration of Associators and References not supported" end unless parms[:query] parms[:classname], parms[:selectors] = parse_classname(ARGV.shift) end #puts "Classname(#{parms[:classname]}) Selectors(#{parms[:selectors].inspect})" enum_properties client, parms, *ARGV