How to merge arbitrary snapshot into base vdi in Virtualbox
Here's how I solved my problem.
First I undid changing the UUID on my base VDI file by using the script by jordoncm
Then I tried simply changing the paths in the vbox file to match the new location. That did not work as various different errors popped up and I wasn't even able to add the VM using the vbox file.
So I found this blog article by Peter Porter who suggested:
as each .vdi contains only those sectors changed from the last .vdi, copying the .vdi’s in chronological order should net us a .vdi containing a full copy of all prior snapshots.
...
Use the “VBoxManage clonehd” command to create a new .vdi file based on your original, then add in each subsequent file using the “–existing” argument to simply add the data to existing .vdi you’re building. The following list of commands are based off my example above:
VBoxManage clonehd Machine.vdi Machine-full.vdi
VBoxManage clonehd Snapshots{UUID1}.vdi Machine-full.vdi
VBoxManage clonehd Snapshots{UUID2}.vdi Machine-full.vdi
VBoxManage clonehd Snapshots{UUID3}.vdi Machine-full.vdi
VBoxManage clonehd Snapshots{UUID4}.vdi Machine-full.vdi
This will give you a “Machine-full.vdi” file that represents the full state of your machine in the active state without any relationship to the parent .vdi files. You can now use this “Machine-full.vdi” file on a new virtual machine or edit your existing VM, removing the old .vdi file and adding this .vdi.
With a little bit of tweaking that seemed to work for me:
This is the hard disk and its snapshots:
<HardDisk uuid="{ed1428ca-76be-440a-894b-e666b50f5c86}" location="H:/vm/ft.vdi" format="VDI" type="Normal">
<HardDisk uuid="{8d8be78f-6648-4503-bee3-8810cb853a99}" location="Snapshots/{8d8be78f-6648-4503-bee3-8810cb853a99}.vdi" format="VDI">
<HardDisk uuid="{cce0ee4f-5052-4be7-81ff-47ea08202716}" location="Snapshots/{cce0ee4f-5052-4be7-81ff-47ea08202716}.vdi" format="VDI">
<HardDisk uuid="{c297d4b9-972d-4b07-a839-5d76ee8d0387}" location="Snapshots/{c297d4b9-972d-4b07-a839-5d76ee8d0387}.vdi" format="VDI">
<HardDisk uuid="{8e9ca914-648f-464c-b515-2606c644d7f0}" location="Snapshots/{8e9ca914-648f-464c-b515-2606c644d7f0}.vdi" format="VDI"/>
</HardDisk>
</HardDisk>
</HardDisk>
</HardDisk>
These are the commands I ran (sorry some of it is cut off its windows...):
C:\Program Files\Oracle\VirtualBox>VBoxManage clonehd N:\vm\ft.vdi N:\vm\ft_full.vdi
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Clone hard disk created in format 'VDI'. UUID: a7fb5e25-c248-4644-a898-f1e26f6570a4
C:\Program Files\Oracle\VirtualBox>VBoxManage clonehd "N:\vm\VirtualBox VMs\lfs\Snapshots\{8d8be78f-6648-4503
VBoxManage.exe: error: Parent medium with UUID {ed1428ca-76be-440a-894b-e666b50f5c86} of the medium 'N:\vm\Vi
03-bee3-8810cb853a99}.vdi' is not found in the media registry ('C:\Users\ <user>/.VirtualBox\VirtualBox.xml')
VBoxManage.exe: error: Details: code E_FAIL (0x80004005), component Medium, interface IMedium, callee IUnknow
Context: "OpenMedium(Bstr(pszFilenameOrUuid).raw(), enmDevType, AccessMode_ReadWrite, fForceNewUuidOnOpen, pM
xManageDisk.cpp
Crap seems I need to add an entry in the VirtualBox.xml under MediaRegistry->HardDisks, but I have to make sure to add each snapshot to it in chronological order after each copy. So its like this:
Copy VM
Add entry to VirtualBox.xml
Copy VM ...
And the rest of what I did in case it helps anyone else:
C:\Program Files\Oracle\VirtualBox>VBoxManage clonehd --existing "N:\vm\VirtualBox VMs\lfs\Snapshots\{8d8be78
_full.vdi
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Clone hard disk created in format 'VDI'. UUID: a7fb5e25-c248-4644-a898-f1e26f6570a4
C:\Program Files\Oracle\VirtualBox>VBoxManage clonehd --existing "N:\vm\VirtualBox VMs\lfs\Snapshots\{cce0ee4f-5052-4be7-81ff-47ea08202716}.vdi" N:\vm\ft_full.vdi
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Clone hard disk created in format 'VDI'. UUID: a7fb5e25-c248-4644-a898-f1e26f6570a4
C:\Program Files\Oracle\VirtualBox>VBoxManage clonehd --existing "N:\vm\VirtualBox VMs\lfs\Snapshots\{c297d4b9-972d-4b07-a839-5d76ee8d0387}.vdi" N:\vm\ft_full.vdi
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Clone hard disk created in format 'VDI'. UUID: a7fb5e25-c248-4644-a898-f1e26f6570a4
C:\Program Files\Oracle\VirtualBox>VBoxManage clonehd --existing "N:\vm\VirtualBox VMs\lfs\Snapshots\{8e9ca914-648f-464c-b515-2606c644d7f0}.vdi" N:\vm\ft_full.vdi
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Clone hard disk created in format 'VDI'. UUID: a7fb5e25-c248-4644-a898-f1e26f6570a4
And then I simply created a new VM using the ft_full.vdi as its base. Matched the rest of the settings in the gui settings pane.
I just went through this headache and there is a seemingly stupid solution. Too bad it took me a full day to get here.
If you take a look at VBoxManage.exe internalcommands dumphdinfo you can see that each VDI has info about its parent. So, what I did is created a blank machine and added "broken" Parent HD as a secondary drive. That placed it into Media Manager.
Then, I added a SATA controller to the blank VM and added layer 3 snapshot. Click ok. Edit again and add layer 2 snapshot, click ok. Edit, add layer 1 snap shot.
This makes them individual drives inside the VM, but inside Media Manager they are all attached to each other.
The final step, is simply delete the bank VM and Add your Old VM. Done... and yes, it's that stupid/simple.
c:\Program Files\Oracle\VirtualBox>VBoxManage.exe internalcommands dumphdinfo D:
\Virtual_box\Virtual_box_HD_C.vdi
1 Header: uuidCreation={13ea5785-58db-4ad9-8459-9b13d89a3aaa}
1 Header: uuidModification={b1bfd84d-6fcc-4640-80fc-b7c1a6b929cb}
1 Header: uuidParent={19ed1b87-d127-402d-b463-59899c683a47}
2 Header: uuidCreation={19ed1b87-d127-402d-b463-59899c683a47}
2 Header: uuidModification={709f1fad-68a3-47c7-9336-f3409fcae95b}
2 Header: uuidParent={436c1ffd-04ee-4d6b-968c-de95e65d8a5a}
3 Header: uuidCreation={436c1ffd-04ee-4d6b-968c-de95e65d8a5a}
3 Header: uuidModification={049d869e-89c2-48aa-b0cc-eb324895f3b9}
3 Header: uuidParent={e09c65f4-828d-4a53-8ecc-20365d43a52e}
4 Header: uuidCreation={e09c65f4-828d-4a53-8ecc-20365d43a52e}
4 Header: uuidModification={6c397704-fe65-4661-b60f-767e207ffb58}
4 Header: uuidParent={00000000-0000-0000-0000-000000000000}