[Skip to main content](#main-content)     [Kevin Lewis](/)  [Blog](/blog)      # Automated Mac Setup Script

 [2025-03-02]    I have found myself needing to set up a machine from scratch and, this time, I’ve decided to write a script to automate setups in future. The full script is on [GitHub](https://github.com/phazonoverload/machine-setup) but I wanted to talk through each step in case others want to do the same.

## [Execution](#execution)

I want the script to be executable from a single shell file hosted on GitHub. As GitHub serves static files via the `githubusercontent.com` domain, the script can be downloaded and immediately run by bash.

- `bash &#x3C;(curl -Ls https://raw.githubusercontent.com/phazonoverload/machine-setup/main/setup.sh)`
At the very top of the script, tell the system to use bash to execute it, and to exit if any command fails.

`#!/bin/bashset -e`
## [Install Xcode and Homebrew](#install-xcode-and-homebrew)

XCode comes with a bunch of essential utilities, so we check if it’s installed and install if not. Homebrew will be used later to install lots of software, so also check if it exists, and install it if not. This also runs postinstall commands for Homebrew, and fetches latest repository data.

Terminal window`if xcode-select --install 2>&#x26;1 | grep installed; then  echo "xcode already installed";else  xcode-select --installfi
if test ! $(which brew); then  /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"  echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/$USER/.zprofile  eval "$(/opt/homebrew/bin/brew shellenv)"fibrew update`&#x26;1 | grep installed; then  echo &#x22;xcode already installed&#x22;;else  xcode-select --installfiif test ! $(which brew); then  /bin/bash -c &#x22;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)&#x22;  echo &#x27;eval &#x22;$(/opt/homebrew/bin/brew shellenv)&#x22;&#x27; >> /Users/$USER/.zprofile  eval &#x22;$(/opt/homebrew/bin/brew shellenv)&#x22;fibrew update">
## [Install &#x26; Configure Git](#install--configure-git)

Install git via Homebrew, configure global settings including `git ac` which I have in muscle memory for lazy committing-all, generate a new SSH key pair, and make it easy to immediately add to GitHub.

Terminal window`brew install git
echo -n 'Git username: 'read usernamegit config --global user.name "$username"
echo -n 'Git email: 'read mailgit config --global user.email $mail
git config --global alias.ac "!git add -A &#x26;&#x26; git commit -m "
ssh-keygen -t rsacat ~/.ssh/id_rsa.pubopen -a Safari https://github.com/settings/keysread -p "Add public key to GitHub and hit [Enter]."`
## [Install Software via Homebrew](#install-software-via-homebrew)

Install the GitHub CLI, wget, and mas to later install apps via the Mac App Store.

Terminal window`clis=(  1password-cli  gh  wget  mas  yt-dlp  ffmpeg)brew install ${clis[@]}`
Then we install all of the tools with a UI available as a cask:

Terminal window`casks=(  1password  arc  caffeine  camo-studio  cleanshot  cyberduck  cyberghost-vpn  discord  elgato-camera-hub  elgato-control-center  elgato-wave-link  firefox  font-geist-mono  google-chrome  numi  orbstack  raycast  reflect  screen-studio  screenflow  signal  slack  todoist  vanilla  visual-studio-code  visual-studio-code@insiders  whatsapp  zoom)brew install --cask ${casks[@]}`
And finally cleanup any unused files or caches:

Terminal window`brew cleanup`
## [Install Software via Mac App Store](#install-software-via-mac-app-store)

Some apps are only accessible via the Mac App Store. The first time I wrote this script, I manually installed them and then used `mas` (installed earlier as a CLI tool with `brew`) to list existing apps with `mas list` to reveal the unique IDs for the apps in order to write the lines below:

Terminal window`mas install 1569813296 # 1Password for Safarimas install 682658836 # GarageBandmas install 409201541 # Pagesmas install 409203825 # Numbersmas install 361285480 # Keynotemas install 6475002485 # Reeder`
## [Install Node via Volta](#install-node-via-volta)

I use Volta as my Node version management tool. Grab the latest version of Node, and make it the default.

Terminal window`brew install voltavolta install node@latestvolta setup`
## [Download &#x26; Configure Oh My Zsh](#download--configure-oh-my-zsh)

I use Zsh as my terminal shell with Oh My Zsh! There’s a couple of manual steps in here because I was too lazy to fully automate editing lines in the default `.zshrc` but that’s ok! This also downloads the common theme which I like.

Terminal window`curl -L http://install.ohmyz.sh | shwget -O ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/common.zsh-theme https://raw.githubusercontent.com/jackharrisonsherlock/common/master/common.zsh-themeopen ~/.zshrcread -p "Set ZSH_THEME=\"common\" and then [enter]"git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestionsgit clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlightingopen ~/.zshrcread -p "Please add zsh-autosuggestions &#x26; zsh-syntax-highlighting to your Plugins! and hit [enter]."chsh -s /usr/local/bin/zshd`
## [Configure Mac Settings](#configure-mac-settings)

A bunch of macOS settings can actually be done via the terminal.

Terminal window`# Dockdefaults write com.apple.dock "orientation" -string "right"defaults write com.apple.dock "tilesize" -int "24"defaults write com.apple.dock "autohide" -bool "true"defaults write com.apple.dock "show-recents" -bool "false"defaults write com.apple.dock "mineffect" -string "scale"defaults write com.apple.dock "autohide-delay" -float "2"killall Dock# Screenshotsdefaults write com.apple.screencapture "type" -string "png"mkdir -p "$HOME/Pictures/screenshots"defaults write com.apple.screencapture "location" -string "$HOME/Pictures/screenshots" &#x26;&#x26; killall SystemUIServerdefaults write com.apple.screencapture "disable-shadow" -bool "true"# Safaridefaults write com.apple.Safari "ShowFullURLInSmartSearchField" -bool "true" &#x26;&#x26; killall Safari# Finderdefaults write NSGlobalDomain "AppleShowAllExtensions" -bool "true"defaults write com.apple.finder "AppleShowAllFiles" -bool "true"defaults write com.apple.finder "ShowPathbar" -bool "true"defaults write com.apple.finder "FXEnableExtensionChangeWarning" -bool "false"killall Finder# Menu Bardefaults write com.apple.menuextra.clock "DateFormat" -string "\"HH:mm\""# Mission Controldefaults write com.apple.dock "mru-spaces" -bool "false" &#x26;&#x26; killall Dock# Window Managerdefaults write com.apple.WindowManager EnableStandardClickToShowDesktop -bool false &#x26;&#x26; killall WindowManager# Powerdefaults write com.apple.screensaver idleTime 0`
## [Last Bits](#last-bits)

Because Raycast and VS Code both have excellent settings syncs, they can just be turned on and authenticated and everything snaps back to what it should be. This includes all of my keyboard shortcuts for window management, clipboard management, and AI panels.

In case this falls out of date, the latest version will be on [GitHub](https://github.com/phazonoverload/machine-setup/).

     Kevin Lewis &copy; 2016-2026