蓝屏错误码别混查:STOP码、Win32错误码与minidump排查
简介:《电脑蓝屏死机代码的大集合》是一份面向Windows普通用户、电脑维护人员和初级运维者的蓝屏错误码速查文档,重点解决蓝屏后只看到停机画面、难以判断故障来源的问题。内容以0x0000至0x0086等十六进制代码为索引,逐条给出中文释义,涉及系统调用、网络通信、磁盘与打印机设备、内存空间、信号量等常见异常,并在后文归纳重启系统、检查系统配置、更新驱动程序、查看磁盘和打印机状态、使用系统还原等处理方向,便于读者按屏幕代码对照现象、缩小排查范围。压缩包内共1个doc文件,大小约47KB,体量轻便,适合放在本机或维护工具盘中随手查阅。已有3792人学习,可作为蓝屏问题初筛、错误码释义和日常排障的常备参考。
1. 蓝屏表不是急救包:先搞清楚它解决的是哪一层的问题
「电脑蓝屏死机代码的大集合」这类资料,几乎每个跑过桌面支持的人硬盘里都躺着一份,可真到蓝屏那一刻,多数人还是条件反射去搜。原因很直接:表里 0x0000 到 0x0427 这一批条目,绝大多数是 Win32 与 NT 状态码,来源是文件读写、网络、注册表、服务控制这些上层接口;而蓝屏画面上那行 0x0000007B 属于内核 BugCheck 码,两套体系只是碰巧都写成十六进制。把它当"蓝屏对照表"背,第一眼就会查偏。
但它依然值得留一份在本地:程序弹窗里的错误数字、事件日志里被截断的返回码、驱动安装失败的 0x 尾数,都能在这张表里对上号。后面按"分清编号体系 → 把表变成能查的东西 → 落到转储和日志取证"的顺序拆,适合经常被喊去"看一眼是不是内存坏了"的桌面支持、驱动调试和自装机玩家。
2. 把上千条错误码拆成可查的结构:区间划分与两个查询脚本
文档给的是一个巨型清单,直接从头翻到尾不现实。先把它还原成有结构的东西,再谈怎么用。
2.1 这份表的取值区间到底按什么划分
原表给出的分组是 0x0000–0x0055 系统错误、0x0056–0x0064 网络、0x0065–0x0070 设备、0x0071–0x0080 磁碟机、0x0081–0x0090 印表机、0x0091–0x0100 系统配置。这个分法按十进制整数凑的边界,好用,但不完全等于真实的消息来源划分。
我一般按"消息由哪个 DLL 提供"重新理解它:低段 0–499 是系统消息,由内核与基础库抛出,覆盖文件、设备、进程、线程;500–999 段大多保留或由系统内部使用;994–1022 这一截集中在注册表与 I/O 子系统,配置库损坏、机码无法读写都落在这里;1051–1063 是服务控制管理器,服务启动超时、循环依赖、服务未安装都在这个区间;50–70 那几行网络错误属于更早的一套网络消息偏移,靠 netmsg.dll 翻译,不在主消息表里。
理解分层的好处是:看到一个码,先判断它属于哪一层,就能立刻缩小排查面。0x03F1 说明配置数据库本身有问题,跟显卡驱动没关系;0x0426 说明你调的服务压根没起来,问题在服务配置不在硬件。拿到码先问"谁抛的",比急着换内存条有效得多。
还有一类坑要提前说清楚:同一个十进制数在不同体系里含义完全不同。表里 1005 是"储存媒体未含任何可辨识的档案系统",这是对的;但如果它在别处出现成 NTSTATUS 的 0x03EB,含义就变了。查表前先确认来源模块,这一步省不掉。
2.2 用 Python 把文档里的表变成可查询字典
原文那种"数值 + 叙述"的平铺格式,最适合先落成字典。下面这段只保留常用片段作示范,完整表按同样格式补进去即可。
# errcode.py —— 把散落的「数值 + 叙述」整理成可查询字典 # 键统一用整数,输出时再转 hex,避免十进制/十六进制混着对不上 ERR = { 0x0000: "作业完成", 0x0002: "系统找不到指定的档案", 0x0005: "拒绝存取", 0x0007: "储存体控制区块已毁", 0x0008: "储存体空间不足,无法处理这个指令", 0x0010: "无法移除目录", 0x0013: "储存媒体为防写状态", 0x0017: "资料错误(CRC 循环冗余检查)", 0x0020: "档案正被另一个行程使用", 0x0021: "档案的一部份被锁定,现在无法存取", 0x0027: "磁碟已满", 0x0033: "远端电脑无法使用", 0x0035: "网路路径找不到", 0x0043: "网路名称找不到", 0x0050: "档案已经存在", 0x0070: "磁碟空间不足", 0x007B: "档名、目录名称或储存体标签语法错误", 0x0085: "join 或 subst 无法用于已结合的磁碟机", 0x0091: "目录仍有资料", 0x00AA: "所要求的资源正在使用中", 0x03F1: "组态系统登录资料库毁损", 0x03F5: "无法写入组态系统登录机码", 0x041B: "停止控制已传送给相依的服务", 0x041D: "服务未在时限内回应启动或控制请求", 0x0426: "服务尚未启动", } def lookup(code: int) -> str: """按整数查码;不在表里时明确告知,而不是返回空串""" return ERR.get(code, "该码不在当前字典中,先确认它来自哪套编号体系") def search(word: str): """只知道现象不知道码时用:按描述反查,返回 (hex, 描述) 列表""" return [(hex(k), v) for k, v in ERR.items() if word in v] if __name__ == "__main__": print(lookup(0x7B)) # 传十六进制字面量,Python 自动按整数处理 print(lookup(1062)) # 传十进制同样能命中 for row in search("磁碟"): print(row)这段的逻辑很朴素:键是整数,所以 0x7B 和 123 是同一个键,不存在"十六进制查不到"的问题。lookup在键缺失时返回一句明确提示,而不是 None,因为排查现场最容易犯的错就是把"查不到"当成"没有这个错误"。search是反向入口——你手里只有"开机就提示磁盘有问题的弹窗",没有码,靠关键词捞候选,再逐个比对上下文。
参数上唯一需要留意的是十六进制字面量必须带0x前缀,否则 7B 会被当成非法标识符。另外字典里我刻意保留了原文的繁体表述(档案、磁碟、储存体),因为很多现场截图的措辞就是这样,用简体关键词反而搜不中,两边都留一份更稳。
2.3 用系统自带的 API 交叉验证码的含义
自己整理的表难免有抄错的时候,系统本身就能翻译这些码。PowerShell 里直接构造 Win32Exception 即可,不需要装任何东西:
# Translate-ErrCode.ps1 —— 用系统消息表校验自查字典是否抄对 param( [int[]]$Code = @(5, 32, 112, 1005, 1062) # 可传十进制或 0x 字面量 ) foreach ($c in $Code) { # 负数会被当作 HRESULT 处理,这里强制转成无符号整数 $msg = [System.ComponentModel.Win32Exception]::new($c) "{0,6} (0x{0:X4}) -> {1}" -f $c, $msg.Message }$Code是数组参数,命令行里写-Code 0x20,0x21也行,PowerShell 会做强转。"{0,6}"里的 6 是右对齐宽度,纯粹为了输出对齐好读。这里最需要注意的是:Win32Exception 只认识 0–4999 这一段以及部分系统消息,遇到 6000 以上的码会统一回一句"未知错误",这不是你表抄错了,而是那一段的消息根本不由这个 API 提供。
实际用法是双向校验:从字典查到的描述,拿去和 Win32Exception 的输出比对;两边措辞不同但语义一致,说明码没抄错,只是翻译版本不同。如果一边说"拒绝存取"另一边说"参数错误",那基本可以确定你手上的表在这一行有问题,以系统输出为准。我见过不止一次因为表里差一位数字,把磁盘满当成权限问题查了半天的血泪经验。
2.4 查出来之后先确认错误发生在哪一层
码查明白了,下一步不是马上动手修,而是确认它是在哪一层冒出来的。同样一个"拒绝存取",出现在应用层是权限配置问题,出现在驱动加载阶段是签名或完整性策略问题,出现在内核里就可能是文件系统元数据损坏,三条路完全不同。
我通常按三个信号源做交叉:界面上弹出的错误框属于应用层,直接看进程名和它操作的路径;事件日志里的服务控制、注册表相关记录属于系统服务层,看来源和事件 ID;转储文件里的 BugCheck 才算内核层。三个来源里只要有两个指向同一模块,基本就能锁定方向。
这一步最忌讳的是"看到码就去搜解决方法"。搜索引擎给你的答案往往对应另一个上下文,照做之后问题没解决,反而多出两三个新变量,后面再排查就说不清是谁引起的。先把层级钉死,再谈修,这个习惯能省掉大量返工。
3. 蓝屏 STOP 码和 Win32 错误码:两套 0x 编号别混着查
这是这份资料最容易让人翻车的地方,单独拎出来讲。
3.1 蓝屏画面上的 0x000000XX 是内核 BugCheck 码
蓝屏版面下方那行形如0x0000007B的东西,是内核在判定无法继续运行后写入的 BugCheck 码,固定八位十六进制,取值范围集中在很窄的一段。它和你表里 0x0007「储存体控制区块已毁」没有任何关系,只是数字长得像。
常见的几个 STOP 码和方向大致是这样:
| STOP 码 | 名称 | 参数通常指向 | 优先怀疑 |
|---|---|---|---|
| 0x0000007B | INACCESSIBLE_BOOT_DEVICE | 无法访问的引导设备对象 | 存储控制器模式变更、引导驱动缺失 |
| 0x00000050 | PAGE_FAULT_IN_NONPAGED_AREA | 被引用的非法地址 | 内存条、驱动越界访问 |
| 0x0000001A | MEMORY_MANAGEMENT | 页表管理异常 | 内存颗粒、缓存、磁盘坏道 |
| 0x000000D1 | DRIVER_IRQL_NOT_LESS_OR_EQUAL | 出错地址与驱动基址 | 网卡、无线、外设驱动 |
| 0x0000003B | SYSTEM_SERVICE_EXCEPTION | 异常记录与出错指令 | 图形驱动、安全软件过滤驱动 |
| 0x000000EF | CRITICAL_PROCESS_DIED | 终止的关键进程对象 | 系统文件损坏、过滤驱动拦截 |
| 0x0000009F | DRIVER_POWER_STATE_FAILURE | 电源状态转换失败的设备栈 | 睡眠唤醒相关驱动 |
| 0x00000024 | NTFS_FILE_SYSTEM | 文件系统结构 | 磁盘坏道、非正常断电 |
这张表的价值不在于让你背下来,而在于给你一个初筛方向。0x7B 和内存基本无关,去跑内存测试纯属浪费时间;0x50 和 0x1A 反复出现,才轮到怀疑内存。方向对了,后面每一步才有意义。
3.2 参数 1 到参数 4 比代码本身更有信息量
蓝屏版面上代码后面还有四个参数,很多人直接忽略。实际上对不少 STOP 码来说,参数才是定位的关键。以 0xD1 为例,参数 1 是驱动试图访问的地址,参数 4 是出错指令所在的地址;把参数 4 拿去和驱动加载基址一减,就能算出偏移,再对着调试器里的模块信息一看,肇事模块基本跑不掉。
以 0x50 为例,参数 1 是被引用的无效地址,参数 2 是访问类型(读还是写),参数 3 是触发访问的指令地址。参数 2 是"写"的时候,问题往往在驱动写坏了指针;是"读"的时候,更可能是对象已被释放后又被引用。同一行代码,读和写两个方向查下去差得很远。
记录的规范做法是把整行抄全,包括四个参数,别只记代码。截图的时候把屏幕上半部分也拍进去,那里往往有"失败的操作:xxx.sys"这一行,直接点名了模块,比任何推断都省事。我在现场遇到过屏幕只拍到下半截的情况,只能靠转储反推,多花了一个多小时。
3.3 用事件日志把 STOP 码和设备、驱动串起来
蓝屏瞬间系统来不及写太多东西,但重启之后事件日志里会留下痕迹。系统日志中的 1001 事件由错误报告组件写入,正文里带着 BugCheck 码和四个参数;41 事件表示上次关机不正常;6008 表示意外断电。三条一起看,能还原出大致时间线。
# Get-BugCheckHistory.ps1 —— 把最近 30 天的蓝屏与异常关机记录拉成表 $since = (Get-Date).AddDays(-30) Get-WinEvent -FilterHashtable @{ LogName = 'System' Id = 1001, 41, 6008 StartTime = $since } -ErrorAction SilentlyContinue | Select-Object TimeCreated, Id, ProviderName, @{Name='Detail'; Expression={ ($_.Message -split "`r?`n")[0] }} | Sort-Object TimeCreated | Format-Table -AutoSize -Wrap-FilterHashtable里的Id接受整数数组,一次筛三个事件比循环调用快得多;StartTime用 DateTime 对象而不是字符串,避免区域格式导致的解析失败。-ErrorAction SilentlyContinue是必须的,日志里一条匹配都没有时它会抛非终止错误,加了这个参数才会安静返回空。
Detail那一列只取消息的第一行,是因为 1001 事件的完整正文很长,包含 dump 路径、代码、参数、报告 ID,全打出来反而看不清。需要完整内容时把表达式去掉即可。时间线拉出来之后重点看两件事:一是同一个 STOP 码是否在固定操作后反复出现(比如每次插某个外设、每次休眠唤醒),二是蓝屏前几秒有没有别的驱动报错——那个报错往往才是真正的起因,BugCheck 只是最后倒下的那一下。
4. 从屏幕上的那行码到肇事驱动:转储、日志、调试器三步取证
代码查明白了,方向也有了,接下来是把证据拿到手。这一步如果没做好,后面全是猜。
4.1 先确认转储真的写下来了
很多人排查到一半才发现转储目录是空的,前面所有分析都白做。先查配置:
# Check-DumpConfig.ps1 —— 确认崩溃转储是否会被写出 Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl' | Select-Object CrashDumpEnabled, DumpFile, MiniDumpDir, AlwaysKeepMemoryDump, Overwrite # 分页文件必须能容纳转储内容,否则系统会静默放弃写盘 Get-CimInstance Win32_PageFileUsage | Select-Object Name, AllocatedBaseSize, CurrentUsageCrashDumpEnabled的取值对应关系是排查时最常查的一项:
| 取值 | 含义 | 典型用途 |
|---|---|---|
| 0 | 不写转储 | 只为快速重启,不建议 |
| 1 | 完整内存转储 | 需要分析内核态全貌时 |
| 2 | 内核内存转储 | 大多数驱动问题的平衡选择 |
| 3 | 小内存转储 | 默认值,只含 BugCheck 上下文 |
| 7 | 自动内存转储 | 由系统按可用空间决定 |
AllocatedBaseSize是分页文件当前分配的兆字节数,小内存转储一般要求系统盘上至少留出足够空间,内核转储则要看物理内存规模。这里有个常被忽略的前提:转储写在系统盘,系统盘上的分页文件就不能取消;如果转储路径指向别的盘,那个盘上必须有分页文件。配置改完必须重启才生效,改完不重启就等着复现蓝屏,属于典型白忙。
修改的方式是写注册表项,写完重启:
# 切换成小内存转储,适合日常排查且占用小 Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl' ` -Name CrashDumpEnabled -Value 3 -Type DWord # 同时保留转储文件,避免被系统在下次崩溃时覆盖 Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl' ` -Name AlwaysKeepMemoryDump -Value 1 -Type DWord-Type DWord不能省,注册表里这两个值的类型是 REG_DWORD,写成字符串会导致系统读不到、回落到默认值,现象就是"改完还是没文件"。
4.2 用调试器把 minidump 拆开
拿到 dmp 之后,命令行调试器足够应付绝大多数场景,不需要图形界面。下面这条是最小可用命令:
kd -z "C:\Windows\Minidump\010125-12345-01.dmp" -c "!analyze -v; q"-z指定要打开的转储文件,-c后面跟一段启动后自动执行的命令串,!analyze -v让调试器把 BugCheck 码、参数、可能的肇事模块、调用栈一次性打印出来,q是退出,避免挂在那里等输入。如果只想交互式看,把-c去掉即可。
进入调试器后,最有用的几条命令是:!analyze -v看结论,重点看MODULE_NAME、IMAGE_NAME、FAILURE_BUCKET_ID三个字段;lmvm <模块名>查具体模块的版本、时间戳、加载基址,版本号和文件时间对定位"是不是某个驱动更新之后开始的"特别有用;kb打印调用栈,参数会跟着显示,能看出是哪个函数调下去的;.bugcheck重看代码和参数,省得翻回去。
符号解析不顺的时候先执行.symfix再.reload,让调试器走本地缓存路径;这一步失败不影响 BugCheck 码和参数,但调用栈会变成一串地址,可读性差很多。我一般会先跑一次.reload,看到明显的函数名出来再往下分析,否则容易把"符号没下到"误判成"栈被打乱了"。
分析结论要交叉验证,不能只看!analyze -v点名的模块。它给出的是"最后出事的那个",不一定是"最先做错的那个"。常见情况是 A 驱动写坏了内存,B 驱动读到坏数据时崩了,调试器点名 B。判断办法是看栈上是否有其他模块的痕迹,以及蓝屏前的事件日志里谁先报错。
4.3 驱动与硬件的交叉验证清单
转储给的线索是软件侧的,还需要和硬件状态对一遍。下面这张清单是我每次必走的:
| 检查项 | 命令或入口 | 看什么 |
|---|---|---|
| 第三方驱动时间分布 | Get-CimInstance Win32_PnPSignedDriver | 蓝屏前是否刚更新过某驱动 |
| 驱动签名状态 | pnputil /enum-drivers | 是否存在未签名或异常发布的驱动 |
| 磁盘健康 | chkdsk /scan、厂商工具 | 坏道、写入失败、文件系统错误 |
| 系统文件完整性 | sfc /scannow、DISM检查 | 是否被替换或损坏 |
| 内存稳定性 | 系统自带内存诊断或压力测试 | 0x50、0x1A 反复出现时必须做 |
| 快速启动与休眠 | 电源选项 | 0x9F 类问题先关快速启动试 |
| 外设与扩展卡 | 逐件移除 | 0xD1 类问题优先怀疑新增外设 |
驱动时间分布这一项最容易被低估。按DriverDate倒序排,把蓝屏时间点之前的几天内更新的驱动列出来,如果肇事模块就在其中,原因基本清楚。pnputil /enum-drivers的输出里会标注发布者与版本,配合设备管理器里的回滚功能,是最快的验证手段。硬件那几项不要一次全上,尤其内存测试耗时很长,先按 STOP 码方向筛,确认相关再跑。
4.4 什么时候该停止修软件转去查硬件
有个判断标准我一直沿用:同一个 STOP 码在完全重装系统后仍然复现,且复现与负载正相关(跑得越久越容易崩、温度越高越容易崩),基本可以判定问题不在软件层。这时候继续调驱动、改注册表、换系统版本,都属于无效劳动。
反向的标准同样清晰:换一个驱动版本后问题消失,或者只在某个特定程序运行时崩溃,那就是软件侧。两种情况下动作完全不同,最怕的是两边同时动手,最后既不知道是哪边修好的,也不知道下次复发该怎么处理。第 5 章会专门讲这个坑。
5. 排查蓝屏时的五个坑:现象、原因与绕开的方式
五个坑都是现场反复出现的,按"现象 → 原因 → 解决"记下来,下次遇到直接对号。
5.1 现象:按表查到的解释和屏幕提示对不上
有人拿蓝屏上的 0x0000007B 去表里查,查到 0x0007「储存体控制区块已毁」,于是开始测内存、重插内存条,折腾一整晚毫无进展。同类情况还有把 0x00000050 当成表里 0x0050「档案已经存在」,越查越离谱。
原因是两套编号体系混用:蓝屏码是内核 BugCheck,固定八位,语义由内核定义;表里的是 Win32/NT 状态码,位数不定,语义由消息表定义。两者碰巧数值接近,才会误导人。
解决办法是查之前先看形态:屏幕上独占一行、前面带STOP:或直接跟在"停止代码"后面的,按 BugCheck 处理;出现在弹窗正文、日志字段、命令行返回值里的,按 Win32 码处理。形态分不清就看来源,事件日志 1001 事件里明确写的是 BugCheck 码,程序返回值里的一般是 Win32 码。
5.2 现象:蓝屏代码每天都不一样,无从下手
同一天里出现 0x3B、0x50、0x1A 三个不同的码,看着像系统全面崩坏,重装之后依旧。只看代码本身永远理不出头绪。
原因是这些码都是结果不是原因。驱动越界写内存,写到哪里崩哪里,每次崩的位置不同,码自然不同。真正稳定的线索在蓝屏前几秒的日志里,以及转储里反复出现的那个模块。
解决办法是放弃逐个码分析,改成按时间窗口拉日志,找"每次蓝屏前都出现的那一条"。再对多个 minidump 分别跑!analyze -v,把MODULE_NAME列出来做交集,交集里那个模块才是要动的目标。这个方法我在多台机器上用过,比单看代码有效得多。
5.3 现象:转储目录永远是空的
明明设置了小内存转储,蓝屏也复现了,Minidump目录里却一个文件都没有,或者只有很早之前的几个。
原因通常有三个:清理工具把 dmp 当垃圾定期删了;转储路径指向了没有分页文件的磁盘;系统盘剩余空间不足或者分页文件被手动设成很小。还有一种隐蔽情况是转储写到了MEMORY.DMP而不是Minidump目录,因为转储类型被设成了完整或内核转储,找错地方自然找不到。
解决办法是先按 4.1 节的脚本把CrashDumpEnabled、DumpFile、MiniDumpDir三个值打出来看,别凭印象;再把转储目录加进清理工具的排除列表;最后确认系统盘分页文件由系统管理或容量足够。改完重启,然后再复现一次。这一步不做,后面所有分析都是空谈。
5.4 现象:同一次排查里改了驱动、关了快速启动、还换了电源计划
问题确实消失了,但说不清是哪一步起的作用。几周后复发,只能把上次的动作全再做一遍,运气好碰对,运气不好继续换。
原因是多变量同时改动,把因果关系彻底破坏了。蓝屏这类问题本来就有偶发性,改十项修好了,可能只是那一项起了作用,也可能只是恰好这段时间没触发。
解决办法是单变量推进,一次只改一项,改完观察足够长的时间(我一般至少覆盖三个工作日加一次完整休眠唤醒周期)再决定下一项。改动记在本子上,包括时间、改了什么、改完有没有复现。这份记录看起来麻烦,但它就是你的后悔药——复发时翻一眼就知道上次到底动了什么。
5.5 现象:换了新硬件之后蓝屏反而更频繁
升级内存或加装扩展卡之后,原本偶发的蓝屏变成每天一次,代码从 0x1A 变成 0xD1。
原因是新硬件引入了新变量:内存条与主板时序不匹配、扩展卡驱动与原有驱动抢资源、供电不足导致高负载下出错。这时候盯着系统文件和旧驱动查,方向从一开始就错了。
解决办法是把时间点和硬件变更对齐,先做最小化配置(只留必要外设)观察,再逐件加回。内存这类部件优先跑一次完整诊断,别嫌慢。另外注意新硬件的驱动版本,出厂附带的光盘驱动往往比系统自带的新,但未必更稳,两个版本各跑一段时间的对比很有必要。
6. 把错误码表变成随手可用的现场采集脚本
到这一步,表、日志、转储三条线都通了,剩下的问题是效率:每次蓝屏都要手工敲五六条命令,时间一长就会偷懒,偷懒就会漏证据。我的做法是固化成一个采集脚本,插上 U 盘跑一遍,所有东西落到一个带时间戳的目录里,回头慢慢看。
# Collect-BugCheck.ps1 —— 一次蓝屏后的现场采集,输出到独立目录 param( [string]$OutDir = "C:\BugCheck_$(Get-Date -Format yyyyMMdd_HHmm)" ) New-Item -ItemType Directory -Path $OutDir -Force | Out-Null # 1. 最近 30 天的 BugCheck、异常关机、意外断电记录 Get-WinEvent -FilterHashtable @{ LogName = 'System' Id = 1001, 41, 6008 StartTime = (Get-Date).AddDays(-30) } -ErrorAction SilentlyContinue | Select-Object TimeCreated, Id, ProviderName, Message | Export-Csv "$OutDir\events.csv" -NoTypeInformation -Encoding UTF8 # 2. 转储文件清单,大小和时间比文件名更有信息量 Get-ChildItem "$env:SystemRoot\Minidump\*.dmp", "$env:SystemRoot\MEMORY.DMP" -ErrorAction SilentlyContinue | Select-Object Name, Length, LastWriteTime | Export-Csv "$OutDir\dumps.csv" -NoTypeInformation -Encoding UTF8 # 3. 已安装驱动,按日期倒序,方便对齐"最近更新过什么" Get-CimInstance Win32_PnPSignedDriver | Where-Object { $_.DeviceName } | Select-Object DeviceName, DriverVersion, DriverDate, Manufacturer | Sort-Object DriverDate -Descending | Export-Csv "$OutDir\drivers.csv" -NoTypeInformation -Encoding UTF8 # 4. 转储配置与分页文件,排除"压根没写下来"这种乌龙 Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl' | Select-Object CrashDumpEnabled, DumpFile, MiniDumpDir, AlwaysKeepMemoryDump | Export-Csv "$OutDir\crashcontrol.csv" -NoTypeInformation -Encoding UTF8 Get-CimInstance Win32_PageFileUsage | Select-Object Name, AllocatedBaseSize, CurrentUsage | Export-Csv "$OutDir\pagefile.csv" -NoTypeInformation -Encoding UTF8 "采集完成:$OutDir"$OutDir默认按分钟级时间戳建目录,同一台机器反复崩溃不会互相覆盖;想统一归档就传-OutDir D:\cases\machine01。StartTime控制回溯窗口,偶发问题可以放大到 90 天,代价是日志拉取变慢。四处-ErrorAction SilentlyContinue是必要的,没有匹配记录时这些 cmdlet 会抛非终止错误,脚本会在第一处就停下来。
输出文件的用途对得很清楚:
| 文件 | 主要用途 |
|---|---|
| events.csv | 还原崩溃时间线,找反复出现的前置事件 |
| dumps.csv | 确认转储数量与时间,判断是否漏采 |
| drivers.csv | 对齐"蓝屏前更新了什么",缩小怀疑面 |
| crashcontrol.csv | 验证转储配置是否真的生效 |
| pagefile.csv | 判断是否因空间不足导致转储丢失 |
这套东西真正省时间的地方不在采集,而在于对比。攒够三四台机器的 csv 之后,把 drivers.csv 按DriverDate排序横向一比,共性问题往往一眼就能看出来——同一个版本号在不同机器上反复出现在蓝屏时间段内,那基本不用再猜了。反过来,如果只有一台机器有问题、驱动列表完全干净,就该往硬件和供电方向走,别再在软件层打转。
我现在的习惯是:只要听到"又蓝了"这三个字,不管对方描述得多清楚,先让他跑一遍采集脚本再开口。吃过太多次亏——凭着记忆复述代码、凭着印象说"最近没装什么东西",最后发现是三天前自动更新了一个外设驱动。从那以后我每次排查蓝屏,都强制走一遍"采集 → 对时间线 → 看驱动日期 → 再动调试器"的顺序,一步都不跳。希望帮到你。
本文还有配套的精品资源,点击获取