13 min read

On VBoxManage

For whatever reason, I’ve never thought to interact with VirtualBox using its command line tool, VBoxManage. I’ve used VirtualBox for years, mainly via Vagrant, but when I’ve configured any virtual machines directly, I’ve always pointed and clicked in the GUI like a child. This disclosure hurts, by the way, and I’m judging myself very harshly.

What if you’re working on a machine that doesn’t have X installed? You don’t want to cry about it like a little baby.

Well, those days are over. Now, whenever I use VirtualBox, I’ll either issue the commands directly on the CLI or script it.

This article will serve as a cheat sheet for basic operations performed on the command line with VBoxManage. Read the docs for all the commands and their parameters and switches.

Hey, ho, let’s go!


Glossary

Let’s first make sure that we’re all on the same page with some clarity. Here are some definitions:

  • OVF

    The Open Virtualization Format (OVF) is an open standard for packaging and distributing virtual appliances and is vendor independent.

  • OVA

    The Open Virtual Appliance is simply a tar archive with an OVF directory inside.

  • VDI

    Virtual Disk Image, VirtualBox’s native disk image format.

  • VMDK

    Virtual Machine Disk format that describes containers for virtual hard disk drives used primarily by VMware but also by VirtualBox.

Examples

Creating

When a new virtual machine is created, it will create a new directory in $HOME/VirtualBox\ VMs with the name of the value of the --name property. If the $HOME/VirtualBox\ VMs directory doesn’t exist, it is created.

This operation will create a file called .vbox in the new directory. The .vbox file is simply an XML file that contains settings and other metadata for the creation of the virtual machine. Of course, you can open this file in your least-favorite text editor.

Here is an example:

my_shitty_web_app.vbox

<?xml version="1.0"?>
<!--
** DO NOT EDIT THIS FILE.
** If you make changes to this file while any VirtualBox related application
** is running, your changes will be overwritten later, without taking effect.
** Use VBoxManage or the VirtualBox Manager GUI to make changes.
-->
<VirtualBox xmlns="http://www.virtualbox.org/" version="1.16-linux">
 <Machine uuid="{5e5fee85-33c4-4c8d-9a00-8a5138df28a3}" name="my_shitty_web_app" OSType="Debian_64" snapshotFolder="Snapshots" lastSta
teChange="2022-12-30T17:46:04Z">
   <Hardware>
     <CPU>
       <PAE enabled="true"/>
       <LongMode enabled="true"/>
       <X2APIC enabled="true"/>
       <HardwareVirtExLargePages enabled="false"/>
     </CPU>
     <Memory RAMSize="128"/>
     <BIOS>
       <IOAPIC enabled="true"/>
       <SmbiosUuidLittleEndian enabled="true"/>
     </BIOS>
     <Network>
       <Adapter slot="0" enabled="true" MACAddress="080027356ADA" type="82540EM">
         <NAT/>
       </Adapter>
     </Network>
     <AudioAdapter driver="Pulse" enabled="true" enabledIn="false" enabledOut="false"/>
     <Clipboard/>
   </Hardware>
 </Machine>
</VirtualBox>

Only the bare minimum properties are written to the .vbox file. Add to it via the modify-vm command.

Of course, you can always create and alter this file by hand, but beware that modifying this file directly could be overwritten by calls to modify-vm.

Note that createvm does not create a virtual disk, as it is expected that you will supply this.

The first example only creates the VM:

$ vboxmanage createvm --name my_shitty_web_app --ostype Debian_64
Virtual machine 'my_shitty_web_app' is created.
UUID: 5e5fee85-33c4-4c8d-9a00-8a5138df28a3
Settings file: '/home/btoll/VirtualBox VMs/my_shitty_web_app/my_shitty_web_app.vbox'
$ tree VirtualBox\ VMs/
VirtualBox VMs/
└── my_shitty_web_app
   └── my_shitty_web_app.vbox
$ vboxmanage list vms
$

The second example creates the VM and registers it, that is, it imports the XML config file into VirtualBox (note the --register switch):

$ vboxmanage createvm --name my_shitty_web_app --ostype Debian_64 --register
Virtual machine 'my_shitty_web_app' is created and registered.
UUID: 7a6291f7-e45d-40b5-8292-193d0e130d5b
Settings file: '/home/btoll/VirtualBox VMs/my_shitty_web_app/my_shitty_web_app.vbox'
$ tree VirtualBox\ VMs/
VirtualBox VMs/
└── my_shitty_web_app
   └── my_shitty_web_app.vbox
$ vboxmanage list vms
"my_shitty_web_app" {7a6291f7-e45d-40b5-8292-193d0e130d5b}

Registering at the time of creation is probably what you want. VirtualBox, for obvious reasons, doesn’t allow VMs with duplicate UUIDs to be registered, so this is a way of ensuring that (probably) won’t happen.

See createvm in the VirtualBox docs.


Here’s an example that combines creating a VM, registering it, add storage and then finally starting the VM.

We’ll first create and register it, followed by customizing its resources:

$ vboxmanage createvm --name debian_11 --ostype Debian_64 --register
$ vboxmanage modifyvm debian_11 --memory 3072 --cpus 4

Now, add the contoller on the VM:

$ vboxmanage storagectl debian_11 --name "SATA Controller" --add sata --controller IntelAHCI --portcount 1 --bootable on

See storagectl in the VirtualBox docs.

Then, attach the VDI to the storage controller:

$ vboxmanage storageattach debian_11 --storagectl "SATA Controller" --device 0 --port 0 --type hdd --medium debian_11_64bit.vdi

See storageattach in the VirtualBox docs.

Instead of issuing two commands to add create the storage controller and attach the VDI, the documentation specifies that you can do it in one command with the --storagectl parameter to the storageattach command.

Finally, start it:

$ vboxmanage startvm debian_11

Weeeeeeeeeeeeeeeeeeeeeeeee

Registering

As we’ve seen, registering a VM simply imports the .vbox XML file into VirtualBox.

The registervm command will look for the .vbox file to import in $HOME/.config/VirtualBox/, so it’s usually a good idea to pass an absolute path to the command. You probably don’t want to put them in that location, though. Instead, it’s a good idea to manage these configurations by putting them in a common location like $HOME/VirtualBox\ VMs/.

For example, if you get the following error, it’s because you haven’t provided an absolute path to the location of your XML .vbox file:

$ vboxmanage registervm VirtualBox\ VMs/kali-linux-2022.4-virtualbox-amd64/kali-linux-2022.4-virtualbox-amd64.vbox
VBoxManage: error: Runtime error opening '/home/btoll/.config/VirtualBox/VirtualBox VMs/kali-linux-2022.4-virtualbox-amd64/kali-linux-2022.4-virtualbox-amd64.vbox' for reading: -102 (File not found.).
VBoxManage: error: /home/vbox/tinderbox/ubuntu22.04-amd64-build-VBox-6.1/svn/src/VBox/Main/src-server/MachineImpl.cpp[499] (nsresult Machine::initFromSettings(VirtualBox*, const com::Utf8Str&, const com::Guid*))
VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component MachineWrap, interface IMachine, callee nsISupports
VBoxManage: error: Context: "OpenMachine(Bstr(a->argv[0]).raw(), machine.asOutParam())" at line 85 of file VBoxManageMisc.cpp

Note that the above command was run in my home directory where the VirtualBox\ VMs/ directory is relative, but the software still cannot find the file because it’s not an absolute path. Instead, it’s looking in /home/btoll/.config/VirtualBox/VirtualBox VMs/kali-linux-2022.4-virtualbox-amd64/, which is not what I want.

Let’s fix that by making it an absolute path and listing the registered VMs:

$ vboxmanage registervm $(pwd)/VirtualBox\ VMs/kali-linux-2022.4-virtualbox-amd64/kali-linux-2022.4-virtualbox-amd64.vbox
$ vboxmanage list vms
"kali-linux-2022.4-virtualbox-amd64" {1b908152-38ed-4fa3-8e81-c60adf3e1102}

Here’s an example managing the files from a central location:

$ mkdir "$HOME/VirtualBox VMs/kali"
$ mv kali-linux-2022.4-virtualbox-amd64.vbox "$HOME/VirtualBox VMs/kali"
$ vboxmanage registervm "$HOME/VirtualBox VMs/kali/kali-linux-2022.4-virtualbox-amd64.vbox"

Here’s an idea to register a bunch of VMs at once:

$ find /path/to/VirtualBox\ VMs -type f -name "*.vbox" \
    -exec vboxmanage registervm {} \;

See registervm in the VirtualBox docs.

Modifying

As we’ve seen when creating a VM createvm, the XML .vbox file that’s generated doesn’t contain much useful configuration settings. However, there’s a very useful command named modifyvm that allows you to change anything from general settings to networking to hardware settings and more.

First, we’ll change the name of the VM to one that’s easier to recall:

$ vboxmanage modifyvm 1b908152-38ed-4fa3-8e81-c60adf3e1102 --name kali

Then, using that new name, we’ll increase the amount of memory that’s allocated to the VM:

$ vboxmanage modifyvm kali --memory 3072

However, it gets fairly tedious changing the settings one at a time, so let’s set a number of them at the same time:

$ vboxmanage modifyvm kali --cpus 4 \
    --memory 3072 \
    --nic1 bridged \
    --bridgeadapter1 eth0 \
    --macaddress1 080027B1BEEF \
    --clipboard-mode bidirectional

Note that the VM must be stopped in order to change the value of its properties.

See modifyvm in the VirtualBox docs.

Importing

I’ve only ever imported an appliance (what a dumb term) in OVF format, but there’s also the option to do so from a cloud service.

Here’s an example:

$ vboxmanage import MSEdge\ -\ Win10.ova
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Interpreting /home/btoll/disk-formats/ova/MSEdge - Win10.ova...
OK.
Disks:
 vmdisk1       42949672960     -1      http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized       MSEdge - Win10-disk001.vm
dk      -1      -1

Virtual system 0:
0: Suggested OS type: "Windows10_64"
   (change with "--vsys 0 --ostype <type>"; use "list ostypes" to list all possible values)
1: Suggested VM name "MSEdge - Win10"
   (change with "--vsys 0 --vmname <name>")
2: Suggested VM group "/"
   (change with "--vsys 0 --group <group>")
3: Suggested VM settings file name "/home/btoll/VirtualBox VMs/MSEdge - Win10/MSEdge - Win10.vbox"
   (change with "--vsys 0 --settingsfile <filename>")
4: Suggested VM base folder "/home/btoll/VirtualBox VMs"
   (change with "--vsys 0 --basefolder <path>")
5: Number of CPUs: 1
   (change with "--vsys 0 --cpus <n>")
6: Guest memory: 4096 MB
   (change with "--vsys 0 --memory <MB>")
7: Network adapter: orig NAT, config 3, extra slot=0;type=NAT
8: IDE controller, type PIIX4
   (disable with "--vsys 0 --unit 8 --ignore")
9: IDE controller, type PIIX4
   (disable with "--vsys 0 --unit 9 --ignore")
10: Hard disk image: source image=MSEdge - Win10-disk001.vmdk, target path=MSEdge - Win10-disk001.vmdk, controller=8;port=0
   (change target path with "--vsys 0 --unit 10 --disk path";
   change controller with "--vsys 0 --unit 10 --controller <index>";
   change controller port with "--vsys 0 --unit 10 --port <n>";
   disable with "--vsys 0 --unit 10 --ignore")
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Successfully imported the appliance.

I didn’t need to move anything into the VirtualBox\ VMs directory before the import command, as it can be imported from anywhere. It will register it and movd the XML config file and virtual hard drive into that centralized, managed directory for you, though. Isn’t that nice.

$ vboxmanage list vms
"kali-linux-2022.4-virtualbox-amd64" {1b908152-38ed-4fa3-8e81-c60adf3e1102}
"MSEdge - Win10" {c15e6153-a5c3-4dd9-92a4-3c46742e6c07}
$ tree VirtualBox\ VMs/
VirtualBox VMs/
├── kali-linux-2022.4-virtualbox-amd64
│   ├── kali-linux-2022.4-virtualbox-amd64.vbox
│   └── kali-linux-2022.4-virtualbox-amd64.vdi
└── MSEdge - Win10
   ├── MSEdge - Win10-disk001.vmdk
   └── MSEdge - Win10.vbox

2 directories, 4 files

Starting

Start the kali VM and augment its environment:

$ vboxmanage startvm kali --putenv=FOO=foo --putenv=BAR=bar
Waiting for VM "kali" to power on...
VM "kali" has been successfully started.

Run headless:

$ vboxmanage startvm kali --putenv=QUUX=quux --type headless
Waiting for VM "kali" to power on...
VM "kali" has been successfully started.

The default is to start the VM as type gui.

See startvm in the VirtualBox docs.

Listing

List the guest OS types known to VirtualBox:

$ vboxmanage list ostypes
...
ID:          ArchLinux
Description: Arch Linux (32-bit)
Family ID:   Linux
Family Desc: Linux
64 bit:      false

ID:          ArchLinux_64
Description: Arch Linux (64-bit)
Family ID:   Linux
Family Desc: Linux
64 bit:      true

ID:          Debian
Description: Debian (32-bit)
Family ID:   Linux
Family Desc: Linux
64 bit:      false

ID:          Debian_64
Description: Debian (64-bit)
Family ID:   Linux
Family Desc: Linux
64 bit:      true
...

List the registered VMs:

$ vboxmanage list vms
"kali-linux-2022.4-virtualbox-amd64" {1b908152-38ed-4fa3-8e81-c60adf3e1102}

List the running VMS:

$ vboxmanage list runningvms
"kali" {1b908152-38ed-4fa3-8e81-c60adf3e1102}

Be aware that if the vms or runningvms subcommands don’t list any VMs but you know that some are registered and/or running, it could be that they were launched as a different user. Login as that user and run the command again.

List the NAT network interfaces available on the host:

$ vboxmanage list natnets
NetworkName:    test
IP:             192.168.1.1
Network:        192.168.1.0/24
IPv6 Enabled:   No
IPv6 Prefix:    fd17:625c:f037:2::/64
DHCP Enabled:   No
Enabled:        Yes
loopback mappings (ipv4)
        127.0.0.1=2

There are many more examples of subcommands to the list command. See list in the VirtualBox docs.

Changing State

Stopping

Shut down a running VM:

$ vboxmanage controlvm kali poweroff
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

Enable bidirectional clipboard:

$ vboxmanage controlvm kali clipboard mode bidirectional

See controlvm in the VirtualBox docs for more examples of its subcommands.

Snapshotting

Let’s take a brief look at manage snapshots of the virtual machines.

Snapshots are saved in the same location from where VirtualBox has registered the VM, usually in $HOME/VirtualBox\ VMs/, and you can get information about them from the showvminfo command.

For example, here we see the location of the Snapshot folder:

$ vboxmanage showvminfo 1b908152-38ed-4fa3-8e81-c60adf3e1102 | head
Name:                        kali-linux-2022.4-virtualbox-amd64
Groups:                      /
Guest OS:                    Debian (64-bit)
UUID:                        1b908152-38ed-4fa3-8e81-c60adf3e1102
Config file:                 /home/btoll/VirtualBox VMs/kali-linux-2022.4-virtualbox-amd64/kali-linux-2022.4-virtualbox-amd64.vbox
Snapshot folder:             /home/btoll/VirtualBox VMs/kali-linux-2022.4-virtualbox-amd64/Snapshots
Log folder:                  /home/btoll/VirtualBox VMs/kali-linux-2022.4-virtualbox-amd64/Logs
Hardware UUID:               1b908152-38ed-4fa3-8e81-c60adf3e1102
Memory size:                 3072MB
Page Fusion:                 disabled

And, here we see the snapshots that have been taken:

$ vboxmanage showvminfo 1b908152-38ed-4fa3-8e81-c60adf3e1102 | tail
https://discord.kali.org
Guest:

Configured memory balloon size: 0MB

Snapshots:

  Name: --description=snap1 (UUID: 8df4b7d6-8630-4d71-9a59-a8e0ba0570aa)
     Name: --description=snap3 (UUID: e305a502-2573-4516-807d-2ee1f7cb9c84) *

Weeeeeeeeeeeeeeeeeeee

Taking

Let’s take a couple of snapshots, yo.

$ vboxmanage snapshot 1b908152-38ed-4fa3-8e81-c60adf3e1102 take --description=snap1
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Snapshot taken. UUID: 8df4b7d6-8630-4d71-9a59-a8e0ba0570aa

$ vboxmanage snapshot 1b908152-38ed-4fa3-8e81-c60adf3e1102 take --description=snap2
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Snapshot taken. UUID: 659d931c-65a5-414b-973d-a7b49df8d764

And let’s list them:

$ vboxmanage snapshot 1b908152-38ed-4fa3-8e81-c60adf3e1102 list
  Name: --description=snap1 (UUID: 8df4b7d6-8630-4d71-9a59-a8e0ba0570aa)
     Name: --description=snap2 (UUID: 659d931c-65a5-414b-973d-a7b49df8d764) *

The second snapshot is the current one, indicated by the asterisk (*).

Here is a different view of the filesystem. The snapshots are snug in their new home:

$ tree VirtualBox\ VMs/kali-linux-2022.4-virtualbox-amd64/Snapshots/
VirtualBox VMs/kali-linux-2022.4-virtualbox-amd64/Snapshots/
├── 2022-12-31T18-47-42-389692000Z.sav
├── {56cb9f0b-d249-4894-bb15-c6ff9357cc98}.vdi
└── {75f94bd8-3c3f-4170-986a-3bb9c3f8e9fa}.vdi

0 directories, 3 files

Deleting

If we delete a snapshot and list the remaining one(s), we can see that the deleted snapshot is, in fact, gonzo:

$ vboxmanage snapshot 1b908152-38ed-4fa3-8e81-c60adf3e1102 delete 659d931c-65a5-414b-973d-a7b49df8d764
Deleting snapshot '--description=snap2' (659d931c-65a5-414b-973d-a7b49df8d764)
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
$ vboxmanage snapshot 1b908152-38ed-4fa3-8e81-c60adf3e1102 list
  Name: --description=snap1 (UUID: 8df4b7d6-8630-4d71-9a59-a8e0ba0570aa) *

The current snapshot is now snap1, as indicated by the beloved asterisk.

Restoring

Let’s look at restoring a particular snapshot. First, we’ll take another snapshot and list them out. There will be two:

$ vboxmanage snapshot 1b908152-38ed-4fa3-8e81-c60adf3e1102 take --description=snap3
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Snapshot taken. UUID: e305a502-2573-4516-807d-2ee1f7cb9c84
sulla ~~> ~/snapshots:
$ vboxmanage snapshot 1b908152-38ed-4fa3-8e81-c60adf3e1102 list
  Name: --description=snap1 (UUID: 8df4b7d6-8630-4d71-9a59-a8e0ba0570aa)
     Name: --description=snap3 (UUID: e305a502-2573-4516-807d-2ee1f7cb9c84) *

The current snapshot is snap3, but let’s restore snap1. Here, we do it by first referencing the VM from which the snapshot was taken and then the reference to the snapshot we want to restore:

$ vboxmanage snapshot 1b908152-38ed-4fa3-8e81-c60adf3e1102 restore 8df4b7d6-8630-4d71-9a59-a8e0ba0570aa
Restoring snapshot '--description=snap1' (8df4b7d6-8630-4d71-9a59-a8e0ba0570aa)
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
$ vboxmanage snapshot 1b908152-38ed-4fa3-8e81-c60adf3e1102 list
  Name: --description=snap1 (UUID: 8df4b7d6-8630-4d71-9a59-a8e0ba0570aa) *
     Name: --description=snap3 (UUID: e305a502-2573-4516-807d-2ee1f7cb9c84)

The VM and snapshot are referenced by their UUIDs, but it could be a name, instead.

Lastly, we can restore the current snapshot. For this, it’s not necessary to reference the snapshot by UUID or name:

$ vboxmanage snapshot 1b908152-38ed-4fa3-8e81-c60adf3e1102 restorecurrent
Restoring snapshot '--description=snap3' (e305a502-2573-4516-807d-2ee1f7cb9c84)
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

See snapshot in the VirtualBox docs.

Exporting

Note that VirtualBox exports disk images in the VMDK format.

Export the kali VM to an OVF virtual appliance:

$ vboxmanage export kali --manifest --output kali.ovf
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Successfully exported 1 machine(s).
$ ls
kali-disk001.vmdk  kali.mf  kali.ovf

Export the kali VM to an OVA tar file:

$ vboxmanage export kali --manifest --output kali.ova
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
Successfully exported 1 machine(s).
$ ls
kali.ova
$ file kali.ova
kali.ova: POSIX tar archive
$ tar xf kali.ova
$ ls
kali-disk001.vmdk  kali.ova  kali.ovf

Of course, you wouldn’t need to untar the kali.ova file, as this can simply be imported into VirtualBox. I only did this to demonstrate that it’s only a tar file and nothing to be scared of.

See export in the VirtualBox docs.

Unregistering

Deleting

Unregister the VM and remove the entry from the VirtualBox:

$ vboxmanage unregistervm kali-linux-2022.4-virtualbox-amd64
$ tree VirtualBox\ VMs/
VirtualBox VMs/
├── kali-linux-2022.4-virtualbox-amd64
│   ├── kali-linux-2022.4-virtualbox-amd64.vbox
│   └── kali-linux-2022.4-virtualbox-amd64.vdi
└── MSEdge - Win10
   ├── MSEdge - Win10-disk001.vmdk
   └── MSEdge - Win10.vbox

Unregister the VM, remove the entry from the VirtualBox and delete all files associated with the VM:

$ vboxmanage unregistervm kali-linux-2022.4-virtualbox-amd64 --delete
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
$ tree VirtualBox\ VMs/
VirtualBox VMs/
└── MSEdge - Win10
   ├── MSEdge - Win10-disk001.vmdk
   └── MSEdge - Win10.vbox

Note the --delete switch.

See unregistervm in the VirtualBox docs.

Miscellaneous Commands

Convert a raw disk image (ISO) to a virtual disk image (VDI):

$ vboxmanage convertfromraw Win10_22H2_English_x64.iso Win10_22H2_English_x64.vdi
Converting from raw image file="Win10_22H2_English_x64.iso" to file="Win10_22H2_English_x64.vdi"...
Creating dynamic image with size 6115186688 bytes (5832MB)...

See convertfromraw in the VirtualBox docs.

Show configuration information:

$ vboxmanage showvminfo kali | head
Name:                        kali
Groups:                      /
Guest OS:                    Debian (64-bit)
UUID:                        1b908152-38ed-4fa3-8e81-c60adf3e1102
Config file:                 /home/btoll/.config/VirtualBox/kali-linux-2022.4-virtualbox-amd64.vbox
Snapshot folder:             /home/btoll/.config/VirtualBox/Snapshots
Log folder:                  /home/btoll/.config/VirtualBox/Logs
Hardware UUID:               1b908152-38ed-4fa3-8e81-c60adf3e1102
Memory size:                 2048MB
Page Fusion:                 disabled

See showvminfo in the VirtualBox docs.

Conclusion

Here is my conclusion…don’t use the GUI any more, you don’t want to embarrass yourself and your family.

Also, this brief introductory tutorial only touches the tip of the proverbial iceberg. Please refer to the VBoxManage docs to view all of the commands, subcommands, parameters and switches.

References