Python小工具:查找Exe文件

       

目录

核心功能特点

🔍 多维度智能搜索

⚡ 高效智能的去重机制

🛡️ 完善的错误处理

典型应用场景

技术亮点


        本文提供了一个专为 Windows 系统设计的强大 Python 脚本,能够通过多种智能途径快速准确地定位系统中安装的可执行文件(.exe)路径。该工具集成了四种不同的查找策略,确保在复杂的企业环境或个人电脑中都能可靠地找到目标程序。

核心功能特点

🔍 多维度智能搜索

采用四级递进式搜索策略,确保查找结果的准确性和完整性:

  1. 运行进程查询 - 通过 PowerShell 获取当前正在运行的指定进程路径
  2. 注册表分析 - 深度扫描系统卸载注册表项,获取软件安装信息
  3. 开始菜单检索 - 解析所有用户的开始菜单快捷方式,找到程序链接
  4. 程序目录扫描 - 在 Program Files 及相关目录中进行深度文件搜索

⚡ 高效智能的去重机制

  • 自动去除重复路径,保持发现顺序
  • 支持路径标准化和大小写不敏感匹配
  • 实时验证路径有效性,确保返回结果都可直接使用

🛡️ 完善的错误处理

  • 全面的异常捕获和处理机制
  • 权限错误的优雅降级处理
  • 支持模糊匹配和部分名称搜索

典型应用场景

软件开发与自动化

  • 自动化软件部署和配置
  • 开发环境中依赖程序的自动检测
  • 持续集成/持续部署(CI/CD)流水线

系统管理与维护

  • 企业环境中的软件资产清点
  • 多版本程序管理
  • 故障排查和系统恢复

终端用户便利

  • 快速找到已安装但忘记位置的程序
  • 创建自定义脚本和快捷方式
  • 批量处理和组织应用程序

技术亮点

  • 跨架构支持:同时处理 32 位和 64 位应用程序
  • 多用户兼容:支持当前用户和所有用户的程序查找
  • 智能过滤:自动跳过系统目录和无关项目,提高搜索效率
  • 编码安全:正确处理系统区域设置和文件编码

附工具源码:

import win32com.client as win32
import re
import string
import subprocess
import locale
import winreg
import os
import win32com.client


def getExeExecutablePath(exe_name: str) -> list[str]:
    """
    获取正在运行的指定可执行文件路径(支持模糊匹配)

    Args:
        exe_name:要查找的进程名(如"chrome.exe"),支持模糊匹配

    Returns:
        按发现顺序排列的进程路径列表(去重)
    """
    safe_name = exe_name.strip().replace(""", '').replace(""", "")
    if not safe_name:
        return []

    command = [
        "powershell.exe",
        "-Command",
        f"Get-CimInstance Win32_Process | "
        f"Where-Object {{ $_.Name -ilike '*{safe_name}*' }} | "
        f"Select-Object -ExpandProperty ExecutablePath | "
        f"Sort-Object -Unique"
    ]

    try:
        result = subprocess.run(
            command,
            check=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            encoding=locale.getpreferredencoding(False),
            creationflags=subprocess.CREATE_NO_WINDOW
        )
    except subprocess.CalledProcessError:
        return []
    except FileNotFoundError:
        return []

    # 处理输出结果
    paths = []
    seen = set()
    for line in result.stdout.splitlines():
        clean_path = line.strip()
        if clean_path and os.path.exists(clean_path):
            # 保持顺序的去重逻辑
            if clean_path not in seen:
                seen.add(clean_path)
                paths.append(clean_path)

    return paths


def findExeFromRegUninstallPath(exe_name: str) -> list[str]:
    """从注册表卸载项中查找包含指定exe的安装路径(已合并为单个函数)

    Args:
        exe_name: 目标exe文件名(如"chrome.exe"),不区分大小写

    Returns:
        按发现顺序排列的有效路径列表(自动去重)
    """
    result = []
    seen = set()
    pattern = re.compile(re.escape(exe_name), re.IGNORECASE)

    registry_paths = [
        (winreg.HKEY_LOCAL_MACHINE, r"SOFTWAREMicrosoftWindowsCurrentVersionUninstall"),
        (winreg.HKEY_LOCAL_MACHINE, r"SOFTWAREWOW6432NodeMicrosoftWindowsCurrentVersionUninstall"),
        (winreg.HKEY_CURRENT_USER, r"SoftwareMicrosoftWindowsCurrentVersionUninstall")
    ]

    for root, path in registry_paths:
        try:
            with winreg.OpenKey(root, path) as main_key:
                for i in range(winreg.QueryInfoKey(main_key)[0]):
                    subkey_name = winreg.EnumKey(main_key, i)

                    # 跳过系统组件
                    if subkey_name.startswith(("{", "KB")) or "microsoft" in subkey_name.lower():
                        continue

                    try:
                        with winreg.OpenKey(main_key, subkey_name) as subkey:
                            # 检查多个可能的键值
                            for value_name in ["DisplayIcon", "InstallLocation", "UninstallString"]:
                                try:
                                    raw_value = winreg.QueryValueEx(subkey, value_name)[0]
                                except FileNotFoundError:
                                    continue

                                # 清理路径字符串
                                clean_path = re.split(r'[,#]', raw_value.split('"')[-1])[0].strip()
                                if not clean_path:
                                    continue

                                # 处理目录路径的情况
                                if os.path.isdir(clean_path):
                                    for root_dir, _, files in os.walk(clean_path):
                                        for file in files:
                                            if file.lower().endswith(".exe") and pattern.search(file):
                                                full_path = os.path.join(root_dir, file)
                                                if full_path not in seen:
                                                    seen.add(full_path)
                                                    result.append(full_path)
                                                break
                                else:
                                    if pattern.search(clean_path) and os.path.exists(clean_path):
                                        if clean_path not in seen:
                                            seen.add(clean_path)
                                            result.append(clean_path)
                    except (OSError, PermissionError):
                        continue
        except (FileNotFoundError, PermissionError):
            continue

    return result


def findExeFromStartMenuLnk(exe_name: str) -> list[str]:
    """
    从系统开始菜单快捷方式中查找包含指定exe名称的路径

    Args:
        exe_name: 要查找的可执行文件名(如"notepad.exe")

    Returns:
        按路径出现顺序排列的匹配项列表,无重复项
    """

    shell = win32com.client.Dispatch("WScript.Shell")
    try:
        # 动态获取所有用户的开始菜单路径
        start_menu_path = shell.SpecialFolders("AllUsersPrograms")
    except Exception:
        # 回退到默认路径
        start_menu_path = r"C:\ProgramData\Microsoft\Windows\Start Menu\Programs"

    ignore_dirs = {
        "Accessibility", "Accessories", "System Tools",
        "Administrative Tools", "Windows Kits",
        "Debugging Tools for Windows (X64)",
        "Debugging Tools for Windows (X86)",
        "Windows PowerShell"
    }

    exe_paths = []
    seen = set()  # 用于去重的集合

    for root, dirs, files in os.walk(start_menu_path):
        # 实时过滤子目录(原地修改dirs列表)
        dirs[:] = [d for d in dirs if d not in ignore_dirs]

        for filename in files:
            # 先进行扩展名过滤提升效率
            if not filename.lower().endswith(".lnk"):
                continue

            full_path = os.path.join(root, filename)

            try:
                # 获取快捷方式目标
                shortcut = shell.CreateShortCut(full_path)
                target_path = shortcut.TargetPath
            except Exception:
                continue  # 跳过无效快捷方式

            # 有效性检查
            if not target_path or not os.path.exists(target_path):
                continue

            # 智能路径匹配(处理短路径和长路径)
            normalized_path = os.path.normpath(target_path).lower()
            search_key = exe_name.strip().lower()

            # 同时匹配文件名和完整路径
            if (search_key in normalized_path or
                    search_key == os.path.basename(normalized_path).lower()):

                if target_path not in seen:
                    seen.add(target_path)
                    exe_paths.append(target_path)

    return exe_paths


def getExeFromProgramFilesDir(exe_name: str, depth: int = 4) -> list[str]:
    """在系统Program Files类目录中查找指定exe文件

    Args:
        exe_name: 目标文件名或关键词(如"chrome"或"chrome.exe"),不区分大小写
        depth: 最大搜索深度(0=仅ProgramFiles根目录),默认4层子目录

    Returns:
        按发现顺序排列的有效路径列表(自动去重)
    """
    found_paths = []
    seen_paths = set()
    target = str(exe_name.strip().lower()).replace(".exe", '')

    program_dirs = {
        os.path.normcase(os.path.normpath(p))
        for env_var in ["ProgramFiles", "ProgramFiles(x86)", "ProgramW6432"]
        if (p := os.environ.get(env_var)) and os.path.exists(p)
    }

    for drive in (f"{d}:/" for d in string.ascii_uppercase if os.path.exists(f"{d}:/")):
        try:
            with os.scandir(drive) as entries:
                program_dirs.update(
                    os.path.normcase(entry.path)
                    for entry in entries
                    if entry.is_dir()
                    and "program" in (name := entry.name.lower())
                    and any(k in name for k in {"file", "files"})
                )
        except OSError:
            continue

    for base_dir in program_dirs:
        if not os.path.isdir(base_dir):
            continue

        try:
            for root, dirs, files in os.walk(base_dir, topdown=True):
                rel_path = os.path.relpath(root, base_dir)
                current_depth = rel_path.count(os.sep) if rel_path != "." else 0

                if current_depth > depth:
                    dirs.clear()
                    continue

                for file in (f for f in files if f.lower().endswith(".exe")):
                    if target not in file.lower():
                        continue

                    full_path = os.path.normpath(os.path.join(root, file))
                    if (norm_path := os.path.normcase(full_path)) not in seen_paths:
                        seen_paths.add(norm_path)
                        found_paths.append(full_path)
        except PermissionError:
            continue

    return found_paths


def findExeFile(exe_name: str, depth: int = 4) -> list[str]:
    """按照"正在运行->注册表->开始菜单->program files目录"的顺序,查找exe文件所在路径

    Args:
        exe_name: 目标文件名(含.exe或不含均可)
        depth: 仅影响最后一级目录搜索深度

    Returns:
        去重后的路径列表(保持发现顺序)
    """
    target = exe_name.lower().rstrip(".exe")

    check_functions = [
        lambda: getExeExecutablePath(target),
        lambda: findExeFromRegUninstallPath(target),
        lambda: findExeFromStartMenuLnk(target),
        lambda: getExeFromProgramFilesDir(target, depth)
    ]

    seen = set()
    for func in check_functions:
        if paths := [p for p in func() if (np := os.path.normpath(p)) not in seen and not seen.add(np)]:
            return paths

    return []

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

python自动化码农

感谢打赏,您的鼓励是我创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值