Moving a Windows installation to a new disk
Situation
A Windows install exists on a old 64 GB Crucial M4 SSD.
According to SMART data (attribute 202), the SSD is reaching the end of its life (20% remaining).
The Windows installation boots with the legacy/PC/BIOS/MBR -> VBR -> bootmgr boot method.
Mission
A new 500 GB SSD has been purchased and the Windows install is to be transferred to the new drive.
The Windows installation's filesystem is to be expanded to make use of the increased space.
Execution
Attach the new SSD to a spare SATA port.
Boot into Linux.
Use fdisk to examine the MBR partition table on the old SSD. There are actually three partitions:
№ |
Type |
Flags |
Size |
Description |
1 |
0x07 |
active |
100 MiB |
"system" partition (Windows boot loader) |
2 |
0x07 |
none |
~64 GiB |
"boot" partition (Windows installation) |
3 |
0x07 |
none |
508 MiB |
recovery partition |
Yes, in Windows terminology the partition with the boot loader code is called the "system" partition, and the partition with the Windows system files is called the "boot" partition 🙄.
Use fdisk to create a new MBR partition table on the new SSD. This tool is preferred over parted because it gives precise control over the partition numbers/offsets/sizes.
Preserve the offset and size of the system partition.
Preserve the size of the recovery partition, but situate it at the end of the disk.
Create a new boot partition in between the other two partitions, filling the remaining space.
Transfer the contents of all three partitions to their counterparts on the new disk. This is done with cp, whcih has the advantage of preserving the filesystem IDs so that the Windows installation does not become confused when booted from the new disk; as well as the volume boot record from the "system" partition, that is needed to load bootmgr (the Windows boot manager). Since the old SSD is quite small, only an insignificant amount of time is wasted by copying unallocated blocks.
Use ntfsresize to expand the new "boot" partition to take advantage of its increased size.
Install a boot loader into the new SSD's MBR; I used TestDisk, alternatives are mbr or ms-sys.
Power off and remove the old SSD. Move the new SSD to the SATA port used by the old SSD.
Power on and see if the boot sequence is able to load Windows.
Discover that it doesn't with a very generic error code: 0xc00000e(?) from winload. At least this means that the MBR boot code -> "system" partition VBR boot code -> bootmgr sequence worked. But it looks like (and I'm not 100% sure) bootmgr was not able to load winload? In any case, it's time to begin recovery.
Prepare a Windows installer USB disk and boot from it.
Explore recovery options:
- As is normal with such Windows features, the automated recovery process takes a very long time to do nothing useful at all
bootrec /RebuildBcd fails
- Give up and drop to command prompt
Research the Windows boot sequence and learn about the BCD which is found on the "system" partition at boot\bcd.
Is this partition mounted? diskpart -> list vol shows that it is mounted at C:. Also our "boot" partition is mounted at H:.
From the command prompt we can examine the BCD. Note the device and osdevice attributes of the entries:
X:\> bcdedit /store C:\boot\bcd /enum Windows Boot Manager -------------------- identifier {bootmgr} device unknown description Windows Boot Manager locale en-US inherit {globalsettings} default {current} resumeobject {08903c75-d529-11ea-bc49-e1ca39795d5d} displayorder {current} toolsdisplayorder {memdiag} timeout 30 Windows Boot Loader ------------------- identifier {default} device unknown path \WINDOWS\system32\winload.exe description Windows 10 locale en-US inherit {bootloadersettings} recoverysequence {be7cca88-d4dd-11ea-952c-d64492fae58f} displaymessageoverride Recovery recoveryenabled Yes allowedinmemorysettings 0x15000075 osdevice unknown systemroot \WINDOWS resumeobject {08903c75-d529-11ea-bc49-e1ca39795d5d} nx OptIn bootmenupolicy Standard
Whatever method the BCD entry uses to identify partitions is not recognizing the "boot" partition and it's printing unknown.
The fix is to run:
bcdedit /store C:\boot\bcd /set {bootmgr} device partition=C:
bcdedit /store C:\boot\bcd /set {default} device partition=H:
bcdedit /store C:\boot\bcd /set {default} osdevice partition=H:
After that, bcdedit /store C:\boot\bcd /enum no longer prints unknown and instead prints partition=C: and partition=H: for the {bootmgr} and {default} entries, respectively.
Reboot. Windows boots up. Success!
Now to battle with Windows Activation. Or so I expected... but running slmgr /xpr shows that the system is still activated; so swapping out the install disk hasn't deactivated the installation.
We're done!
Post-mortem
We really could have used a better diagnostic information from bootmgr than a single extremely generic error code.
In order to figure out why the bootmgr couldn't find the new "system" and "boot" partitions, we must examine the BCD and get our thinking caps on:
Unfortunately the output of bcdedit is not useful for this purpose:
If an attribute refers to a partition that contains a mounted filesytem, it prints e.g., partition=C: depending on the drive letter of the filesystem
If an attribute refers to a partition that contains an unmounted filesystem, it prints e.g., partition=\Device\HarddiskVolume1
If an attribute refers to a partition that can't be found, it prints unknown; in this case there's no way to find out exactly why the partition can't be found
Fortunately there is an undocumented /raw flag that shows the 'actual' contents of the attributes instead of their interpretation, given currently present partitions.
After booting successfully we can use this to discover exactly how attributes refer to partitions, and deduce why the "boot" partition couldn't be found after transfer.
PS C:\Users\root> bcdedit /enum /raw Windows Boot Manager -------------------- identifier {bootmgr} device PartEx 100000 HD MBR Sig:30ed3ac0 description Windows Boot Manager locale en-US inherit {globalsettings} default {current} resumeobject {08903c75-d529-11ea-bc49-e1ca39795d5d} displayorder {current} toolsdisplayorder {memdiag} timeout 30 Windows Boot Loader ------------------- identifier {current} device PartEx 6500000 HD MBR Sig:30ed3ac0 path \WINDOWS\system32\winload.exe description Windows 10 locale en-US inherit {bootloadersettings} recoverysequence {be7cca88-d4dd-11ea-952c-d64492fae58f} displaymessageoverride Recovery recoveryenabled Yes allowedinmemorysettings 0x15000075 osdevice PartEx 6500000 HD MBR Sig:30ed3ac0 systemroot \WINDOWS resumeobject {08903c75-d529-11ea-bc49-e1ca39795d5d} nx OptIn bootmenupolicy Standard
And now we can see how a partition is referred to in the database.
PartEx 6500000 HD MBR Sig:30ed3ac0
We can deduce that partitions (on a disk with an MBR partition table) are identified by "disk signature" (4 bytes in the MBR) and offset (the larger number).
In creating a new MBR partition table on the new disk, I forgot to preserve the "disk signature" from the old disk. Thus the BCD entries were referring to partitions on the old disk, which couldn't be found.
We know the larger number is the partition table offset in big-endian hexadecimal, because our "system" and "boot" partition start exactly 1 and 101 MiB into the disk, respectively, and using Python we can convert that into exact byte offsets, formatted in hexadecimal.
>>> hex(1 * 2**20) '0x100000' >>> hex(101 * 2**20) '0x6500000'
And we can confirm what we already know, that the attribute now matches the "disk signature" of the new SSD's partition table:
PS C:\Users\root> diskpart Microsoft DiskPart version 10.0.19041.964 Copyright (C) Microsoft Corporation. On computer: TYCHO DISKPART> select disk 0 Disk 0 is now the selected disk. DISKPART> uniqueid disk Disk ID: 30ED3AC0
There are actually a number of other entries in the BCD to do with resuming from hibernation and booting into the recovery partition.
PS C:\Users\root> bcdedit /enum all /raw Windows Boot Manager -------------------- identifier {bootmgr} device PartEx 100000 HD MBR Sig:30ed3ac0 description Windows Boot Manager locale en-US inherit {globalsettings} default {current} resumeobject {08903c75-d529-11ea-bc49-e1ca39795d5d} displayorder {current} toolsdisplayorder {memdiag} timeout 30 Windows Boot Loader ------------------- identifier {current} device PartEx 6500000 HD MBR Sig:30ed3ac0 path \WINDOWS\system32\winload.exe description Windows 10 locale en-US inherit {bootloadersettings} recoverysequence {be7cca88-d4dd-11ea-952c-d64492fae58f} displaymessageoverride Recovery recoveryenabled Yes allowedinmemorysettings 0x15000075 osdevice PartEx 6500000 HD MBR Sig:30ed3ac0 systemroot \WINDOWS resumeobject {08903c75-d529-11ea-bc49-e1ca39795d5d} nx OptIn bootmenupolicy Standard Windows Boot Loader ------------------- identifier {13c7b309-851c-11e1-9794-8a7ddd0bbd15} device RAMDISK Image:0/0 File PartEx 6500000 HD MBR Sig:5a0cba8d \Recovery\13c7b309-851c-11e1-9794-8a7ddd0bbd15\Winre.wim path \windows\system32\winload.exe description Windows Recovery Environment inherit {bootloadersettings} osdevice RAMDISK Image:0/0 File PartEx 6500000 HD MBR Sig:5a0cba8d \Recovery\13c7b309-851c-11e1-9794-8a7ddd0bbd15\Winre.wim systemroot \windows nx OptIn winpe Yes Windows Boot Loader ------------------- identifier {ae221c28-5a77-11e8-aa97-b089d7fd1b5f} device RAMDISK Image:0/0 File PartEx ecbe00000 HD MBR Sig:5a0cba8d \Recovery\WindowsRE\Winre.wim path \windows\system32\winload.exe description Windows Recovery Environment locale en-US inherit {bootloadersettings} displaymessage Recovery osdevice RAMDISK Image:0/0 File PartEx ecbe00000 HD MBR Sig:5a0cba8d \Recovery\WindowsRE\Winre.wim systemroot \windows nx OptIn bootmenupolicy Standard winpe Yes Windows Boot Loader ------------------- identifier {be7cca88-d4dd-11ea-952c-d64492fae58f} device RAMDISK Image:0/0 File PartEx ec8400000 HD MBR Sig:5a0cba8d \Recovery\WindowsRE\Winre.wim path \windows\system32\winload.exe description Windows Recovery Environment locale en-US inherit {bootloadersettings} displaymessage Recovery osdevice RAMDISK Image:0/0 File PartEx ec8400000 HD MBR Sig:5a0cba8d \Recovery\WindowsRE\Winre.wim systemroot \windows nx OptIn bootmenupolicy Standard winpe Yes Resume from Hibernate --------------------- identifier {08903c75-d529-11ea-bc49-e1ca39795d5d} device PartEx 6500000 HD MBR Sig:30ed3ac0 path \WINDOWS\system32\winresume.exe description Windows Resume Application locale en-US inherit {resumeloadersettings} recoverysequence {be7cca88-d4dd-11ea-952c-d64492fae58f} recoveryenabled Yes allowedinmemorysettings 0x15000075 filedevice PartEx 6500000 HD MBR Sig:30ed3ac0 filepath \hiberfil.sys bootmenupolicy Standard debugoptionenabled No Windows Memory Tester --------------------- identifier {memdiag} device PartEx 100000 HD MBR Sig:5a0cba8d path \boot\memtest.exe description Windows Memory Diagnostic locale en-US inherit {globalsettings} badmemoryaccess Yes EMS Settings ------------ identifier {emssettings} bootems No Debugger Settings ----------------- identifier {dbgsettings} debugtype Serial debugport 1 baudrate 115200 RAM Defects ----------- identifier {badmemory} Global Settings --------------- identifier {globalsettings} inherit {dbgsettings} {emssettings} {badmemory} Boot Loader Settings -------------------- identifier {bootloadersettings} inherit {globalsettings} {hypervisorsettings} Hypervisor Settings ------------------- identifier {hypervisorsettings} hypervisordebugtype Serial hypervisordebugport 1 hypervisorbaudrate 115200 Resume Loader Settings ---------------------- identifier {resumeloadersettings} inherit {globalsettings} Device options -------------- identifier {13c7b30a-851c-11e1-9794-8a7ddd0bbd15} description Ramdisk Options ramdisksdidevice PartEx 6500000 HD MBR Sig:5a0cba8d ramdisksdipath \Recovery\13c7b309-851c-11e1-9794-8a7ddd0bbd15\boot.sdi Device options -------------- identifier {be7cca89-d4dd-11ea-952c-d64492fae58f} description Windows Recovery ramdisksdidevice PartEx ec8400000 HD MBR Sig:5a0cba8d ramdisksdipath \Recovery\WindowsRE\boot.sdi
I should probably go through each entry and fix up any that still reference partitions on my old disk, which I can see has the "disk signature" of 5a0cba8d. But to be honest I never use hibernation and if I need to boot the recovery partition I'll just boot off a separate USB, so this is not urgent.
Sources
http://woshub.com/how-to-rebuild-bcd-file-in-windows-10/#h2_5 explains how to use bcdedit to fix entries within a BCD.
https://ss64.com/nt/bcdedit.html which is the only place on the Internet that documents the vital /raw option for bcdedit, and in general being a great source of information about the Windows boot process, the BCD database and the tools that can explore, create and manipulate it.
https://thestarman.pcministry.com/asm/mbr/BCD.htm for more useful information about the BCD
http://www.mistyprojects.co.uk/documents/BCDEdit/files/device_partition.htm and other pages on that site which have even more expert detail about the structure of the BCD and how to interpret its raw data file (if you are ever unlucky enough to need this information in anger then my condelences)
http://reboot.pro/topic/20468-create-a-windows-system-from-scratch-using-linux/ which would be useful if you ever wanted to replace the Windows installer with a small shell script
https://lukasznojek.com/blog/2019/08/windows-boot-disk-repairing-toolkit/ has a great list of system recovery commands to do things like fixing MBR/VBR code, etc.