Python从Windows进程/开始菜单/注册表/ProgramFiles目录,根据指定exe文件名称,找到该exe文件所在路径
这种莫名其妙的需求,来自于每次调用下载程序,要调用的下载程序exe文件不知道安装到哪里去了(甚至可能是绿色版的,就没安装过)
从Windows进程中查找应用程序安装路径
import subprocess
import locale
def getExeExecutablePath(exeName):
"""
要获取的exe必须在运行,才能从进程中获取到
匹配模式:包含并忽略大小写
返回list
"""
patharr = list()
command = f'''wmic process where "name like '%{exeName}%'" get executablepath'''
p = subprocess.Popen(command,shell=True,stdout=subprocess.PIPE,)
stdout = p.communicate()[0].decode(locale.getpreferredencoding())
arr = [i.strip() for i in stdout.split('\n') if i.strip() not in ['ExecutablePath','']]
for i in arr:
if i not in patharr:
patharr.append(i)
return patharr
getExeExecutablePath("chrome")
返回结果
['C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe']
locale.getpreferredencoding()
获取一下系统编码,用于返回数据的解码,避免乱码。
subprocess.Popen
是通过子进程的方式,实现类型命令行执行,加上stdout=subprocess.PIPE
是为了拿到输出内容。
从Windows注册表已安装程序注册的卸载路径中查找应用程序安装路径
涉及到注册表操作,官网文档比较简单函数也不多,没找到直接能取出所有包含项目的方法,所以用了winreg.QueryInfoKey
取项目数量,然后遍历逐项提取,才实现了遍历查找。
import winreg
def findExeFromRegUninstallPath(exeName):
"""
从注册表卸载路径中获取exe文件路径
匹配模式:包含并忽略大小写
返回list
"""
pathArr = list()
# 取出卸载路径上层的key值
regPath = r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
key = winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, regPath)
# 取出key包含项目数,并枚举每一项
for i in range(winreg.QueryInfoKey(key)[0]):
item = winreg.EnumKey(key,i) # 取出项目名
if item[0]!='{': # 屏蔽非用户安装的系统项目
# 取key值以取出对应DisplayIcon位置
key1 = winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, regPath+'\\'+item)
try:
# 取出图标命名中的路径部分
exePath = winreg.QueryValueEx(key1, "DisplayIcon")[0].split(',')[0].strip().strip('"').strip()
if exeName.lower() in exePath.lower():
pathArr.append(exePath)
except FileNotFoundError as e:
pass
winreg.CloseKey(key1)
winreg.CloseKey(key)
return pathArr
findExeFromRegUninstallPath("Chrome")
返回结果
['C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe']
从Windows Start Menu查找应用程序安装路径
基本就是遍历查询,只有从lnk中取出指向路径,算是个比较罕见的操作。
import os
import sys
import win32com.client
def findExeFromStartMenuLnk(exeName):
"""
从Start Menu获取exe文件路径
匹配模式:包含并忽略大小写
返回list
"""
pathArr = list()
# 开始菜单文件夹
path = r'C:\ProgramData\Microsoft\Windows\Start Menu\Programs'
# 忽略下一系统自带原生程序文件夹名
ignorePath = [
'Accessibility',
'Accessories',
'System Tools',
'Administrative Tools',
'Windows Kits',
'Debugging Tools for Windows (X64)',
'Debugging Tools for Windows (X86)',
'Windows PowerShell',
]
shell = win32com.client.Dispatch("WScript.Shell")
# 遍历文件夹,取出所有lnk图标
for record in os.walk(path):
dirname = record[0]
if dirname.split('\\')[-1] in ignorePath:
continue
for filename in record[2]:
filepath = os.path.join(dirname, filename)
filepath = os.path.abspath(filepath)
# 从lnk中取出指向路径
if os.path.splitext(filepath)[1]=='.lnk':
shortcut = shell.CreateShortCut(filepath)
exePath = shortcut.Targetpath
# 包含且不重复的,加入到返回列表
if exeName.lower() in exePath.lower() and exePath not in pathArr:
pathArr.append(exePath)
return pathArr
findExeFromStartMenuLnk('chrome')
返回结果
['C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe']
遍历常见安装路径(针对绿色安装的)
思路是所有磁盘根目录下,前3-5层目录中的exe文件,这个比较简单,参照Start Menu
里面的遍历写法即可,因为目前还没有这种需求先不写了。
2021-07-15 早上有空顺便写了,实际写出来发现想的简单了,os.walk迭代器,遍历结果过于庞大,各种应用程序附带的零碎文件实在太多,考虑到效率需要限制文件夹挖掘深度。
【注意】这里我们假设,程序厂商或用户遵守常识,将程序放在了系统默认的"Program*File*"这样的目录下
def getExeFromProgramFilesDir(exeName, deepth=4):
"""
从所有磁盘根目录下,文件夹名同时包含'program'和'file'的文件夹中,获取exe文件。
考虑到效率问题,设置挖掘深度
匹配模式:包含并忽略大小写
返回list
"""
pathArr = list()
exeName = exeName.lower()
# 找出所有磁盘驱动器
driveArr = [f'{c}:\\' for c in string.ascii_uppercase if os.path.exists(f'{c}:')]
# 遍历找出所有ProgramFilew文件夹
programfileArr = list()
for drive in driveArr:
for d in os.listdir(drive):
d = drive + d
dlower = d.lower()
if 'program' in dlower and 'file' in dlower and os.path.isdir(d):
programfileArr.append(d)
# 遍历ProgramFiles文件夹
for pf in programfileArr:
for root, dirs, files in os.walk(pf):
if root[len(pf):].count('\\') == deepth: # 限制遍历深度,1层表示当前文件夹;2表示当前及当前子文件夹;依此类推...
del dirs[:]
else:
for i in files:
ilower = i.lower()
if ilower[-4:] == '.exe' and exeName in ilower:
pathArr.append(os.path.join(root, i))
return pathArr
总结
来个大合集
def findExeFile(exeName, deepth=4):
"""
按照'正在运行 > 注册表 > 开始菜单 > programfiles目录'的顺序,查找exe文件所在路径
按照该顺序去重后返回结果
匹配模式:包含并忽略大小写
返回list
"""
pathArr = getExeExecutablePath(exeName) + \
findExeFromRegUninstallPath(exeName) + \
findExeFromStartMenuLnk(exeName) + \
getExeFromProgramFilesDir(exeName, deepth=deepth)
distinctPathArr = list()
for i in pathArr:
if i not in distinctPathArr:
distinctPathArr.append(i)
return distinctPathArr