macOS automatic customization script_

🇺🇦 Resources to help support the people of Ukraine. 🇺🇦
September 16, 2018 @15:00

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.

Mojave

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. 👍 🥃

Comment via e-mail. Subscribe via RSS.