Reworking windows.com.Variant + working on new wmi API + wmi test

This commit is contained in:
hakril
2018-11-19 14:45:52 +01:00
parent a18c08ee53
commit 267eddb5fe
3 changed files with 440 additions and 137 deletions
+179
View File
@@ -0,0 +1,179 @@
import pytest
import windows
import windows.generated_def as gdef
from pfwtest import *
## This comment was in test_system.py: still revelant ?
# Well, pytest initialize COM with its own parameters
# It might make our own com.init() in WMI fail and therefore not call
# CoInitializeSecurity. But looks like pytest/default COM-security parameters
# does not allow to perform the request we want..
# So we try & do it ourself here.
wmimanager = windows.system.wmi
@pytest.mark.parametrize("name, expected_cls", [
("root\\cimv2", "Win32_Process"),
("root\\subscription", "__EventFilter"),
])
def test_wmimanager_getnamespace(name, expected_cls):
namespace = wmimanager[name]
assert namespace.name == name
assert namespace.get_object(expected_cls)
def test_wmimanager_subnamespaces():
subnamespaces = wmimanager.get_subnamespaces("root")
subnamespaces = [x.lower() for x in subnamespaces]
assert "cimv2" in subnamespaces
assert "security" in subnamespaces
assert "subscription" in subnamespaces
# Test WmiNamespace
@pytest.mark.parametrize("name, query",[
("root\\cimv2", "select * from Win32_Process"),
("root\\subscription", "select * from __EventFilter"),
])
def test_query_select(name, query):
namespace = wmimanager[name]
x = namespace.query(query)
assert x
assert isinstance(x, list)
def test_bad_query_raise():
namespace = wmimanager["root\\cimv2"]
with pytest.raises(WindowsError) as e:
x = namespace.query("BADSELECT QUERY BAD")
assert (e.value.winerror & 0xffffffff) == gdef.WBEM_E_INVALID_QUERY
def test_create_class_enum():
namespace = wmimanager["root\\cimv2"]
enum = namespace.create_class_enum(None)
assert enum
classes = list(enum)
cls_names = [cls["__CLASS"].lower() for cls in classes]
assert "win32_process" in cls_names
assert "win32_shortcutfile" in cls_names
assert "__win32provider" in cls_names
@pytest.mark.parametrize("name, cls", [
("root\\cimv2", "Win32_Process"),
("root\\subscription", "__EventFilter"),
])
def test_get_object(name, cls):
namespace = wmimanager[name]
assert namespace.name == name
obj = namespace.get_object(cls)
assert obj["__CLASS"] == cls
assert obj["__PATH"]
# Todo: test
# - put_instance
# - exec_method
@pytest.mark.parametrize("cmdline", [r"c:\windows\notepad.exe trolol.exe"])
def test_exec_method_Win32_Process_create(cmdline):
namespace = wmimanager["root\\cimv2"]
win32_process_cls = namespace.get_object("Win32_Process")
inparam = win32_process_cls.get_method("Create").inparam.spawn_instance()
inparam["CommandLine"] = cmdline
result = namespace.exec_method(win32_process_cls, "Create", inparam)
assert result
assert not result["ReturnValue"]
assert result["ProcessId"]
proc = windows.WinProcess(pid=result["ProcessId"])
assert proc.peb.commandline.str == cmdline
proc.exit(0)
## Test enum
def test_enumeration_iteration_no_timeout():
namespace = wmimanager["root\\cimv2"]
processes = namespace.exec_query("select * from Win32_Process").all()
assert isinstance(processes, list)
assert processes
processes = list(namespace.exec_query("select * from Win32_Process"))
assert processes
assert isinstance(processes, list)
proc = namespace.exec_query("select * from Win32_Process").next()
assert proc
assert proc["__CLASS"].lower() == "win32_process"
def test_enumeration_iteration_timeout():
namespace = wmimanager["root\\cimv2"]
timegen = namespace.exec_query("select * from Win32_Process").iter_timeout(0)
# Iter on Win32_Process should not be immediat
# so itering on timegen should trigger a timeout
with pytest.raises(WindowsError) as e:
x = list(timegen)
assert (e.value.winerror & 0xffffffff) == gdef.WBEM_S_TIMEDOUT
@pytest.fixture
def wmi_cls():
# Test expect the cls to have a "Name" attribute & "Create" method
# Maybe doing something more generic
namespace = wmimanager["root\\cimv2"]
yield namespace.get_object("Win32_Process")
def test_wmiobject_spawn(wmi_cls):
assert wmi_cls["__Genus"] == wmi_cls.genus == gdef.WBEM_GENUS_CLASS
wmi_obj = wmi_cls()
assert wmi_obj["__Genus"] == wmi_obj.genus == gdef.WBEM_GENUS_INSTANCE
assert wmi_obj["__CLASS"] == wmi_cls["__CLASS"]
def test_wmiobject_getitem(wmi_cls):
assert wmi_cls["Name"] is None
wmi_obj = wmi_cls()
assert wmi_obj["Name"] is None
with pytest.raises(WindowsError) as e:
wmi_obj["BAD_NAME"]
assert (e.value.winerror & 0xffffffff) == gdef.WBEM_E_NOT_FOUND
# Complexe type
assert isinstance(wmi_obj["__CLASS"], basestring)
assert isinstance(wmi_obj["__PROPERTY_COUNT"], int)
assert isinstance(wmi_obj["__DERIVATION"], list)
props = wmi_obj.get_properties()
assert isinstance(props, list)
assert len(props) > wmi_obj["__PROPERTY_COUNT"]
# Check that other dict-like methods exists
assert wmi_obj.keys()
assert wmi_obj.values()
assert wmi_obj.items()
def test_wmiobject_getmethod(wmi_cls):
wmi_method = wmi_cls.get_method("Create")
# Wmi method is a custom PFW object (namedtuple)
assert wmi_method
assert wmi_method.inparam
inparam_attrs = wmi_method.inparam.keys()
assert "CommandLine" in inparam_attrs
assert wmi_method.outparam
outparam_attrs = wmi_method.outparam.keys()
assert "ProcessId" in outparam_attrs
def test_wmiobject_setitem(wmi_cls):
wmi_obj = wmi_cls()
assert wmi_obj["Name"] is None
wmi_obj["Name"] = "Test"
assert wmi_obj["Name"] == "Test"
# Strange but that how WMI api works with variant :D
wmi_obj["Name"] = 2
assert wmi_obj["Name"] == "2"
with pytest.raises(WindowsError) as e:
wmi_obj["PageFaults"] = "ERROR_BAD_INT"
assert (e.value.winerror & 0xffffffff) == gdef.WBEM_E_TYPE_MISMATCH
with pytest.raises(WindowsError) as e:
wmi_obj["__PROPERTY_COUNT"] = 42
assert (e.value.winerror & 0xffffffff) == gdef.WBEM_E_READ_ONLY
+147 -94
View File
@@ -7,6 +7,7 @@ import windows
from windows import winproxy
from windows.generated_def.winstructs import *
import windows.generated_def as gdef
from windows.generated_def import RPC_C_IMP_LEVEL_IMPERSONATE, CLSCTX_INPROC_SERVER
from windows.generated_def import interfaces
from windows.generated_def.interfaces import generate_IID, IID
@@ -35,9 +36,17 @@ def create_instance(clsiid, targetinterface, custom_iid=None, context=CLSCTX_INP
custom_iid = targetinterface.IID
return winproxy.CoCreateInstance(byref(clsiid), None, context, byref(custom_iid), byref(targetinterface))
def resolve_progid(progid):
clsid = CLSID()
winproxy.CLSIDFromProgID(progid, clsid)
# We just filed the CLSID: refresh the __repr__
clsid.update_strid()
return clsid
# Improved COM object
# Todo: ctypes_genertation extended struct ?
class ImprovedSAFEARRAY(SAFEARRAY):
# Todo: ctypes_generation extended struct ?
class SafeArray(SAFEARRAY):
@classmethod
def of_type(cls, addr, t):
self = cls.from_address(addr)
@@ -46,7 +55,7 @@ class ImprovedSAFEARRAY(SAFEARRAY):
@classmethod
def from_PSAFEARRAY(self, psafearray):
res = cast(psafearray, POINTER(ImprovedSAFEARRAY))[0]
res = cast(psafearray, POINTER(SafeArray))[0]
return res
def to_list(self, t=None):
@@ -83,111 +92,155 @@ class ImprovedSAFEARRAY(SAFEARRAY):
#VT_LPWSTR : LPWSTR,
#}
class ImprovedVariant(VARIANT):
@property
def asbstr(self):
if self.vt != VT_BSTR:
raise ValueError("asbstr on non-bstr variant")
#import pdb;pdb.set_trace()
return self._VARIANT_NAME_3.bstrVal
# VARIANT type checker
# Allow to guess a VARIANT_TYPE og a python value
@property
def aslong(self):
if not self.vt in [VT_I4]:
raise ValueError("aslong on non-long variant")
return self._VARIANT_NAME_3.lVal
def never_match(value):
return False
@property
def asbool(self):
if not self.vt in [VT_BOOL]:
raise ValueError("get_bstr on non-bool variant")
return bool(self._VARIANT_NAME_3.boolVal)
def check_type_null(value):
return value is None
@property
def asdispatch(self):
if not self.vt in [VT_DISPATCH]:
raise ValueError("asdispatch on non-VT_DISPATCH variant")
return interfaces.IDispatch(self._VARIANT_NAME_3.pdispVal)
def check_type_i4(value):
# 31 ? as we may want to keep sign :)
return isinstance(value, (int, long)) and (value).bit_length() <= 32
@property
def asshort(self):
if not self.vt in [VT_I2]:
raise ValueError("asshort on non-VT_I2 variant")
return self._VARIANT_NAME_3.iVal
def check_type_i8(value):
# 63 ? as we may want to keep sign :)
return isinstance(value, (int, long)) and (value).bit_length() <= 64
@property
def asbyte(self):
if not self.vt in [VT_UI1]:
raise ValueError("asbyte on non-VT_UI1 variant")
return self._VARIANT_NAME_3.bVal
def check_type_bstr(value):
return isinstance(value, basestring)
@property
def asunknown(self):
if not self.vt in [VT_UNKNOWN]:
raise ValueError("asunknown on non-VT_UNKNOWN variant")
return self._VARIANT_NAME_3.punkVal
def check_type_bool(value):
return isinstance(value, bool)
@property
def asarray(self):
if not self.vt & VT_ARRAY:
raise ValueError("asarray on non-VT_ARRAY variant")
# TODO: auto extract VT_TYPE for the array ?
#type = VT_VALUE_TO_TYPE[self.vt & VT_TYPEMASK]
return ImprovedSAFEARRAY.from_PSAFEARRAY(self._VARIANT_NAME_3.parray)
def check_type_array(value):
return True
@property
def aslong_array(self):
if not self.vt & VT_I4:
raise ValueError("as_bstr_array on non-VT_BSTR variant")
return self.asarray.to_list(LONG)
VARIAN_NAME_3_TYPE = [f[1] for f in VARIANT._fields_ if f[0] == "_VARIANT_NAME_3"][0]
def generate_asarray_property(vttype):
empty = object()
class Variant(VARIANT):
def __init__(self, value=empty, type=None):
if type is not None:
self.set_value_and_type(value, type)
return
elif value is empty:
self.vt = VT_EMPTY
return
self.guess_type_and_set_value(value)
# Copy raw-ctypes fields which is a descriptor :)
rawvt = VARIANT.vt
# Most of the value in the colunm[1]
# are attribute of the sub-union _VARIANT_NAME_3
# This union must be ctypes-anonymous for this code to works
# We want to access these directly from the VARIANT
# to allow custom descriptor for complexe type to be referenced here
CHECK_TYPE = [
# Order is important
# as VT_I4 check may match VT_BOOL values
# VT_BOOL check must be before VT_I4 one
(VT_BOOL, "boolVal", check_type_bool),
(VT_I4, "lVal", check_type_i4),
(VT_I8, "llVal", check_type_i8),
(VT_BSTR, "bstrVal", check_type_bstr),
(VT_NULL, None, check_type_null),
(VT_EMPTY, None, never_match),
(VT_DISPATCH, "pdispVal", never_match), # I cannot recognize DISPATCH ptr for now
(VT_UNKNOWN, "punkVal", never_match), # recognise PFW ComInterface ?
# Test: do not allow auto-creation of small int values
# I don't know but a feel it may confuse some API expecting VT_I4
(VT_I2, "iVal", never_match),
(VT_UI1, "bVal", never_match),
]
VARIANT_TYPE_BY_NAME = {f[0]: f[1] for f in VARIAN_NAME_3_TYPE._fields_}
QUICK_CHECK_TYPE = {x: y for x,y, _ in CHECK_TYPE}
def get_vt(self):
rawvt = super(Variant, self).vt
return gdef.VARENUM.mapper[self.rawvt]
def set_vt(self, value):
self.rawvt = value
vt = property(get_vt, set_vt)
def set_value_and_type(self, value, type):
attr = self.QUICK_CHECK_TYPE[type]
# No check: user must be careful about non-match value&type
setattr(self, attr, value)
self.vt = type
def get_value_based_on_type(self):
rawvt = self.rawvt
if rawvt & VT_ARRAY:
realtype = rawvt & ~VT_ARRAY
attr = self.QUICK_CHECK_TYPE[realtype]
attrtype = self.VARIANT_TYPE_BY_NAME[attr]
array = SafeArray.from_PSAFEARRAY(self._VARIANT_NAME_3.parray)
return array.to_list(attrtype)
attr = self.QUICK_CHECK_TYPE[rawvt]
if attr is None:
return None
return getattr(self, attr)
def guess_type_and_set_value(self, value):
for t, attr, check in self.CHECK_TYPE:
try:
checkres = check(value)
except TypeError as e:
continue
if checkres:
self.vt = t
if attr is not None:
setattr(self, attr, value)
return True
raise ValueError("Could not guess VT_TYPE for <{0}> of type <{1}>".format(value, type(value)))
value = property(get_value_based_on_type, guess_type_and_set_value)
# quick_check: bypass python lookup-limitation
def generate_getter(vt_type, transfo=(lambda x:x), quick_check=QUICK_CHECK_TYPE):
attr = quick_check[vt_type]
@property
def as_array_generated(self):
# TODO: vt check like the others ?
return self.asarray.to_list(vttype)
return as_array_generated
def getter(self):
if not self.rawvt == vt_type:
raise ValueError("Invalid vt-type for attribute expected <{0}> got <{1}>".format(vt_type, self.vt))
return transfo(getattr(self, attr))
return getter
asbstr_array = generate_asarray_property(BSTR)
aslong_array = generate_asarray_property(LONG)
asbyte_array = generate_asarray_property(BYTE)
asbool_array = generate_asarray_property(VARIANT_BOOL)
asbstr = generate_getter(VT_BSTR)
aslong = generate_getter(VT_I4)
asbool = generate_getter(VT_BOOL)
asdispatch = generate_getter(VT_DISPATCH, transfo=interfaces.IDispatch)
asshort = generate_getter(VT_I2)
asbyte = generate_getter(VT_UI1)
asunknown = generate_getter(VT_UNKNOWN)
def to_pyobject(self):
# if self.vt & VT_ARRAY:
# # Something better TODO i guess
# if self.vt & VT_TYPEMASK == VT_BSTR:
# import pdb;pdb.set_trace()
# print("VT_TYPEMASK ARRAY")
# return self.asarray.to_list(BSTR)
# if self.vt & VT_TYPEMASK == VT_I4:
# import pdb;pdb.set_trace()
# print("VT_TYPEMASK ARRAY")
# return self.asarray.to_list(LONG)
# raise NotImplementedError("Variant of type {0:#x}".format(self.vt))
# use the ImprovedVariant.MAPPER that dispatch by self.vt
try:
return self.MAPPER[self.vt](self)
except KeyError:
raise NotImplementedError("Variant of type {0:#x}".format(self.vt))
def __repr__(self):
return """<{0} of type {1}>""".format(type(self).__name__, self.vt)
ImprovedVariant.MAPPER = {
VT_UI1: ImprovedVariant.asbyte.fget,
VT_I2: ImprovedVariant.asshort.fget,
VT_DISPATCH: ImprovedVariant.asdispatch.fget,
VT_BOOL: ImprovedVariant.asbool.fget,
VT_I4: ImprovedVariant.aslong.fget,
VT_BSTR: ImprovedVariant.asbstr.fget,
VT_EMPTY: (lambda x: None),
VT_NULL: (lambda x: None),
VT_UNKNOWN: ImprovedVariant.asunknown.fget,
(VT_ARRAY | VT_BSTR): ImprovedVariant.asbstr_array.fget,
(VT_ARRAY | VT_I4): ImprovedVariant.aslong_array.fget,
(VT_ARRAY | VT_UI1): ImprovedVariant.asbyte_array.fget,
(VT_ARRAY | VT_BOOL): ImprovedVariant.asbool_array.fget
}
# Deprecated: remove me when test pass :)
# ImprovedVariant.MAPPER = {
# VT_UI1: ImprovedVariant.asbyte.fget,
# VT_I2: ImprovedVariant.asshort.fget,
# VT_DISPATCH: ImprovedVariant.asdispatch.fget,
# VT_BOOL: ImprovedVariant.asbool.fget,
# VT_I4: ImprovedVariant.aslong.fget,
# VT_BSTR: ImprovedVariant.asbstr.fget,
# VT_EMPTY: (lambda x: None),
# VT_NULL: (lambda x: None),
# VT_UNKNOWN: ImprovedVariant.asunknown.fget,
# (VT_ARRAY | VT_BSTR): ImprovedVariant.asbstr_array.fget,
# (VT_ARRAY | VT_I4): ImprovedVariant.aslong_array.fget,
# (VT_ARRAY | VT_UI1): ImprovedVariant.asbyte_array.fget,
# (VT_ARRAY | VT_BOOL): ImprovedVariant.asbool_array.fget
# }
+114 -43
View File
@@ -2,13 +2,13 @@ import windows
import ctypes
import struct
import functools
from collections import namedtuple
from ctypes.wintypes import *
import windows.com
import windows.generated_def as gdef
from windows.generated_def.winstructs import *
from windows.generated_def.interfaces import IWbemLocator, IWbemServices, IEnumWbemClassObject, IWbemClassObject, IWbemCallResult
# Common error check for all WMI COM interfaces
# This 'just' add the corresponding 'WBEMSTATUS' to the hresult error code
@@ -16,36 +16,47 @@ class WmiComInterface(object):
def errcheck(self, result, func, args):
if result < 0:
wmitag = gdef.WBEMSTATUS.mapper[result & 0xffffffff]
raise WindowsError(result , wmitag)
raise WindowsError(result, wmitag)
return args
# https://docs.microsoft.com/en-us/windows/desktop/api/wbemcli/nn-wbemcli-iwbemclassobject
WmiMethod = namedtuple("WmiMethod", ["inparam", "outparam"])
# https://docs.microsoft.com/en-us/windows/desktop/WmiSdk/calling-a-method
class WmiObject(IWbemClassObject, WmiComInterface):
class WmiObject(gdef.IWbemClassObject, WmiComInterface):
## low level API
def get_variant(self, name):
variant_res = windows.com.ImprovedVariant()
if not isinstance(name, basestring):
nametype = type(name).__name__
raise TypeError("WmiObject attributes name must be str, not <{0}>".format(nametype))
variant_res = windows.com.Variant()
self.Get(name, 0, variant_res, None, None)
return variant_res
def get(self, name):
return self.get_variant(name).to_pyobject()
return self.get_variant(name).value
def get_method(self, name):
inpararm = type(self)()
outpararm = type(self)()
variant_res = windows.com.ImprovedVariant()
variant_res = windows.com.Variant()
self.GetMethod(name, 0, inpararm, outpararm)
return inpararm, outpararm
return WmiMethod(inpararm, outpararm)
def put_variant(self, name, variant):
if not isinstance(name, basestring):
nametype = type(name).__name__
raise TypeError("WmiObject attributes name must be str, not <{0}>".format(nametype))
return self.Put(name, 0, variant, 0)
def put(self, name, value):
variant_value = windows.com.ImprovedVariant(value)
variant_value = windows.com.Variant(value)
return self.put_variant(name, variant_value)
def spawn(self):
def spawn_instance(self):
instance = type(self)()
self.SpawnInstance(0, instance)
return instance
@@ -54,19 +65,35 @@ class WmiObject(IWbemClassObject, WmiComInterface):
def genus(self):
return gdef.tag_WBEM_GENUS_TYPE.mapper[self.get("__GENUS")]
@property
def properties(self):
res = POINTER(SAFEARRAY)()
self.GetNames(None, 0, None, byref(res))
safe_array = ctypes.cast(res, POINTER(windows.com.ImprovedSAFEARRAY))[0]
safe_array.elt_type = BSTR
return safe_array.to_list()
## Higher level API
# TODO: put this in WmiObject
def as_dict(self, attrs="**"):
return {k: self.get(k) for k in self.properties}
def get_properties(self):
# res = POINTER(SAFEARRAY)()
res = POINTER(windows.com.SafeArray)()
x = ctypes.pointer(res)
self.GetNames(None, 0, None, cast(x, POINTER(POINTER(gdef.SAFEARRAY))))
# need to free the safearray / unlock ?
return res[0].to_list(BSTR)
properties = property(get_properties)
# Make WmiObject a mapping object
keys = get_properties
__getitem__ = get
__setitem__ = put
def items(self):
return [(k, self.get(k)) for k in self.properties]
def values(self): # Not sur anyone will use this but keep the dict interface
return [x[1] for x in self.items()]
## Make it callable like any class :D
__call__ = spawn_instance
def __repr__(self):
if not self:
return """<{0} (NULL)>""".format(type(self).__name__,)
if self.genus == gdef.WBEM_GENUS_CLASS:
return """<{0} class "{1}">""".format(type(self).__name__, self.get("__Class"))
return """<{0} instance of "{1}">""".format(type(self).__name__, self.get("__Class"))
@@ -80,14 +107,20 @@ class WmiEnumeration(gdef.IEnumWbemClassObject, WmiComInterface):
# For now the count is hardcoded to 1
obj = WmiObject()
return_count = gdef.ULONG(0)
self.Next(timeout, 1, obj, return_count)
if not return_count or not obj:
error = self.Next(timeout, 1, obj, return_count)
if error == gdef.WBEM_S_TIMEDOUT:
raise WindowsError(gdef.WBEM_S_TIMEDOUT, "Wmi timeout")
elif error == WBEM_S_FALSE:
return None
return obj
else:
return obj
def __iter__(self):
return self.iter_timeout(self.DEFAULT_TIMEOUT)
def iter_timeout(self, timeout=None):
while True:
obj = self.next()
obj = self.next(timeout)
if obj is None:
return
yield obj
@@ -95,12 +128,45 @@ class WmiEnumeration(gdef.IEnumWbemClassObject, WmiComInterface):
def all(self):
return list(self) # SqlAlchemy like :)
class WmiLocator(IWbemLocator, WmiComInterface):
class WmiCallResult(gdef.IWbemCallResult, WmiComInterface):
def __init__(self, result_type=None, namespace_name=None):
self.result_type = result_type
self.namespace_name = namespace_name
def get_call_status(self, timeout=gdef.WBEM_INFINITE):
status = gdef.LONG()
self.GetCallStatus(timeout, status)
return WBEMSTATUS.mapper[status.value & 0xffffffff]
def get_result_object(self, timeout=gdef.WBEM_INFINITE):
result = WmiObject()
self.GetResultObject(timeout, result)
return result
def get_result_string(self, timeout=gdef.WBEM_INFINITE):
result = gdef.BSTR()
self.GetResultString(timeout, result)
return result
def get_result_service(self, timeout=gdef.WBEM_INFINITE):
result = WmiNamespace()
self.GetResultServices(timeout, result)
return result
@property
def result(self):
if self.result_type is None:
raise ValueError("Cannot call <result> with no result_type")
return getattr(self, "get_result_" + self.result_type)()
class WmiLocator(gdef.IWbemLocator, WmiComInterface):
pass # Just for the WMI errcheck callback
# !TEST CODE
class WmiNamespace(IWbemServices, WmiComInterface):
class WmiNamespace(gdef.IWbemServices, WmiComInterface):
r"""An object to perform wmi request to ``a given namespace``"""
#CLSID_WbemAdministrativeLocator_IID = windows.com.IID.from_string('CB8555CC-9128-11D1-AD9B-00C04FD8FDFF')
@@ -110,7 +176,7 @@ class WmiNamespace(IWbemServices, WmiComInterface):
WBEM_FLAG_FORWARD_ONLY)
def __init__(self, namespace, *args, **kwargs):
self.namespace = namespace
self.name = namespace
@classmethod
def connect(cls, namespace, user=None, password=None):
@@ -122,9 +188,6 @@ class WmiNamespace(IWbemServices, WmiComInterface):
locator.Release()
return self
### OLD IMPLEM
def query(self, query):
"""TODO: doc"""
return list(self.exec_query(query))
@@ -141,6 +204,8 @@ class WmiNamespace(IWbemServices, WmiComInterface):
execq("WQL", query, flags, ctx, enumerator)
return enumerator
# Create friendly name for create_class_enum & create_instance_enum ?
def create_class_enum(self, superclass, flags=DEFAULT_ENUM_FLAGS, deep=True):
flags |= gdef.WBEM_FLAG_DEEP if deep else gdef.WBEM_FLAG_SHALLOW
@@ -148,7 +213,7 @@ class WmiNamespace(IWbemServices, WmiComInterface):
self.CreateClassEnum(superclass, flags, None, enumerator)
return enumerator
# subclasses
# subclasses ?
def create_instance_enum(self, filter, flags=DEFAULT_ENUM_FLAGS, deep=True):
# ??? marche pas :(
@@ -160,7 +225,6 @@ class WmiNamespace(IWbemServices, WmiComInterface):
select = create_instance_enum
# TEST 2
def get_object(self, path):
result = WmiObject()
self.GetObject(path, gdef.WBEM_FLAG_RETURN_WBEM_COMPLETE, None, result, None)
@@ -168,30 +232,37 @@ class WmiNamespace(IWbemServices, WmiComInterface):
def put_instance(self, instance):
# TODO: change flag
res = IWbemCallResult()
self.service.PutInstance(instance, gdef.WBEM_FLAG_CREATE_ONLY, None, res)
res = WmiCallResult(result_type="string")
self.PutInstance(instance, gdef.WBEM_FLAG_CREATE_ONLY, None, res)
return res
def exec_method(self, obj, method, inparam):
result = IWbemCallResult()
outparam = IWbemClassObject()
if isinstance(obj, IWbemClassObject):
def exec_method(self, obj, method, inparam, flags=0):
if flags & gdef.WBEM_FLAG_RETURN_IMMEDIATELY:
# semisynchronous call -> WmiCallResult
result = WmiCallResult(result_type="object")
outparam = None
else:
# Synchronous call -> WmiObject (outparam)
result = None
outparam = WmiObject()
if isinstance(obj, gdef.IWbemClassObject):
obj = obj.get("__Path")
# Flags 0 -> synchronous call
# No WmiCallResult result is directly in outparam
self.ExecMethod(obj, method, 0, None, inparam, outparam, result)
return outparam, result
return outparam or result
def __repr__(self):
null = "" if self else " (NULL)"
return """<{0} "{1}"{2}>""".format(type(self).__name__, self.namespace, null)
return """<{0} "{1}"{2}>""".format(type(self).__name__, self.name, null)
class WmiManager(dict):
"""The main WMI class exposed, used to list and access differents WMI namespace, can be used as a dict to access
:class:`WmiRequester` by namespace
:class:`WmiNamespace` by name
Example:
>>> windows.system.wmi["root\\SecurityCenter2"]
<WmiRequester namespace="root\\SecurityCenter2">
<WmiNamespace "root\SecurityCenter2">
"""
DEFAULT_NAMESPACE = "root\\cimv2" #: The default namespace for :func:`select` & :func:`query`
def __init__(self):
@@ -214,7 +285,7 @@ class WmiManager(dict):
return self.default_namespace.query
def get_subnamespaces(self, root="root"):
return [x["Name"] for x in self[root].select("__NameSpace", ["Name"])]
return [x["Name"] for x in self[root].select("__NameSpace")]
namespaces = property(get_subnamespaces)
"""The list of available WMI namespaces"""