Device Snapshots and Crafting A Restore Device User Experience for Macs

I recently worked on something where a design requirement was to build a good snapshot restore option but not to use Time Machine backups. You can capture a snapshot of a Mac without enabling Time Machine. To do so, you’d still use the same binary as you would with Time Machine, /usr/bin/tmutil. To do so, simply use the snapshot verb as follows:

/usr/bin/tmutil snapshot

Once you’ve run that, you get output similar to the following:

Created local snapshot with date: 2019-04-12-110248

Now you have a snapshot that can be used to restore a Mac using the steps shown in this article:

You can make a snapshot at the provisioning time of a Mac and then see that snapshot at any point by awking for the first line in a list of snapshots, unless it’s been deleted:

snapshot=`tmutil listlocalsnapshots / | awk -F "." '{print $4}' | head -1`

Now when it comes to making it simple for end user restores, there’s a few gaps. The first is that you have to boot with Command-R and can’t build a scripted restore option. So the following won’t work on a machine with SIP:

sudo nvram boot-args="-x"; restart

You can prune the list of snapshots so it’s simple for a user to pick the right one though. To see a list of all your snapshots for the current boot volume, use that listlocalsnapshots verb:

tmutil listlocalsnapshots /

This provides the output as and when deleting snapshots you don’t need the portion of that string, so to delete the last snapshot we’ll gather it into a variable with the following:

snapshot=`tmutil listlocalsnapshots / | awk -F "." '{print $4}' | tail -1`

Alternatively you can list snapshots with the diskutil command, using the apfs option and listSnapshots verb, followed by your boot volume as follows, but the output isn’t pretty:

diskutil apfs listSnapshots disk1s1

Once you’ve parsed the service name portion out, you can then delete a given snapshot using the deletelocalsnapshots verb with tmutil:

tmutil deletelocalsnapshots 2019-04-12-110248

Or to use that snapshot variable:

tmutil deletelocalsnapshots $snapshot

So I can present the user, when they try to revert, with a shorter list of snapshots, hopefully helping them to select the right one. But, I can only do a scripted restore if I’m actually using Time Machine and I have a volume taking those backups. If I’m doing a snapshot restore I have to restart the Mac holding down the command- R keys and then once booted in recovery mode, select the snapshot and wait for the restore.

Booting into recovery mode takes a long time so seems like something you’d teach the desktop techs to do rather than expect users to do a-la-“Erase all Contents and Settings” button. The whole process takes about 20 minutes because of how long it takes to boot into this state and revert.

It’s actually just as quick to do a full reinstallation. This can be as simple as using the startosinstall --eraseinstall command, which provides a number of options. It seems silly to load up a whole new operating system when you have one there, but assuming you have decent internet speeds, it’s just as fast to do so. There’s even a gui wrapper for it to make the whole process easier for your users at which could then be provided in tools like Managed Software Center and Self Service. You could also try and remove all user and app data using a script but that has turned out to be a lot of moving parts that requires constant updates.

If you were to opt into a snapshot-based restore option, it’s also worth noting that if you have outdated certificates, outdated passwords, outdated software, etc, that it can be problematic. So we’re pretty much right back to erase-install.

Other people have gone down this same rabbit hole:


So my initial goal was to create an article on doing an elegant restore process for the Mac, where you script more of it and provide a better experience. But alas, I have failed ya’. Sorry. Do you have a better way? If so, please comment!