使用python的wmi模块创建vss快照,我发现参数不起作用,除非我将它们反转:
import wmi
def vss_create():
shadow_copy_service = wmi.WMI(moniker='winmgmts:\\\\.\\root\\cimv2:Win32_ShadowCopy')
res = shadow_copy_service.Create('ClientAccessible', 'C:\\')
在msdn docs中,该函数应该以这种方式使用:
Win32_ShadowCopy.Create("C:\\", "ClientAccessible");
为什么会出现这种情况,是否有办法使用预定的订单?
答案 0 :(得分:4)
看起来Wmi对象方法的参数排序与PyWin32层的正常情况相反,并且这种行为已存在至少五年。相关的wmi规范说wmi客户端可以按任何顺序传递参数,因此PyWin32不是错误的'要做到这一点,虽然我无法判断它是故意的还是偶然的。我推测,出于向后兼容性原因,它不太可能发生变化,但您可以通过将参数指定为关键字参数来解决此问题并按参数顺序排列参数:Create(Volume=, Context=)
。
NB。在下面的细节中,我试图从Python WMI模块代码到PyWin32代码中的COM访问的WMI对象,到文档中记录和使用的WMI对象,以及MOF文件的WMI对象规范。 ,到规范文件。有几层,我写了#34; WMI"很多,意思是不同层次的不同事物。
当你说" Python的wmi模块"你的意思是建立在PyWin32上的Tim Golden's Python WMI module(链接到源代码)?
当你从wmi模块获得一个 Python WMI 对象时,它经历的初始化步骤都在类_wmi_object
中,并且包括查询底层wmi对象的可用方法:
for m in ole_object.Methods_:
self.methods[m.Name] = None
我将跳过Python的wmi模块,并直接使用PyWin32来查看在查询WMI COM对象时获得的可用方法:
>>> from win32com.client import GetObject
>>> vss = GetObject('winmgmts:\\\\.\\root\\cimv2:Win32_ShadowCopy')
>>> [method.Name for method in list(vss.Methods_)]
[u'Create', u'Revert']
我们看到Win32_ShadowCopy对象具有方法Create
和Revert
。这就是Python wmi包装器首先了解您正在使用的Create
方法的地方。
从那里开始,Python WMI包装器类会完成一些我无法完全跟踪的设置工作,但它似乎为COM对象的每个可用方法初始化class _wmi_method
一次。该类包括以下初始化步骤:
self.method = ole_object.Methods_ (method_name)
self.in_parameter_names = [(i.Name, i.IsArray) for i in self.in_parameters.Properties_]
列表解析以获取每个方法的可用参数。回到我的测试,探索没有Python WMI层的情况,它会提供如下输出:
>>> CreateMethod = vss.Methods_('Create')
>>> [n.Name for n in list(CreateMethod.InParameters.Properties_)]
[u'Context', u'Volume']
此示例测试稍后显示PyWin32,Win32_ShadowCopy的COM对象,Create
方法 - 按您看到的顺序列出其可用参数 - "错误"订购。 Python WMI层正在接受这种排序。
当您通过Python WMI的包装器调用Win32_ShadowCopy对象的Create()
方法时,_wmi_method
执行此操作:
def __call__ (self, *args, **kwargs):
for n_arg in range (len (args)):
arg = args[n_arg]
parameter = parameters.Properties_[n_arg]
parameter.Value = arg
换句话说;它将您传入的参数(*args
)与存储的参数列表逐个配对,按照您传递的顺序获取参数,并将它们与WMI返回的顺序中的方法参数配对 - 即它不是智能的,它只是将您输入的第一个参数与“上下文”相关联。第二个是' Volume'并让他们倒退,你的代码崩溃。
调用方法还包含Python的**kwargs
参数,该参数包含所有给定的关键字,建议您可以执行
Create(Volume='C:\\', Context="ClientAccessible")
并将它们作为关键字参数按照您想要的顺序放置。 (我还没试过)。
我尝试通过PyWin32com跟踪.Properties_
查找,以尝试识别排序来自较低层的位置,并通过一长串动态和缓存查找。我无法看到会发生什么,我不会理解足够的COM或PyWin32知道要寻找什么样的东西,这对我来说是死路一条。
采用不同的方法并尝试从WMI对象设置文件中找出排序来源:运行Windows附带的mofcomp.exe
并处理托管对象格式(MOF)文件...单击“连接”,“创建” Class" Win32_ShadowCopy&#34 ;;点击"创建"方法列表中的方法,然后单击"编辑方法"按钮;然后单击"编辑输入参数"然后单击"显示MOF",并得到此结果:
[abstract]
class __PARAMETERS
{
[in, ID(0): DisableOverride ToInstance] string Volume;
[in, ID(1): DisableOverride ToInstance] string Context = "ClientAccessible";
};
"正确"来自Windows MOF文件的参数顺序,带有参数的数字ID - 暗示它们具有正确的排序0,1等。
c:\windows\system32\wbem\vss.mof
,MOF文件似乎涵盖了卷影复制对象,其中包含:
[static,implemented,constructor] uint32 Create([in] string Volume,[in] string Context = "ClientAccessible",[out] string ShadowID);
并且this MSDN link的评论中的PowerShell示例包括$class.create("C:\", "ClientAccessible")
。
所以这三件事都与相同的顺序相关,并暗示有正确的或标准的排序。
这让我想到了这些可能性:
没有官方订购。为了证实这一点,我们得到了一个有趣的链条:
本文档:http://www.dmtf.org/sites/default/files/standards/documents/DSP0221_3.0.0.pdf似乎是MOF规范。请参阅第18页的 7.3.3班级声明部分:
第570行:
"方法可以包含零个或多个参数"。
第626至628行:
方法参数通过名称而不是位置来识别 调用方法的客户端可以传递相应的参数 任何订单。因此,可以添加具有默认值的参数 任何位置的方法签名。
我不确定这是否是权威的当前规范,也不是我所有的都在寻找异常,但听起来你应该使用命名参数。
WMI对象和方法有一个MOF定义,MOF规范说你不应该依赖于参数排序;但是,通过PyWin32通过COM访问WMI对象显示了不同的排序(MSDN文档,MOF文件和PowerShell示例)。我还是不知道为什么。
和谷歌搜索 leads me to this邮件列表帖子来自Python wmi模块的作者Tim Golden,说的基本上和我刚刚找到的一样,除了五年前:
方法定义按照WMI返回它们的顺序选择参数[..] 我不知道参数的顺序是否有任何保证[...] 看一下其他一些方法定义,似乎WMI一直以MOF中定义的相反顺序返回params。
此时,看起来PyWin32正在向典型的Windows参数顺序返回一个反转列表,但如果CIM管理对象方法参数列表规范文档明确表示不依赖于参数排序,那就是一个错误?