Or how to perform actions in a virtual machine without leaving the terminal…

From Linux, I was looking for a way to automate the compilation of a piece of software on Windows, and without using Wine which is not an official Microsoft product.

VirtualBox is multi-platform virtualization software. It comes with VBoxManage, a command line tool for managing virtual machines.

Let’s take a concrete case: here is the execution of a bash script on Linux that performs actions in a Windows 10 virtual machine, in order to compile a piece of software, execute it, take a screenshot and copy it to the host.

Here is the result: we are in a Linux terminal that displays the output of DOS commands!

Compile on Windows with the 'Win10' VM

Starting VM
Waiting for VM "Win10" to power on...
VM "Win10" has been successfully started.

Creating directory c:/users/jeff/desktop/work
Copying main.js
Copying package.json
Copying the host directory app/

yarn install
yarn install v1.19.2
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 49.30s.

yarn run buildwin64
yarn run v1.19.2
$ electron-builder -w --x64
  • electron-builder version=20.44.4
  • loaded configuration file=package.json ("build" field)
  • no native production dependencies
  • packaging       platform=win32 arch=x64 electron=4.2.12 appOutDir=c:\Users\jeff\Desktop\dist\win-unpacked
  • building        target=portable file=c:\Users\jeff\Desktop\dist\app.exe archs=x64
Done in 67.88s.

Starting app in GUI
Screenshot for fun
Copying the app to host OS
Cleanup
Stopping VM
0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%

Source code of the bash script for the remote control of Windows, whose result is displayed above:

#!/bin/bash

# Automating tasks in a virtualized OS

# directory to create in the guest OS to copy the app to compile
GUEST_PATH="c:/users/jeff/desktop"

# login in guest OS
GUEST_USER="jeff"

# password
GUEST_PASSWD="123456"

echo "Compile on Windows with the 'Win10' VM"
echo # carriage return in the terminal

# Starting VM without graphical user interface
# INFO: to list available VM from your host, type the command: VBoxManage list vms
echo "Starting VM"
VBoxManage startvm "Win10" --type headless
echo

# Creating directory in the VM
echo "Creating directory ${GUEST_PATH}/work"
VBoxManage guestcontrol "Win10" mkdir "${GUEST_PATH}/work" --username $GUEST_USER --password $GUEST_PASSWD

echo "Copying main.js"
VBoxManage guestcontrol "Win10" copyto main.js --target-directory "${GUEST_PATH}/work" --username $GUEST_USER --password $GUEST_PASSWD

echo "Copying package.json"
VBoxManage guestcontrol "Win10" copyto package.json --target-directory "${GUEST_PATH}/work" --username $GUEST_USER --password $GUEST_PASSWD

echo "Copying the host directory app/"
VBoxManage guestcontrol "Win10" mkdir "${GUEST_PATH}/work/app" --username $GUEST_USER --password $GUEST_PASSWD
VBoxManage guestcontrol "Win10" copyto -R app/ --target-directory "${GUEST_PATH}/work/app" --username $GUEST_USER --password $GUEST_PASSWD
echo

# Creating a DOS script that will be executed in the guest OS to install the project dependencies
cat > install.bat <<EOL
@echo off
chdir /d c:\\Users\\jeff\\desktop\\work
yarn install
EOL
VBoxManage guestcontrol "Win10" copyto install.bat --target-directory "${GUEST_PATH}/work" --username $GUEST_USER --password $GUEST_PASSWD

# Creating a DOS script that will be executed in the guest OS to build the project
cat > build.bat <<EOL
@echo off
chdir /d c:\\Users\\jeff\\desktop\\work
yarn run buildwin64
EOL
VBoxManage guestcontrol "Win10" copyto build.bat --target-directory "${GUEST_PATH}/work" --username $GUEST_USER --password $GUEST_PASSWD

# Executing the 1st DOS script
echo "yarn install"
VBoxManage guestcontrol "Win10" run --exe "${GUEST_PATH}/work/install.bat" --username $GUEST_USER --password $GUEST_PASSWD --wait-stdout --wait-stderr
echo

# Executing the 2nd DOS script
echo "yarn run buildwin64"
VBoxManage guestcontrol "Win10" run --exe "${GUEST_PATH}/work/build.bat" --username $GUEST_USER --password $GUEST_PASSWD --wait-stdout --wait-stderr
echo

echo "Starting app in GUI in the VM"
VBoxManage guestcontrol "Win10" start --exe "${GUEST_PATH}/dist/app.exe" --username $GUEST_USER --password $GUEST_PASSWD

# Screenshot (video recording is also available)
echo "Screenshot for fun"
VBoxManage controlvm "Win10" screenshotpng 01.png

echo "Copying the app to host OS"
VBoxManage guestcontrol "Win10" copyfrom -R "${GUEST_PATH}/dist/" ../dist --username $GUEST_USER --password $GUEST_PASSWD

# INFO: to close an app in the guest OS, you must get its process ID and the session ID with the command :
# VBoxManage guestcontrol "Win10" list processes
# To quit the app :
# VBoxManage guestcontrol "Win10" closeprocess --session-id 1 2484

# Cleaning up the directories on host and guest
echo
echo "Cleanup"
rm install.bat
rm build.bat
VBoxManage guestcontrol "Win10" rmdir -R "${GUEST_PATH}/work" --username $GUEST_USER --password $GUEST_PASSWD
VBoxManage guestcontrol "Win10" rmdir -R "${GUEST_PATH}/dist" --username $GUEST_USER --password $GUEST_PASSWD

# Shutting down the VM
echo "Stopping VM"
VBoxManage controlvm "Win10" savestate