I have a virtual machine to control incoming faxes and other tasks that I perform a snapshot on nightly. To ensure that I can port the vm to another piece of hardware, I use a Linux cron job to turn-off the vm at 3a.m. using the acpipowerbutton, wait until the shutdown is complete, delete the previous week's (7-days ago) snapshot, make a new snapshot, and power-up the vm to get ready for the day.
I have edited the script I use to make it generic from any vm. Of course, you can change the name of the script, but this is my current production candidate. This can be put in your /usr/local/bin. I used the .sh extension isn't required, it is just a little insurance so I don't accidentally kick-off the script and turn-off a vm that I didn't want to. I have not put in a check to verify that a vm name was input, if the script is invoked without adding a vm name to the script, you will just get a few screens of error messages.
# snaptake.sh - take a snapshot of vm in virtualbox
# snapshot is named by the dow (Mon, Tue, ...) vm name must have no spaces.
# Push the virtual power button to shut-off and wait so many minutes to complete
# You need to have your vm configured to shutdown when the power button is pressed.
# This method gives a much more controlled turn-off than the "pull-the-plug" methods.
# A snapshot made with the vm not running, makes it easier to port to a different
# Syntax: snaptake.sh VBName
# where VBName is the name of the virtual machine. There can be no spaces in the name.
# This script first attempts to turn-off the virtual machine with the acpipowerbutton method. The
# vm must have been configured to turn-off when the power button is pressed.
#Then, the oldest snapshot with the name for the day of week (Mon, Tue, Wed ... )
# is deleted. The name is derived from the date function. Then a new snaphot
# is taken, using the same day of week. Finally the vm is restarted.
VBoxManage controlvm $1 acpipowerbutton
# Wait until vm has stopped running, waiting a few seconds between checks to keep cpu use down
while [ `vboxmanage list runningvms | grep -c \"$1\"` -gt 0 ]
# Now delete last week's snapshot and make a new snapshot, using the 'dow' (Mon, Tue, Wed .... )
vboxmanage --nologo snapshot $1 delete `date '+%a'` 2>/dev/null
# This might be unnecessary, I haven't verified yet whether the wait is required
# or not for delete to complete.
while [ `ps -ax | grep /VBoxManage\ | grep \ $1\ | grep -c delete` -gt 0 ]
# Take the new snapshot, give it the name of the day of week (Mon, Tue, ... )
vboxmanage --nologo snapshot $1 take `date '+%a'` 2>/dev/null
# wait a few more seconds, the snapshot goes fast
while [ `ps -ax | grep /VBoxManage\ | grep \ $1\ | grep -c take` -gt 0 ]
# Uncomment following line to start the vm, comment it to keep the vm off
DISPLAY=:0 VBoxManage startvm "$1" --type gui 2>/dev/null
This solution comes from ideas on this website and others and trial and error to get things working for my configuration. This script is running on an Ubuntu 20.04. I believe the syntax and functions I have used will operate only on the exact virtual machine named and not similarly named vm's.