Skip to main content

I'm looking for advice on getting homebrew on new employee machines automatically. We have a work flow we would like to keep to as few clicks as possible.



I am trying to get the process of pulling down XCode CLI, installing homebrew, adding cask, and then installing third party apps for new employee machines.



I have the XCode CLI component down but having problems with installing homebrew and adding cask. Curious if anyone has a working script to make this happen. I am deploying this process through self service.

This may be of some help to you.



#!/bin/bash

# Script to install Homebrew on a Mac.
# Author: richard at richard - purves dot com
# Version: 1.0 - 21st May 2017

# Set up variables and functions here
consoleuser="$(python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");')"
brandid="com.application.id"
tn="/path/to/terminal-notifier.app/Contents/MacOS/terminal-notifier"
cd="/path/to/cocoaDialog.app/Contents/MacOS/cocoaDialog"

# Logging stuff starts here
LOGFOLDER="/private/var/log/"
LOG=$LOGFOLDER"Homebrew.log"

if [ ! -d "$LOGFOLDER" ];
then
mkdir $LOGFOLDER
fi

function logme()
{
# Check to see if function has been called correctly
if [ -z "$1" ]
then
echo $( date )" - logme function call error: no text passed to function! Please recheck code!"
echo $( date )" - logme function call error: no text passed to function! Please recheck code!" >> $LOG
exit 1
fi

# Log the passed details
echo -e $( date )" - $1" >> $LOG
echo -e $( date )" - $1"
}

function notify()
{
su -l "$consoleuser" -c " "'"'$tn'"'" -sender "'"'$brandid'"'" -title "'"'$title'"'" -message "'"'$1'"'" "
logme "$1"
}

# Check and start logging - done twice for local log and for JAMF
logme "Homebrew Installation"

# Let's start here by caffinating the mac so it stays awake or bad things happen.
caffeinate -d -i -m -u &
caffeinatepid=$!
logme "Caffinating the mac under process id: $caffeinatepid"

# Have the xcode command line tools been installed?
notify "Checking for Xcode Command Line Tools installation"
check=$( pkgutil --pkgs | grep com.apple.pkg.CLTools_Executables | wc -l | awk '{ print $1 }' )

if [[ "$check" != 1 ]];
then
notify "Installing Xcode Command Tools"
# This temporary file prompts the 'softwareupdate' utility to list the Command Line Tools
touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
clt=$(softwareupdate -l | grep -B 1 -E "Command Line (Developer|Tools)" | awk -F"*" '/^ +\\*/ {print $2}' | sed 's/^ *//' | tail -n1)
softwareupdate -i "$clt"
rm -f /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
/usr/bin/xcode-select --switch /Library/Developer/CommandLineTools
fi

# Is homebrew already installed?
which -s brew
if [[ $? = 1 ]];
then
# Install Homebrew. This doesn't like being run as root so we must do this manually.
notify "Installing Homebrew"

# Curl down the latest tarball and install to /usr/local
curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C /usr/local

# Manually make all the appropriate directories and set permissions
mkdir -p /usr/local/Cellar /usr/local/Homebrew /usr/local/Frameworks /usr/local/bin /usr/local/etc /usr/local/include /usr/local/lib /usr/local/opt /usr/local/sbin /usr/local/share /usr/local/share/zsh /usr/local/share/zsh/site-functions /usr/local/var
chown -R $consoleuser /usr/local
chmod g+rwx /usr/local/Cellar /usr/local/Homebrew /usr/local/Frameworks /usr/local/bin /usr/local/etc /usr/local/include /usr/local/lib /usr/local/opt /usr/local/sbin /usr/local/share /usr/local/share/zsh /usr/local/share/zsh/site-functions /usr/local/var
chmod 755 /usr/local/share/zsh /usr/local/share/zsh/site-functions
chgrp admin /usr/local/Cellar /usr/local/Homebrew /usr/local/Frameworks /usr/local/bin /usr/local/etc /usr/local/include /usr/local/lib /usr/local/opt /usr/local/sbin /usr/local/share /usr/local/share/zsh /usr/local/share/zsh/site-functions /usr/local/var

# Create a system wide cache folder
mkdir -p /Library/Caches/Homebrew
chmod g+rwx /Library/Caches/Homebrew
chown $consoleuser:wheel /Library/Caches/Homebrew

# Install the MD5 checker or the recipes will fail
su -l "$consoleuser" -c "/usr/local/bin/brew install md5sha1sum"
su -l "$consoleuser" -c "echo "'"export PATH=/usr/local/opt/openssl/bin:$PATH"'" >> ~/.bash_profile"

# Remove temporary folder
rm -rf /usr/local/Homebrew
else
# Run an update and quit
notify "Updating Homebrew"
su -l "$consoleuser" -c "/usr/local/bin/brew update" 2>&1 | tee -a ${LOG}
exit 0
fi

# Make sure everything is up to date
notify "Updating Homebrew"
su -l "$consoleuser" -c "/usr/local/bin/brew update" 2>&1 | tee -a ${LOG}

# Notify user that all is completed
notify "Installation complete"

# No more caffeine please. I've a headache.
kill "$caffeinatepid"

exit 0

@jhbush1973 thank you! I had been looking for something like this a little while ago and couldn't find anything.



I just modified it to remove the caffinate and terminal notifier stuff and was able to install brew successfully via the script.


@jwojda just sharing the work of @franton I don't think this one is on his GitHub


Dropped this script in our JSS and this is the output that I got.



Executing Policy Install Homebrew - JAMFNation
Running script Install Homebrew - JAMFNation...
Script exit code: 0
Script result: Tue Aug 8 12:08:02 EDT 2017 - Homebrew Installation
Tue Aug 8 12:08:02 EDT 2017 - Caffinating the mac under process id: 4998
for: -c: line 0: unexpected EOF while looking for matching `"'
for: -c: line 1: syntax error: unexpected end of file
Tue Aug 8 12:08:02 EDT 2017 - Checking for Xcode Command Line Tools installation
Homebrew" : -c: line 0: unexpected EOF while looking for matching `"'
Homebrew" : -c: line 1: syntax error: unexpected end of file
Tue Aug 8 12:08:02 EDT 2017 - Installing Homebrew
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed

0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 128 0 128 0 0 700 0 --:--:-- --:--:-- --:--:-- 703

82 1067k 82 878k 0 0 1332k 0 --:--:-- --:--:-- --:--:-- 1332k
100 1067k 100 1067k 0 0 1407k 0 --:--:-- --:--:-- --:--:-- 1922k
Updating Homebrew...
==> Homebrew has enabled anonymous aggregate user behaviour analytics.
Read the analytics documentation (and how to opt-out) here:
https://docs.brew.sh/Analytics.html

==> Tapping homebrew/core
Cloning into '/usr/local/Library/Taps/homebrew/homebrew-core'...
Tapped 4290 formulae (4,547 files, 11.2MB)
Error: /usr/local/Homebrew already exists.
Please remove it manually or uninstall and reinstall Homebrew into a new
location as the migration cannot be done automatically.
==> Cleaning up /Library/Caches/Homebrew...
==> Migrating /Library/Caches/Homebrew to /Users/adeveloper/Library/Caches/Homebrew...
==> Deleting /Library/Caches/Homebrew...
==> Migrating HOMEBREW_REPOSITORY (please wait)...
Warning: md5sha1sum 0.9.5 is already installed
Homebrew" : -c: line 0: unexpected EOF while looking for matching `"'
Homebrew" : -c: line 1: syntax error: unexpected end of file
Tue Aug 8 12:08:23 EDT 2017 - Updating Homebrew
Initialized empty Git repository in /usr/local/.git/
From https://github.com/Homebrew/brew
* [new branch] master -> origin/master
HEAD is now at 93051b2 formula_cellar_checks: fix broken dylib spacing.
==> Homebrew has enabled anonymous aggregate user behaviour analytics.
Read the analytics documentation (and how to opt-out) here:
https://docs.brew.sh/Analytics.html

Already up-to-date.
==> Migrating HOMEBREW_REPOSITORY (please wait)...
==> Migrated HOMEBREW_REPOSITORY to /usr/local/Homebrew!
Homebrew no longer needs to have ownership of /usr/local. If you wish you can
return /usr/local to its default ownership with:
sudo chown root:wheel /usr/local
complete" : -c: line 0: unexpected EOF while looking for matching `"'
complete" : -c: line 1: syntax error: unexpected end of file
Tue Aug 8 12:08:43 EDT 2017 - Installation complete


When trying to run a brew command from terminal on the machine (non-admin standard user) i'm getting 'brew' command not found. Any ideas on the errors above in the script, and why brew commands won't work even though all the folders were created and permissions seem right?


probably not in the path:
link text
either add to path or specify full path in terminal / scripts


Since i'd rather change the script, what specifically would need editing in the script code above? It looks like full paths are laid out there.



@franton Any ideas here regarding your script and how it operates in the JSS?


@jlang_remedy Ok you run this as a self service policy. The only variables that should need changes are at the top of the script.


We threw this in Self Service:



#!/bin/bash

osascript <<'EOF'
tell application "Terminal"
activate
do script ("/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"") in window 1
end tell
EOF

exit 0

@franton I threw the script in self-service and it seemed to install successfully, even despite some error statements in the log.



Eg. : -c: line 0: unexpected EOF while looking for matching `"'<br/>complete" : -c: line 1: syntax error: unexpected end of file<br/>Fri Aug 25 13:29:48 EDT 2017 - Installation complete<br/>



I opened terminal and tried some brew commands and still getting "-bash: brew: command not found". errors.



By the way, my use case is that an non-administrator local account is performing the self-service install and is the account that will be using brew. Does this script not work for that scenario?


@jlang_remedy And yet my local copy works from Self Service ok.



#!/bin/bash

# Script to install Homebrew on a Mac.
# Author: richard at richard - purves dot com
# Version: 1.0 - 21st May 2017

# Set up variables and functions here
export consoleuser="$(python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");')"
export brandid="com.company.id"
export tn="/usr/local/cs/bin/terminal-notifier"
export cd="/usr/local/cs/bin/cocoaDialog.app/Contents/MacOS/cocoaDialog"
export title="Homebrew Installation"

# Logging stuff starts here
export LOGFOLDER="/private/var/log/"
export LOG=$LOGFOLDER"Homebrew.log"

if [ ! -d "$LOGFOLDER" ];
then
mkdir $LOGFOLDER
fi

function logme()
{
# Check to see if function has been called correctly
if [ -z "$1" ]
then
echo $( date )" - logme function call error: no text passed to function! Please recheck code!"
echo $( date )" - logme function call error: no text passed to function! Please recheck code!" >> $LOG
exit 1
fi

# Log the passed details
echo -e $( date )" - $1" >> $LOG
echo -e $( date )" - $1"
}

function notify()
{
OIFS=$IFS
IFS=$'
'
su -l "$consoleuser" -c " "'"'$tn'"'" -sender "'"'$brandid'"'" -title "'"'$title'"'" -message "'"'$1'"'" "
logme "$1"
IFS=$OIFS
}

# Check and start logging - done twice for local log and for JAMF
logme "Homebrew Installation"

# Let's start here by caffinating the mac so it stays awake or bad things happen.
caffeinate -d -i -m -u &
caffeinatepid=$!
logme "Caffinating the mac under process id: $caffeinatepid"

# Have the xcode command line tools been installed?
notify "Checking for Xcode Command Line Tools installation"
check=$( pkgutil --pkgs | grep com.apple.pkg.CLTools_Executables | wc -l | awk '{ print $1 }' )

if [[ "$check" != 1 ]];
then
notify "Installing Xcode Command Tools"
# This temporary file prompts the 'softwareupdate' utility to list the Command Line Tools
touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
clt=$(softwareupdate -l | grep -B 1 -E "Command Line (Developer|Tools)" | awk -F"*" '/^ +\\*/ {print $2}' | sed 's/^ *//' | tail -n1)
softwareupdate -i "$clt"
rm -f /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
/usr/bin/xcode-select --switch /Library/Developer/CommandLineTools
fi

# Is homebrew already installed?
which -s brew
if [[ $? = 1 ]];
then
# Install Homebrew. This doesn't like being run as root so we must do this manually.
notify "Downloading Homebrew"

# Curl down the latest tarball and install to /usr/local
curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C /usr/local 2>&1 | tee -a ${LOG}

# Manually make all the appropriate directories and set permissions
mkdir -p /usr/local/Cellar /usr/local/Homebrew /usr/local/Frameworks /usr/local/bin /usr/local/etc /usr/local/include /usr/local/lib /usr/local/opt /usr/local/sbin /usr/local/share /usr/local/share/zsh /usr/local/share/zsh/site-functions /usr/local/var
chown -R $consoleuser /usr/local
chmod g+rwx /usr/local/Cellar /usr/local/Homebrew /usr/local/Frameworks /usr/local/bin /usr/local/etc /usr/local/include /usr/local/lib /usr/local/opt /usr/local/sbin /usr/local/share /usr/local/share/zsh /usr/local/share/zsh/site-functions /usr/local/var
chmod 755 /usr/local/share/zsh /usr/local/share/zsh/site-functions
chgrp admin /usr/local/Cellar /usr/local/Homebrew /usr/local/Frameworks /usr/local/bin /usr/local/etc /usr/local/include /usr/local/lib /usr/local/opt /usr/local/sbin /usr/local/share /usr/local/share/zsh /usr/local/share/zsh/site-functions /usr/local/var

# Create a system wide cache folder
mkdir -p /Library/Caches/Homebrew
chmod g+rwx /Library/Caches/Homebrew
chown $consoleuser /Library/Caches/Homebrew

# Remove temporary folder
rm -rf /usr/local/Homebrew

# Install the MD5 checker or the recipes will fail
notify "Installing md5sha1sum"
su -l "$consoleuser" -c "/usr/local/bin/brew install md5sha1sum" 2>&1 | tee -a ${LOG}
su -l "$consoleuser" -c "echo 'export PATH=/usr/local/opt/openssl/bin:$PATH' >> /Users/$consoleuser/.bash_profile"
else
# Run an update and quit
notify "Updating Homebrew"
su -l "$consoleuser" -c "/usr/local/bin/brew update" 2>&1 | tee -a ${LOG}
exit 0
fi

# Make sure everything is up to date
notify "Updating Homebrew"
su -l "$consoleuser" -c "/usr/local/bin/brew update" 2>&1 | tee -a ${LOG}

# Notify user that all is completed
notify "Installation complete"

# No more caffeine please. I've a headache.
kill "$caffeinatepid"

exit 0


I have no explanation for your errors. Above is what I'm using for Self Service install on non-admin accounts and it works.


@franton Thanks for this version! It's working now for me in self-service. Looks like a few differences in this version, especially exporting variables. Thanks!


This script is not safe if your users aren't admin and you don't want them to be admin. It changes the ownership of /usr/local and everything in it to the user that is logged in, which may not be admin. If nothing is installed there before this script runs it isn't a problem, but if you've got scripts already installed there then this will script will have some unintended consequences...


My question is, I am building a workflow to install 32 new macs for a lab situation and i want the install of brew to be in the initial workflow. There will be no self service on these machines. So will this script work using Jamf Imaging?


My own script is designed for self service only.


I've been trying to use the script posted by @franton however run into problems relating to High Sierra. In High Sierra I can't chown /usr/local anymore. The suggested fix I've been able to find is instead chown $(brew --prefix)/* So the only change made to the script is replacing:



chown -R $consoleuser /usr/local
with
chown -R $consoleuser $(brew --prefix)/*



running the script from self-service of a non-admin user, the following error is producing during the install:



Error: /usr/local is not writable



but the install appears to complete. Running brew doctor or brew update produces the same error however. This happens with a fresh install of the OS and homebrew. If anyone's had success getting homebrew installed via self-service in High Sierra I'd be very interested in how you've done it (the only info I've been able to find from the homebrew side is the changed chown command and the suggestion of re-installing homebrew).


@paulkenworthy Were you able to find a solution? I've found this post on Medium, but haven't had a chance to try it out yet. I think it'd be silly to use this solution though, since you'd essentially be installing brew twice.


@isterling.goaaa I'm afraid I wasn't.



I've tried uninstalling and reinstalling homebrew as per that link, however if I run the commands exactly as given on that page via JSS it fails, as installing Homebrew as root is dangerous. If I modify the uninstall and reinstall commands to match the installing command given earlier in this thread than the same /usr/local/ is not writable error is given.


Hi all, here is what I'm using to install xcode, homebrew, and apps:



#!/bin/bash
# redirect stdout/stderr to a file
exec &> /var/log/HomeBrew.log

consoleuser=$(/usr/bin/python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");')

su -l "$consoleuser" -c "defaults read /Users/$consoleuser/Library/Preferences/com.apple.dock | grep corner"

echo -ne '
' | sudo -u "$consoleuser" /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

sudo -u $consoleuser /usr/local/bin/brew cask
sudo -u $consoleuser /usr/local/bin/brew install caskroom/versions/sequel-pro-nightly
sudo -u $consoleuser /usr/local/bin/brew install caskroom/cask/iterm2
sudo -u $consoleuser /usr/local/bin/brew install caskroom/cask/intellij-idea
sudo -u $consoleuser /usr/local/bin/brew install caskroom/cask/charles
sudo -u $consoleuser /usr/local/bin/brew install caskroom/versions/sublime-text-dev
sudo -u $consoleuser /usr/local/bin/brew install caskroom/cask/sourcetree
sudo -u $consoleuser /usr/local/bin/brew install node
sudo -u $consoleuser /usr/local/bin/brew install python3
sudo -u $consoleuser /usr/local/bin/brew install nginx
sudo -u $consoleuser /usr/local/bin/brew install docker
sudo -u $consoleuser /usr/local/bin/brew install caskroom/cask/firefox


here is what happens next:



==> This script will install:
/usr/local/bin/brew
/usr/local/share/doc/homebrew
/usr/local/share/man/man1/brew.1
/usr/local/share/zsh/site-functions/_brew
/usr/local/etc/bash_completion.d/brew
/usr/local/Homebrew
==> The following existing directories will be made group writable:
/usr/local/bin
==> The following existing directories will have their owner set to testtester:
/usr/local/bin
==> The following existing directories will have their group set to admin:
/usr/local/bin
==> The following new directories will be created:
/usr/local/Cellar
/usr/local/Homebrew
/usr/local/Frameworks
/usr/local/etc
/usr/local/include
/usr/local/lib
/usr/local/opt
/usr/local/sbin
/usr/local/share
/usr/local/share/zsh
/usr/local/share/zsh/site-functions
/usr/local/var
==> The Xcode Command Line Tools will be installed.
==> /usr/bin/sudo /bin/chmod u+rwx /usr/local/bin
sudo: no tty present and no askpass program specified
Failed during: /usr/bin/sudo /bin/chmod u+rwx /usr/local/bin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin
sudo: unknown user: /usr/local/bin/brew
sudo: unable to initialize policy plugin


Where it goes wrong:



sudo: no tty present and no askpass program specified 
Failed during: /usr/bin/sudo /bin/chmod u+rwx /usr/local/bin


Any thoughts on this? NOTE: this works through executing a terminal command via policy trigger, however, on initial enrollment we have setup with splashbuddy, it constantly gives us this error.


Does maybe anyone having a solution on installing homebrew on High Sierra?



The ideal solution for us would be to install homebrew at the deployment process and provide application installers through self service to our non-admin user with the following example: „brew cask install cyberduck“.



Thank you in advance.


@Danko -
I've had a terrible time trying to install homebrew without interaction and unattended. Eventually we switched over to this which I modified from @emily 's post above and it's been the most consistent experience for us. It also doesn't require the user to run manually and doesn't run as root (which is preferred for Homebrew installs) so if your techs aren't onboarding, this is safe to run as a pre-stage for users as a policy in Self Service.



We have other applications that install via brew during deployment so they would also run those commands in this script which is why Homebrew has a pause while Window 1 of Terminal is active so they don't overlap each other. I removed those from below as you'll do that via Self Service.



#!/bin/bash

# Running caffeinate command so system doesn't bork the Homebrew install
caffeinate -d -i -m -u &
caffeinatepid=$!
echo "Caffeinating the mac under process id: $caffeinatepid"

# Open non-admin safe Terminal window, install Homebrew and wait until process is complete before continuing
osascript -e 'tell application "Terminal" to quit'
osascript <<'EOF'
tell application "Terminal"
activate
do script ("/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"") in window 1
repeat
delay 0.5
if not busy of window 1 then exit repeat
end repeat
end tell
EOF

# Insert additional brew installs here

# Ending caffeinate command
kill "$caffeinatepid"

# Close Terminal window
osascript -e 'tell application "Terminal" to quit'

exit 0

@kevinwilemon - Thank you for the quick response.
How do you run this script? Policy? Self Service?



I've tried both way, but got stuck when the user have to press enter to continue the installation process.



Our idea would be to run the initial setup of Homebrew inside our deployment process as a policy (as localadmin).
After Homebrew is correctly installed we would like to provide Applications in the Self Service which just run a "brew cask install" command in the background to get the Apps installed.


We run via Self Service (though it can be run as a policy as well). As I mentioned, we've had a terrible time trying to install Homebrew successfully when attempting to skip the interactive step and switched to this method for onboarding which then allows the user to install via brew whether they're an admin or not.


@kevinwilemon When I ran this script as a Self-Service item while logged in as a standard user, I got an error that I must be an administrator to install


@kevinwilemon I was able to install homebrew as a standard user, but how are you deploying applications after it has been installed? I'm getting errors about user not being in sudoers file or not being able to move the .app from their home directory to /Applications .


I am having a difficult time getting this to work in in Mojave.



The script highlighted as the solution here keeps giving errors on the /usr/local folder. I have noticed that the script, written as is, and brought in to Jamf Pro's script section, and deployed to a new machine, does not execute any of the tasks beneath "# Manually make all the appropriate directories and set permissions"



Anyone have any ideas? I have tried writing those lines to execute as su -l "$consoleuser" -c, i've tried packaging it as a separate script and running it under files and processes, and I'm running in to every dead end.


Reply