Module wmi
[hide private]
[frames] | no frames]

Source Code for Module wmi

   1  ##
 
   2  # wmi - a lightweight Python wrapper around Microsoft's WMI interface
 
   3  #
 
   4  # Windows Management Instrumentation (WMI) is Microsoft's answer to
 
   5  # the DMTF's Common Information Model. It allows you to query just
 
   6  # about any conceivable piece of information from any computer which
 
   7  # is running the necessary agent and over which have you the
 
   8  # necessary authority.
 
   9  #
 
  10  # The implementation is by means of COM/DCOM and most of the examples
 
  11  # assume you're running one of Microsoft's scripting technologies.
 
  12  # Fortunately, Mark Hammond's pywin32 has pretty much all you need
 
  13  # for a workable Python adaptation. I haven't tried any of the fancier
 
  14  # stuff like Async calls and so on, so I don't know if they'd work.
 
  15  #
 
  16  # Since the COM implementation doesn't give much away to Python
 
  17  # programmers, I've wrapped it in some lightweight classes with
 
  18  # some getattr / setattr magic to ease the way. In particular:
 
  19  #
 
  20  # <ul>
 
  21  # <li>
 
  22  # The _wmi_namespace object itself will determine its classes
 
  23  # and allow you to return all instances of any of them by
 
  24  # using its name as an attribute. As an additional shortcut,
 
  25  # you needn't specify the Win32_; if the first lookup fails
 
  26  # it will try again with a Win32_ on the front:
 
  27  #
 
  28  # <pre class="code">
 
  29  # disks = wmi.WMI ().Win32_LogicalDisk ()
 
  30  # </pre>
 
  31  #
 
  32  # In addition, you can specify what would become the WHERE clause
 
  33  # as keyword parameters:
 
  34  #
 
  35  # <pre class="code">
 
  36  # fixed_disks = wmi.WMI ().Win32_LogicalDisk (DriveType = 3)
 
  37  # </pre>
 
  38  # </li>
 
  39  #
 
  40  # <li>
 
  41  # The objects returned by a WMI lookup are wrapped in a Python
 
  42  # class which determines their methods and classes and allows
 
  43  # you to access them as though they were Python classes. The
 
  44  # methods only allow named parameters.
 
  45  #
 
  46  # <pre class="code">
 
  47  # for p in wmi.WMI ().Win32_Process ():
 
  48  #   if p.Name.lower () == 'notepad.exe':
 
  49  #     p.Terminate (Result=1)
 
  50  # </pre>
 
  51  # </li>
 
  52  #
 
  53  # <li>
 
  54  #  Doing a print on one of the WMI objects will result in its
 
  55  #  GetObjectText_ method being called, which usually produces
 
  56  #  a meaningful printout of current values.
 
  57  #  The repr of the object will include its full WMI path,
 
  58  #  which lets you get directly to it if you need to.
 
  59  # </li>
 
  60  #
 
  61  # <li>
 
  62  # You can get the associators and references of an object as
 
  63  #  a list of python objects by calling the associators () and
 
  64  #  references () methods on a WMI Python object.
 
  65  #  NB Don't do this on a Win32_ComputerSystem object; it will
 
  66  #  take all day and kill your machine!
 
  67  #
 
  68  # <pre class="code">
 
  69  # for p in wmi.WMI ().Win32_Process ():
 
  70  #   if p.Name.lower () == 'notepad.exe':
 
  71  #     for r in p.references ():
 
  72  #       print r.Name
 
  73  # </pre>
 
  74  # </li>
 
  75  #
 
  76  # <li>
 
  77  # WMI classes (as opposed to instances) are first-class
 
  78  # objects, so you can get hold of a class, and call
 
  79  # its methods or set up a watch against it.
 
  80  #
 
  81  # <pre class="code">
 
  82  # process = wmi.WMI ().Win32_Process
 
  83  # process.Create (CommandLine="notepad.exe")
 
  84  # </pre>
 
  85  #
 
  86  # </li>
 
  87  #
 
  88  # <li>
 
  89  # To make it easier to use in embedded systems and py2exe-style
 
  90  # executable wrappers, the module will not force early Dispatch.
 
  91  # To do this, it uses a handy hack by Thomas Heller for easy access
 
  92  # to constants.
 
  93  # </li>
 
  94  #
 
  95  # <li>
 
  96  # Typical usage will be:
 
  97  #
 
  98  # <pre class="code">
 
  99  # import wmi
 
 100  #
 
 101  # vodev1 = wmi.WMI ("vodev1")
 
 102  # for disk in vodev1.Win32_LogicalDisk ():
 
 103  #   if disk.DriveType == 3:
 
 104  #     space = 100 * long (disk.FreeSpace) / long (disk.Size)
 
 105  #     print "%s has %d%% free" % (disk.Name, space)
 
 106  # </pre>
 
 107  # </li>
 
 108  #
 
 109  # </ul>
 
 110  #
 
 111  # Many thanks, obviously to Mark Hammond for creating the win32all
 
 112  # extensions, but also to Alex Martelli and Roger Upole, whose
 
 113  # c.l.py postings pointed me in the right direction.
 
 114  # Thanks especially in release 1.2 to Paul Tiemann for his code
 
 115  # contributions and robust testing.
 
 116  #
 
 117  # (c) Tim Golden - mail at timgolden.me.uk 5th June 2003
 
 118  # Licensed under the (GPL-compatible) MIT License:
 
 119  # http://www.opensource.org/licenses/mit-license.php
 
 120  #
 
 121  # For change history see CHANGELOG.TXT
 
 122  ##
 
 123  try: 
 124    True, False 
 125  except NameError: 
 126    True = 1 
 127    False = 0 
 128  
 
 129  try: 
 130    object 
 131  except NameError: 
132 - class object: pass
133 134 __VERSION__ = "1.3.2" 135 136 _DEBUG = False 137 138 import sys 139 import re 140 import datetime 141 from win32com.client import GetObject, Dispatch 142 import pywintypes 143
144 -class ProvideConstants (object):
145 """ 146 A class which, when called on a win32com.client.Dispatch object, 147 provides lazy access to constants defined in the typelib. 148 149 They can be accessed as attributes of the _constants property. 150 From Thomas Heller on c.l.py 151 """
152 - def __init__(self, comobj):
153 "@param comobj A COM object whose typelib constants are to be exposed" 154 comobj.__dict__["_constants"] = self 155 # Get the typelibrary's typecomp interface 156 self.__typecomp = \ 157 comobj._oleobj_.GetTypeInfo().GetContainingTypeLib()[0].GetTypeComp()
158
159 - def __getattr__(self, name):
160 if name.startswith("__") and name.endswith("__"): 161 raise AttributeError, name 162 result = self.__typecomp.Bind(name) 163 # Bind returns a 2-tuple, first item is TYPEKIND, 164 # the second item has the value 165 if not result[0]: 166 raise AttributeError, name 167 return result[1].value
168 169 obj = GetObject ("winmgmts:") 170 ProvideConstants (obj) 171 172 wbemErrInvalidQuery = obj._constants.wbemErrInvalidQuery 173 wbemErrTimedout = obj._constants.wbemErrTimedout 174 wbemFlagReturnImmediately = obj._constants.wbemFlagReturnImmediately 175 wbemFlagForwardOnly = obj._constants.wbemFlagForwardOnly 176
177 -def handle_com_error (error_info):
178 """Convenience wrapper for displaying all manner of COM errors. 179 Raises a x_wmi exception with more useful information attached 180 181 @param error_info The structure attached to a pywintypes.com_error 182 """ 183 hresult_code, hresult_name, additional_info, parameter_in_error = error_info 184 exception_string = ["%s - %s" % (hex (hresult_code), hresult_name)] 185 if additional_info: 186 wcode, source_of_error, error_description, whlp_file, whlp_context, scode = additional_info 187 exception_string.append (" Error in: %s" % source_of_error) 188 exception_string.append (" %s - %s" % (hex (scode), (error_description or "").strip ())) 189 raise x_wmi, "\n".join (exception_string)
190 191 BASE = datetime.datetime (1601, 1, 1)
192 -def from_1601 (ns100):
193 return BASE + datetime.timedelta (microseconds=int (ns100) / 10)
194
195 -def from_time (year=None, month=None, day=None, hours=None, minutes=None, seconds=None, microseconds=None, timezone=None):
196 """ 197 Convenience wrapper to take a series of date/time elements and return a WMI time 198 of the form yyyymmddHHMMSS.mmmmmm+UUU. All elements may be int, string or 199 omitted altogether. If omitted, they will be replaced in the output string 200 by a series of stars of the appropriate length. 201 202 @param year The year element of the date/time 203 @param month The month element of the date/time 204 @param day The day element of the date/time 205 @param hours The hours element of the date/time 206 @param minutes The minutes element of the date/time 207 @param seconds The seconds element of the date/time 208 @param microseconds The microseconds element of the date/time 209 @param timezone The timeezone element of the date/time 210 211 @return A WMI datetime string of the form: yyyymmddHHMMSS.mmmmmm+UUU 212 """ 213 def str_or_stars (i, length): 214 if i is None: 215 return "*" * length 216 else: 217 return str (i).rjust (length, "0")
218 219 wmi_time = "" 220 wmi_time += str_or_stars (year, 4) 221 wmi_time += str_or_stars (month, 2) 222 wmi_time += str_or_stars (day, 2) 223 wmi_time += str_or_stars (hours, 2) 224 wmi_time += str_or_stars (minutes, 2) 225 wmi_time += str_or_stars (seconds, 2) 226 wmi_time += "." 227 wmi_time += str_or_stars (microseconds, 6) 228 wmi_time += str_or_stars (timezone, 4) 229 230 return wmi_time 231
232 -def to_time (wmi_time):
233 """ 234 Convenience wrapper to take a WMI datetime string of the form 235 yyyymmddHHMMSS.mmmmmm+UUU and return a 9-tuple containing the 236 individual elements, or None where string contains placeholder 237 stars. 238 239 @param wmi_time The WMI datetime string in yyyymmddHHMMSS.mmmmmm+UUU format 240 241 @return A 9-tuple of (year, month, day, hours, minutes, seconds, microseconds, timezone) 242 """ 243 def int_or_none (s, start, end): 244 try: 245 return int (s[start:end]) 246 except ValueError: 247 return None
248 249 year = int_or_none (wmi_time, 0, 4) 250 month = int_or_none (wmi_time, 4, 6) 251 day = int_or_none (wmi_time, 6, 8) 252 hours = int_or_none (wmi_time, 8, 10) 253 minutes = int_or_none (wmi_time, 10, 12) 254 seconds = int_or_none (wmi_time, 12, 14) 255 microseconds = int_or_none (wmi_time, 15, 21) 256 timezone = wmi_time[21:] 257 258 return year, month, day, hours, minutes, seconds, microseconds, timezone 259 260 # 261 # Exceptions 262 #
263 -class x_wmi (Exception):
264 pass
265
266 -class x_wmi_invalid_query (x_wmi):
267 pass
268
269 -class x_wmi_timed_out (x_wmi):
270 pass
271
272 -class x_wmi_no_namespace (x_wmi):
273 pass
274 275 WMI_EXCEPTIONS = { 276 wbemErrInvalidQuery : x_wmi_invalid_query, 277 wbemErrTimedout : x_wmi_timed_out 278 } 279
280 -def _set (obj, attribute, value):
281 """ 282 Helper function to add an attribute directly into the instance 283 dictionary, bypassing possible __getattr__ calls 284 285 @param obj Any python object 286 @param attribute String containing attribute name 287 @param value Any python object 288 """ 289 obj.__dict__[attribute] = value
290
291 -class _wmi_method:
292 """ 293 A currying sort of wrapper around a WMI method name. It 294 abstract's the method's parameters and can be called like 295 a normal Python object passing in the parameter values. 296 297 Output parameters are returned from the call as a tuple. 298 In addition, the docstring is set up as the method's 299 signature, including an indication as to whether any 300 given parameter is expecting an array, and what 301 special privileges are required to call the method. 302 """ 303
304 - def __init__ (self, ole_object, method_name):
305 """ 306 @param ole_object The WMI class/instance whose method is to be called 307 @param method_name The name of the method to be called 308 """ 309 try: 310 self.ole_object = Dispatch (ole_object) 311 self.method = ole_object.Methods_ (method_name) 312 self.qualifiers = {} 313 for q in self.method.Qualifiers_: 314 self.qualifiers[q.Name] = q.Value 315 self.provenance = "\n".join (self.qualifiers.get ("MappingStrings", [])) 316 317 self.in_parameters = self.method.InParameters 318 self.out_parameters = self.method.OutParameters 319 if self.in_parameters is None: 320 self.in_parameter_names = [] 321 else: 322 self.in_parameter_names = [(i.Name, i.IsArray) for i in self.in_parameters.Properties_] 323 if self.out_parameters is None: 324 self.out_parameter_names = [] 325 else: 326 self.out_parameter_names = [(i.Name, i.IsArray) for i in self.out_parameters.Properties_] 327 328 doc = "%s (%s) => (%s)" % ( 329 method_name, 330 ", ".join ([name + ("", "[]")[is_array] for (name, is_array) in self.in_parameter_names]), 331 ", ".join ([name + ("", "[]")[is_array] for (name, is_array) in self.out_parameter_names]) 332 ) 333 privileges = self.qualifiers.get ("Privileges", []) 334 if privileges: 335 doc += " | Needs: " + ", ".join (privileges) 336 self.__doc__ = doc 337 except pywintypes.com_error, error_info: 338 handle_com_error (error_info)
339
340 - def __call__ (self, *args, **kwargs):
341 """ 342 Execute the call to a WMI method, returning 343 a tuple (even if is of only one value) containing 344 the out and return parameters. 345 """ 346 try: 347 if self.in_parameters: 348 parameter_names = {} 349 for name, is_array in self.in_parameter_names: 350 parameter_names[name] = is_array 351 352 parameters = self.in_parameters 353 354 # 355 # Check positional parameters first 356 # 357 for n_arg in range (len (args)): 358 arg = args[n_arg] 359 parameter = parameters.Properties_[n_arg] 360 if parameter.IsArray: 361 try: list (arg) 362 except TypeError: raise TypeError, "parameter %d must be iterable" % n_arg 363 parameter.Value = arg 364 365 # 366 # If any keyword param supersedes a positional one, 367 # it'll simply overwrite it. 368 # 369 for k, v in kwargs.items (): 370 is_array = parameter_names.get (k) 371 if is_array is None: 372 raise AttributeError, "%s is not a valid parameter for %s" % (k, self.__doc__) 373 else: 374 if is_array: 375 try: list (v) 376 except TypeError: raise TypeError, "%s must be iterable" % k 377 parameters.Properties_ (k).Value = v 378 379 result = self.ole_object.ExecMethod_ (self.method.Name, self.in_parameters) 380 else: 381 result = self.ole_object.ExecMethod_ (self.method.Name) 382 383 results = [] 384 for name, is_array in self.out_parameter_names: 385 value = result.Properties_ (name).Value 386 if is_array: 387 # 388 # Thanks to Jonas Bjering for bug report and patch 389 # 390 results.append (list (value or [])) 391 else: 392 results.append (value) 393 return tuple (results) 394 395 except pywintypes.com_error, error_info: 396 handle_com_error (error_info)
397
398 - def __repr__ (self):
399 return "<function %s>" % self.__doc__
400 401 # 402 # class _wmi_object 403 #
404 -class _wmi_object:
405 "A lightweight wrapper round an OLE WMI object" 406
407 - def __init__ (self, ole_object, instance_of=None, fields=[], property_map={}):
408 try: 409 _set (self, "ole_object", ole_object) 410 _set (self, "_instance_of", instance_of) 411 _set (self, "properties", {}) 412 _set (self, "methods", {}) 413 _set (self, "property_map", property_map) 414 415 if fields: 416 for field in fields: 417 self.properties[field] = None 418 else: 419 for p in ole_object.Properties_: 420 self.properties[p.Name] = None 421 422 for m in ole_object.Methods_: 423 self.methods[m.Name] = None 424 425 _set (self, "_properties", self.properties.keys ()) 426 _set (self, "_methods", self.methods.keys ()) 427 428 _set (self, "qualifiers", {}) 429 for q in self.ole_object.Qualifiers_: 430 self.qualifiers[q.Name] = q.Value 431 _set (self, "is_association", self.qualifiers.has_key ("Association")) 432 433 except pywintypes.com_error, error_info: 434 handle_com_error (error_info)
435
436 - def __str__ (self):
437 """ 438 For a call to print [object] return the OLE description 439 of the properties / values of the object 440 """ 441 try: 442 return self.ole_object.GetObjectText_ () 443 except pywintypes.com_error, error_info: 444 handle_com_error (error_info)
445
446 - def __repr__ (self):
447 """ 448 Indicate both the fact that this is a wrapped WMI object 449 and the WMI object's own identifying class. 450 """ 451 try: 452 return "<%s: %s>" % (self.__class__.__name__, str (self.Path_.Path)) 453 except pywintypes.com_error, error_info: 454 handle_com_error (error_info)
455
456 - def _cached_properties (self, attribute):
457 if self.properties[attribute] is None: 458 self.properties[attribute] = self.ole_object.Properties_ (attribute) 459 return self.properties[attribute]
460
461 - def _cached_methods (self, attribute):
462 if self.methods[attribute] is None: 463 self.methods[attribute] = _wmi_method (self.ole_object, attribute) 464 return self.methods[attribute]
465
466 - def __getattr__ (self, attribute):
467 """ 468 Attempt to pass attribute calls to the proxied COM object. 469 If the attribute is recognised as a property, return its value; 470 if it is recognised as a method, return a method wrapper which 471 can then be called with parameters; otherwise pass the lookup 472 on to the underlying object. 473 """ 474 try: 475 if self.properties.has_key (attribute): 476 factory = self.property_map.get (attribute, lambda x: x) 477 value = factory (self._cached_properties (attribute).Value) 478 # 479 # If this is an association, its properties are 480 # actually the paths to the two aspects of the 481 # association, so translate them automatically 482 # into WMI objects. 483 # 484 if self.is_association: 485 return WMI (moniker=value) 486 else: 487 return value 488 elif self.methods.has_key (attribute): 489 return self._cached_methods (attribute) 490 else: 491 return getattr (self.ole_object, attribute) 492 except pywintypes.com_error, error_info: 493 handle_com_error (error_info)
494
495 - def __setattr__ (self, attribute, value):
496 """ 497 If the attribute to be set is valid for the proxied 498 COM object, set that objects's parameter value; if not, 499 raise an exception. 500 """ 501 try: 502 if self.properties.has_key (attribute): 503 self._cached_properties (attribute).Value = value 504 if self.ole_object.Path_.Path: 505 self.ole_object.Put_ () 506 else: 507 raise AttributeError, attribute 508 except pywintypes.com_error, error_info: 509 handle_com_error (error_info)
510
511 - def __eq__ (self, other):
512 """ 513 Use WMI's CompareTo_ to compare this object with 514 another. Don't try to do anything if the other 515 object is not a wmi object. It might be possible 516 to compare this object's unique key with a string 517 or something, but this doesn't seem to be universal 518 enough to merit a special case. 519 """ 520 if isinstance (other, self.__class__): 521 return self.ole_object.CompareTo_ (other.ole_object) 522 else: 523 raise x_wmi, "Can't compare a WMI object with something else"
524
525 - def _getAttributeNames (self):
526 """Return list of methods/properties for IPython completion""" 527 attribs = [str (x) for x in self.methods.keys ()] 528 attribs.extend ([str (x) for x in self.properties.keys ()]) 529 return attribs
530
531 - def put (self):
532 self.ole_object.Put_ ()
533
534 - def set (self, **kwargs):
535 """ 536 Set several properties of the underlying object 537 at one go. This is particularly useful in combination 538 with the new () method below. However, an instance 539 which has been spawned in this way won't have enough 540 information to write pack, so only try if the 541 instance has a path. 542 """ 543 if kwargs: 544 try: 545 for attribute, value in kwargs.items (): 546 if self.properties.has_key (attribute): 547 self._cached_properties (attribute).Value = value 548 else: 549 raise AttributeError, attribute 550 # 551 # Only try to write the attributes 552 # back if the object exists. 553 # 554 if self.ole_object.Path_.Path: 555 self.ole_object.Put_ () 556 except pywintypes.com_error, error_info: 557 handle_com_error (error_info)
558
559 - def path (self):
560 """ 561 Return the WMI URI to this object. Can be used to 562 determine the path relative to the parent namespace. eg, 563 564 <pre class="code"> 565 pp0 = wmi.WMI ().Win32_ParallelPort ()[0] 566 print pp0.path ().RelPath 567 </pre> 568 """ 569 try: 570 return self.ole_object.Path_ 571 except pywintypes.com_error, error_info: 572 handle_com_error (error_info)
573
574 - def derivation (self):
575 """Return a tuple representing the object derivation for 576 this object, with the most specific object first. eg, 577 578 pp0 = wmi.WMI ().Win32_ParallelPort ()[0] 579 print ' <- '.join (pp0.derivation ()) 580 """ 581 try: 582 return self.ole_object.Derivation_ 583 except pywintypes.com_error, error_info: 584 handle_com_error (error_info)
585
586 - def associators (self, wmi_association_class="", wmi_result_class=""):
587 """Return a list of objects related to this one, optionally limited 588 either by association class (ie the name of the class which relates 589 them) or by result class (ie the name of the class which would be 590 retrieved) 591 592 <pre class="code"> 593 c = wmi.WMI () 594 pp = c.Win32_ParallelPort ()[0] 595 596 for i in pp.associators (wmi_association_class="Win32_PortResource"): 597 print i 598 599 for i in pp.associators (wmi_result_class="Win32_PnPEntity"): 600 print i 601 </pre> 602 """ 603 try: 604 return [ 605 _wmi_object (i) for i in \ 606 self.ole_object.Associators_ ( 607 strAssocClass=wmi_association_class, 608 strResultClass=wmi_result_class 609 ) 610 ] 611 except pywintypes.com_error, error_info: 612 handle_com_error (error_info)
613
614 - def references (self, wmi_class=""):
615 """Return a list of associations involving this object, optionally 616 limited by the result class (the name of the association class). 617 618 NB Associations are treated specially; although WMI only returns 619 the string corresponding to the instance of each associated object, 620 this module will automatically convert that to the object itself. 621 622 <pre class="code"> 623 c = wmi.WMI () 624 sp = c.Win32_SerialPort ()[0] 625 626 for i in sp.references (): 627 print i 628 629 for i in sp.references (wmi_class="Win32_SerialPortSetting"): 630 print i 631 </pre> 632 """ 633 try: 634 return [_wmi_object (i) for i in self.ole_object.References_ (strResultClass=wmi_class)] 635 except pywintypes.com_error, error_info: 636 handle_com_error (error_info)
637 638 # 639 # class _wmi_event 640 #
641 -class _wmi_event (_wmi_object):
642 """Slight extension of the _wmi_object class to allow 643 objects which are the result of events firing to return 644 extra information such as the type of event. 645 """ 646 event_type_re = re.compile ("__Instance(Creation|Modification|Deletion)Event")
647 - def __init__ (self, event, event_info):
648 _wmi_object.__init__ (self, event) 649 _set (self, "event_type", None) 650 _set (self, "timestamp", None) 651 _set (self, "previous", None) 652 653 if event_info: 654 event_type = self.event_type_re.match (event_info.Path_.Class).group (1).lower () 655 _set (self, "event_type", event_type) 656 if hasattr (event_info, "TIME_CREATED"): 657 _set (self, "timestamp", from_1601 (event_info.TIME_CREATED)) 658 if hasattr (event_info, "PreviousInstance"): 659 _set (self, "previous", event_info.PreviousInstance)
660 661 # 662 # class _wmi_class 663 #
664 -class _wmi_class (_wmi_object):
665 """Currying class to assist in issuing queries against 666 a WMI namespace. The idea is that when someone issues 667 an otherwise unknown method against the WMI object, if 668 it matches a known WMI class a query object will be 669 returned which may then be called with one or more params 670 which will form the WHERE clause. eg, 671 672 <pre class="code"> 673 c = wmi.WMI () 674 c_drive = c.Win32_LogicalDisk (Name='C:') 675 </pre> 676 """
677 - def __init__ (self, namespace, wmi_class):
678 _wmi_object.__init__ (self, wmi_class) 679 _set (self, "_class_name", wmi_class.Path_.Class) 680 if namespace: 681 _set (self, "_namespace", namespace) 682 else: 683 class_moniker = wmi_class.Path_.DisplayName 684 winmgmts, namespace_moniker, class_name = class_moniker.split (":") 685 namespace = _wmi_namespace (GetObject (winmgmts + ":" + namespace_moniker), False) 686 _set (self, "_namespace", namespace)
687
688 - def query (self, fields=[], **where_clause):
689 """Make it slightly easier to query against the class, 690 by calling the namespace's query with the class preset. 691 Won't work if the class has been instantiated directly. 692 """ 693 if self._namespace is None: 694 raise x_wmi_no_namespace, "You cannot query directly from a WMI class" 695 696 try: 697 field_list = ", ".join (fields) or "*" 698 wql = "SELECT " + field_list + " FROM " + self._class_name 699 if where_clause: 700 wql += " WHERE " + " AND ". join (["%s = '%s'" % (k, v) for k, v in where_clause.items ()]) 701 return self._namespace.query (wql, self, fields) 702 except pywintypes.com_error, error_info: 703 handle_com_error (error_info)
704 705 __call__ = query 706
707 - def watch_for ( 708 self, 709 notification_type="operation", 710 delay_secs=1, 711 **where_clause 712 ):
713 if self._namespace is None: 714 raise x_wmi_no_namespace, "You cannot watch directly from a WMI class" 715 716 return self._namespace.watch_for ( 717 notification_type=notification_type, 718 wmi_class=self, 719 delay_secs=delay_secs, 720 **where_clause 721 )
722
723 - def instances (self):
724 """Return a list of instances of the WMI class 725 """ 726 try: 727 return [_wmi_object (instance, self) for instance in self.Instances_ ()] 728 except pywintypes.com_error, error_info: 729 handle_com_error (error_info)
730
731 - def new (self, **kwargs):
732 """This is the equivalent to the raw-WMI SpawnInstance_ 733 method. Note that there are relatively few uses for 734 this, certainly fewer than you might imagine. Most 735 classes which need to create a new *real* instance 736 of themselves, eg Win32_Process, offer a .Create 737 method. SpawnInstance_ is generally reserved for 738 instances which are passed as parameters to such 739 .Create methods, a common example being the 740 Win32_SecurityDescriptor, passed to Win32_Share.Create 741 and other instances which need security. 742 743 The example here is Win32_ProcessStartup, which 744 controls the shown/hidden state etc. of a new 745 Win32_Process instance. 746 747 <pre class="code"> 748 import win32con 749 import wmi 750 c = wmi.WMI () 751 startup = c.Win32_ProcessStartup.new (ShowWindow=win32con.SW_SHOWMINIMIZED) 752 pid, retval = c.Win32_Process.Create ( 753 CommandLine="notepad.exe", 754 ProcessStartupInformation=startup 755 ) 756 </pre> 757 758 NB previous versions of this module, used this function 759 to create new process. This is *not* a good example 760 of its use; it is better handled with something like 761 the example above. 762 """ 763 try: 764 obj = _wmi_object (self.SpawnInstance_ (), self) 765 obj.set (**kwargs) 766 return obj 767 except pywintypes.com_error, error_info: 768 handle_com_error (error_info)
769 770 # 771 # class _wmi_result 772 #
773 -class _wmi_result:
774 """Simple, data only result for targeted WMI queries which request 775 data only result classes via fetch_as_classes. 776 """
777 - def __init__(self, obj, attributes):
778 if attributes: 779 for attr in attributes: 780 self.__dict__[attr] = obj.Properties_ (attr).Value 781 else: 782 for p in obj.Properties_: 783 attr = p.Name 784 self.__dict__[attr] = obj.Properties_(attr).Value
785 786 # 787 # class WMI 788 #
789 -class _wmi_namespace:
790 """A WMI root of a computer system. The classes attribute holds a list 791 of the classes on offer. This means you can explore a bit with 792 things like this: 793 794 <pre class="code"> 795 c = wmi.WMI () 796 for i in c.classes: 797 if "user" in i.lower (): 798 print i 799 </pre> 800 """
801 - def __init__ (self, namespace, find_classes):
802 _set (self, "_namespace", namespace) 803 # 804 # wmi attribute preserved for backwards compatibility 805 # 806 _set (self, "wmi", namespace) 807 808 # Initialise the "classes" attribute, to avoid infinite recursion in the 809 # __getattr__ method (which uses it). 810 self.classes = {} 811 # 812 # Pick up the list of classes under this namespace 813 # so that they can be queried, and used as though 814 # properties of the namespace by means of the __getattr__ 815 # hook below. 816 # If the namespace does not support SubclassesOf, carry on 817 # regardless 818 # 819 if find_classes: 820 try: 821 self.classes.update (self.subclasses_of ()) 822 except AttributeError: 823 pass
824
825 - def __repr__ (self):
826 return "<_wmi_namespace: %s>" % self.wmi
827
828 - def __str__ (self):
829 return repr (self)
830
831 - def get (self, moniker):
832 try: 833 return _wmi_object (self.wmi.Get (moniker)) 834 except pywintypes.com_error, error_info: 835 handle_com_error (error_info)
836
837 - def handle (self):
838 """The raw OLE object representing the WMI namespace""" 839 return self._namespace
840
841 - def subclasses_of (self, root="", regex=r".*"):
842 classes = {} 843 for c in self._namespace.SubclassesOf (root): 844 klass = c.Path_.Class 845 if re.match (regex, klass): 846 classes[klass] = None 847 return classes
848
849 - def instances (self, class_name):
850 """Return a list of instances of the WMI class. This is 851 (probably) equivalent to querying with no qualifiers. 852 853 <pre class="code"> 854 system.instances ("Win32_LogicalDisk") 855 # should be the same as 856 system.Win32_LogicalDisk () 857 </pre> 858 """ 859 try: 860 return [_wmi_object (obj) for obj in self._namespace.InstancesOf (class_name)] 861 except pywintypes.com_error, error_info: 862 handle_com_error (error_info)
863
864 - def new (self, wmi_class, **kwargs):
865 """This is now implemented by a call to _wmi_namespace.new (qv)""" 866 return getattr (self, wmi_class).new (**kwargs)
867 868 new_instance_of = new 869
870 - def _raw_query (self, wql):
871 """Execute a WQL query and return its raw results. Use the flags 872 recommended by Microsoft to achieve a read-only, semi-synchronous 873 query where the time is taken while looping through. Should really 874 be a generator, but ... 875 NB Backslashes need to be doubled up. 876 """ 877 flags = wbemFlagReturnImmediately | wbemFlagForwardOnly 878 wql = wql.replace ("\\", "\\\\") 879 if _DEBUG: print "_raw_query(wql):", wql 880 try: 881 return self._namespace.ExecQuery (strQuery=wql, iFlags=flags) 882 except pywintypes.com_error, (hresult, hresult_text, additional, param_in_error): 883 raise WMI_EXCEPTIONS.get (hresult, x_wmi (hresult))
884
885 - def query (self, wql, instance_of=None, fields=[]):
886 """Perform an arbitrary query against a WMI object, and return 887 a list of _wmi_object representations of the results. 888 """ 889 return [ _wmi_object (obj, instance_of, fields) for obj in self._raw_query(wql) ]
890
891 - def fetch_as_classes (self, wmi_classname, fields=(), **where_clause):
892 """Build and execute a wql query to fetch the specified list of fields from 893 the specified wmi_classname + where_clause, then return the results as 894 a list of simple class instances with attributes matching fields_list. 895 896 If fields is left empty, select * and pre-load all class attributes for 897 each class returned. 898 """ 899 wql = "SELECT %s FROM %s" % (fields and ", ".join (fields) or "*", wmi_classname) 900 if where_clause: 901 wql += " WHERE " + " AND ".join (["%s = '%s'" % (k, v) for k, v in where_clause.items()]) 902 return [_wmi_result (obj, fields) for obj in self._raw_query(wql)]
903
904 - def fetch_as_lists (self, wmi_classname, fields, **where_clause):
905 """Build and execute a wql query to fetch the specified list of fields from 906 the specified wmi_classname + where_clause, then return the results as 907 a list of lists whose values correspond fields_list. 908 """ 909 wql = "SELECT %s FROM %s" % (", ".join (fields), wmi_classname) 910 if where_clause: 911 wql += " WHERE " + " AND ".join (["%s = '%s'" % (k, v) for k, v in where_clause.items()]) 912 results = [] 913 for obj in self._raw_query(wql): 914 results.append ([obj.Properties_ (field).Value for field in fields]) 915 return results
916
917 - def watch_for ( 918 self, 919 raw_wql=None, 920 notification_type="operation", 921 wmi_class=None, 922 delay_secs=1, 923 **where_clause 924 ):
925 """Set up an event tracker on a WMI event. This function 926 returns an wmi_watcher which can be called to get the 927 next event. eg, 928 929 <pre class="code"> 930 c = wmi.WMI () 931 932 raw_wql = "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'" 933 watcher = c.watch_for (raw_wql=raw_wql) 934 while 1: 935 process_created = watcher () 936 print process_created.Name 937 938 # or 939 940 watcher = c.watch_for ( 941 notification_type="Creation", 942 wmi_class="Win32_Process", 943 delay_secs=2, 944 Name='calc.exe' 945 ) 946 calc_created = watcher () 947 </pre> 948 949 Now supports timeout on the call to watcher, eg: 950 951 <pre class="code"> 952 import pythoncom 953 import wmi 954 c = wmi.WMI (privileges=["Security"]) 955 watcher1 = c.watch_for ( 956 notification_type="Creation", 957 wmi_class="Win32_NTLogEvent", 958 Type="error" 959 ) 960 watcher2 = c.watch_for ( 961 notification_type="Creation", 962 wmi_class="Win32_NTLogEvent", 963 Type="warning" 964 ) 965 966 while 1: 967 try: 968 error_log = watcher1 (500) 969 except wmi.x_wmi_timed_out: 970 pythoncom.PumpWaitingMessages () 971 else: 972 print error_log 973 974 try: 975 warning_log = watcher2 (500) 976 except wmi.x_wmi_timed_out: 977 pythoncom.PumpWaitingMessages () 978 else: 979 print warning_log 980 </pre> 981 """ 982 if isinstance (wmi_class, _wmi_class): 983 class_name = wmi_class._class_name 984 else: 985 class_name = wmi_class 986 wmi_class = getattr (self, class_name) 987 is_extrinsic = "__ExtrinsicEvent" in wmi_class.derivation () 988 if raw_wql: 989 wql = raw_wql 990 else: 991 if is_extrinsic: 992 if where_clause: 993 where = " WHERE " + " AND ".join (["%s = '%s'" % (k, v) for k, v in where_clause.items ()]) 994 else: 995 where = "" 996 wql = "SELECT * FROM " + class_name + where 997 else: 998 if where_clause: 999 where = " AND " + " AND ".join (["TargetInstance.%s = '%s'" % (k, v) for k, v in where_clause.items ()]) 1000 else: 1001 where = "" 1002 wql = \ 1003 "SELECT * FROM __Instance%sEvent WITHIN %d WHERE TargetInstance ISA '%s' %s" % \ 1004 (notification_type, delay_secs, class_name, where) 1005 1006 if _DEBUG: print wql 1007 1008 try: 1009 return _wmi_watcher (self._namespace.ExecNotificationQuery (wql), is_extrinsic=is_extrinsic) 1010 except pywintypes.com_error, error_info: 1011 handle_com_error (error_info)
1012
1013 - def __getattr__ (self, attribute):
1014 """Offer WMI classes as simple attributes. Pass through any untrapped 1015 unattribute to the underlying OLE object. This means that new or 1016 unmapped functionality is still available to the module user. 1017 """ 1018 # 1019 # Don't try to match against known classes as was previously 1020 # done since the list may not have been requested 1021 # (find_classes=False). 1022 # 1023 try: 1024 return self._cached_classes (attribute) 1025 except pywintypes.com_error, error_info: 1026 try: 1027 return self._cached_classes ("Win32_" + attribute) 1028 except pywintypes.com_error, error_info: 1029 return getattr (self._namespace, attribute)
1030
1031 - def _cached_classes (self, class_name):
1032 """Standard caching helper which keeps track of classes 1033 already retrieved by name and returns the existing object 1034 if found. If this is the first retrieval, store it and 1035 pass it back 1036 """ 1037 if self.classes.get (class_name) is None: 1038 self.classes[class_name] = _wmi_class (self, self._namespace.Get (class_name)) 1039 return self.classes[class_name]
1040
1041 - def _getAttributeNames (self):
1042 """Return list of classes for IPython completion engine""" 1043 classes = [str (x) for x in self.classes.keys () if not x.startswith ('__')] 1044 return classes
1045 1046 # 1047 # class _wmi_watcher 1048 #
1049 -class _wmi_watcher:
1050 """Helper class for WMI.watch_for below (qv)""" 1051 1052 _event_property_map = { 1053 "TargetInstance" : _wmi_object, 1054 "PreviousInstance" : _wmi_object 1055 }
1056 - def __init__ (self, wmi_event, is_extrinsic):
1057 self.wmi_event = wmi_event 1058 self.is_extrinsic = is_extrinsic
1059
1060 - def __call__ (self, timeout_ms=-1):
1061 """When called, return the instance which caused the event. Supports 1062 timeout in milliseconds (defaulting to infinite). If the watcher 1063 times out, x_wmi_timed_out is raised. This makes it easy to support 1064 watching for multiple objects. 1065 """ 1066 try: 1067 event = self.wmi_event.NextEvent (timeout_ms) 1068 if self.is_extrinsic: 1069 return _wmi_event (event, None) 1070 else: 1071 return _wmi_event ( 1072 event.Properties_ ("TargetInstance").Value, 1073 _wmi_object (event, property_map=self._event_property_map) 1074 ) 1075 except pywintypes.com_error, error_info: 1076 hresult_code, hresult_name, additional_info, parameter_in_error = error_info 1077 if additional_info: 1078 wcode, source_of_error, error_description, whlp_file, whlp_context, scode = additional_info 1079 if scode == wbemErrTimedout: 1080 raise x_wmi_timed_out 1081 handle_com_error (error_info)
1082 1083 PROTOCOL = "winmgmts:" 1084 IMPERSONATION_LEVEL = "impersonate" 1085 AUTHENTICATION_LEVEL = "default" 1086 NAMESPACE = "root/cimv2"
1087 -def connect ( 1088 computer=".", 1089 impersonation_level="", 1090 authentication_level="", 1091 authority="", 1092 privileges="", 1093 moniker="", 1094 wmi=None, 1095 namespace="", 1096 suffix="", 1097 user="", 1098 password="", 1099 find_classes=True, 1100 debug=False 1101 ):
1102 """The WMI constructor can either take a ready-made moniker or as many 1103 parts of one as are necessary. Eg, 1104 1105 <pre class="code"> 1106 c = wmi.WMI (moniker="winmgmts:{impersonationLevel=Delegate}//remote") 1107 1108 # or 1109 1110 c = wmi.WMI (computer="remote", privileges=["!RemoteShutdown", "Security"]) 1111 </pre> 1112 1113 I daren't link to a Microsoft URL; they change so often. Try Googling for 1114 WMI construct moniker and see what it comes back with. 1115 1116 For complete control, a named argument "wmi" can be supplied, which 1117 should be a SWbemServices object, which you create yourself. Eg, 1118 1119 <pre class="code"> 1120 loc = win32com.client.Dispatch("WbemScripting.SWbemLocator") 1121 svc = loc.ConnectServer(...) 1122 c = wmi.WMI(wmi=svc) 1123 </pre> 1124 1125 This is the only way of connecting to a remote computer with a different 1126 username, as the moniker syntax does not allow specification of a user 1127 name. 1128 1129 If the "wmi" parameter is supplied, all other parameters are ignored. 1130 """ 1131 global _DEBUG 1132 _DEBUG = debug 1133 1134 # 1135 # If namespace is a blank string, leave 1136 # it unaltered as it might to trying to 1137 # access the root namespace 1138 # 1139 #if namespace is None: 1140 # namespace = NAMESPACE 1141 1142 try: 1143 if wmi: 1144 obj = wmi 1145 1146 elif moniker: 1147 if not moniker.startswith (PROTOCOL): 1148 moniker = PROTOCOL + moniker 1149 if _DEBUG: print moniker 1150 obj = GetObject (moniker) 1151 1152 else: 1153 if user: 1154 if impersonation_level or authentication_level or privileges or suffix: 1155 raise x_wmi, "You can't specify an impersonation, authentication or privilege as well as a username" 1156 else: 1157 obj = connect_server ( 1158 server=computer, 1159 namespace=namespace, 1160 user=user, 1161 password=password, 1162 authority=authority 1163 ) 1164 1165 else: 1166 moniker = construct_moniker ( 1167 computer=computer, 1168 impersonation_level=impersonation_level or IMPERSONATION_LEVEL, 1169 authentication_level=authentication_level or AUTHENTICATION_LEVEL, 1170 authority=authority, 1171 privileges=privileges, 1172 namespace=namespace, 1173 suffix=suffix 1174 ) 1175 if _DEBUG: print moniker 1176 obj = GetObject (moniker) 1177 1178 wmi_type = get_wmi_type (obj) 1179 1180 if wmi_type == "namespace": 1181 return _wmi_namespace (obj, find_classes) 1182 elif wmi_type == "class": 1183 return _wmi_class (None, obj) 1184 elif wmi_type == "instance": 1185 return _wmi_object (obj) 1186 else: 1187 raise x_wmi, "Unknown moniker type" 1188 1189 except pywintypes.com_error, error_info: 1190 handle_com_error (error_info)
1191 1192 WMI = connect 1193
1194 -def construct_moniker ( 1195 computer=None, 1196 impersonation_level="Impersonate", 1197 authentication_level="Default", 1198 authority=None, 1199 privileges=None, 1200 namespace=None, 1201 suffix=None 1202 ):
1203 security = [] 1204 if impersonation_level: security.append ("impersonationLevel=%s" % impersonation_level) 1205 if authentication_level: security.append ("authenticationLevel=%s" % authentication_level) 1206 # 1207 # Use of the authority descriptor is invalid on the local machine 1208 # 1209 if authority and computer: security.append ("authority=%s" % authority) 1210 if privileges: security.append ("(%s)" % ", ".join (privileges)) 1211 1212 moniker = [PROTOCOL] 1213 if security: moniker.append ("{%s}/" % ",".join (security)) 1214 if computer: moniker.append ("/%s/" % computer) 1215 if namespace: 1216 parts = re.split (r"[/\\]", namespace) 1217 if parts[0] != 'root': 1218 parts.insert (0, "root") 1219 moniker.append ("/".join (parts)) 1220 if suffix: moniker.append (":%s" % suffix) 1221 return "".join (moniker)
1222
1223 -def get_wmi_type (obj):
1224 try: 1225 path = obj.Path_ 1226 except AttributeError: 1227 return "namespace" 1228 else: 1229 if path.IsClass: 1230 return "class" 1231 else: 1232 return "instance"
1233
1234 -def connect_server ( 1235 server, 1236 namespace = "", 1237 user = "", 1238 password = "", 1239 locale = "", 1240 authority = "", 1241 security_flags = 0, 1242 named_value_set = None 1243 ):
1244 """Return a remote server running WMI 1245 1246 server - name of the server 1247 namespace - namespace to connect to: defaults to whatever's defined as default 1248 user - username to connect as, either local or domain (dom\name or user@domain for XP) 1249 password: leave blank to use current context 1250 locale: desired locale in form MS_XXXX (eg MS_409 for Am En) 1251 authority: either "Kerberos:" or an NT domain. Not needed if included in user 1252 security_flags: if 0, connect will wait forever; if 0x80, connect will timeout at 2 mins 1253 named_value_set: typically empty, otherwise a context-specific SWbemNamedValueSet 1254 1255 <pre class="code"> 1256 c = wmi.WMI (wmi=wmi.connect_server (server="remote_machine", user="myname", password="mypassword")) 1257 </pre> 1258 """ 1259 if _DEBUG: 1260 print server 1261 print namespace 1262 print user 1263 print password 1264 print locale 1265 print authority 1266 print security_flags 1267 print named_value_set 1268 1269 return Dispatch ("WbemScripting.SWbemLocator").\ 1270 ConnectServer ( 1271 server, 1272 namespace, 1273 user, 1274 password, 1275 locale, 1276 authority, 1277 security_flags, 1278 named_value_set 1279 )
1280
1281 -def Registry ( 1282 computer=None, 1283 impersonation_level="Impersonate", 1284 authentication_level="Default", 1285 authority=None, 1286 privileges=None, 1287 moniker=None 1288 ):
1289 1290 if not moniker: 1291 moniker = construct_moniker ( 1292 computer=computer, 1293 impersonation_level=impersonation_level, 1294 authentication_level=authentication_level, 1295 authority=authority, 1296 privileges=privileges, 1297 namespace="default", 1298 suffix="StdRegProv" 1299 ) 1300 1301 try: 1302 return _wmi_object (GetObject (moniker)) 1303 1304 except pywintypes.com_error, error_info: 1305 handle_com_error (error_info)
1306 1307 # 1308 # From a post to python-win32 by Sean 1309 #
1310 -def machines_in_domain (domain_name):
1311 adsi = Dispatch ("ADsNameSpaces") 1312 nt = adsi.GetObject ("","WinNT:") 1313 result = nt.OpenDSObject ("WinNT://%s" % domain_name, "", "", 0) 1314 result.Filter = ["computer"] 1315 domain = [] 1316 for machine in result: 1317 domain.append (machine.Name) 1318 return domain
1319 1320 # 1321 # Typical use test 1322 # 1323 if __name__ == '__main__': 1324 system = WMI () 1325 for my_computer in system.Win32_ComputerSystem (): 1326 print "Disks on", my_computer.Name 1327 for disk in system.Win32_LogicalDisk (): 1328 print disk.Caption, disk.Description, disk.ProviderName or "" 1329