I installed one of the Mojave public betas last week on the Mac Mini I have in the office. I used it as an excuse to finally tweak a script I wrote for customizing macOS out of the box.
I'll annotate inline below, you can snag the original if it looks useful to you. The first hunk is just standard shell boilerplate. I tend to write POSIX shell and eschew any bash specific nonsense for maximum compatibility.
#!/bin/sh
# install-macos (c) 2017-2018 Matthew J. Ernisse <matt@going-flying.com>
# All Rights Reserved.
#
# Customize a base macOS install.
#
# Redistribution and use in source and binary forms,
# with or without modification, are permitted provided
# that the following conditions are met:
#
# * Redistributions of source code must retain the
# above copyright notice, this list of conditions
# and the following disclaimer.
# * Redistributions in binary form must reproduce
# the above copyright notice, this list of conditions
# and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
I don't use iCloud, I run ownCloud instead. This just makes the directory I use to sync my files to/from.
create_owncloud_dir()
{
if [ ! -d "$HOME/Documents/cloud" ]; then
echo "Creating ownCloud directory"
mkdir -p "$HOME/Documents/cloud"
fi
}
Disable more things I don't use or care about. Touristd is a bit annoying because they can push more crap to bother you with down the line. This at least shuts it up after initial install.
disable_siri()
{
echo "Disabling Siri"
defaults write com.apple.Siri StatusMenuVisible -bool false
defaults write com.apple.Siri UserHasDeclinedEnable -bool true
defaults write com.apple.assistant.support 'Assistant Enabled' 0
}
disable_touristd()
{
defaults write com.apple.touristd \
seed-https://help.apple.com/osx/mac/10.13/whats-new \
-date "$(date)"
}
Set a whole bunch of system preferences. Disable automatic spelling and unicode quote correction. Set my preferred Finder style (list view), and enable daily update check and installation. Also try to keep finder from crapping .DS_Store folders all over the network shares.
set_defaults()
{
echo "Writing various macOS defaults"
# I suspect I am missing some...
defaults write NSGlobalDomain AppleKeyboardUIMode -int 3
defaults write NSGlobalDomain AppleICUForce24HourTime -int 1
defaults write NSGlobalDomain AppleAquaColorVariant -int 6
defaults write NSGlobalDomain AppleInterfaceStyle "Dark"
defaults write NSGlobalDomain \
AppleMiniturizeOnDoubleClick -bool false
defaults write NSGlobalDomain AppleShowScrollBars "Always"
defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false
defaults write NSGlobalDomain \
NSAutomaticCapitalizationEnabled -int 0
defaults write NSGlobalDomain \
NSAutomaticDashSubstitutionEnabled -int 0
defaults write NSGlobalDomain \
NSAutomaticPeriodSubstitutionEnabled -int 0
defaults write NSGlobalDomain \
NSAutomaticQuoteSubstitutionEnabled -int 0
defaults write NSGlobalDomain \
NSAutomaticSpellingCorrectionEnabled -int 0
defaults write NSGlobalDomain \
NSAutomaticTextCompletionEnabled -int 1
defaults write NSGlobalDomain NSCloseAlwaysConfirmsChanges -int 1
defaults write com.apple.keyboard.fnState -int 1
defaults write com.apple.screencapture disable-shadow -bool true
defaults write com.apple.finder FXPreferredViewStyle -string '"Nlsv"'
# Check for updates automatically, daily, and auto-install
# security updates
defaults write com.apple.SoftwareUpdate \
AutomaticCheckEnabled -bool true
defaults write com.apple.SoftwareUpdate ScheduleFrequency -int 1
defaults write com.apple.SoftwareUpdate AutomaticDownload -int 1
defaults write com.apple.SoftwareUpdate CriticalUpdateInstall -int 1
# Don't shit .DS_Store all over the show.
defaults write com.apple.desktopservices \
DSDontWriteNetworkStores true
}
As it says, install my internal CA into the trust store.
# Install and trust my local CA.
install_ca()
{
echo "Installing CA, you will be prompted for your password"
local tmpfile=$(mktemp)
curl --fail \
--silent \
--location \
--insecure \
--output $tmpfile \
http://apollo.internal.ub3rgeek.net/ca/ub3rgeek_Internal_CA.pem
security add-trusted-cert \
-k "$HOME/Library/Keychains/login.keychain-db" \
$tmpfile
rm $tmpfile
}
This gets called to install homebrew and a bunch of applications. There is a nasty hack later as the script needs to be run with sudo, but homebrew won't work that way.
# I hate you so much homebrew for having a fucking trustmeprompt shell
# pipe to a thing installer. Fuck you.
install_homebrew()
{
echo "Installing Homebrew and sundry applications"
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew analytics off
brew install caskroom/cask/docker
brew install caskroom/cask/firefox
brew install caskroom/cask/iterm2
brew install caskroom/cask/owncloud
brew install caskroom/cask/visual-studio-code
brew install caskroom/cask/vnc-viewer
brew install caskroom/cask/vlc
# broken?!
# brew install caskroom/fonts/font-inconsolata
brew install imagemagick
brew install flake8
brew install ffmpeg
brew install fdk-aac-encoder
brew install gnupg
brew install gnutls
# this doesn't seem to function correctly.
# brew install opensc
brew install pass
brew install tmux
brew install telnet
brew install pwgen
brew install wget
}
Setup my default shell environment.
install_profile()
{
echo "Installing .profile"
curl --fail \
--silent \
--location \
--output "$HOME/.profile" \
"https://ssl.ub3rgeek.net/git/?p=misc.git;a=blob_plain;f=profile;hb=HEAD"
}
Setup autofs, this gets customized a bit for different sites. It also setups the client to match my NFSv4 configuration.
create_automount()
{
local nfs_server="tardis.internal.ub3rgeek.net"
local shares="/vol/staff/mernisse /vol/backup /vol/media"
echo "Setting up NFS automount."
if [ ! -d "$HOME/Shares" ]; then
mkdir $HOME/Shares
fi
if [ ! -f /etc/auto_nfs ]; then
touch /etc/auto_nfs
chown root:wheel /etc/auto_nfs
chmod 644 /etc/auto_nfs
fi
for share in $shares; do
if ! grep -q "nfs://$nfs_server$share" /etc/auto_nfs; then
echo "$(basename $share) nfs://$nfs_server$share" \
>> /etc/auto_nfs
fi
done
if ! grep -q "$HOME/Shares auto_nfs" /etc/auto_master; then
echo "$HOME/Shares auto_nfs" >> /etc/auto_master
fi
if ! grep -q nfs.client.default_nfs4domain /etc/nfs.conf; then
echo "nfs.client.default_nfs4domain = localdomain" >> /etc/nfs.conf
fi
automount -c
}
This just says hello and is called at the start of the script.
say_hello()
{
local reset="\033[0m"
local green="\033[32;1;m"
local yellow="\033[33;1;m"
local red="\033[31;1;m"
local magenta="\033[35;1;m"
local blue="\033[34;1;m"
local cyan="\033[36;1;m"
local hello=" ${green}H${yellow}e${red}l${magenta}l${blue}o${reset}"
hello="${hello}, I am the Macintosh. "
hello="${hello} $(sysctl -n hw.model)"
hello="${hello} ${cyan}macOS $(sw_vers -productVersion)${reset}"
printf "$hello\n"
}
The default uid/gid doesn't match my network so I change it here. This is why the script needs to be run as root. You do have to be careful with this since it can do wonky things to your login session once it does what its thing.
update_uid_and_groups()
{
if [ "$(id -u mernisse)" -eq 1000 ]; then
return
fi
echo "Setting uid to 1000 and creating media group"
dscl . -change $HOME UniqueID $SUDO_UID 1000
dseditgroup -o create -i 1042 media
dseditgroup -o edit -a mernisse media
echo "Changing ownership of $HOME to reflect new uid"
chown -R 1000 $HOME
}
This is the start of execution. It checks to see if you are running as root or doing the homebrew step.
# TODO:
# https://download.panic.com/transmit/Transmit%204.4.13.zip
# ublock origin?
if [ ! "$UID" -eq 0 ] && [ ! "$1" = "homebrew" ]; then
echo "Please run this script with sudo(8)."
exit 1
fi
Catch the homebrew install which needs to be run as the user, not as root.
if [ "$1" = "homebrew" ]; then
install_homebrew
echo "Returning to sudo session..."
exit
fi
Call all the stuff above.
say_hello
set_defaults
disable_siri
disable_touristd
install_ca
create_owncloud_dir
I replaced all the spinning disks with SSDs a while ago. So I don't need the sudden motion sensor..
echo "Disabling SuddenMotionSensor"
pmset -a sms 0
Some finder related things here. I don't like things being hidden.
echo "Unhiding /Volumes and ~/Library"
chflags nohidden ~/Library
chflags nohidden /Volumes
locate is a good thing to have.
echo "Enabling locatedb"
launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist
install_profile
This re-executes the script as the user that ran sudo. This is done to make homebrew happy.
echo "Dropping privs to $SUDO_USER to install homebrew"
echo "************************************************"
# This is a hack...
sudo -u $SUDO_USER $0 homebrew
Finally, change my UID and GID if needed.
# Do this late, because my window session will still have the old UID cached
# it gets... wonky.
update_uid_and_groups
create_automount
And that's it. There is still a few things I have to do manually, including installing a Configuration Profile with my WiFi and VPN settings but it really reduces the amount of things that I have to do to get a new macOS install up and running. 👍 🥃