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:

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:

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:

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:

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.

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.

And we can confirm what we already know, that the attribute now matches the "disk signature" of the new SSD's partition table:

There are actually a number of other entries in the BCD to do with resuming from hibernation and booting into the recovery partition.

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

robots.org.uk: MovingWindowsInstallationToNewDisk (last edited 2022-11-02 15:44:24 by sam)

© Sam Morris <sam@robots.org.uk>.
Content may be distributed and modified providing this notice is preserved.