去年已经使用此方法迁移过一次 Windows XP,期间出现过问题,并解决掉了(请参见《XP 疑云》和《XP 疑云(续)》,以及另一篇与此相关的《安全删除 Windows 的保留分区》),本次实践为迁移 Windows 10。
1. 任务描述
从源硬盘 A 上把正常使用的 Windows 10 专业版迁移至目的硬盘 B 的目的分区。细节有,源硬盘 A 为单一系统 Windows 10,引导分区为其安装时自动划分出来的保留分区(未分配盘符),系统分区紧随其后(盘符为 C:);目的盘 B 为单一系统 Ubuntu 18.04 LTS(标准的 Grub 引导),在其上有一个空分区,容量足以放得下源硬盘 A 上的内容。均非 UEFI 引导模式。
2. 思路
之前曾观测到 Grub 能够自动探测到 Windows 的存在并将之引导起来,因此设想的理想状况为:
- 将源硬盘引导分区以及系统分区上的内容均以文件的方式复制到目的分区上;
- 引导进入 Ubuntu,让 Grub 自动识别并添加 Windows 10 系统的引导菜单项;
- 每次引导均可在 Grub 菜单里选择进入 Ubuntu 还是 Windows 10。
3. 实践
为了避免无谓的大量文件的复制,首先在 Windows 10 中(注意,此时两块硬盘均成功在 Windows 10 下挂载着,这个情况后文会提到,对迁移是有影响的),使用 DiskGenius 将引导分区上的内容(bootmgr、BOOTNXT、BOOTSECT.BAK 三个文件以及 Boot 一个目录)复制到了目的分区上(使用 DiskGenius 的原因是引导分区没有盘符,所以普通的文件管理器都无法访问)。然后关机,将 Windows 10 硬盘取下(主要是为了防止后续操作 Grub 时,把这一份 Windows 10 也探测到并添加到菜单里),开机启动进入 Ubuntu,执行 update-grub
命令,其信息输出中可以看到已经发现了 Windows 10。至此,初步概念验证通过。 当然,如果在 Grub 里选择进入 Windows 10 肯定无法成功。
关机,将 Windows 10 盘接入。为了保证不是复制一个热系统,使用 51nb 出品的 51PE 工具 U 盘引导后,使用其附带的 DiskGenius 执行分区复制(文件复制并消除碎片的模式),将 Windows 10 的系统分区(上的所有文件)完整复制到目的分区。此过程会清除目的分区,所以之前复制过的引导分区上的内容,要再复制一次,好在引导分区很小,而且一直都在 DiskGenius 之内操作即可。至此,目的分区文件都已到位,关机,将 Windows 10 所在源盘摘除。如果一切顺利的话,源盘就应该用不到了。
开机,从 Grub 中选择进入 Windows 10,这个尝试可能要进行多次。因为最开始,很可能是得到一个类似于“找不到 ID 为 XXXXXXXX 的设备”的信息,这个信息很可能是 Grub 显示的,意味着它还没有进行到把控制权交给 Windows 10 的 bootmgr;反复重启,期望看到的理想状态应该是,蓝色底的一屏错误信息,告诉你错误 0xc000000e,文件 \Windows\system32\winload.exe 文件找不到(能够直接正常进入 Windows 的概率应该仅存在于理论中,至少我自己都没有奢望能够达到那么完美的效果)。
这一错误信息的出现,意味着 bootmgr 在试图把控制权交给操作系统的时候失去了目标,解决的关键点在于 \Boot 目录下的 BCD 文件。再次用 51PE 引导,使用其附带的 Bootice 小工具,在高级模式下打开 BCD 文件进行编辑(事先备份一下是个好习惯),把左侧的导航树里的节点都过一遍,重点是 Windows Boot Manager 和 Windows 10 这两个节点(可能还有个 resume 节点),选中查看它们的设置,不出所料的话,带 Device 字样的项可能都是 Unknown,双击进行设置,选中目的盘的目的分区即可。选择结束后,可能显示的是盘符,比如 D:,这个不要紧张它不是 C:,因为当下是在 PE 环境里,这个盘符是 PE 系统分配的。退出 Bootice,关机,取下 PE 盘。
再次尝试引导 Windows 10。在这一步,如果你是照着做的,且发现已经可以正常进入系统,则后续的内容无需再看。如果你看到的是 CRITICAL_PROCESS_DIE 这样的错误码,请多次重启,直到进入黑屏图形界面,只有鼠标指针可以移动,不能做其余任何操作。一开始看到这个局面我的内心是崩溃的,但我在最短的时间里就联想到了文首的 XP 疑云。核心就是,由于前文 3 一开头说的那个情况,导致目的分区在源系统中已经被成功分配过盘符并记录到了系统中,此盘符分配的记录也随着整个系统的迁移而存在着。验证的方法很简单,再次用 51PE 引导系统,打开注册表编辑器,选中 HKEY_LOCAL_MACHINE,通过文件菜单下的加载配置单元,去把目的分区下的 \Windows\system32\config\SYSTEM 文件加载起来,在指定命名后的注册表键下,定位到 MountedDevices,查看以 \DosDevices\ 开头的各个值。根据小四的分析结果,每个值的二进制数据的前四个字节是硬盘 ID。再打开一个命令提示符,执行 diskpart,通过 list disk、select disk、detail disk 一系列命令,即可以看到硬盘 ID,与前述各项进行比对,果然与 D: 匹配,而 C: 的值首,无疑是迁移之前的源硬盘的 ID。把 C: 随便改为其他名称或者直接删除,将 D: 改为 C:,关闭各个程序后关机。取下 51PE 重启。
通过 Grub 选择进入 Windows 10,毫无悬念地,统统正常了。后注:正常的是系统层面,应用层面还有一些余波,例如 Unity 开发环境就探测到系统发生了变化而导致申请的试用许可失效了。
特别提示,最后这一步修改 C: 硬盘 ID 的操作,如果在上一次的 51PE 环境下就执行,会使整个过程更加顺畅一些。
最后,得出最佳的复制粘贴式迁移 Windows 的方案,其简要汇总步骤:
1. 把源盘和目的盘连接妥当,用 PE 系统引导;
2. 用 DiskGenius 将系统分区以及引导分区(如果是单独分区的话)的文件复制到目的分区,前者最好通过分区克隆的方式;
3. 用 Bootice 将引导管理器所需的 BCD 文件中各项的目标设备的设置项调整正确;
4. 用注册表编辑器离线编辑目的分区上的系统注册表,将盘符分配调整正确;
5. 关机,去除 PE 介质以及源盘;
6. 引导进入 Ubuntu(或者其他 Linux),更新 Grub 后重启。
注意,第 4 步里其实还涉及到分区起始偏移,我们上述的实践过程中此值已经存在因此无需理会,要是哪位想手动实践此完美过程,那就需要手工创建 \DosDevices\C: 这个值的内容来把源系统赋予的值覆盖掉。经过测试,在 diskpart 中,经过 list part、select part、detail part 这一系列命令,可以显示出分区的起始字节偏移,省去自行计算之苦。