msiexec在python中编写脚本

大多数是背景,跳过接下来的3段问题: 我开发了一个工具,调用一些安装程序,更改注册表项,并移动文件,以帮助我测试具有相当快的更新周期的产品。到目前为止,我有一个GUI,它在一个单独的进程中运行到业务逻辑,以防止它由于GIL而锁定,一切正常等等,但是我对我的代码的一部分有所顾虑,我调用了msiexec。 具体来说,卸载部分给了我关注的问题。目前GUID没有改变所以我可以使用
os.system('msiexec /x "{GUID}" /passive')
的东西卸载产品。它实际上有点复杂,因为我正在使用subprocess.Popen并轮询它,直到它从一个事件循环中完成,以允许与其他步骤的并发。 我担心的是,如果GUID发生变化,显然这不起作用。我不想直接在安装源上指出msiexec,因为这意味着如果我“丢失”我存储在临时目录中的msi文件它将无法工作。 我正在寻找的是一种通过程序名查询来获取GUID的方法,甚至是msiexec的包装器,它可以完成所有这些,包括卸载,对我来说。我想通过注册表进行扫描,但是_winreg模块看起来很慢,所以如果可能的话,我宁愿避免这种情况。如果有更好的方法来扫描注册表,我会全力以赴,因为这也会加快工具的其他部分。 Update0 在此方面的性能至关重要,因为设计目标之一是使工具遵循的过程比任何其他方法(手动或其他方法)更快,以便获得批量采用。 UPDATE1 我尝试了下面的注册表版本的轻微变化,但它始终返回
None
。我不太确定这是怎么回事 - 似乎没有打开相应的密钥,因为我在
with
语句之后插入了一个断点,它从未到达...
def get_guid_by_name(name):
  from _winreg import (OpenKey,
                       QueryInfoKey,
                       EnumKey,
                       QueryValueEx,
                       HKEY_LOCAL_MACHINE,
                       )
  with OpenKey(HKEY_LOCAL_MACHINE, 
               r'SOFTWAREMicrosoftWindowsCurrentVersionUninstall') as key:
      subkeys, _0, _1 = QueryInfoKey(key) # The breakpoint here is never reached
      del _0, _1
      for i in range(subkeys):
        subkey = EnumKey(key, i)
        if subkey[0] != '{' or subkey[-1] != '}':
          continue
        with OpenKey(key, subkey) as _subkey:
          if name in QueryValueEx(_subkey, 'DisplayName')[0]:
            return subkey
  return None

  print get_guid_by_name('Microsoft Visual Studio')
UPDATE2 罢工 - 我是一个傻瓜谁不彻底检查他的缩进 -
print get_guid_by_name('Microsoft Visual Studio')
get_guid_by_name
...     
已邀请:
我不确定_winreg模块是那么慢。我想如果你试图枚举整个注册表来查找可能需要一段时间的字符串的所有实例,但是使用一个体面的目标查询它似乎相当快。 这是一个例子:
from _winreg import *

def get_guid_by_name(name):
    # Open the uninstaller key
    with OpenKey(HKEY_LOCAL_MACHINE, r'SoftwareMicrosoftWindowsCurrentVersionUninstall') as key:
        # We only care about subkeys of the installer key
        subkeys, _, _ = QueryInfoKey(key)
        for i in range(subkeys):
            subkey = EnumKey(key, i)
            # Since we're looking for uninstallers for MSI products,
            # the key name will always be the GUID. We assume that any
            # key starting with '{' and ending with '}' is a GUID, but
            # if not the name won't match.
            if subkey[0] != '{' or subkey[-1] != '}':
                 continue
            # Query the display name or other property of the key to
            # see if it's the one we want
            with OpenKey(key, subkey) as _subkey:
                if QueryValueEx(_subkey, 'DisplayName')[0] == name:
                    return subkey
     return None
在我的机器上,查询Ac​​tiveState的Komodo Edit(我实际上使用的是正则表达而不是直接值比较),1000次迭代需要8.18秒(使用timeit定时),这对我来说似乎是一个可以忽略不计的时间。更好的是,您可以从注册表中提取UninstallString键并将其直接传递给您的子进程(尽管您可能希望将
/passive
开关添加到末尾。 编辑 当然,Microsoft确实提供了一个WMI类(Win32_Product),它提供了一个相当方便的接口来完成所有这些工作。使用Tim Golden的优秀WMI包装器,可以启动这样的安装:
import wmi
c = wmi.WMI()
c.Win32_Product(Name = 'ProductName')[0].Uninstall()
但是,正如本博文中所述,Win32_Product类的使用速度极其缓慢。     

要回复问题请先登录注册