├── .gitignore ├── DockBuilder-component.plist ├── README.md ├── build.sh ├── com.github.ryangball.dockbuilder.defaults.plist ├── com.github.ryangball.dockbuilder.plist ├── dockbuilder.sh ├── dockutil.pkg ├── images └── dock_message.png └── postinstall.sh /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | dockbuilder.sh.old 3 | .DS_Store -------------------------------------------------------------------------------- /DockBuilder-component.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | BundleIsRelocatable 7 | 8 | BundleIsVersionChecked 9 | 10 | BundleOverwriteAction 11 | upgrade 12 | RootRelativeBundlePath 13 | Applications/Utilities/DockBuilder.app 14 | 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DockBuilder 2 | A LaunchAgent and .app to build a user's Dock upon login and/or on demand. 3 | 4 | DockBuilder allows for the building of a user's Dock based on an organization's needs. DockBuilder eliminates the need for a user template which only allows for a static Dock for all users, and template manipulation can cause issues in newer versions of macOS. DockBuilder not only allows for easy creation of a new user's Dock out of the box, but also has the potential to dynamically set up a different Dock for users based on some criteria; like AD groups for example (you'd have to modify the source based on your criteria). 5 | 6 | ## Features 7 | - Builds a Dock based on pre-defined defaults 8 | - Includes a framework for building unique Docks for certain users based on some criteria (including an example) 9 | - Logs to ~/Library/Logs/DockBuilder.log (by default) 10 | - Does not start until the Dock.app is loaded upon login 11 | - Only builds a Dock for user's who's Dock is younger than 300 seconds (to minimize re-building a pre-existing user's Dock after the installation of DockBuilder) 12 | - Option to hide the Dock and display a message to the user while the Dock is being built 13 | 14 |

15 | DockBuilder Message 16 |

17 | 18 | ## Requirements for Building 19 | - [Platypus](https://sveinbjorn.org/platypus): A developer tool that creates native Mac applications from command line scripts such as shell scripts or Python, Perl, Ruby, Tcl, JavaScript and PHP programs. 20 | - You must install the command line tool associated with Platypus. Open Platypus, in the Menu Bar choose "Platypus" > "Preferences" and click the "Install" button to install the Platypus command line tool. 21 | - jamfHelper: jamfHelper is used to display the message when the Dock is being built (if you choose to use that feature). CocoaDialog could also be leveraged pretty easily for environments without Jamf Pro. AppleScript could also be used, but you can't create an AppleScript dialog void of buttons. 22 | 23 | *Note: [Dockutil](https://github.com/ryangball/DockBuilder#Dockutil) is also required, but included in the resulting .pkg and releases.* 24 | 25 | ## Build Project 26 | To build new versions you can simply run the [build.sh](/build.sh) script and specify a version number for both the .app and .pkg. The resulting .pkg will include the LaunchAgent and .app as well as necessary preinstall/postinstall scripts. If you do not include a version number as a parameter then version 1.0 will be assigned as the default. 27 | ```bash 28 | # Clone the repo and traverse into the created directory 29 | git clone https://github.com/ryangball/DockBuilder.git 30 | cd DockBuilder 31 | 32 | # At this point you'd customize the variables in the build.sh script 33 | 34 | # Build the .pkg 35 | ./build.sh 1.5 36 | ``` 37 | 38 | ## Customize DockBuilder 39 | Within the [build.sh](/build.sh) script, you can modify the top-most variables to create a custom DockBuilder .app and .pkg. 40 | 41 | Some things to keep in mind: 42 | 1. Within both the breadcrumb and log variables, you'll notice the $HOME environmental variable. You should leave this in there as both should be in the user's home folder. 43 | 2. Within the defaultItemsToAdd array (and alternateItemsToAdd_1 if you use it), you need to follow the same pattern that I used in the example. When specifying view options for the persistent-others Dock items, you need to separate the Dock item and options with a comma (",") as per the example. 44 | 3. After modifying the variables in build.sh, please test for full functionality before deploying. 45 | 4. If you want to set up a unique Dock for certain users you must populate the alternateItemsToAdd_1 ion [build.sh](/build.sh) **and** modify [this logic in dockbuilder.sh](https://github.com/ryangball/DockBuilder/blob/e6c4bab519648bdcdc812293bdd0ad098a798cc9/dockbuilder.sh#L108-L119)) to include the users or criteria to build the alternate Dock. 46 | 5. If you want to exclude specific existing users from the initial breadcrumb creation so that they will get a new Dock created, you must populate the skipInitialBreadcrumbUsers variable in [build.sh](/build.sh). 47 | 48 | ## Testing 49 | To test DockBuilder, install the .pkg, then unload/load/start the LaunchAgent. 50 | ```bash 51 | # Delete the breadcrumb for the user if it exists 52 | find ~/Library/Preferences -name com.github.ryangball.dockbuilder.breadcrumb.plist -delete 53 | 54 | # Unload the LaunchAgent 55 | launchctl unload /Library/LaunchAgents/com.github.ryangball.dockbuilder.plist 56 | 57 | # Load the LaunchAgent 58 | launchctl load /Library/LaunchAgents/com.github.ryangball.dockbuilder.plist 59 | 60 | # Start the LaunchAgent (if necessary) 61 | launchctl start com.github.ryangball.dockbuilder 62 | 63 | # Tail the log to see what is occurring 64 | tail -f ~/Library/Logs/DockBuilder.log 65 | ``` 66 | 67 | ## Re-create a User's Dock 68 | Upon DockBuilder's execution, a breadcrumb is placed into the user's home folder by default: ~/Library/Preferences/com.github.ryangball.dockbuilder.breadcrumb.plist 69 | 70 | In the event that this breadcrumb exists for a user, DockBuilder will exit without any action. To re-create a user's Dock, open terminal as the user and run the following to remove the breadcrumb: 71 | ```bash 72 | rm ~/Library/Preferences/com.github.ryangball.dockbuilder.breadcrumb.plist 73 | ``` 74 | Then you can simply run the /Applications/Utilities/DockBuilder.app or unload/load the LaunchAgent as per the [Testing](https://github.com/ryangball/DockBuilder#Testing) section above. 75 | 76 | ## Dockutil 77 | [Dockutil](https://github.com/kcrawford/dockutil) is included in the resulting .pkg and is licensed under the [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) license. Dockutil is automatically downloaded from the releases section when using the build.sh script, or included if you download one of the DockBuilder Releases. -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #shellcheck disable=SC2088,SC2016 3 | 4 | # Identifier for the .app and .pkg 5 | identifier="com.github.ryangball.dockbuilder" 6 | 7 | # Version of the .app and .pkg, you can leave this alone and specify at the command line 8 | version="1.0" 9 | 10 | # Path and filename of the main property list used to store preferences for the .app 11 | preferenceFileFullPath="/Library/Preferences/com.github.ryangball.dockbuilder.defaults.plist" 12 | 13 | # Path to the breadcrumb dropped when DockBuilder runs for a user, this should be in the user's home folder 14 | # Note: You should keep this in single quotes and don't remove the $HOME environmental variable 15 | breadcrumb='$HOME/Library/Preferences/com.github.ryangball.dockbuilder.breadcrumb.plist' 16 | 17 | # Path to the DockBuilder log, this should be in the user's home folder 18 | # Note: You should keep this in single quotes and don't remove the $HOME environmental variable 19 | log='$HOME/Library/Logs/DockBuilder.log' 20 | 21 | # The icon for the .app 22 | appIcon="/System/Library/CoreServices/Dock.app/Contents/Resources/Dock.icns" 23 | 24 | # Determines if the user's Dock is hidden while being built for the first time 25 | hideDockWhileBuilding="true" # (true|false) 26 | 27 | # If the above variable is set to true, the message below will be displayed 28 | hideDockMessage="Your Mac's Dock is being built for the first time." 29 | 30 | # Array of users where a breadcrumb will not be created during the postinstall 31 | # Handy if you want to force a new Dock for a user that might have existed already 32 | skipInitialBreadcrumbUsers=("admin" "admin2") 33 | 34 | # Array to hold all the items we need to add for a default Dock 35 | # Note: if you need to add options you must seperate the item from the options with a , (comma) 36 | # Example: "/Applications/,--view grid --display stack --sort name" 37 | # This will add the /Applications folder to the persistent-others section of the Dock and sets 38 | # the view to grid, the display to stack, and sorts by name. 39 | # All options available here: https://github.com/kcrawford/dockutil 40 | defaultItemsToAdd=( 41 | "/Applications/System Preferences.app/" 42 | "/Applications/Self Service.app/" 43 | "/Applications/Safari.app/" 44 | "/Applications/Google Chrome.app/" 45 | "/Applications/App Store.app/" 46 | "/Applications/Utilities/Console.app/" 47 | "/Applications/Utilities/Terminal.app/" 48 | "/Applications/,--view grid --display stack --sort name" 49 | "~/Downloads" 50 | ) 51 | 52 | # Array to hold all the items we need to add for an alternate Dock 53 | # Be sure to change the logic under the "Set up the Dock" comment in dockbuilder.sh if you want 54 | # to use this alternate Dock for a specific user/users 55 | alternateItemsToAdd_1=( 56 | "/Applications/System Preferences.app/" 57 | "/Applications/Safari.app/" 58 | "/Applications/App Store.app/" 59 | "/System/Library/CoreServices/Applications/Directory Utility.app/" 60 | "/Applications/Utilities/Activity Monitor.app/" 61 | "/Applications/Utilities/Console.app/" 62 | "/Applications/Utilities/Terminal.app/" 63 | "/System/Library/CoreServices/Applications/Network Utility.app/" 64 | "/Applications/Utilities/Disk Utility.app/" 65 | "/Applications/Utilities/Keychain Access.app/" 66 | "/Applications/,--view grid --display stack --sort name" 67 | "~/Downloads" 68 | ) 69 | 70 | ########### It is not necessary to edit beyond this point, do at your own risk ########### 71 | 72 | function install_dockutil_pkg () { 73 | if [[ -e /private/tmp/DockBuilder/files/usr/local/bin/dockutil ]]; then 74 | echo "dockutil binary has been installed in test build directory" 75 | else 76 | pkgutil --expand-full "$PWD/dockutil.pkg" /private/tmp/DockBuilder/temp 77 | cp -R /private/tmp/DockBuilder/temp/Payload/usr /private/tmp/DockBuilder/files/ 78 | rm -R /private/tmp/DockBuilder/temp 79 | fi 80 | 81 | if [[ ! -e /private/tmp/DockBuilder/files/usr/local/bin/dockutil ]]; then 82 | echo "dockutil binary failed to install in the temp build directory; exiting." 83 | exit 1 84 | fi 85 | } 86 | 87 | function get_dockutil_pkg () { 88 | latestDockutilReleaseURL=$(curl -s https://api.github.com/repos/kcrawford/dockutil/releases/latest | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["assets"][0]["browser_download_url"];') 89 | if [[ ! -e "$PWD/dockutil.pkg" ]]; then 90 | echo "Getting the latest version of dockutil..." 91 | curl -L "$latestDockutilReleaseURL" > "$PWD/dockutil.pkg" 92 | install_dockutil_pkg 93 | fi 94 | } 95 | 96 | # Check for platypus command line, bail if it does not exist 97 | if [[ ! -f /usr/local/bin/platypus ]]; then 98 | echo "Platypus command line tool not installed, see the following URL for more information:" 99 | echo "https://github.com/ryangball/DockBuilder/blob/master/README.md#requirements-for-building" 100 | fi 101 | 102 | # Update the variables in the dockbuilder.sh script 103 | # If you know of a more elegant/efficient way to do this please create a PR 104 | sed -i '' "s#preferenceFileFullPath=.*#preferenceFileFullPath=\"$preferenceFileFullPath\"#" "$PWD/dockbuilder.sh" 105 | sed -i '' "s#preferenceFileFullPath=.*#preferenceFileFullPath=\"$preferenceFileFullPath\"#" "$PWD/postinstall.sh" 106 | 107 | # Create clean temp build directories 108 | find /private/tmp/DockBuilder -mindepth 1 -delete 109 | mkdir -p /private/tmp/DockBuilder/files/Applications/Utilities 110 | mkdir -p /private/tmp/DockBuilder/files/Library/LaunchAgents 111 | mkdir -p /private/tmp/DockBuilder/files/Library/Preferences 112 | mkdir -p /private/tmp/DockBuilder/scripts 113 | mkdir -p "$PWD/build" 114 | 115 | # Check for version number as arg 1 116 | if [[ -n "$1" ]]; then 117 | version="$1" 118 | echo "Version set to $version" 119 | else 120 | echo "No version passed, using version $version" 121 | fi 122 | 123 | # Make sure dockutil is in the temp build directory 124 | get_dockutil_pkg 125 | install_dockutil_pkg 126 | 127 | # Clear the default_items plist if it exists 128 | preferenceFileName="${preferenceFileFullPath##*/}" 129 | if [[ -e "$PWD/$preferenceFileName" ]]; then 130 | /usr/libexec/PlistBuddy -c Clear "$PWD/$preferenceFileName" 131 | fi 132 | /usr/libexec/PlistBuddy -c "Add :DefaultItemsToAdd array" "$PWD/$preferenceFileName" 133 | /usr/libexec/PlistBuddy -c "Add :AlternateItemsToAdd_1 array" "$PWD/$preferenceFileName" 134 | /usr/libexec/PlistBuddy -c "Add :SkipInitialBreadcrumbUsers array" "$PWD/$preferenceFileName" 135 | 136 | # Populate our variables into the plist 137 | /usr/bin/plutil -insert BreadcrumbPath -string "$breadcrumb" "$PWD/$preferenceFileName" 138 | /usr/bin/plutil -insert LogPath -string "$log" "$PWD/$preferenceFileName" 139 | /usr/bin/plutil -insert AppIcon -string "$appIcon" "$PWD/$preferenceFileName" 140 | /usr/bin/plutil -insert HideDockWhileBuilding -bool "$hideDockWhileBuilding" "$PWD/$preferenceFileName" 141 | /usr/bin/plutil -insert HideDockMessage -string "$hideDockMessage" "$PWD/$preferenceFileName" 142 | 143 | # Populate our DefaultItemsToAdd array 144 | index="0" 145 | for item in "${defaultItemsToAdd[@]}"; do 146 | plutil -insert DefaultItemsToAdd.$index -string "$item" "$PWD/$preferenceFileName" 147 | ((index++)) 148 | done 149 | 150 | # Populate our AlternateItemsToAdd_1 array 151 | index="0" 152 | for item in "${alternateItemsToAdd_1[@]}"; do 153 | plutil -insert AlternateItemsToAdd_1.$index -string "$item" "$PWD/$preferenceFileName" 154 | ((index++)) 155 | done 156 | 157 | # Populate our SkipInitialBreadcrumbUsers array 158 | for user in "${skipInitialBreadcrumbUsers[@]}"; do 159 | plutil -insert SkipInitialBreadcrumbUsers.0 -string "$user" "$PWD/$preferenceFileName" 160 | ((index++)) 161 | done 162 | 163 | # Ensure the plist is xml 164 | plutil -convert xml1 "$PWD/$preferenceFileName" 165 | 166 | # Build the .app 167 | echo "Building the .app with Platypus..." 168 | /usr/local/bin/platypus \ 169 | --background \ 170 | --quit-after-execution \ 171 | --app-icon "$appIcon" \ 172 | --name 'DockBuilder' \ 173 | --interface-type 'None' \ 174 | --interpreter '/bin/bash' \ 175 | --author 'Ryan Ball' \ 176 | --app-version "$version" \ 177 | --bundle-identifier "$identifier" \ 178 | --optimize-nib \ 179 | --overwrite \ 180 | 'dockbuilder.sh' \ 181 | "/private/tmp/DockBuilder/files/Applications/Utilities/DockBuilder.app" 182 | 183 | # Migrate postinstall script to temp build directory 184 | cp "$PWD/postinstall.sh" /private/tmp/DockBuilder/scripts/postinstall 185 | chmod +x /private/tmp/DockBuilder/scripts/postinstall 186 | 187 | # Copy the LaunchAgent plist to the temp build directory 188 | cp "$PWD/com.github.ryangball.dockbuilder.plist" "/private/tmp/DockBuilder/files/Library/LaunchAgents/" 189 | 190 | # Copy the main preference list to the temp build directory 191 | cp "$PWD/$preferenceFileName" "/private/tmp/DockBuilder/files/Library/Preferences/" 192 | chmod 644 "/private/tmp/DockBuilder/files/Library/Preferences/$preferenceFileName" 193 | 194 | # Remove any unwanted .DS_Store files from the temp build directory 195 | find "/private/tmp/DockBuilder/" -name '*.DS_Store' -type f -delete 196 | 197 | # Remove any extended attributes (ACEs) from the temp build directory 198 | /usr/bin/xattr -rc "/private/tmp/DockBuilder" 199 | 200 | echo "Building the PKG..." 201 | /usr/bin/pkgbuild --quiet --root "/private/tmp/DockBuilder/files/" \ 202 | --install-location "/" \ 203 | --scripts "/private/tmp/DockBuilder/scripts/" \ 204 | --identifier "$identifier" \ 205 | --version "$version" \ 206 | --ownership recommended \ 207 | --component-plist "$PWD/DockBuilder-component.plist" \ 208 | "$PWD/build/DockBuilder_${version}.pkg" 209 | 210 | exit 0 -------------------------------------------------------------------------------- /com.github.ryangball.dockbuilder.defaults.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AlternateItemsToAdd_1 6 | 7 | /Applications/System Preferences.app/ 8 | /Applications/Safari.app/ 9 | /Applications/App Store.app/ 10 | /System/Library/CoreServices/Applications/Directory Utility.app/ 11 | /Applications/Utilities/Activity Monitor.app/ 12 | /Applications/Utilities/Console.app/ 13 | /Applications/Utilities/Terminal.app/ 14 | /System/Library/CoreServices/Applications/Network Utility.app/ 15 | /Applications/Utilities/Disk Utility.app/ 16 | /Applications/Utilities/Keychain Access.app/ 17 | /Applications/,--view grid --display stack --sort name 18 | ~/Downloads 19 | 20 | AppIcon 21 | /System/Library/CoreServices/Dock.app/Contents/Resources/Dock.icns 22 | BreadcrumbPath 23 | $HOME/Library/Preferences/com.github.ryangball.dockbuilder.breadcrumb.plist 24 | DefaultItemsToAdd 25 | 26 | /Applications/System Preferences.app/ 27 | /Applications/Self Service.app/ 28 | /Applications/Safari.app/ 29 | /Applications/Google Chrome.app/ 30 | /Applications/App Store.app/ 31 | /Applications/Utilities/Console.app/ 32 | /Applications/Utilities/Terminal.app/ 33 | /Applications/,--view grid --display stack --sort name 34 | ~/Downloads 35 | 36 | HideDockMessage 37 | Your Mac's Dock is being built for the first time. 38 | HideDockWhileBuilding 39 | 40 | LogPath 41 | $HOME/Library/Logs/DockBuilder.log 42 | SkipInitialBreadcrumbUsers 43 | 44 | admin2 45 | admin 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /com.github.ryangball.dockbuilder.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | com.github.ryangball.dockbuilder 7 | LimitLoadToSessionType 8 | Aqua 9 | ProgramArguments 10 | 11 | /usr/bin/open 12 | /Applications/Utilities/DockBuilder.app 13 | 14 | RunAtLoad 15 | 16 | 17 | -------------------------------------------------------------------------------- /dockbuilder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # These variables will be replaced with values from the build.sh script automagically 4 | preferenceFileFullPath="/Library/Preferences/com.github.ryangball.dockbuilder.defaults.plist" 5 | 6 | ########### It is not necessary to edit beyond this point, do at your own risk ########### 7 | # These variables are populated from the main preference file, created 8 | # with the build.sh script and deployed to clients using resulting .pkg 9 | breadcrumb=$(eval echo "$(/usr/libexec/PlistBuddy -c "Print :BreadcrumbPath" "$preferenceFileFullPath")") # Using eval here to expand $HOME 10 | log=$(eval echo "$(/usr/libexec/PlistBuddy -c "Print :LogPath" "$preferenceFileFullPath")") # Using eval here to expand $HOME 11 | appIcon=$(/usr/libexec/PlistBuddy -c "Print :AppIcon" "$preferenceFileFullPath") 12 | hideDockWhileBuilding=$(/usr/libexec/PlistBuddy -c "Print :HideDockWhileBuilding" "$preferenceFileFullPath") 13 | hideDockMessage=$(/usr/libexec/PlistBuddy -c "Print :HideDockMessage" "$preferenceFileFullPath") 14 | defaultItemsToAddFromPlist=$(/usr/libexec/PlistBuddy -c "Print DefaultItemsToAdd:" "$preferenceFileFullPath" | grep '/' | sed 's/^ *//') 15 | alternateItemsToAdd_1FromPlist=$(/usr/libexec/PlistBuddy -c "Print AlternateItemsToAdd_1:" "$preferenceFileFullPath" | grep '/' | sed 's/^ *//') 16 | loggedInUser=$(/usr/sbin/scutil <<< "show State:/Users/ConsoleUser" | /usr/bin/awk '/Name :/ && ! /loginwindow/ { print $3 }') 17 | scriptName=$(basename "$0") 18 | 19 | function writelog () { 20 | DATE=$(date +%Y-%m-%d\ %H:%M:%S) 21 | /bin/echo "${1}" 22 | /bin/echo "$DATE" " $1" >> "$log" 23 | } 24 | 25 | function finish () { 26 | kill "$jamfHelperPID" 2>/dev/null; wait "$jamfHelperPID" 2>/dev/null 27 | writelog "======== Finished $scriptName ========" 28 | } 29 | 30 | function build_dock () { 31 | for item in "${itemsToAdd[@]}"; do 32 | if [[ "$item" =~ , ]]; then 33 | params=${item##*,} 34 | item=${item%,*} 35 | #shellcheck disable=SC2086 36 | /usr/local/bin/dockutil --add "$item" $params --no-restart "$HOME/Library/Preferences/com.apple.dock.plist" 2>&1 | while read -r LINE; do writelog "$LINE"; done; 37 | else 38 | /usr/local/bin/dockutil --add "$item" --no-restart "$HOME/Library/Preferences/com.apple.dock.plist" 2>&1 | while read -r LINE; do writelog "$LINE"; done; 39 | fi 40 | done 41 | } 42 | 43 | function create_breadcrumb () { 44 | # Create a breadcrumb to track the creation of the Dock 45 | writelog "Creating DockBuilder user breadcrumb." 46 | /usr/bin/defaults write "$breadcrumb" build-date "$(date +%m-%d-%Y)" 47 | /usr/bin/defaults write "$breadcrumb" build-time "$(date +%r)" 48 | } 49 | 50 | trap finish EXIT 51 | 52 | writelog " " 53 | writelog "======== Starting $scriptName ========" 54 | 55 | # Validate we got values from the plist 56 | if [[ -f "$preferenceFileFullPath" ]]; then 57 | # Create array for default items 58 | while read -r line; do 59 | defaultItemsToAdd+=("$line") 60 | done <<< "$defaultItemsToAddFromPlist" 61 | 62 | # Create array for alternate_1 items 63 | while read -r line; do 64 | alternateItemsToAdd_1+=("$line") 65 | done <<< "$alternateItemsToAdd_1FromPlist" 66 | 67 | # Verify that we obtained values for each variable 68 | if [[ -z "$breadcrumb" ]] || [[ -z "$log" ]] || [[ -z "$appIcon" ]] || [[ -z "$hideDockWhileBuilding" ]] || [[ -z "$hideDockMessage" ]] || [[ -z "${defaultItemsToAdd[*]}" ]]; then 69 | writelog "One or more default settings not present in main preference file; exiting." 70 | exit 1 71 | fi 72 | else 73 | writelog "Preference file does not exist; exiting." 74 | exit 1 75 | fi 76 | 77 | # Make sure DockUtil is installed 78 | if [[ ! -f "/usr/local/bin/dockutil" ]]; then 79 | writelog "DockUtil does not exist, exiting." 80 | exit 1 81 | fi 82 | 83 | # We need to wait for the Dock to actually start 84 | until [[ $(pgrep -x Dock) ]]; do 85 | wait 86 | done 87 | 88 | # Check to see if the Dock was previously set up for the user 89 | if [[ -f "$breadcrumb" ]]; then 90 | writelog "DockBuilder ran previously on $(defaults read "$breadcrumb" build-date) at $(defaults read "$breadcrumb" build-time)." 91 | exit 0 92 | fi 93 | 94 | if [[ "$hideDockWhileBuilding" == "true" ]]; then 95 | # Display a jamfHelper dialog box to user informing them that we are configuring their Dock (in background) 96 | writelog "Unloading the Dock." 97 | /Library/Application\ Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "DockBuilder" -icon "$appIcon" -description "$hideDockMessage" & 98 | jamfHelperPID=$! 99 | 100 | # Unload the Dock while it is being updated 101 | launchctl unload /System/Library/LaunchAgents/com.apple.Dock.plist 102 | fi 103 | 104 | writelog "Clearing Dock." 105 | /usr/local/bin/dockutil --remove all --no-restart "$HOME/Library/Preferences/com.apple.dock.plist" 2>&1 | while read -r LINE; do writelog "$LINE"; done; 106 | /bin/sleep 5 107 | 108 | # Set up the Dock 109 | if [[ "$loggedInUser" == "admin" ]]; then 110 | writelog "Building alternate_1 Dock." 111 | for item in "${alternateItemsToAdd_1[@]}"; do 112 | itemsToAdd+=("$item") 113 | done 114 | /usr/bin/defaults write "$HOME/Library/Preferences/com.apple.dock.plist" 'orientation' -string 'left' # Position the Dock to the left 115 | else 116 | writelog "Building default Dock." 117 | for item in "${defaultItemsToAdd[@]}"; do 118 | itemsToAdd+=("$item") 119 | done 120 | fi 121 | build_dock 122 | create_breadcrumb 123 | 124 | # Load the Dock if unloaded or restart the Dock 125 | if [[ "$hideDockWhileBuilding" == "true" ]]; then 126 | writelog "Loading the newly built Dock." 127 | launchctl load /System/Library/LaunchAgents/com.apple.Dock.plist 128 | launchctl start com.apple.Dock.agent 129 | else 130 | writelog "Resetting Dock." 131 | /usr/bin/killall Dock 132 | fi 133 | 134 | exit 0 135 | -------------------------------------------------------------------------------- /dockutil.pkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryangball/DockBuilder/d8a955ddfa8c89f276a5f7864b493e5f7096c237/dockutil.pkg -------------------------------------------------------------------------------- /images/dock_message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryangball/DockBuilder/d8a955ddfa8c89f276a5f7864b493e5f7096c237/images/dock_message.png -------------------------------------------------------------------------------- /postinstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #shellcheck disable=SC2012 3 | 4 | preferenceFileFullPath="/Library/Preferences/com.github.ryangball.dockbuilder.defaults.plist" 5 | breadcrumbPathMinusHome=$(/usr/libexec/PlistBuddy -c "Print BreadcrumbPath" $preferenceFileFullPath | cut -d/ -f2-) 6 | skipInitialBreadcrumbUsers=$(/usr/libexec/PlistBuddy -c "Print SkipInitialBreadcrumbUsers" $preferenceFileFullPath | sed -e 1d -e '$d' | sed 's/^ *//') 7 | 8 | log="/Library/Logs/DockBuilder_Install.log" 9 | 10 | function writelog () { 11 | DATE=$(date +%Y-%m-%d\ %H:%M:%S) 12 | /bin/echo "${1}" 13 | /bin/echo "$DATE" " $1" >> "$log" 14 | } 15 | 16 | create_breadcrumb () { 17 | # Create a breadcrumb to track the creation of the Dock 18 | writelog "Creating DockBuilder user breadcrumb for $1." 19 | /usr/bin/defaults write "$2" build-date "$(date +%m-%d-%Y)" 20 | /usr/bin/defaults write "$2" build-time "$(date +%r)" 21 | chown "$1" "$2" 22 | } 23 | 24 | writelog "Looping through all users to ensure Dock will be configured correctly..." 25 | 26 | # Run through all normal accounts 27 | for userName in $(dscl . -list /Users uid | awk '$2 >= 100 && $0 !~ /^_/ { print $1 }'); do 28 | if [[ "$skipInitialBreadcrumbUsers" =~ $userName ]]; then 29 | writelog "Initial breadcrumb creation for $userName is being skipped." 30 | continue 31 | fi 32 | userHome=$(/usr/bin/dscl . read "/Users/$userName" NFSHomeDirectory | cut -c 19-) 33 | breadcrumb="$userHome/$breadcrumbPathMinusHome" 34 | 35 | # Check to see if a breadcrumb is already created in the user's home folder 36 | if [[ -f "$breadcrumb" ]]; then 37 | writelog "$userName's Dock was built by DockBuilder on $(defaults read "$breadcrumb" build-date) at $(defaults read "$breadcrumb" build-time)." 38 | continue 39 | fi 40 | 41 | # Check to see if the user's home folder exists, and if so get the age in seconds 42 | if [[ -d "$userHome" ]]; then 43 | userHomeAge=$(( $(date +%s)-$(stat -f%B "$userHome") )) 44 | # Check to see if the user's home folder is at least 5 minutes old 45 | if [[ "$userHomeAge" -gt "300" ]]; then 46 | writelog "$userName's home folder has existed since $(stat -f "%SB" -t "%m-%d-%Y" "$userHome") at $(stat -f "%SB" -t "%r" "$userHome")." 47 | # Check to see if the user's home folder contains the dock plist indicating the dock has been built 48 | if [[ -f "$userHome/Library/Preferences/com.apple.dock.plist" ]]; then 49 | create_breadcrumb "$userName" "$breadcrumb" 50 | else 51 | writelog "$userName's Dock has not been created yet, skipping." 52 | fi 53 | else 54 | writelog "$userName's home folder is less than 5 minutes old; skipping." 55 | fi 56 | else 57 | writelog "$userName's Dock has not been created yet, skipping." 58 | fi 59 | done 60 | 61 | # if someone is logged in 62 | if who | grep -q console; then 63 | 64 | # get the logged in user's uid 65 | LOGGED_IN_UID=$(ls -ln /dev/console | awk '{ print $3 }') 66 | 67 | # use launchctl asuser to run launchctl in the same Mach bootstrap namespace hierachy as the Finder 68 | launchctl asuser "$LOGGED_IN_UID" launchctl load /Library/LaunchAgents/com.github.ryangball.dockbuilder.plist 69 | fi 70 | 71 | touch /Applications/Utilities/DockBuilder.app 72 | 73 | exit 0 74 | --------------------------------------------------------------------------------