Skip to content

Instantly share code, notes, and snippets.

@bashtheshell
Last active December 15, 2023 18:51
Show Gist options
  • Save bashtheshell/e456f9294905b50150f7e93c75cb5103 to your computer and use it in GitHub Desktop.
Save bashtheshell/e456f9294905b50150f7e93c75cb5103 to your computer and use it in GitHub Desktop.
Install Slack app in User's ~/Applications directory - macOS

Install Slack app in User's Applications Directory - macOS

Background

This work was inspired by the challenges I encountered in the workplace. I manage several macOS remotely, and one of the biggest pains is that our users aren't administrators on those machines. Thus, they aren't able to dismiss the Squirrel Update prompts on their own, which was a productivity hindrance.

Initially as a fun side-project to satisfy my curiosity, I came up with a solution to mitigate this by having the Slack app, which was already installed in the main /Applications directory, automatically update itself as soon as the Launch Daemon script fetches a new update from slack.com. The script would notify all users actively using Slack that the app would restart itself in several seconds.

Admittedly, the above solution wasn't organic and understandably it can be a grave security concern for some. The only upside of this solution is that all users on the same machine would be using the same copy of the latest Slack version, which simplifies the deployment.

Solution

Fortunately for us, Slack developed a knowledge-base article on enterprise deployment best practices. Optionally, we can deploy Slack app to each user's ~/Applications directory. By default the directory doesn't exist and has to be created. This would also requires multiple copies of Slack apps on the same machine for multiple non-admin users to access. From an administrative prospective, one would have to be extremely mindful to also query the apps installed in users' home directories as several management tools rarely take ~/Applications directory in consideration.

The new solution script below would help simplify the deployment by installing the Slack app in the users' ~/Applications directory and add the shortcut to Dock. The only caveat is that you must provide a pre-determined list of users for the machine you attempt to run the script against. Not every user on the system would need Slack in their Dock. Also, this script wouldn't run if the installed copy of Slack was originally sourced from the App Store or MDM managed by the IT organization. Those copies of Slack don't have the Squirrel Update prompts.

Quick Start

Update the user list nears line 32. You'd need to list the available users on the system that need Slack app in their home directories. The script must be run by root. At the time of this writing, the script was compatible with Big Sur (macOS 11) and Sierra (macOS 10.12).

chmod +x slack_app_installer_homedir_macOS.sh
sudo slack_app_installer_homedir_macOS.sh

PLEASE NOTE: The system can be left without a working copy of Slack if the app has been removed from /Applications and there is no eligible user to receive the app in their ~/Applications directory.

#!/usr/bin/env bash
# Attempting to remove the existing system-wide Slack app
if [ -d "/Applications/Slack.app" ]; then
if [[ $(mdls -name kMDItemAppStoreReceiptIsVPPLicensed /Applications/Slack.app | awk '{ print $NF }') == "(null)" ]]; then
echo "Direct-download system Slack app was detected. This copy of Slack app will be removed."
# Kill Slack app if still running
if [ ! -z "$(pgrep '[Ss]lack')" ]; then
echo "Slack was running. Closing Slack..."
killall -SIGKILL "Slack"
fi
# Removing Slack app
echo "Deleting Slack app..."
rm -rf /Applications/Slack.app
else
echo "The installed copy of Slack app either has a valid VPP license or is purchased through the App Store. The script will now exit."
exit 1
fi
else
# Proceed to attempt installing Slack in user's ~/Applications directory
echo "Slack app wasn't installed in /Applications. The script will now attempt to install Slack in user(s)' ~/Applications."
fi
##################################################################################
# PLEASE UPDATE THE USER LIST HERE IF NECESSARY. THEY MUST BE SEPARATED BY SPACE #
##################################################################################
# List of users
listed_users="bashtheshell travis.johnson testuser"
# Slack download variables
slackDownloadUrl=$(curl "https://slack.com/ssb/download-osx" -s -L -I -o /dev/null -w '%{url_effective}')
dmgName=$(printf "%s" "${slackDownloadUrl[@]}" | sed 's@.*/@@')
slackDmgPath="/private/tmp/$dmgName"
# Check if there exists a listed user without Slack app in their ~/Applications directory before proceeding to download Slack
set -- $listed_users
no_user="true"
while [ $# -gt 0 ]; do
# Check if user's home directory actually exist before attempting to download Slack
if [ ! -d "/Users/${1}/" ]; then
# Skip to next user if user's home directory is non-existent
shift
else
# Download Slack for user(s) with missing Slack app
if [ ! -d "/Users/${1}/Applications/Slack.app" ]; then
no_user="false" # Set to false as there exists a user
# Detach Slack DMG volume if already mounted
if [ ! -z "$(ls -d /Volumes/Slack* 2>/dev/null)" ]; then
echo 'Ejecting all the DMG volumes...'
for disk in $(hdiutil info | grep /dev/disk | grep partition | cut -f 1); do
hdiutil detach ${disk}
done
fi
# Downloads latest version of Slack or else exit script if download fails
echo "Downloading latest Slack app (${dmgName})..."
curl -L -o "$slackDmgPath" "$slackDownloadUrl"
if [ $? -ne 0 ]; then
echo "ERROR: Unable to download Slack. System may be offline. This script will now exit."
exit 10
fi
# Mounts the DMG volume
echo 'Mounting the DMG volume...'
hdiutil attach -nobrowse $slackDmgPath
break
fi
shift
fi
done
# Print if no eligible user is available
if [[ "$no_user" == "true" ]]; then
echo "There is no eligible user account with missing Slack app. The script will not install..."
fi
# Install Slack for user(s) without Slack app in their ~/Applications directory
set -- $listed_users
while [ $# -gt 0 ]; do
# Check if user's home directory actually exist before creating ~/Applications path
if [ ! -d "/Users/${1}/" ]; then
# Skip to next user if user's home directory is non-existent
shift
else
# Remove 'Slack' app from the user's Dock
echo "Attempting to remove Slack app from ${1}'s Dock..."
cat << 'EOF' > /tmp/remove_app_from_dock.sh
#!/usr/bin/env bash
listOfAppsToRemove=("Slack")
for i in "${listOfAppsToRemove[@]}"
do
appFileLabel=$i # Name of the app as shown in the Dock
lengthOfPlistArray=$(defaults read com.apple.dock persistent-apps | grep "file-label" | wc -l | tr -d " ") # Get length of array
appPosition=$lengthOfPlistArray # The position as shown in dock (count starts after 'Finder'). Starting with an invalid index intentionally to prevent accidental deletion.
numOfPersistApps=$(( $lengthOfPlistArray - 1 )) # Since counting starts at zero
# Find the position that matches the app name
for i in $(seq 0 $numOfPersistApps)
do
if [[ $(/usr/libexec/PlistBuddy -c "Print persistent-apps:${i}:tile-data:file-label" ~/Library/Preferences/com.apple.dock.plist) == $appFileLabel ]]
then
appPosition=$i
fi
done
# Exit if app is not found in Dock
if [[ $appPosition -eq $lengthOfPlistArray ]]
then
echo "The \"${appFileLabel}\" app is not found in dock. Moving on..."
continue
fi
# Remove this entry from Dock's plist file : com.apple.dock.plist
/usr/libexec/PlistBuddy -c "Delete persistent-apps:$appPosition" ~/Library/Preferences/com.apple.dock.plist
# Print to STDOUT if command's successful
if [[ $? -eq 0 ]]
then
echo "The \"${appFileLabel}\" app has been removed. Restarting Dock..."
fi
# Restart Dock to persist changes
killall Dock
done
EOF
chmod +x /tmp/remove_app_from_dock.sh
su - $1 -c '/tmp/remove_app_from_dock.sh'
rm /tmp/remove_app_from_dock.sh
# Install Slack for user(s) with missing Slack app
if [ ! -d "/Users/${1}/Applications/Slack.app" ]; then
echo "Installing Slack app for ${1}..."
mkdir -p /Users/${1}/Applications
ditto -rsrc /Volumes/Slack*/Slack.app /Users/${1}/Applications/Slack.app
chown -R $1: /Users/${1}/Applications
fi
# Add Slack app to Dock in user's profile if not added already
account_user=$1
if [[ -z $(su - $account_user -c 'defaults read com.apple.dock persistent-apps | grep "Slack.app"') ]]
then
sleep 2 # OS doesn't update the Dock information fast enough at each iteration
echo "Adding Slack app to $account_user's Dock..."
su - $account_user -c "defaults write com.apple.dock persistent-apps -array-add '<dict><key>tile-data</key><dict><key>file-data</key><dict><key>_CFURLString</key><string>/Users/'"$account_user"'/Applications/Slack.app</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>'"
if [[ ! -z "$(sudo -u $account_user SHELL=/bin/bash -i sh -c 'pgrep -U $(id -u) [dD]ock')" ]]; then
su - $account_user -c 'killall Dock'
fi
fi
shift
fi
done
# Unmount and eject the DMG volume
echo 'Attempting to eject the DMG volumes if any...'
hdiutil detach /Volumes/Slack.app
# Clean up the downloaded files in /tmp directory
echo 'Cleaning up temporary files if any...'
rm -rf "$slackDmgPath"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment