How to decrease virtual size/capacity of a Virtualbox vdi file

I want turn a physical machine running MS Windows 7 into a VirtualBox virtual machine. This is easy, I have done this before, but this time I needed the virtual size/capacity of the disk to be a fixed and smaller size.

It needs to be fixed because I will install PGP disk encryption on it for compliance reasons. This will expand a dynamic disk to it maximum size.

Aside from this special case there are other reasons for wanting disks to be smaller and fixed. Is my experience. If you run for example a Jenkins build server on a dynamically expanding disk you could see the disk expanding quickly to its maximum size while in the guest OS disk space usage is stable and there is lots of free space.

Using Disk2vhd I have created a vhdx file. This file I converted to vdi format.

vboxmanage clonehd --format VDI MSWIN7.VHDX MSWIN7.vdi

Purportedly with vdi you could decrease virtual size/capacity with commands similar to

vboxmanage modifyhd MSWIN7.vdi --resize 160000

I found that this doesn't work. Even if you try variants you will consistently get error messages like:

Progress state: VBOX_E_NOT_SUPPORTED VBoxManage: error: Resize hard disk operation for this format is not implemented yet!

Below is the disk layout of my vdi disk. I added this to a Ubuntu VM to look at it using Gparted and CloneZilla. Capacity is around 300GB. Unallocated 145GB. Used is around 153GB.

I want to shrink capacity to around 160GB. This should be enough to fit /dev/sdb1 and /dev/sdb2.

BTW, I tried CloneZilla but it also does not seem to like to shrink the capacity to a smaller disk. I tried various settings in CloneZilla but no success.

How can I decrease virtual size/capacity?

enter image description here


Solution 1:

  1. Deallocate space at the end of disk in guest OS, where space >= size(source-disk) - size(new-disk). Typically by shrinking last partition.

  2. Turn off virtual machine.

  3. Create new Virtual Box disk with desired size.

  4. Move content from old disk to inside new disk:

     vboxmanage clonemedium disk "source-disk.vmdk" "new-disk.vmdk" --existing
    
  5. Turn on virtual machine.

  6. You may have to resize partition in guest OS to fill the rest of the disk depending of the space deallocated on step 1.

Solution 2:

In the end I managed to solve this puzzle in a unexpected easy way using the preinstalled command line utility dd see Disk Cloning. As shown below I now have my 160GB drive in my guest OS stored in a 160GB fixed VirtualBox vdi file.

enter image description here

I solved it using following steps:

  1. Resize the disk using Disk Management in MS Windows to a size equal or better a little smaller than the size of the VDI.
  2. Add source vdi MSWIN7.vdi with MS Windows 7 to a Ubuntu VM as a second disk.
  3. Create a new fixed 160GB vdi and also add this to the Ubuntu VM. Now there are three disks: /dev/sda1 with the running Ubuntu VM, /dev/sdb2 with the source MSWIN7.vdi and /dev/sdc1 with the new vdi.
  4. Create the correct partitioning on /dev/sdc. CloneZilla did this for me. It did not copy data but it did create the partitioning I wanted. Of course you can do this manually.
  5. Copy sdb to sdc with dd command similar to sudo dd if=/dev/sdb of=/dev/sdc. The command ends with a no space left error message, that is expected. This I ignored because this is just unallocated space that it failed to copy.

I think it is possible to run the command for each partition. Maybe it is better and will not show an error message. sudo dd if=/dev/sdb1 of=/dev/sdc1 and sudo dd if=/dev/sdb2 of=/dev/sdc2.

vagrant@devops:~$ sudo dd if=/dev/sdb of=/dev/sdc
dd: writing to ‘/dev/sdc’: No space left on device
335544321+0 records in
335544320+0 records out
171798691840 bytes (172 GB) copied, 6360.3 s, 27.0 MB/s

Solution 3:

I believe this solution is extremely dangerous! It relies upon all the files being in the first 153 GB of the original 300 GB partition. The dd command does not copy files. It simply copies ALL blocks in sequence. Thus, if you were unfortunate enough to have important files AFTER the 160 GB cutoff, dd will not know to copy them.

The typical solution I have seen in many, many posts is to power up the Windows VM and use some combination of defrag tools and administrative tools to consolidate all files to the front of the disk - the difficulty is that many defrag tools do not move unmovable Windows system files (I had to turn off System Recovery to delete a 7 GB unmovable chunk of disk), which are somewhere in the middle of the space you are trying to consolidate.

Once you have consolidated files to front of disk (MyDefrag is a freeware tool that provides a display of where on disk your files are), you must reduce the size of your Windows partition. I used the diskpart tool with the shrink option.

At this point, you can use dd to copy the now smaller partition to a new vdi.

I have also used vboxmanage modifymedium win10.vdi --compact, on my Linux host, but I first had to run sdelete.exe within the Windows system to zero out all the unused space first (sdelete -z c:). Using vboxmanage to compact the existing vdi file allows you to do everything in-place (but always have a backup).

Solution 4:

In my case I had a windows VM with 50GB vdi to shrink to 20GB.

I have tried Andre Figueiredo solution but I had a problem with the cloned vdi.

When I apply Andre Figueiredo solution and attach the shrinked vdi to the VM, while booting, Virtualbox stops with I/O error.

Perhaps this is related to my btrfs filesystem (I heard btrfs causes problems with Vritualbox vdi).

My solution:

I tried a different solution in order to shrink the VM disk (vdi), named OVdi, (OVdi has disk size of 50GB, single ntfs partition with 40GB free space).

Let's follow these steps (this is my case, you can adapt/invent different vdi names):

  • stop the VM (poweroff)

  • create a new disk (vdi) with name DVdi of desired size (20GB my case..)

  • attach DVdi to the VM

  • boot VM and install the utility EaseUS Backup Free

  • Execute EasyUS and use the EasyUS Clone function (it clones OVdi MBR, and the ntfs partition of OVdi by shrinking to new disk DVdi)

  • Poweroff the VM

  • Detach OVdi from VM

  • Check if DVdi is the first boot device for the VM

  • reboot the VM

  • Have fun

Don't forget to delete the OVdi volume.

Following these steps I successfully reduced the VM disk size from 50GB to 20GB