#shellwaffle

free software, self hosting, streaming and more

VirtualBox: executing commands inside a VM with vboxmanage

Installing the guest additions in your VM lets you interact with it using VirtualBox’s utility vboxmanage from the host.

One of the features is letting you execute any command on the guest, from the comfort of you own host . It can be helpful in a number of contexts and help streamline your workflow without having to use SSH!

Basic example

Let’s start simple, and execute “hostname“:

vboxmanage guestcontrol "VM_NAME" \
  --username "VM_USER" --password "VM_PASSWORD" \
  run -- "/bin/hostname"

VM_NAME is the name of the VM such as it appears in the VirtualBox manager, or in the list given by this command:

vboxmanage list vms |cut -d '"' -f 2

VM_USER and VM_PASSWORD are the username and its matching password for the user you want to execute the command as, inside the VM.

Reading the password from a file

Providing the password on the command line is never a great idea, as it will end up in your shell’s history and maybe other places. You can avoid that by putting the password inside a simple text file and using the “--passwordfile” parameter instead of “--password“.

vboxmanage guestcontrol "VM_NAME" \
  --username "VM_USER" --passwordfile "./password.txt" \
  run -- "/bin/hostname"

All further examples will use “--passwordfile” and assume the file containing the password is located at ./password.txt.

Executing a command with parameters

If the command you want to run needs parameters, you need to specify them as separate strings.

For example, to run “/usr/bin/find /home/user -name Documents“, you need to split it as in this example:

vboxmanage guestcontrol "VM_NAME" \
  --username "VM_USER" --passwordfile "./password.txt" \
  run -- "/usr/bin/find" "/home/user" "-name" "Documents"

Notice how you need to split “-name Documents” in two separate strings also!

I’ve been using the full path to “uname” and “find” in the examples above. You can avoid that by calling a shell and execute your command inside it. For example you could chose bash and execute the commands using "bash -c 'your command'“. Calling bash will also let you run built-in commands such as “ls” and “pwd“, but also use environment variables such as “$HOME“. Another advantage: the whole command being an argument to bash, you won’t need to split it, which improves readability:

vboxmanage guestcontrol "VM_NAME" \
  --username "VM_USER" --passwordfile "./password.txt" \
  run -- "/bin/bash" "-c" 'find $HOME -name Documents'

You’re using bash, so you can write anything you’d write on a bash CLI or in a script:

vboxmanage guestcontrol "VM_NAME" \
  --username "VM_USER" --passwordfile "./password.txt" \
  run -- "/bin/bash" "-c" \
  '[ -w $HOME/Documents ] && echo "Can write." || echo "Cannot write."'

Properly escaping variables

When using variables, make sure to include them in a single quoted string, or properly escape the $ so that the variables don’t expand on the host (unless that’s what you want).

The following incorrect example outputs /home/lefractal (my home directory on the host) instead of foo, because $HOME is expanded on the host inside the double quoted string:

vboxmanage guestcontrol "VM_NAME" \
  --username "VM_USER" --passwordfile "./password.txt" \
  run -- "/bin/bash" "-c" "HOME=foo; echo $HOME"

These examples are correct and output foo, using single quoted strings and variable escaping, respectively:

vboxmanage guestcontrol "VM_NAME" \
  --username "VM_USER" --passwordfile "./password.txt" \
  run -- "/bin/bash" "-c" 'HOME=foo; echo $HOME'
vboxmanage guestcontrol "VM_NAME" \
  --username "VM_USER" --passwordfile "./password.txt" \
  run -- "/bin/bash" "-c" "HOME=foo; echo \$HOME"

Executing GUI apps

All of our examples so far have been about executing CLI apps, but you can also execute graphical apps! Please note that I’ve only tested this with guests running an X server, I’m not sure if it works if the guest runs Wayland.

The trick is to tell the system which display to launch the app on. The right display for any use case is almost certainly “:0” . But If you want to check, launch a terminal emulator on your guest’s desktop and check the value of the “$DISPLAY” variable:

echo $DISPLAY

We need to set the environment variable “DISPLAY” to that value using the “--putenv” parameter, when trying to launch a GUI app with vboxmanage.

So, let’s launch VLC in the VM and tell it to play my stream (maybe I’m online?):

vboxmanage guestcontrol "VM_NAME" \
  --username "VM_USER" --passwordfile "./password.txt" \
  run --putenv DISPLAY=:0 -- \
  "/usr/bin/vlc" "https://direct.disquette.top/hls/stream.m3u"

Or, let’s launch Firefox in the VM:

vboxmanage guestcontrol "VM_NAME" \
  --username "VM_USER" --passwordfile "./password.txt" \
  run --putenv DISPLAY=:0.0 -- \
  "/usr/bin/firefox" "https://shellwaffle.com"

Conclusion

We’ve been using the “guestcontrol” subcommand, but there are more! I encourage you to check out the official documentation and discover all the ways you can manage and interact with your VirtualBox VMs from the host’s CLI.

Do you have anything to say about this? Leave a comment below!

Comments

One response to “VirtualBox: executing commands inside a VM with vboxmanage”

  1. […] can combine these “xsel” operations with what we learnt in my previous article: “VirtualBox: executing commands inside a VM with vboxmanage”. We’ll use VirtualBox’s “vboxmanage guestcontrol” command on the host, to […]

Leave a Reply

Your email address will not be published. Required fields are marked *