February 18, 2021
A locally-connected Time Machine drive1 mounts automatically when you log in and stays mounted for the duration of your entire computing session. Normally this isn't a problem, but if you want to yank the cable and grab your notebook to go you have to remember to manually eject the Time Machine drive first. Otherwise you'll see this:
Disk not ejected properly
You can usually ignore this warning and suffer no ill effects but there is always a risk that it could lead to actual backup corruption or enough of a danger signal that Time Machine will want to wipe your backup history and do a full backup from scratch. Neither scenario is great.
This procedure shows you how to set up an automated Time Machine backup schedule that mounts the drive, does the backup, and unmounts as soon as the backup completes. The process assumes you're on macOS 11 (Big Sur) or later, and that you use an encrypted APFS Time Machine volume.
Click the Time Machine icon in your menu bar and choose Open Time Machine Preferences...
Uncheck Back Up Automatically.
We're going to write a shell script to handle the mounting, backup, and ejecting of the Time Machine drive. I could not find a way to make a bare shell script reliably mount an encrypted APFS volume, but a real Mac app can. Luckily you can wrap any shell script in a folder structure to make it look and work just like a regular Mac app. Let's call ours
timemachine_go.app and save it in our
mkdir -p timemachine_go.app/Contents/MacOS
Create the file
~/bin/timemachine_go.app/Contents/MacOS/timemachine_go using your editor of choice. This is the script, based on the approach described in this StackOverflow response, but adding support for AFPS encrypted volumes.
d="Time Machine" # (change this to match the name of your backup drive)
diskutil mount "$d"
tmutil startbackup -b
diskutil eject "$d"
diskutil apfs lockVolume "$d"
Make the script executable:
chmod +x ~/bin/timemachine_go.app/Contents/MacOS/timemachine_go
Open System Preferences > Security & Privacy. Select Full Disk Access. Click the lock and authenticate so you can make changes, then click + and add the timemachine_go.app you just created.
This script will only work if your Mac is able to automatically mount your Time Machine drive without asking you for a passphrase. If your Time Machine volume automatically appears on your desktop when you log in, you should be good to go.
Click the Time Machine icon in your menu bar and note the time of the most recent successful backup. Right-click on your Time Machine drive on the Desktop and Eject it. Navigate to and double-click timemachine_go.app in Finder.
If all goes well you should see the Time Machine drive appear on your desktop, the icon in the menu bar change for a few minutes while the backup runs, and then the Time Machine drive should disappear again. Click the Time Machine icon in the menu bar and confirm that the last backup time was updated.
We're going to create a LaunchAgent to run the backup script on a set schedule when you are logged into your Mac user account2. Create the file
~/Library/LaunchAgents/com.flakygoodness.timemachine_go.plist (feel free to substitute your own reverse-DNS name for the script)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
A few notes about the script:
Be sure to substitute YOURUSERNAME above, as well as the correct reverse-DNS name you chose for the script if different than mine. The StartInterval of 7200 seconds (run a backup every 2 hours) can be customized to your taste. I suggest starting with 900 (15 minutes) for testing, and then when you're confident the script is working as intended you can set this to whatever you'd like.
Changes you make to the LaunchAgent file won't take effect until you've reloaded the plist, which happens for you automatically when you log out and back into your Mac account.
When you boot your Mac and log in you'll see the Time Machine drive on the desktop3. After a 2 minute delay4 the backup will run, and then the drive will eject and disappear. In another 2 hours (or whatever interval you've set in the LaunchAgent script) the drive will mount and appear, the backup will run, and then disappear again.
Every once in a while it's a good idea to click the Time Machine icon in the menu bar and confirm that the last successful backup occurred when you think it should have. Better yet, manually mount your Time Machine drive (using Disk Utility or the command-line) and open up the Time Machine interface. Use it to restore a data file or two, and then eject the drive with confidence that it will be mounted again when it's time for the next backup.
1 Alternatively you could use a network-attached Time Machine volume like a Time Capsule or Time Machine-compatible NAS. This comes with its own set of performance and reliability trade-offs. A fast, locally-attached Time Machine is a nice way to go. With an APFS-formatted SSD my incremental backups typically take only take a few seconds to complete.
2 I don't believe that this script will run during Power Nap wakes, but I'm not sure about this.
3 Although there are a number of approaches for completely hiding the Time Machine drive from the desktop I didn't find any of them suitable. There was a way to set a hidden flag on any macOS file/folder/volume but this no longer seems to work, at least for Time Machine volumes. It's possible to prevent a volume from automatically mounting at startup, but this seems to prevent the script from ever being to mount the drive without user intervention (the drive still mounts from Disk Utility). Finally, it's possible to prevent Finder from showing any externally attached drives on the Desktop but I actually find this behavior useful for things like USB thumbdrives.
4 You may have noticed the
sleep 120 (2 minute delay) hard-coded at the top of the
timemachine_go script. This is to workaround a timing issue where, if the backup starts immediately upon login, the Time Machine drive may not have yet been detected by the OS. Two minutes is enough time to allow for this, and also gives us a little opportunity to do something quickly and log out again if we want to avoid a backup entirely.