Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python can't import WMI under special circumstance

I've created a standalone exe Windows service written in Python and built with pyInstaller. When I try to import wmi, an exception is thrown.

What's really baffling is that I can do it without a problem if running the code in a foreground exe, or a foreground python script, or a python script running as a background service via pythonservice.exe!

Why does it fail under this special circumstance of running as a service exe?

import wmi

Produces this error for me:

com_error: (-2147221020, 'Invalid syntax', None, None)

Here's the traceback:

Traceback (most recent call last):
  File "<string>", line 43, in onRequest
  File "C:\XXX\XXX\XXX.pyz", line 98, in XXX
  File "C:\XXX\XXX\XXX.pyz", line 31, in XXX
  File "C:\XXX\XXX\XXX.pyz", line 24, in XXX
  File "C:\XXX\XXX\XXX.pyz", line 34, in XXX
  File "C:\Program Files (x86)\PyInstaller-2.1\PyInstaller\loader\pyi_importers.py", line 270, in load_module
  File "C:\XXX\XXX\out00-PYZ.pyz\wmi", line 157, in <module>
  File "C:\XXX\XXX\out00-PYZ.pyz\win32com.client", line 72, in GetObject
  File "C:\XXX\XXX\out00-PYZ.pyz\win32com.client", line 87, in Moniker

wmi.py line 157 has a global call to GetObject:

obj = GetObject ("winmgmts:")

win32com\client__init.py__ contains GetObject(), which ends up calling Moniker():

def GetObject(Pathname = None, Class = None, clsctx = None):
  """
    Mimic VB's GetObject() function.

    ob = GetObject(Class = "ProgID") or GetObject(Class = clsid) will
    connect to an already running instance of the COM object.

    ob = GetObject(r"c:\blah\blah\foo.xls") (aka the COM moniker syntax)
    will return a ready to use Python wrapping of the required COM object.

    Note: You must specifiy one or the other of these arguments. I know
    this isn't pretty, but it is what VB does. Blech. If you don't
    I'll throw ValueError at you. :)

    This will most likely throw pythoncom.com_error if anything fails.
  """
  if clsctx is None:
    clsctx = pythoncom.CLSCTX_ALL

  if (Pathname is None and Class is None) or \
     (Pathname is not None and Class is not None):
    raise ValueError("You must specify a value for Pathname or Class, but not both.")

  if Class is not None:
    return GetActiveObject(Class, clsctx)
  else:
    return Moniker(Pathname, clsctx)    

The first line in Moniker(), i.e. MkParseDisplayName() is where the exception is encountered:

def Moniker(Pathname, clsctx = pythoncom.CLSCTX_ALL):
  """
    Python friendly version of GetObject's moniker functionality.
  """
  moniker, i, bindCtx = pythoncom.MkParseDisplayName(Pathname)
  dispatch = moniker.BindToObject(bindCtx, None, pythoncom.IID_IDispatch)
  return __WrapDispatch(dispatch, Pathname, clsctx=clsctx)

Note: I tried using

pythoncom.CoInitialize()

which apparently solves this import problem within a thread, but that didn't work...

like image 808
BuvinJ Avatar asked Jan 05 '23 13:01

BuvinJ


2 Answers

I also face the same issue and I figure out this issue finally, import pythoncom and CoInitialize pythoncom.CoInitialize (). They import wmi

import pythoncom
pythoncom.CoInitialize ()
import wmi
like image 138
Rogin Thomas Avatar answered Jan 09 '23 20:01

Rogin Thomas


I tried solving this countless ways. In the end, I threw in the towel and had to just find a different means of achieving the same goals I had with wmi.

Apparently that invalid syntax error is thrown when trying to create an object with an invalid "moniker name", which can simply mean the service, application, etc. doesn't exist on the system. Under this circumstance "winmgmts" just can't be found at all it seems! And yes, I tried numerous variations on that moniker with additional specs, and I tried running the service under a different user account, etc.

like image 39
BuvinJ Avatar answered Jan 09 '23 18:01

BuvinJ