如何通过Python读取Windows更新文件元数据获取目标Windows版本
如何通过Python读取Windows更新文件元数据获取目标Windows版本
哥们,我之前折腾过一模一样的需求——靠文件名判断Win10/Win11更新太不靠谱了,毕竟微软的文件命名有时候真的让人头大。试了好几种方法,终于找到了几个靠谱的路子,分不同文件类型给你讲讲,亲测有效:
处理 .msu 文件
其实MSU本质就是个换了后缀的ZIP压缩包,里面藏着关键的元数据XML文件。用Python自带的zipfile就能解压,再解析XML就能拿到目标系统版本:
import zipfile import xml.etree.ElementTree as ET def get_win_version_from_msu(msu_path): with zipfile.ZipFile(msu_path, 'r') as zip_ref: # 找出包里的XML文件,一般叫Update.xml或者类似的 xml_files = [f for f in zip_ref.namelist() if f.endswith('.xml')] if not xml_files: return "找不到元数据XML文件" with zip_ref.open(xml_files[0]) as xml_file: tree = ET.parse(xml_file) root = tree.getroot() # Windows更新XML有固定命名空间,必须带上 ns = {'wu': 'http://schemas.microsoft.com/msus/2002/12/Update'} target_os = root.find('.//wu:TargetOperatingSystem', ns) if target_os: version_str = target_os.find('wu:Version', ns).text major, minor, build = map(int, version_str.split('.')) # Win10的build从10240开始,Win11是22000及以上 if build >= 22000: return f"Windows 11 (版本号: {version_str})" elif build >= 10240: return f"Windows 10 (版本号: {version_str})" else: return f"未知Windows版本 (版本号: {version_str})" return "未找到目标系统版本信息"
处理 .msi 和 .msp 文件
这俩属于Windows安装包格式,得用Windows Installer的COM接口来读元数据,需要先装pywin32库(pip install pywin32):
import win32com.client def get_win_version_from_msi_msp(file_path): installer = win32com.client.Dispatch("WindowsInstaller.Installer") try: # 以只读模式打开安装包数据库 db = installer.OpenDatabase(file_path, 0) # 先查VersionNT属性,这是Windows Installer标记的最低支持系统版本 view = db.OpenView("SELECT Value FROM Property WHERE Property='VersionNT'") view.Execute() record = view.Fetch() if record: version_nt = record.StringData(1) # VersionNT的数值对应:603=Win10,1001=Win11 if version_nt == '603': return "Windows 10" elif version_nt == '1001': return "Windows 11" # 如果VersionNT查不到,就看ProductVersion里的build号 view = db.OpenView("SELECT Value FROM Property WHERE Property='ProductVersion'") view.Execute() record = view.Fetch() if record: product_ver = record.StringData(1) if '22000' in product_ver or '22621' in product_ver: return f"Windows 11 (产品版本: {product_ver})" elif any(build in product_ver for build in ['1904', '1836', '1776']): return f"Windows 10 (产品版本: {product_ver})" return "未找到有效版本信息" except Exception as e: return f"读取失败: {str(e)}" finally: # 记得释放资源,避免内存泄漏 try: view.Close() except: pass
处理 .cab 文件
CAB是最麻烦的,因为里面可能装着各种内容——有时候是MSI,有时候是驱动,有时候是纯更新文件。给你两种方案:
方案1:用Windows自带的DISM命令
DISM是Windows内置的部署工具,能直接读取CAB里的映像信息:
import subprocess import re def get_win_version_from_cab_dism(cab_path): try: # 调用DISM命令获取映像信息 result = subprocess.run( ['dism', '/Get-WimInfo', '/WimFile:' + cab_path, '/Index:1'], capture_output=True, text=True, check=True ) # 从输出里提取版本号 version_match = re.search(r'Version\s*:\s*(\d+\.\d+\.\d+\.\d+)', result.stdout) if version_match: full_ver = version_match.group(1) build = int(full_ver.split('.')[2]) if build >= 22000: return f"Windows 11 (版本号: {full_ver})" elif build >= 10240: return f"Windows 10 (版本号: {full_ver})" return "DISM未识别到有效版本信息" except subprocess.CalledProcessError as e: return f"DISM命令执行失败: {e.stderr}"
方案2:解压CAB处理内部文件
如果DISM报错(比如CAB不是WIM格式),就解压CAB找里面的MSI/XML文件,用前面的方法处理。可以用pycabinet库(pip install pycabinet):
import pycabinet import xml.etree.ElementTree as ET def get_win_version_from_cab_extract(cab_path): try: with pycabinet.Cabinet(cab_path) as cab: for entry in cab: # 遇到MSI/MSP就用之前的方法处理 if entry.name.endswith(('.msi', '.msp')): with open('temp_installer.msi', 'wb') as f: f.write(entry.read()) ver = get_win_version_from_msi_msp('temp_installer.msi') if ver != "未找到有效版本信息": return ver # 遇到XML就用MSU的解析逻辑 elif entry.name.endswith('.xml'): xml_content = entry.read() tree = ET.fromstring(xml_content) ns = {'wu': 'http://schemas.microsoft.com/msus/2002/12/Update'} target_os = tree.find('.//wu:TargetOperatingSystem', ns) if target_os: version_str = target_os.find('wu:Version', ns).text build = int(version_str.split('.')[2]) if build >=22000: return f"Windows 11 (版本号: {version_str})" elif build>=10240: return f"Windows 10 (版本号: {version_str})" return "未找到有效版本信息" except Exception as e: return f"解压处理失败: {str(e)}"
最后提醒几句
- Win10的build号范围是10240~21999,Win11是22000及以上,这个判断标准是微软官方的,不会错
- 处理XML的时候一定要注意命名空间,不然会找不到元素
- COM对象用完记得释放,不然容易留内存泄漏的坑
内容来源于stack exchange
相关产品推荐
相关产品推荐

