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 byVirtualBox
.
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 themodify-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 UUID
s 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 thestorageattach
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
orrunningvms
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
UUID
s, 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 theVMDK
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 intoVirtualBox
. 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.