Automated MacBook Setup

I just started at Anchore and am eager to start digging into some coding problems as well as helping to cultivate an amazing engineering organization.

While setting up my new MacBook, I figured I should make setup easier for the next person, or even my future self. I learned about Homebrew’s Brewfile for easily installing a whole toolbox of software. I also recalled tricky and scary setup steps in the past and wanted to make sure that whatever I left behind was relatively safe to run blindly. That is, it would be idempotent (running multiple times would have the same effect as running once) and non-destructive.

While the Homebrew install instructions are really simple, I wanted to leave an even simpler script to combine several steps:

#!/usr/bin/env zsh
brew_major_version=$(brew –version | head -c 10)
if [ "$brew_major_version" = 'Homebrew 3' ]; then
echo 'Homebrew already installed'
echo 'Updating Homebrew'
brew update
echo 'Installing Homebrew'
/bin/bash -c "$(curl -fsSL"
echo 'Install and update packages in the Brewfile`
brew bundle

The Brewfile will probably get long, but here’s how a short one looks:

tap "homebrew/bundle"
tap "homebrew/cask"
tap "homebrew/core"
cask "docker"
cask "iterm2"
cask "visual-studio-code"
view raw Brewfile hosted with ❤ by GitHub

You can manually install from the Brewfile by running brew bundle and you can create a new one based on what you’ve currently installed with brew bundle dump. If you’re tracking the Brewfile in version control, then brew bundle dump --force is handy for overwriting it.

I haven’t used zsh before, but I knew I wanted to try oh-my-zsh as well as use what my teammates were using. Here’s the install script I wrote up for installing, setting plugins, and installing the Powerlevel10k theme:

#!/usr/bin/env zsh
export OMZ=~/.oh-my-zsh
if [ -d $OMZ ]; then
echo 'Oh My Zsh is already installed.'
echo 'Installing Oh My Zsh:'
sh -c "$(curl -fsSL"
export PLUGINS="alias-finder brew common-aliases git"
if grep -qF "plugins=(git)" ~/.zshrc; then
sed -i '' "s/plugins=(git)/plugins=($PLUGINS)/g" ~/.zshrc
echo 'Oh My Zsh plugins set to baseline.'
source ~/.zshrc
echo 'Oh My Zsh plugins left alone because they are not default. Current set of plugins:'
grep "^plugins=" ~/.zshrc
if [ ! -d $ZSH_CUSTOM/themes/powerlevel10k ]; then
git clone –depth=1 ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
echo 'Set ZSH_THEME="powerlevel10k/powerlevel10k" in ~/.zshrc if you want this awesome theme.'

I’m pretty happy with this so far and wanted to share.

If I end up with an important set of VS Code extensions (which is likely), I think I’ll lean toward providing them as recommended extensions in each code repo. If they seem important for initial setup, though, then I’m considering something along the lines of dumping the list to a text file with code --list-extensions and then automatically installing with cat vs_code_extensions_list.txt | xargs -n 1 code --install-extension.

Automated MacBook Setup

Tech Support: BitLocker failure on a dual-boot ThinkPad

Thank you, Mike Ober (Mike400), for sharing the solution! I want to share my tech support solution for the next person trying to figure this out by searching the amazing knowledge repository that is the Web.


  1. I have a nice new Thinkpad X1 Extreme.
  2. I installed Pop!_OS as a dual-boot Linux option. I can’t remember, but I believe I had to disable a setting or two in the BIOS/UEFI to allow Linux to boot.
  3. After using both OSes successfully, I decided it was time to enable disk encryption, and I turned on BitLocker for my Windows partition.
  4. After rebooting to Windows, I got the following error:

BitLocker error message

I searched the Web for “The data drive specified is not set to automatically unlock on the current computer and cannot be unlocked automatically” to figure out why “BitLocker could not be enabled.” It wasn’t great and there was no obvious answer in the results.

Mike400‘s answer to a question on a site I’ve never heard about struck me, because it sounded like the solution to so many Windows problems (off/on, uninstall/reinstall, disable,enable).

For posterity, here are the steps when the problem is the Microsoft TPM driver:

  1. Disable TPM in the BIOS.
  2. Boot to Windows and open an Admin command prompt.
  3. Run the following to open Device Manager showing the absent TPM:
    set devmgr_show_nonpresent_devices=1
    start devmgmt.msc
  4. In Device Manager, go to “View” and enable “Show Hidden Devices.”
  5. Under “Security Devices” is the “Trusted Platform Module”. DELETE IT.
  6. Reboot to Windows again. Just to be sure.
  7. Shutdown and enable TPM in the BIOS.
  8. Boot to Windows and try BitLocker again.

It worked for me!

Tech Support: BitLocker failure on a dual-boot ThinkPad

Create a PDF from your Swagger definition in two lines!

# swagger2markup output fed to asciidoctor-pdf – all via published docker images
# The following is a Makefile command in the root of a web service repo with the following assumptions:
# ./swagger/v1/swagger.json is the swagger definition (created by rswag in my case)
# ./_docs/ is where we want the PDF and intermediate ADOC to live
# The ADOC file is pretty useful, but if you just want the PDF, it's a byproduct you might want to clean up
docker run –rm -v $(shell pwd):/opt swagger2markup/swagger2markup convert -i /opt/swagger/v1/swagger.json -f /opt/_docs/api-definition
docker run –rm -v $(shell pwd)/_docs:/documents/ asciidoctor/docker-asciidoctor asciidoctor-pdf api-definition.adoc
# To add configuration options for swagger2markup, create a file and specify with
# -c /opt/
# asciidoctor-pdf supports pretty extensive styling:

Continue reading “Create a PDF from your Swagger definition in two lines!”

Create a PDF from your Swagger definition in two lines!

If it hurts, do it more often

I’ve been thinking that I should refresh my Surface Book, especially in light of the findings of Consumer Reports and Microsoft’s objections and my own freeze/dark screen problems, but I’ve been putting it off because it’s painful.

Reinstalling multiple applications, restoring my configurations, and retrieving my data all seem like big chores. Once I realized that, however, I reflected on one of the batch-size principles: if it hurts, do it more often.

So I started to look into automating the process and ran across an old, eye-opening series of blog posts about “Scripting the setup of a developer PC.”


Continue reading “If it hurts, do it more often”

If it hurts, do it more often

Writing legacy code and a few git commands

I’m having a blast learning Ruby and Rails right now.

I’m building a site as a learning exercise, but I decided to learn by building the Maintenance App that I previously wrote about.

I don’t believe that Ruby or Rails will be the way I want the app to run in the end, but it’s still a great learning exercise. Essentially, I’m writing “legacy code” now that will probably be replaced with a one-page JavaScript app. That will be another great learning experience, including how I maintain a set of automated tests through the transition and always have working software.

Here are also a few git commands that I’ve been using. I doubt that I’ll forget these anytime soon, but this might still be a handy reference for me in the future:

Reorient by getting the latest info from GitHub and looking at the branches and status I’m working with locally

git fetch
git branch
git status

Start a new feature branch and commit to it

git checkout -b feature_branch_name
git status
git commit -a -m "Describe changes made in committed changes"

Rebase before pushing to GitHub (to create or update a Pull Request)

git pull origin
git rebase origin/master
. . .
git add .
git rebase --continue
. . .
git push origin --force

Abort a rebase if I messed up

git rebase --abort

Wipe my local changes and go back to the feature branch on GitHub

git reset --hard origin/feature_branch_name

Closing out a feature branch after it has been merged in GitHub

git checkout master
git pull
git branch
git branch -d feature_branch_name
Writing legacy code and a few git commands

Artoo, Drag, Dead Code, and the Zeroth Constraint

Just a few web pages that I’ll probably come back to again later:

  • I’m trying my hand at scraping data out of a horribly formatted web page and reformatting it for attractive printing. So far I’m messing around with HTML parsing, using Python libraries and possibly artoo.js.
  • When I have a chance, I’m going to try optimizing JPEG files with Guetzli.
  • Some good reminders that executives don’t always have an easy time seeing things from the Agile or Lean point of view.
  • A cool idea if you need to make a point about bad code removed from a product: the big book of dead code.
  • While using the Theory of Constraints to coach an organization, “The Zeroth constraint is that the organisation do not see the coach as a close trusted advisor.”
  • Roman Pichler’s article on MVP vs. MMP came up at work and I’m thinking about more concrete ways to lay out what a Minimum Viable Product, Minimal Marketable Product, and some sort of Full Marketable Product look like.
  • AirTable looks intriguing, both for customized workflows but also, perhaps, personal kanban.
  • I have run into people with small (or even large) amounts of power within an organization who don’t seem to understand how hard it is for people with less power to speak up to them: the problem with saying, “my door is always open.”
  • I remember the PBJ instructions challenge from my childhood. Thinking about the ways instructions gloss over all of the steps involved can help you really grasp a user’s experience.
  • Someone I used to work with recommended that I check out Drag for managing my email. It does seem up my alley, at least if I wanted to address all of my personal email.
  • AgileCraft certainly says good things, and since I may get to try out their software at work, I hope their software matches what they say.
Artoo, Drag, Dead Code, and the Zeroth Constraint

Maintenance Reminder Android App

I want an Android app that will remind me to perform various maintenance activities. I have a few use cases:

  • Yearly (renew my vehicle registration)
  • 90 days after last action (replace house air filter)
  • Last weekday before the 16th (usually the 15th) each month (to submit my timesheet)
  • Same as the above, but for the end of the month.
  • Monday, every other week (tasks related to my two-week sprint schedule at work).
  • Every weekday, appears until I check it off (update a daily metric chart)
  • Three times each week (work out)

Some that I’m looking at:

  • Loop – Habit Tracker // doesn’t handle yearly reminders. Looks like it might be really nice for habit-building.
  • Habitica // doesn’t handle monthly actions. Again, looks like it might be really nice for habit-building.
  • BZ Reminder // Looks better, but can’t handle my every-other-week reminder, nor the monthly end-of-month.
  • Life Reminders // This is pretty impressive. The monthly+weekday-only criteria doesn’t seem possible, but monthly plus a day warning is. This is a contender.
  • Reminder // Does have quite as many options as Life Reminders, but it might be close enough that other features could make the difference.
  • Just Reminder // At first this appears to have the most schedule options, but it still can’t do the last weekday of the month. I don’t like the interface as much, but this is in the running.

I’ve been thinking about creating my own app for this, but getting the reminders is more urgent and more important than building the app.

Maintenance Reminder Android App

Surface Book power problems

Secret procedure:

  1. Depress power button for 30 seconds, no matter what (force full shutdown).
  2. Depress volume-up and power button for 15 seconds, no matter what (secret sauce!).
  3. Exit/restart/power-on/reboot – whatever it takes to let Windows 10 right itself.

My fancy new Microsoft Surface Book (a splurge because my new employer is subsidizing it) has caused a handful of minor disappointments and annoyances, but the one big headache has been the unexpected reboots when I just want the machine to wake from sleep. Microsoft rolled out updates that seem to have fixed this issue for others, but installing the updates didn’t help me.

While I was ready to get a replacement machine (which would’ve had the nice side-effect of addressing the minor physical imperfections of my machine), I ended up calling Surface Support and Daphne had me perform the secret procedure above to do some sort of magic. If I understood her correctly, step two tells Windows to reinstall driver software in the correct order.

Whatever it did, I’m now ten sleeps in with no unplanned restarts. Fingers crossed!

Surface Book power problems