diff --git a/Exercise3a/Firefox-testing.jss.recipe b/Exercise3a/Firefox-testing.jss.recipe new file mode 100644 index 0000000..f76beb2 --- /dev/null +++ b/Exercise3a/Firefox-testing.jss.recipe @@ -0,0 +1,33 @@ + + + + + Identifier + local.jss.Firefox-testing + Input + + CATEGORY + Web Browsers + GROUP_NAME + %NAME%-update-smart + GROUP_TEMPLATE + SmartGroupTemplate.xml + LOCALE + en_US + NAME + Firefox + POLICY_CATEGORY + Testing + POLICY_TEMPLATE + PolicyTemplate.xml + RELEASE + latest + SELF_SERVICE_DESCRIPTION + Web Browser. + SELF_SERVICE_ICON + Firefox.png + + ParentRecipe + com.github.jss-recipes.jss.Firefox_EN + + diff --git a/Exercise5b/Firefox-autoupdate.jss.recipe b/Exercise5b/Firefox-autoupdate.jss.recipe new file mode 100644 index 0000000..5c6ece2 --- /dev/null +++ b/Exercise5b/Firefox-autoupdate.jss.recipe @@ -0,0 +1,21 @@ + + + + + Identifier + local.jss.Firefox-autoupdate + Input + + GROUP_NAME + %NAME%-autoupdate + GROUP_TEMPLATE + SmartGroupTemplate-autoupdate.xml + POLICY_CATEGORY + Auto Update + POLICY_TEMPLATE + PolicyTemplate-autoupdate.xml + + ParentRecipe + com.github.jss-recipes.jss.Firefox_EN + + diff --git a/RecipeOverrides/PolicyTemplate.xml b/Exercise5b/PolicyTemplate-autoupdate.xml similarity index 65% rename from RecipeOverrides/PolicyTemplate.xml rename to Exercise5b/PolicyTemplate-autoupdate.xml index 562c2d1..a9384e5 100755 --- a/RecipeOverrides/PolicyTemplate.xml +++ b/Exercise5b/PolicyTemplate-autoupdate.xml @@ -6,19 +6,18 @@ %POLICY_CATEGORY% + true autoupdate-%PROD_NAME% - - - - - + + + + + - + - - true diff --git a/RecipeOverrides/SmartGroupTemplate.xml b/Exercise5b/SmartGroupTemplate-autoupdate.xml old mode 100644 new mode 100755 similarity index 72% rename from RecipeOverrides/SmartGroupTemplate.xml rename to Exercise5b/SmartGroupTemplate-autoupdate.xml index 53e3040..b8148a2 --- a/RecipeOverrides/SmartGroupTemplate.xml +++ b/Exercise5b/SmartGroupTemplate-autoupdate.xml @@ -16,12 +16,5 @@ is not %VERSION% - - Application Version - 1 - and - is not - - diff --git a/Exercise5c/auto_update_magic.sh b/Exercise5c/auto_update_magic.sh new file mode 100755 index 0000000..f79cce8 --- /dev/null +++ b/Exercise5c/auto_update_magic.sh @@ -0,0 +1,155 @@ +#!/bin/bash + +### +# +# Name: auto_update_magic.sh +# Description: A script and LaunchDaemon pair designed to leverage +# autopkg, AutoPkgr, JSSImporter, and Casper to keep apps on +# Mac endpoints up to date automatically. Details at: +# https://github.com/homebysix/auto-update-magic +# Author: Elliot Jordan +# Created: 2013-03-24 +# Last Modified: 2015-09-22 +# Version: 2.0 +# +### + + +################################## SETTINGS ################################### + +# Add a line here for each auto update custom trigger. This is almost always +# the same as the recipe's name. Trigger and recipe names may contain spaces. +TRIGGERS=( + + # "Adobe Flash Player" + + # "Firefox" + + # "Google Chrome" + + # "Oracle Java 7" + + # "Oracle Java 8" + + # "MSOffice2011" + +) + +# For each recipe above, add a corresponding line here for each "blocking +# application" (apps/processes that must not be open if the app is to be +# updated automatically). You can add multiple comma-separated applications per +# line. Use `pgrep _____` to test whether the blocking behaves as expected. +BLOCKING_APPS=( + + # "Safari, Firefox" # blocking apps for Flash + + # "Firefox" # blocking apps for Firefox + + # "Google Chrome" # blocking apps for Chrome + + # "Safari, Firefox" # blocking apps for Java 7 + + # "Safari, Firefox" # blocking apps for Java 8 + + # "MSN Messenger, Microsoft Lync, Microsoft Cert Manager, Microsoft Chart Converter, Microsoft Clip Gallery, Microsoft Entourage, Microsoft Outlook, Microsoft Error Reporting, Microsoft Excel, Microsoft Graph, Microsoft Help Viewer, Microsoft Language Register, Microsoft Communicator, Microsoft Messenger, Microsoft PowerPoint, Microsoft Query, Microsoft Word, My Day, Organization Chart, Expression Media, Remote Desktop Connection" # blocking apps for latest Office 2011 update + +) + +# Preference list that will be used to track last auto update timestamp. +# Omit ".plist" extension. +PLIST="/Library/Application Support/JAMF/com.jamfsoftware.jamfnation" + +# Set DEBUG_MODE to true if you wish to do a "dry run." This means the custom +# triggers that cause the apps to actually update will be logged, but NOT +# actually executed. Set to false prior to deployment. +DEBUG_MODE=true + + +############################################################################### +######################### DO NOT EDIT BELOW THIS LINE ######################### +############################################################################### + + +######################## VALIDATION AND ERROR CHECKING ######################## + +APPNAME=$(basename "$0" | sed "s/\.sh$//") + +# Let's make sure we have the right numbers of settings above. +if [[ ${#TRIGGERS[@]} != ${#BLOCKING_APPS[@]} ]]; then + echo "[ERROR] Please carefully check the settings in the $APPNAME script. The number of parameters don't match." >&2 + exit 1001 +fi + +# Let's verify that DEBUG_MODE is set to true or false. +if [[ $DEBUG_MODE != true && $DEBUG_MODE != false ]]; then + echo "[ERROR] DEBUG_MODE should be set to either true or false." >&2 + exit 1002 +fi + +if [[ -x /usr/sbin/jamf ]]; then + jamf=/usr/sbin/jamf +elif [[ -x /usr/local/bin/jamf ]]; then + jamf=/usr/local/bin/jamf +else + echo "[ERROR] The jamf binary could not be found." >&2 + exit 1003 +fi + + +################################ MAIN PROCESS ################################# + +# Count how many recipes we need to process. +RECIPE_COUNT=${#TRIGGERS[@]} + +# Save the default internal field separator. +OLDIFS=$IFS + +# Begin iterating through recipes. +for (( i = 0; i < RECIPE_COUNT; i++ )); do + + echo " " # for some visual separation between apps in the log + + # Iterate through each recipe's corresponding blocking apps. + echo "Checking for apps that would block the ${TRIGGERS[$i]} update..." + IFS="," + UPDATE_BLOCKED=false + + for APP in ${BLOCKING_APPS[$i]}; do + + # Strip leading spaces from app name. Save lowercase version. + APP_CLEAN="$(echo "$APP" | sed 's/^ *//')" + APP_CLEAN_LOWER="$(echo "$APP_CLEAN" | tr "[:upper:]" "[:lower:]")" + + # Check whether the app is running. + if pgrep "$APP_CLEAN" &> /dev/null || pgrep "$APP_CLEAN_LOWER" &> /dev/null; then + echo " $APP_CLEAN is running. Skipping auto update." + UPDATE_BLOCKED=true + break + else + echo " $APP_CLEAN is not running." + fi + + done + + # Only run the auto-update policy if no blocking apps are running. + if [[ $UPDATE_BLOCKED == false ]]; then + if [[ $DEBUG_MODE == false ]]; then + echo "No apps are blocking the ${TRIGGERS[$i]} update. Calling policy trigger autoupdate-${TRIGGERS[$i]}." + $jamf policy -event "autoupdate-${TRIGGERS[$i]}" + else + echo "[DEBUG] No apps are blocking the ${TRIGGERS[$i]} update. This is the point where we would run:" + echo " $jamf policy -event \"autoupdate-${TRIGGERS[$i]}\"" + fi + fi + +done # End iterating through recipes. + +# Reset back to default internal field separator. +IFS=$OLDIFS + +# Record the timestamp of the last auto update check. +if [[ $DEBUG_MODE == false ]]; then + /usr/bin/defaults write "$PLIST" LastAutoUpdate "$(date +%s)" +fi + +exit 0 diff --git a/Exercise5c/com.jamfsoftware.jamfnation.auto_update_magic.plist b/Exercise5c/com.jamfsoftware.jamfnation.auto_update_magic.plist new file mode 100644 index 0000000..6ff8643 --- /dev/null +++ b/Exercise5c/com.jamfsoftware.jamfnation.auto_update_magic.plist @@ -0,0 +1,19 @@ + + + + + Comment + A script and LaunchDaemon pair designed to leverage autopkg, AutoPkgr, JSSImporter, and Casper to keep apps on Mac endpoints up to date automatically. Details at: https://github.com/homebysix/auto-update-magic + Label + com.jamfsoftware.jamfnation.auto_update_magic + ProgramArguments + + sh + /Library/Scripts/auto_update_magic.sh + + RunAtLoad + + StartInterval + 3600 + + diff --git a/Exercise5c/create_pkg.sh b/Exercise5c/create_pkg.sh new file mode 100755 index 0000000..ed44bc0 --- /dev/null +++ b/Exercise5c/create_pkg.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +### +# +# Name: create_pkg.sh +# Description: This script automatically creates a pkg file that you can +# use to deploy the Auto Update Magic script/LaunchDaemon +# pair to your managed clients. +# Author: Elliot Jordan +# Created: 2015-09-18 +# Last Modified: 2015-09-23 +# Version: 1.0.1 +# +### + +cd "$(dirname "$0")" + +if [[ ! -f "./auto_update_magic.sh" || + ! -f "./com.jamfsoftware.jamfnation.auto_update_magic.plist" || + ! -f "./pkg_scripts/postinstall" ]]; then + echo "[ERROR] At least one required file is missing. Ensure that the following files exist in the Exercise5c folder:" + echo " auto_update_magic.sh" + echo " com.jamfsoftware.jamfnation.auto_update_magic.plist" + echo " pkg_scripts/postinstall" + exit 1 +fi + +script_md5=$(md5 -q ./auto_update_magic.sh) +if [[ "$script_md5" == "a1fd08b32853ca004212e98d7ea5a99e" ]]; then + echo "[ERROR] It looks like you haven't customized the auto_update_magic.sh script yet. Please do that now, then run create_pkg.sh again." + exit 2 +fi + +read -p "[SANITY CHECK] Have you already added the TRIGGERS to auto_update_magic.sh? [y/n]: " -n 1 check_triggers +echo +if [[ "$check_triggers" != "y" && "$check_triggers" != "Y" ]]; then + echo "You should go back and add the TRIGGERS to auto_update_magic.sh now, then run create_pkg.sh again." + exit 3 +fi + +read -p "[SANITY CHECK] Have you already added the BLOCKING_APPS to auto_update_magic.sh? [y/n]: " -n 1 check_blocking_apps +echo +if [[ "$check_blocking_apps" != "y" && "$check_blocking_apps" != "Y" ]]; then + echo "You should go back and add the BLOCKING_APPS to auto_update_magic.sh now, then run create_pkg.sh again." + exit 4 +fi + +read -p "[SANITY CHECK] Have you already adjusted the StartInterval in the com.jamfsoftware.jamfnation.auto_update_magic LaunchDaemon to your liking? [y/n]: " -n 1 check_schedule +echo +if [[ "$check_schedule" != "y" && "$check_schedule" != "Y" ]]; then + echo "You should go back and adjust the StartInterval now, then run create_pkg.sh again." + exit 5 +fi + +echo "Great! Sounds like you're good to go." + +TMP_PKGROOT="/private/tmp/auto_update_magic/pkgroot" +echo "Building package root in /tmp folder..." +mkdir -p "$TMP_PKGROOT/Library/LaunchDaemons" "$TMP_PKGROOT/Library/Scripts" + +echo "Copying the files to the package root..." +cp "./com.jamfsoftware.jamfnation.auto_update_magic.plist" "$TMP_PKGROOT/Library/LaunchDaemons/" +cp "./auto_update_magic.sh" "$TMP_PKGROOT/Library/Scripts/" + +echo "Setting mode and permissions..." +chown -R root:wheel "$TMP_PKGROOT" +chmod +x "$TMP_PKGROOT/Library/Scripts/auto_update_magic.sh" + +echo "Building the package..." +pkgbuild --root "/tmp/auto_update_magic/pkgroot" \ + --scripts "./pkg_scripts" \ + --identifier "com.jamfsoftware.jamfnation.auto_update_magic" \ + --version "2.0" \ + --install-location "/" \ + "./auto_update_magic-$(date "+%Y%m%d").pkg" + +exit 0 diff --git a/Exercise5c/pkg_scripts/postinstall b/Exercise5c/pkg_scripts/postinstall new file mode 100755 index 0000000..06b74b4 --- /dev/null +++ b/Exercise5c/pkg_scripts/postinstall @@ -0,0 +1,5 @@ +#!/bin/bash + +launchctl load -w /Library/LaunchDaemons/com.jamfsoftware.jamfnation.auto_update_magic.plist + +exit 0 diff --git a/Exercise6a/Adobe Flash Player-autoupdate.jss.recipe b/Exercise6a/Adobe Flash Player-autoupdate.jss.recipe new file mode 100644 index 0000000..cfe9a0b --- /dev/null +++ b/Exercise6a/Adobe Flash Player-autoupdate.jss.recipe @@ -0,0 +1,23 @@ + + + + + Identifier + local.jss.AdobeFlashPlayer-autoupdate + Input + + NAME + Adobe Flash Player + GROUP_NAME + %NAME%-autoupdate + GROUP_TEMPLATE + AdobeFlashPlayerSmartGroupTemplate-autoupdate.xml + POLICY_CATEGORY + Auto Update + POLICY_TEMPLATE + PolicyTemplate-autoupdate.xml + + ParentRecipe + com.github.jss-recipes.jss.AdobeFlashPlayer + + diff --git a/Exercise6a/AdobeFlashPlayerSmartGroupTemplate-autoupdate.xml b/Exercise6a/AdobeFlashPlayerSmartGroupTemplate-autoupdate.xml new file mode 100755 index 0000000..1969e2b --- /dev/null +++ b/Exercise6a/AdobeFlashPlayerSmartGroupTemplate-autoupdate.xml @@ -0,0 +1,20 @@ + + %group_name% + true + + + AdobeFlashVersion + 0 + and + is not + %VERSION% + + + AdobeFlashVersion + 1 + and + is not + + + + diff --git a/Exercise6a/Google Chrome-autoupdate.jss.recipe b/Exercise6a/Google Chrome-autoupdate.jss.recipe new file mode 100644 index 0000000..bd0bffd --- /dev/null +++ b/Exercise6a/Google Chrome-autoupdate.jss.recipe @@ -0,0 +1,21 @@ + + + + + Identifier + local.jss.GoogleChrome-autoupdate + Input + + GROUP_NAME + %NAME%-autoupdate + GROUP_TEMPLATE + SmartGroupTemplate-autoupdate.xml + POLICY_CATEGORY + Auto Update + POLICY_TEMPLATE + PolicyTemplate-autoupdate.xml + + ParentRecipe + com.github.jss-recipes.jss.GoogleChrome + + diff --git a/Exercise6a/Oracle Java 7-autoupdate.jss.recipe b/Exercise6a/Oracle Java 7-autoupdate.jss.recipe new file mode 100644 index 0000000..1659e4a --- /dev/null +++ b/Exercise6a/Oracle Java 7-autoupdate.jss.recipe @@ -0,0 +1,23 @@ + + + + + Identifier + local.jss.OracleJava7-autoupdate + Input + + NAME + Oracle Java 7 + GROUP_NAME + %NAME%-autoupdate + GROUP_TEMPLATE + OracleJava7SmartGroupTemplate-autoupdate.xml + POLICY_CATEGORY + Auto Update + POLICY_TEMPLATE + PolicyTemplate-autoupdate.xml + + ParentRecipe + com.github.jss-recipes.jss.OracleJava7 + + diff --git a/Exercise6a/Oracle Java 8-autoupdate.jss.recipe b/Exercise6a/Oracle Java 8-autoupdate.jss.recipe new file mode 100644 index 0000000..363dc87 --- /dev/null +++ b/Exercise6a/Oracle Java 8-autoupdate.jss.recipe @@ -0,0 +1,23 @@ + + + + + Identifier + local.jss.OracleJava8-autoupdate + Input + + NAME + Oracle Java 8 + GROUP_NAME + %NAME%-autoupdate + GROUP_TEMPLATE + OracleJava8SmartGroupTemplate-autoupdate.xml + POLICY_CATEGORY + Auto Update + POLICY_TEMPLATE + PolicyTemplate-autoupdate.xml + + ParentRecipe + com.github.jss-recipes.jss.OracleJava8 + + diff --git a/Exercise6a/OracleJava7SmartGroupTemplate-autoupdate.xml b/Exercise6a/OracleJava7SmartGroupTemplate-autoupdate.xml new file mode 100755 index 0000000..9dad08d --- /dev/null +++ b/Exercise6a/OracleJava7SmartGroupTemplate-autoupdate.xml @@ -0,0 +1,27 @@ + + %group_name% + true + + + OracleJavaVersion + 0 + and + like + 1.7. + + + OracleJavaVersion + 1 + and + is not + %VERSION% + + + OracleJavaVersion + 2 + and + is not + + + + diff --git a/Exercise6a/OracleJava8SmartGroupTemplate-autoupdate.xml b/Exercise6a/OracleJava8SmartGroupTemplate-autoupdate.xml new file mode 100755 index 0000000..f31b723 --- /dev/null +++ b/Exercise6a/OracleJava8SmartGroupTemplate-autoupdate.xml @@ -0,0 +1,27 @@ + + %group_name% + true + + + OracleJavaVersion + 0 + and + like + 1.8. + + + OracleJavaVersion + 1 + and + is not + %VERSION% + + + OracleJavaVersion + 2 + and + is not + + + + diff --git a/Exercise6b/Adobe Flash Player-testing.jss.recipe b/Exercise6b/Adobe Flash Player-testing.jss.recipe new file mode 100644 index 0000000..79c1635 --- /dev/null +++ b/Exercise6b/Adobe Flash Player-testing.jss.recipe @@ -0,0 +1,25 @@ + + + + + Identifier + local.jss.AdobeFlashPlayer-testing + Input + + NAME + Adobe Flash Player + CATEGORY + Everything else + POLICY_CATEGORY + Trusted Testers + POLICY_TEMPLATE + PolicyTemplate-testing.xml + GROUP_NAME + + GROUP_TEMPLATE + + + ParentRecipe + com.github.jss-recipes.jss.AdobeFlashPlayer + + diff --git a/Exercise6b/Google Chrome-testing.jss.recipe b/Exercise6b/Google Chrome-testing.jss.recipe new file mode 100644 index 0000000..52b338d --- /dev/null +++ b/Exercise6b/Google Chrome-testing.jss.recipe @@ -0,0 +1,23 @@ + + + + + Identifier + local.jss.GoogleChrome-testing + Input + + CATEGORY + Productivity + POLICY_CATEGORY + Trusted Testers + POLICY_TEMPLATE + PolicyTemplate-testing.xml + GROUP_NAME + + GROUP_TEMPLATE + + + ParentRecipe + com.github.jss-recipes.jss.GoogleChrome + + diff --git a/Exercise6b/Oracle Java 7-testing.jss.recipe b/Exercise6b/Oracle Java 7-testing.jss.recipe new file mode 100644 index 0000000..51367e3 --- /dev/null +++ b/Exercise6b/Oracle Java 7-testing.jss.recipe @@ -0,0 +1,25 @@ + + + + + Identifier + local.jss.OracleJava7-testing + Input + + NAME + Oracle Java 7 + CATEGORY + Everything else + POLICY_CATEGORY + Trusted Testers + POLICY_TEMPLATE + PolicyTemplate-testing.xml + GROUP_NAME + + GROUP_TEMPLATE + + + ParentRecipe + com.github.jss-recipes.jss.OracleJava7 + + diff --git a/Exercise6b/Oracle Java 8-testing.jss.recipe b/Exercise6b/Oracle Java 8-testing.jss.recipe new file mode 100644 index 0000000..06cf3ac --- /dev/null +++ b/Exercise6b/Oracle Java 8-testing.jss.recipe @@ -0,0 +1,27 @@ + + + + + Identifier + local.jss.OracleJava8-testing + Input + + NAME + Oracle Java 8 + CATEGORY + Everything else + POLICY_CATEGORY + Trusted Testers + POLICY_TEMPLATE + PolicyTemplate-testing.xml + SELF_SERVICE_DESCRIPTION + Browser plugin to allow execution of Java applets. + GROUP_NAME + + GROUP_TEMPLATE + + + ParentRecipe + com.github.jss-recipes.jss.OracleJava8 + + diff --git a/Exercise6b/PolicyTemplate-testing.xml b/Exercise6b/PolicyTemplate-testing.xml new file mode 100755 index 0000000..a0cfa57 --- /dev/null +++ b/Exercise6b/PolicyTemplate-testing.xml @@ -0,0 +1,35 @@ + + + Test Latest %PROD_NAME% + true + Ongoing + + %POLICY_CATEGORY% + + test-%PROD_NAME% + + + false + + + + 123 + Testing + + + + + + + + + + + true + Install %VERSION% + %SELF_SERVICE_DESCRIPTION% + + + true + + diff --git a/RecipeOverrides/PolicyTemplate-SelfService.xml b/Exercise6c/PolicyTemplate-selfservice.xml similarity index 56% rename from RecipeOverrides/PolicyTemplate-SelfService.xml rename to Exercise6c/PolicyTemplate-selfservice.xml index 1d7f1f2..d2e4fad 100755 --- a/RecipeOverrides/PolicyTemplate-SelfService.xml +++ b/Exercise6c/PolicyTemplate-selfservice.xml @@ -8,21 +8,21 @@ selfservice-%PROD_NAME% - - true - - - + + true + + + - + true - Install %VERSION% - %SELF_SERVICE_DESCRIPTION% + Install %VERSION% + %SELF_SERVICE_DESCRIPTION% - true + false diff --git a/Exercise6c/Slack-selfservice.jss.recipe b/Exercise6c/Slack-selfservice.jss.recipe new file mode 100644 index 0000000..0df3d6e --- /dev/null +++ b/Exercise6c/Slack-selfservice.jss.recipe @@ -0,0 +1,23 @@ + + + + + Identifier + local.jss.Slack-selfservice + Input + + CATEGORY + Productivity + GROUP_NAME + + GROUP_TEMPLATE + + POLICY_CATEGORY + Productivity + POLICY_TEMPLATE + PolicyTemplate-selfservice.xml + + ParentRecipe + com.github.jss-recipes.jss.Slack + + diff --git a/Exercise6c/TextWrangler-selfservice.jss.recipe b/Exercise6c/TextWrangler-selfservice.jss.recipe new file mode 100644 index 0000000..7615cbb --- /dev/null +++ b/Exercise6c/TextWrangler-selfservice.jss.recipe @@ -0,0 +1,23 @@ + + + + + Identifier + local.jss.TextWrangler-selfservice + Input + + CATEGORY + Productivity + GROUP_NAME + + GROUP_TEMPLATE + + POLICY_CATEGORY + Productivity + POLICY_TEMPLATE + PolicyTemplate-selfservice.xml + + ParentRecipe + com.github.jss-recipes.jss.TextWrangler + + diff --git a/Exercise6d/1Password-selfservice.jss.recipe b/Exercise6d/1Password-selfservice.jss.recipe new file mode 100644 index 0000000..dfefba4 --- /dev/null +++ b/Exercise6d/1Password-selfservice.jss.recipe @@ -0,0 +1,27 @@ + + + + + Identifier + local.jss.1Password-selfservice + Input + + CATEGORY + Security + GROUP_NAME + + GROUP_TEMPLATE + + MAJOR_VERSION + 5 + POLICY_CATEGORY + Security + POLICY_TEMPLATE + LicensedAppPolicyTemplate-selfservice.xml + LICENSE_TRIGGER + 1Password + + ParentRecipe + com.github.jss-recipes.jss.1Password + + diff --git a/Exercise6d/LicensedAppPolicyTemplate-selfservice.xml b/Exercise6d/LicensedAppPolicyTemplate-selfservice.xml new file mode 100755 index 0000000..422b4cc --- /dev/null +++ b/Exercise6d/LicensedAppPolicyTemplate-selfservice.xml @@ -0,0 +1,31 @@ + + + %PROD_NAME% + true + Ongoing + + %POLICY_CATEGORY% + + selfservice-%PROD_NAME% + + + true + + + + + + + + + true + Install %VERSION% + %SELF_SERVICE_DESCRIPTION% + + + false + + + jamf policy -event license-%LICENSE_TRIGGER% + + diff --git a/README-images/configure-jssimporter.png b/README-images/configure-jssimporter.png new file mode 100644 index 0000000..a9575ce Binary files /dev/null and b/README-images/configure-jssimporter.png differ diff --git a/README-images/email-notification.png b/README-images/email-notification.png new file mode 100644 index 0000000..bfa12bc Binary files /dev/null and b/README-images/email-notification.png differ diff --git a/README-images/firefox-download.png b/README-images/firefox-download.png new file mode 100644 index 0000000..3178e70 Binary files /dev/null and b/README-images/firefox-download.png differ diff --git a/README-images/firefox-install.png b/README-images/firefox-install.png new file mode 100644 index 0000000..7927a2d Binary files /dev/null and b/README-images/firefox-install.png differ diff --git a/README-images/firefox-jss-policy.png b/README-images/firefox-jss-policy.png new file mode 100644 index 0000000..5df3b9c Binary files /dev/null and b/README-images/firefox-jss-policy.png differ diff --git a/README-images/firefox-pkg-inspection.png b/README-images/firefox-pkg-inspection.png new file mode 100644 index 0000000..bb091ba Binary files /dev/null and b/README-images/firefox-pkg-inspection.png differ diff --git a/README-images/mantra.png b/README-images/mantra.png new file mode 100644 index 0000000..b381230 Binary files /dev/null and b/README-images/mantra.png differ diff --git a/README-images/notifications.png b/README-images/notifications.png new file mode 100644 index 0000000..d26014b Binary files /dev/null and b/README-images/notifications.png differ diff --git a/README-images/policy-looping-01.png b/README-images/policy-looping-01.png new file mode 100644 index 0000000..c235a8d Binary files /dev/null and b/README-images/policy-looping-01.png differ diff --git a/README-images/policy-looping-02.png b/README-images/policy-looping-02.png new file mode 100644 index 0000000..045cfd7 Binary files /dev/null and b/README-images/policy-looping-02.png differ diff --git a/README-images/schedule.png b/README-images/schedule.png new file mode 100644 index 0000000..b72b89e Binary files /dev/null and b/README-images/schedule.png differ diff --git a/README-images/sw-dist-cycle-01.png b/README-images/sw-dist-cycle-01.png new file mode 100644 index 0000000..ba7b04e Binary files /dev/null and b/README-images/sw-dist-cycle-01.png differ diff --git a/README-images/sw-dist-cycle-02.png b/README-images/sw-dist-cycle-02.png new file mode 100644 index 0000000..9bb1447 Binary files /dev/null and b/README-images/sw-dist-cycle-02.png differ diff --git a/README-images/sw-dist-cycle-03.png b/README-images/sw-dist-cycle-03.png new file mode 100644 index 0000000..0ab7810 Binary files /dev/null and b/README-images/sw-dist-cycle-03.png differ diff --git a/README-images/sw-dist-cycle-04.png b/README-images/sw-dist-cycle-04.png new file mode 100644 index 0000000..f8b249a Binary files /dev/null and b/README-images/sw-dist-cycle-04.png differ diff --git a/README-images/sw-dist-cycle-05.png b/README-images/sw-dist-cycle-05.png new file mode 100644 index 0000000..85bc5a2 Binary files /dev/null and b/README-images/sw-dist-cycle-05.png differ diff --git a/README-images/sw-dist-cycle.png b/README-images/sw-dist-cycle.png new file mode 100644 index 0000000..ac3df03 Binary files /dev/null and b/README-images/sw-dist-cycle.png differ diff --git a/doc-images/update-graphic.png b/README-images/update-graphic.png similarity index 100% rename from doc-images/update-graphic.png rename to README-images/update-graphic.png diff --git a/README.md b/README.md index 21a2c0d..e7bdcc6 100644 --- a/README.md +++ b/README.md @@ -1,134 +1,203 @@ # Auto Update Magic   -![Auto Update Magic](doc-images/update-graphic.png) +![Auto Update Magic](README-images/update-graphic.png) -_[Auto Update Magic: Keeping Mac apps up to date automatically with Casper and AutoPkgr](http://www.jamfsoftware.com/news/auto-update-magic-keep-mac-apps-current-with-the-casper-suite-and-autopkgr/)_
_Presented by Elliot Jordan, Senior Consultant, [Linde Group](http://www.lindegroup.com)_
_JAMF Nation User Conference - October 22, 2014 - Minneapolis, MN_ +_[Auto Update Magic: Keeping Mac apps up to date automatically with Casper and AutoPkgr](http://www.jamfsoftware.com/news/auto-update-magic-keep-mac-apps-current-with-the-casper-suite-and-autopkgr/)_
_Originally presented by Elliot Jordan, Senior Consultant, [Linde Group](http://www.lindegroup.com)_
_JAMF Nation User Conference - October 22, 2014 - Minneapolis, MN_ ---- +  ## Table of Contents + + - [Overview](#overview) -- [Status quo](#status-quo) -- [New tools to the rescue](#new-tools-to-the-rescue) - - [AutoPkg](#autopkg) - - [JSSImporter](#jssimporter) - - [AutoPkgr](#autopkgr) -- [The Magic](#the-magic) - - [Level 1: Self Service](#level-1-self-service) - - [Level 2: Auto to Some](#level-2-auto-to-some) - - [Level 3: Auto to All](#level-3-auto-to-all) - - [Bonus: Creating both Self Service and Auto Update policies](#bonus-creating-both-self-service-and-auto-update-policies) -- [Notes and caveats](#notes-and-caveats) -- [Acknowledgements](#acknowledgements) -- [Files included in this repo](#files-included-in-this-repo) - ---- +- [Requirements](#requirements) +- [Standardized software distribution](#standardized-software-distribution) + - [1. New Release](#1-new-release) + - [Exercise 1: Automate checking for new software with AutoPkgr](#exercise-1-automate-checking-for-new-software-with-autopkgr) + - [2. Development](#2-development) + - [Exercise 2a: Install new software for local testing](#exercise-2a-install-new-software-for-local-testing) + - [Exercise 2b: Create a deployable pkg file using AutoPkg](#exercise-2b-create-a-deployable-pkg-file-using-autopkg) + - [3. Testing](#3-testing) + - [Exercise 3a: Automatically create Self Service policies for testing new software](#exercise-3a-automatically-create-self-service-policies-for-testing-new-software) + - [4. Feedback](#4-feedback) + - [5. Deployment](#5-deployment) + - [Exercise 5a: Promote Self Service policies to use new packages](#exercise-5a-promote-self-service-policies-to-use-new-packages) + - [Exercise 5b: Automatically create Auto Update policies](#exercise-5b-automatically-create-auto-update-policies) + - [Exercise 5c: Configure Macs to check for updates periodically](#exercise-5c-configure-macs-to-check-for-updates-periodically) +- [Further enhancement and advanced workflows](#further-enhancement-and-advanced-workflows) + - [Exercise 6a: Adding More Apps](#exercise-6a-adding-more-apps) + - [Exercise 6b: Organizing and customizing the testing recipes](#exercise-6b-organizing-and-customizing-the-testing-recipes) + - [Exercise 6c: Sending software directly to Self Service policies](#exercise-6c-sending-software-directly-to-self-service-policies) + - [Exercise 6d: Create installation policies for site-licensed software](#exercise-6d-create-installation-policies-for-site-licensed-software) + - [Exercise 6e: Store your -autoupdate.jss recipes outside the search path](#exercise-6e-store-your--autoupdatejss-recipes-outside-the-search-path) +- [Operational workflow](#operational-workflow) +- [Rollback plan](#rollback-plan) +- [Troubleshooting](#troubleshooting) + - [Remove one layer and try again](#remove-one-layer-and-try-again) + - [Check for bad recipe overrides](#check-for-bad-recipe-overrides) + - [Check for missing parent recipes](#check-for-missing-parent-recipes) + - [Test the LaunchDaemon and script pair](#test-the-launchdaemon-and-script-pair) + - [Find and fix loopers](#find-and-fix-loopers) +- [Getting help](#getting-help) + - [Community support](#community-support) + - [Consulting services](#consulting-services) + - [Found a problem?](#found-a-problem) + + +  ## Overview -Mac app patch management in Casper is not trivial, and yet it's one of the most important functions of any device management framework. Outdated apps can expose security vulnerabilities, cause file format incompatibilities, and prevent people from taking advantage of the latest and greatest app features. +Keeping Mac apps up to date with Casper is anything but trivial, and yet it's one of the most critical tasks of any management system. Outdated apps can expose security vulnerabilities, cause file format incompatibilities, and prevent people from taking advantage of the latest and greatest app features. + +Auto Update Magic is my attempt to make updating apps easier for Casper administrators. In this newly rewritten guide, I have provided instructions, example workflows, scripts, recipes, and a LaunchDaemon that will help you keep your Mac apps updated with your Casper JSS. + +Yes, JAMF will probably be incorporating "patch management" features into Casper soon. However, Auto Update Magic lets you automate your Mac app patching _today_, and gives you total control over how apps are packaged, imported, and deployed. + +  + +## Requirements + +Before we start, you'll probably want to download this repo to your local computer, for easy reference to the included files. Click here to download a zip file.

I'll assume that the path to the downloaded repository is ~/Downloads/auto-update-magic-master. If you move the repo elsewhere, be sure to update the paths referenced below. + +Also, you'll want each of the following: + +- Admin access to your JSS, including the ability to create user accounts. +- A Mac that is always on and has OS X 10.8 or higher, for running AutoPkgr. +- If the above Mac is not also suitable for testing new software releases (e.g. if it's a distribution point), then you'll also need another Mac for testing. +- At least one full workday. Allow at least 4 hours to step through the example exercises with Firefox, and another 2-4 hours to add additional apps and customized workflows. Add another 2-4 hours to write decent documentation once you've got things working. + +  + +## Standardized software distribution + +Starting with a very big-picture view, consider the following illustration of the standard software distribution cycle. __This is the cycle upon which Auto Update Magic is built.__ -In this article, I'll take you thorugh a new method to keep your Mac apps updated with your Casper JSS. Following the directions below, you can start automating your Mac app patching _today_. +![sw-dist-cycle.png](README-images/sw-dist-cycle.png) +1. New software is released by the developer. +2. The software is downloaded and basic dev testing is performed by the IT team. (i.e. "Does it install? Will it launch?") +3. The software is installed and tested on "trusted testers," which represent a fraction of the company's total Macs. +4. Feedback is collected from the trusted testers about whether the new version of the software works well. +5. Upon receiving positive feedback, the IT team makes the software available to the rest of the company, either by Self Service or automatically. -## Status quo +This process may vary slightly depending on the software you're deploying and your organizational needs, but you'll find that most software deployments follow this path. -First, let me share with you the way I used to keep apps updated in Casper. This isn't necessarily a "best practice," but simply one method that worked well for me. +We will be automating some of these steps, but not all. To adapt a popular mantra: -- The IT team downloads the installer package (or creates it with Composer), and puts it into Casper. -- A **smart group** is created to select computers with an out of date version of this app. -- A recurring **"trigger" policy** is scoped to the smart group, and triggers a script. -- The **script** checks to see whether the app to be updated is currently open. -- If the app is not currently open, the script triggers an **"installer" policy** which installs the update and runs recon. +![mantra.png](README-images/mantra.png) -This process works fine, but it has several pain points. +Let's walk through each step in the above process using Firefox as an example and focus on how we can automate and standardize things to make our lives easier, shall we? + +  -- Composing a new package of each software version is tedious and error-prone. -- The smart group criteria must be manually updated with each version. -- Waiting too long to update Casper may result in newer versions of apps being overwritten with older versions — not good at all. -- Trigger policies basically double the number of policies you must maintain. -- The installer must be updated manually with each new version of the software, which can be tedious in itself. +### 1. New Release -The benefit of a workflow like this is you maintain total control over your available software updates, but it's tedious, prone to errors, and requires babysitting. There's got to be a better way, right? +![sw-dist-cycle.png](README-images/sw-dist-cycle-01.png) +Let's start from the beginning. It's no fun to manually check for new software. Instead, the combination of [AutoPkgr](https://github.com/lindegroup/autopkgr) and [AutoPkg](https://github.com/autopkg/autopkg) can do this for you. You can configure new software checks to happen on a scheduled basis, and you can even receive notifications when new software is found. -## New tools to the rescue + -Fortunately, several tools have emerged in the last year that have significantly improved this workflow. +#### Exercise 1: Automate checking for new software with AutoPkgr -### [AutoPkg](https://github.com/autopkg/autopkg) +1. Download the [latest release of AutoPkgr](https://github.com/lindegroup/autopkgr/releases/latest). -AutoPkg is a relatively new command-line tool from [Greg Neagle](https://github.com/gregneagle), [Tim Sutton](https://github.com/timsutton), and [Per Olofsson](https://github.com/MagerValp), that automatically packages OS X software for easy distribution. It uses community-contributed "recipes" to produce a neat and tidy .pkg file that can be used with many deployment systems, including Casper. +2. Copy the app to your __Applications__ folder, then launch it from there. -### [JSSImporter](https://github.com/sheagcraig/JSSImporter) +3. If AutoPkg is not already installed, click the __Install AutoPkg__ button and enter your password when prompted. -Conceived by [Allister Banks](https://github.com/arubdesu) and rewritten by [Shea Craig](https://github.com/sheagcraig/), JSSImporter serves as the direct link between AutoPkg and your JSS. Combined with a `.jss` recipe, JSSImporter allows automatic creation of the smart groups, policies, and packages necessary to distribute apps in Casper. +4. If Git is not already installed, click the __Install Git__ button and enter your password when prompted. -### [AutoPkgr](https://github.com/lindegroup/autopkgr) +5. On the __Repos & Recipes__ tab, check the box to add the topmost repository, `https://github.com/autopkg/recipes.git`. -AutoPkgr is a Mac app that puts a friendly face on AutoPkg and makes it super easy to get started using it. It was created by [James Barclay](https://github.com/futureimperfect), [Josh Senick](https://github.com/jsenick), and Elliot Jordan (that's me) at the [Linde Group](http://www.lindegroup.com/), with significant help from [Eldon Ahrold](https://github.com/eahrold). +6. In the list of recipes at the bottom of the window, check the box to add __Firefox.download__. (You can use the "Filter recipes" box to narrow down the list.) + ![firefox-download.png](README-images/firefox-download.png) -The goal of AutoPkgr is to make it simple and straightforward to start using AutoPkg, and to that end, we're happy to announce that **AutoPkgr now supports basic AutoPkg-to-JSS integration out of the box**. +7. Switch to the __Schedule__ tab, and configure the schedule to run as desired. Check the __Enable scheduled AutoPkg runs__ box. -![Casper Suite integration](doc-images/autopkgr-casper-integration.png) + ![schedule.png](README-images/schedule.png) -Here's how to use it: +8. Switch to the __Notifications__ tab, and configure the notifications as desired. -1. Open AutoPkgr, and use the **Install** tab to install Git and AutoPkg if you haven't already. -2. Click on the **Folders & Integration** tab. -3. Enter your JSS URL and API account credentials. Click **Connect**. -4. Install JSSImporter when prompted. -5. Enter the read/write password for each distribution point when prompted. -6. Switch back to the **Repos & Recipes** tab. Filter for recipes that end in `.jss`, and add the ones you need. -7. On the **Schedule** tab, click **Check Apps Now**. The apps you selected will be imported automatically to your JSS! + ![notifications.png](README-images/notifications.png) +9. Switch back to the __Repos & Recipes__ tab, and click __Run Recipes Now__. After a minute or so, assuming you haven't run this recipe before, you should receive notification that a new version of Firefox is available. + +Congratulations! You've just configured AutoPkgr to check for updates regularly, and to tell you when a new version is released. For Firefox in your organization, Phase 1 of the software distribution cycle is now fully automated. Let's move on to Phase 2. + +  -## The Magic +### 2. Development -Here's the magic you've been waiting to see. Fully automatic updates using Casper. +![sw-dist-cycle.png](README-images/sw-dist-cycle-02.png) -[![Click here to view the (silent) screencast](doc-images/screencast-thumbnail.png)](https://www.youtube.com/watch?v=ZUD8C8Tr3XI) +Now that we know there's a new release, we've got to make sure it passes some basic "lemon tests." There's a type of recipe called an install recipe that will actually install the app on the Mac running AutoPkg. Let's schedule that recipe to run regularly, so that our IT lab test Mac is always up to date for local testing. -#### On the JSS + -1. AutoPkgr triggers AutoPkg to run regularly (perhaps every 4 hours). -2. When new versions of apps are detected, they are _automatically_ imported into the JSS, assigned to a policy, and scoped to a smart group. +#### Exercise 2a: Install new software for local testing -#### On the managed Mac +1. Open AutoPkgr and navigate to the Repos & Recipes tab. -1. The JAMF agent runs a recurring check-in. (This normally happens _automatically_ every 15 or 30 minutes; we have used Terminal here to call it manually with the same effect.) +2. Uncheck the __Firefox.download__ recipe, and check the __Firefox.install__ recipe instead. - ![magic-01.png](doc-images/magic-01.png) + ![firefox-install.png](README-images/firefox-install.png) -2. Firefox is not up to date. A single **Auto Update Magic** policy runs a script on each managed Mac that determines whether the apps are running. +3. Click __Run Recipes Now__. - ![magic-02.png](doc-images/magic-02.png) +4. After a minute, you should receive notification that Firefox was installed. Check the Applications folder on your AutoPkgr Mac and verify that this is true. -3. If not, the script calls the policy that updates them automatically. +5. Does it launch? Open Firefox and see. Does it work as expected? Browse to a few websites. - ![magic-03.png](doc-images/magic-03.png) +Great! You've just configured AutoPkgr to automatically update Firefox on your AutoPkgr Mac. This makes it easy for you to test apps to make sure there are no major flaws before you dive in further. -4. Firefox is now up to date. +Next, we need to prepare the software for mass distribution, which often includes creating a package that can be used by Casper. Of course, this is what AutoPkg was born to do! Let's run the __Firefox.pkg__ recipe, and see the nice tidy pkg file that results: - ![magic-04.png](doc-images/magic-04.png) + +#### Exercise 2b: Create a deployable pkg file using AutoPkg -That's the end goal: completely automated patch management, from end to end. But let's back up and put the pieces together. +1. Open AutoPkgr and navigate to the __Repos & Recipes__ tab. -There are three possible levels of automation that you can use AutoPkgr to enact. Here's a detailed look at each level. +2. Check the box to enable the __Firefox.pkg__ recipe. +3. Click __Run Recipes Now__. After a minute, you should receive notification that a new Firefox package was built. -### Level 1: Self Service +4. Switch to the __Folders & Integration__ tab, then click the __Open in Finder__ button next for the AutoPkg Cache folder. Open the __com.github.autopkg.pkg.Firefox_EN__ folder. (Note: This matches the identifier of the recipe, which you can see in AutoPkgr's recipe list.) -This workflow, which is the default for JSSImporter, is a very safe and conservative way to begin testing app packages in your Casper environment. It imports app updates into Casper and makes them available to the Testing group via Self Service. Our new version of AutoPkgr makes this super easy to configure. +5. Verify that a Firefox package was created. You may also want to use a tool like [Pacifist](https://www.charlessoft.com/) or [Suspicious Package](http://www.mothersruin.com/software/SuspiciousPackage/) to inspect its contents. As you can see below, the app installs at the expected location, and with the expected version. Looks good. + + ![firefox-pkg-inspection.png](README-images/firefox-pkg-inspection.png) + +6. Copy the package to a test Mac or VM and try installing it. Verify that it produces a working copy of Firefox. + + It may also be worth launching the app as a non-admin user after installing the package in your test Mac or VM. Occasionally this will reveal permissions issues that need to be corrected upstream (e.g. in the pkg recipe). + +Great, now we have a deployable package that installs what we expect it to install. Now we're ready to start testing the app on a larger scale. + +  -Here's how to set it up, assuming you already have a working JSS: +### 3. Testing -1. Create a static computer group on your JSS called **Testing**. Add one or more test computers to the group. -2. Create an account on your JSS with Create, Read, and Update access to the following objects: +![sw-dist-cycle.png](README-images/sw-dist-cycle-03.png) + +Small batch testing (or "staging") allows us to catch _small_ problems in the wild before they become _large_ problems in the wild. + +In order to do proper testing, I recommend that you reach out to your organization and designate/ask for volunteers to help the IT department test new software. They should understand that they'll have first access to new features and the ability to help guide deployment strategy, but they will also have the responsibility to submit feedback to IT in a timely manner. + +Once you've got a group of "trusted testers," we can use JSSImporter to automate the process of sending them new software. Specifically, we'll create Self Service policies for testers that are automatically updated whenever new software is released. This is the default behavior for recipes in the official [jss-recipes](https://github.com/autopkg/jss-recipes#jss-recipes) repo, and is a good, safe way to get started integrating AutoPkg with Casper. + + + +#### Exercise 3a: Automatically create Self Service policies for testing new software + +1. Create a (static or smart) computer group on your JSS called __Testing__. Add the testers' computers to the group. + +2. Create an account on your JSS with __Create__, __Read__, and __Update__ access to the following objects: - Categories - Computer Extension Attributes - File Share Distribution Points (only needs Read access) @@ -137,237 +206,524 @@ Here's how to set it up, assuming you already have a working JSS: - Scripts - Smart Computer Groups - Static Computer Groups -3. Install version 1.1 or higher of [AutoPkgr](https://github.com/lindegroup/autopkgr/releases/latest). -4. Open AutoPkgr and click the buttons to install Git and AutoPkg, if you haven't already. -5. In AutoPkgr, click on the **Folders & Integration** tab. -6. In the **Casper Suite integration** section, enter your JSS URL, API username, and API password. Then click **Connect**. -7. When prompted, follow the instructions to install JSSImporter. -8. When prompted, enter the read/write password for each distribution point. - -You'll also want to make sure you have a few `.jss` recipes selected. AutoPkgr will automatically add the [sheagcraig/jss-recipes](https://github.com/sheagcraig/jss-recipes) repo so you'll have a few to choose from. If the `.jss` recipes you choose have any parent recipes, be sure to add their repos too. (For example, `Firefox.jss` requires adding the [autopkg/recipes](https://github.com/autopkg/recipes) repo.) - -When a `.jss` recipe runs, the package is uploaded to your distribution points, a Self Service policy is created and scoped to a new smart group. As a result, computers in the Testing group with less than the latest version of the app should now be able to install the latest version through Self Service. - - -### Level 2: Auto to Some - -This workflow is more automatic than the Self Service policy above, but still allows for deliberate testing prior to mass deployment. The script, recipe, and template customizations require an administrator who is comfortable with editing XML files and shell scripts. - -Here's how to set it up with `Firefox.jss`, assuming you've already done the Level 1 steps above: - -1. Create a new category called **Auto Update** (in **Settings > Global Management > Categories**). -2. Upload my `auto_update_magic.sh` script (included in this repo) to your JSS. - 1. Assign it to the **Auto Update** category. - 1. In the **Options** tab, set parameter 4 to **Hours between auto updates**. - 1. Click **Save**. -3. Create a policy called **Auto Update Magic**: - 1. Assign it to the **Auto Update** category. - 1. Have it trigger on **Recurring Check-in**, and also on **Startup**. - 1. Set the **Execution Frequency** to **Ongoing** (or less frequently if you like). - 1. Add the `auto_update_magic.sh` script into the policy. (Doesn't matter whether you choose Before or After.) - 1. Set the parameter value for **Hours between auto updates** to your preferred number. (I recommend an integer between 1 and 8, inclusive.) - 1. Set the **Scope** to the **Testing** static computer group. - 1. Click **Save**. -4. In AutoPkgr, locate the `Firefox.jss` recipe, and right-click on it. Choose **Create Override**. Right-click again and choose **Open Recipe Override** to open the file in a text editor. -5. In the `Input` dictionary, remove all but this key: -``` - POLICY_CATEGORY - Auto Update -``` -6. Copy the `Firefox.png`, `PolicyTemplate.xml`, and `SmartGroupTemplate.xml` files from `~/Library/AutoPkg/RecipeRepos/com.github.sheagcraig.jss-recipes/` to `~/Library/AutoPkg/RecipeOverrides/`. -7. Edit the `PolicyTemplate.xml` file with a text editor. - 1. Remove the contents of the `self_service` section. - 2. In the `general` section, change the name of the policy: - `Auto Update %PROD_NAME%` - 3. Also in the `general` section, create the custom trigger: - `autoupdate-%PROD_NAME%` -8. Return to the `auto_update_magic.sh` script on your JSS and add new lines as appropriate to the RECIPE_NAME and BLOCKING_APPLICATION sections, using the examples to guide you. For example: -``` -RECIPE_NAME=( - "Firefox" -) -BLOCKING_APPS=( - "Firefox" -) -``` -If no blocking apps are required (for example, if you want to go ahead and update Flash regardless of which browsers are running), then speficy a fake blocking app name. -``` -RECIPE_NAME=( - "Firefox" - "AdobeFlashPlayer" -) -BLOCKING_APPS=( - "Firefox" - "NoBlockingAppForAdobeFlashPlayer" -) -``` -9. Open AutoPkgr and click **Check Apps Now**, or run `autopkg run Firefox.jss` in Terminal. -10. Verify that your policy and smart group were created successfully. +3. Open AutoPkgr and click on the __Folders & Integration__ tab, then click __Install JSSImporter__. Enter your admin password when prompted. + +4. Click the button that now says __Configure JSSImporter__. + +5. Enter the JSS URL, API username, and API password (for the account you created in step 2 above). Then click __Connect__. + + ![configure-jssimporter.png](README-images/configure-jssimporter.png) + +6. If you use file share distribution points, you'll be prompted to enter their passwords. If you use a cloud distribution point or JDS as your master, check the __Use Master JDS__ checkbox. Click __Save and Close__. + +7. Return to the __Recipe & Repos__ tab, and find (but don't check the box for) __Firefox.jss__ in the recipe list. + +8. Right-click on __Firefox.jss__ and choose __Create Override__. + +9. Name the override __Firefox-testing.jss__. + +10. The new recipe should appear in AutoPkgr's recipe list. Right-click on __Firefox-testing.jss__ and choose __Set Recipe Editor__. Select your preferred text editor. (If you don't have one, I suggest [TextWrangler](http://www.barebones.com/products/textwrangler/) to get you started. Don't use TextEdit, Pages, or Word.) + +11. Right-click on __Firefox-testing.jss__ again, and choose __Open Recipe Override__. + + Does this look familiar? If you've seen Apple preference files before, you'll recognize this as a plist (property list) file. + +12. Change the CATEGORY to __Web Browsers__, but leave the POLICY_CATEGORY and everything else as-is. The CATEGORY key/value pair will look like this: + + ``` + CATEGORY + Web Browsers + ``` + + This is just an example; you can change the category to whatever you want. The point I'm illustrating is that a recipe "override" allows you to override specific keys in pre-fabricated recipes. Overrides also allow you to name your recipes in a consistent manner, as with the __-testing__ suffix we're using here. This makes it easier to find in the AutoPkgr recipe list later. + +13. Save, then quit your text editor. I have provided an example __Firefox-testing.jss.recipe__ file in the [Exercise3a](Exercise3a) folder in this repo. Compare your finished override to that file to make sure it looks the same. + + If so, congratulations! You just created a recipe override. + + :warning: Note: Now we're ready to run our __Firefox-testing.jss__ recipe override. Although you could easily run this recipe in AutoPkgr, I want you to use the Terminal for two reasons: + + - It's important to know what's happening behind the scenes. + - Knowing basic `autopkg` commands in Terminal will make things much easier to troubleshoot later. -### Level 3: Auto to All +14. Open Terminal, type `autopkg run -v Firefox-testing.jss` and press Enter. Observe the messages that appear on screen. The first word of each line indicates which "processor" AutoPkg is currently running. -This is the "magic" workflow demonstrated in the screencast above. It is by far the most automatic way to update apps using Casper, but should be implemented with great care. The apps are updated quickly and without testing, so it's likely that this will cause something to break someday. Only do this for non-mission-critical apps, and only after you've tested using Level 2 above. +If everything goes according to plan, you'll see the following processors make an appearance: MozillaURLProvider, URLDownloader, EndOfCheckPhase, AppDmgVersioner, PkgRootCreator, Copier, PkgCreator, and JSSImporter. + +The output in Terminal will also reflect the changes made to your JSS: -1. Navigate to `~/Library/AutoPkg/RecipeOverrides` and edit the `SmartGroupTemplate.xml` file. -2. Remove these lines from the file: ``` - - Computer Group - 2 - and - member of - Testing - +The following changes were made to the JSS: +Package Categories Groups Scripts Extension Attributes Policy Icon +------- ---------- ------ ------- -------------------- ------ -  +Firefox-40.0.3.pkg Firefox-update-smart Install Latest Firefox Firefox.png ``` -3. Set the scope of the Auto Update Magic policy to **All Managed Clients**. -This will install automatic updates for all Macs, rather than just the ones in the Testing group. +If any errors occur, read through the last few lines of output (including any "traceback" messages), and you may be able to tell what went wrong. + +It's not uncommon for a 404 error to occur the first time you run each recipe, because Casper's API doesn't reliably handle uploading icons for Self Service policies. If this happens, try running the recipe again a second time. + +Once your `autopkg` run is error-free, navigate to your JSS web app and log in. You should see the following new items: + +- A package with the latest version of Firefox. +- A smart group called "Firefox-update-smart" that contains Macs in the Testing group which don't have the latest version of Firefox. +- A policy called "Install Latest Firefox" that allows your testers to install Firefox via Self Service. + +![firefox-jss-policy.png](README-images/firefox-jss-policy.png) + +Once the Self Service policy is created in Casper, you should email your testers to let them know there's new software to install. Ask them to install the app, kick the tires thoroughly, and let you know within a specific time whether they have anything to report. + +Finally, be sure to return to AutoPkgr and check the box to enable the __Firefox-testing.jss__ recipe and uncheck the __Firefox.pkg__ recipe. + +  + +### 4. Feedback + +![sw-dist-cycle.png](README-images/sw-dist-cycle-04.png) + +It's important not to skip this step! Collecting feedback from your testers ensures that you'll have the best chance possible of finding show-stopping bugs before you deploy the software to the rest of your company. It also makes people within your company more aware of an important IT process. + +The process of collecting feedback from your testers can be made easier by creating a Self Service plugin that points to a Google Form. I won't provide specific instructions for doing that, because you and I both know that this article is already going to be way too long. + +Once you've collected feedback, your IT department will need to make a decision about whether to proceed with deployment or hold back. In case you need to hold back, I've provided a [Rollback Plan](#rollback-plan) below. + +  + +### 5. Deployment + +![sw-dist-cycle.png](README-images/sw-dist-cycle-05.png) + +Here comes the really fun part! Once you've decided to proceed with deployment, you'll probably want to consider two deployment methods, depending on the specific software and how important it is to your organization. + +- __Self Service policy__ for delivering the newly tested and approved version of Firefox to your company Macs on an opt-in basis. The Self Service policies are easy to set up and maintain, and we'll do that in [Exercise 5a](#e5a). + +- __Auto Update policy__ for silently updating Firefox on all the Macs that have an outdated version of it. The Auto Update policies are admittedly complex to set up, but are relatively painless to maintain after that. We'll tackle that in [Exercise 5b](#e5b). + +__Historical note:__ The [previous version](https://github.com/homebysix/auto-update-magic/tree/v1.0) of this workflow used a Casper "trigger" policy instead of a local LaunchDaemon. There are some pros and cons to the two different approaches: + +|   | Script runs in Casper policy | Script runs via local LaunchDaemon | +|:---:|:--- |:--- | +| __Pros__
:thumbsup: | - Easy to update the script centrally. | - Much cleaner log output.
- More granular adjustment of checking schedule. | +| __Cons__
:thumbsdown: | - The Casper policy logs fill with output, even if no updates were installed. | - Must repackage and reinstall LaunchDaemon/script pair when making changes to schedule or updated apps. | + +I now prefer the LaunchDaemon method, which is detailed in [Exercise 5b](#e5b) below. If you prefer the old Casper policy method, [version 1.0 of this document still contains those instructions](https://github.com/homebysix/auto-update-magic/tree/v1.0#level-3-auto-to-all). + +:warning: Note: The following script, recipe, and template customizations require an administrator (that's you!) who is comfortable with editing plist files and shell scripts. Also, be sure to proceed with a sleeves-rolled-up attitude, since troubleshooting and tweaking will more than likely be necessary. Be sure you test these methods on a non-production JSS before making changes to your production environment. + + + +#### Exercise 5a: Promote Self Service policies to use new packages + +1. If you don't already have one, manually create a Self Service policy on the JSS that installs Firefox for anybody who wants it. Here's an example: + - __General__ + - Name: Firefox + - Category: Productivity + - Enabled: Yes + - Trigger: None + - Execution Frequency: Ongoing + - __Packages__ + - Firefox-39.0.5.pkg + (or any old version of Firefox, as long as the package name is in the format "Firefox-x.x.x.pkg") + - __Scope__ + - Targets: All Computers + - __Self Service__ + - Make this policy available in Self Service: Yes + - Description: Popular web browser. + - Icon: Upload a 128x128 Firefox icon in png format. + +2. Install the jss_helper command line tool. You can do that with the following command in Terminal. (Substitute `~/Developer` for the directory you'd like to store jss_helper in. Create the directory first, if needed.) + + ``` + cd ~/Developer + /usr/local/git/bin/git clone https://github.com/sheagcraig/jss_helper + ``` + + (Using Git to install jss_helper makes it trivial to keep the tool up to date as new versions are released, using `git pull -C ~/Developer/jss_helper`. You may want to make a note to run this command every so often.) + +3. Configure jss_helper with your Casper API information, substituting your JSS URL, JSS API username, and JSS API password for ``, ``, and ``: + ``` + defaults write com.github.sheagcraig.python-jss jss_url + defaults write com.github.sheagcraig.python-jss jss_user + defaults write com.github.sheagcraig.python-jss jss_pass + ``` + + :warning: Note: If you have characters or symbols in your password, you may want to use a text editor to verify that the ~/Library/Preferences/com.github.sheagcraig.python-jss.plist file contains the correct password after you run the above commands. Certain characters don't parse as expected in Terminal and may require you to enter them directly into the plist. + +4. Now, use jss_helper to "promote" your Self Service policy to the latest version of Firefox: + + ``` + cd ~/Developer/jss_helper + ./jss_helper promote + ``` + + :warning: Note: If your JSS uses a self-signed certificate, you'll get errors that say `InsecureRequestWarning: Unverified HTTPS request is being made.` This is normal, but you should really invest in a proper SSL cert if this is your production JSS. + +5. All the policies for which there is a newer package available will be listed. Type the number corresponding to your "Firefox" policy. + +6. Confirm that the `(CURRENT)` package is your previously-approved package, and the `(DEFAULT)` package is the one you just finished testing and is now approved. If so, press __Enter__. (To cancel, press Control-C.) -For each recipe you add, be sure to: +Cool! Your Self Service policy has just been updated to use the new Firefox package. -1. Make and edit a recipe override. -2. Add the app's name to the `auto_update_magic.sh` script on your JSS. -3. (Optionally) Copy the icon file (in PNG format) to the RecipeOverrides folder. (This is only needed if you plan to use Self Service policies.) + -If you add a recipe like `AdobeFlashPlayer.jss`, `OracleJava7.jss`, or `Silverlight.jss`, be sure to also add the supporting files such as `_____SmartGroupTemplate.xml` and `_____ExtensionAttribute.xml`. +#### Exercise 5b: Automatically create Auto Update policies +Now strap yourselves in and get ready. We're going to enter the wormhole... Installing newly tested and approved updates on all managed Macs using some "Auto Update Magic." Here's what we'll be configuring in order to make that happen: -### Bonus: Creating both Self Service and Auto Update policies +- __Recipe override and JSSImporter templates__ - A set of AutoPkg recipe overrides will be run _manually_ in order to create/update policies that automatically update Firefox on all managed Macs when a custom trigger is called. -Chances are, you've got Self Service policies that you want to keep up to date, even if a separate policy automatically updates the already-installed apps. Better to deploy apps that are already up to date, right? +- __Script__ - The auto_update_magic.sh script on all managed Macs checks to see whether Firefox is running, and if not, it uses the custom trigger to execute the "auto update Firefox" policy. -Here's how to run the Level 2/3 Auto Update recipes side-by-side with recipes that keep Self Service up to date. +- __LaunchDaemon__ - A LaunchDaemon on all managed Macs runs the auto_update_magic.sh script on a regular basis. + +Now you can start to see how this is all going to fit together. The LaunchDaemon basically serves as a recurring "do I need updates?" check, the script makes sure the installation won't stomp on any running apps, and the policy (created by our recipe override) actually does the work of updating. + +Here we go! Let's start with the recipe override and JSSImporter templates: + +1. Copy the provided __Firefox-autoupdate.jss__, __PolicyTemplate-autoupdate.xml__, and __SmartGroupTemplate-autoupdate.xml__ files from the [Exercise5b](Exercise5b) folder of this repo into your `~/Library/AutoPkg/RecipeOverrides` folder. + + Here is how the files differ from the standard recipes and templates included in jss-recipes: + + - __Firefox-autoupdate.jss__ has the policy category set to "Auto Update," so that all the policies created by __-autoupdate.jss__ recipes will be listed together in the Policies page on the JSS. + - __PolicyTemplate-autoupdate.xml__ uses "Auto Update Firefox" as the policy name, the policy frequency is set to Ongoing, and the policy is triggered by a custom trigger "autoupdate-Firefox". (The reason for this will become clear in [Exercise 5b](#e5b.) + - __SmartGroupTemplate-autoupdate.xml__ includes computers from the entire organization which have an obsolete version of Firefox, rather than being limited to the Testing group only. + +2. Open Terminal and run your __Firefox-autoupdate.jss__ recipe override: + + ``` + autopkg run -v Firefox-autoupdate.jss + ``` + +3. After a moment, you should see the summary of changes made to your JSS. Log in to your JSS and check out the newly created items: + + - A __smart group__ called "Firefox-autoupdate" that includes all Macs with old versions of Firefox. + - A __policy__ called "Auto Update Firefox" that installs Firefox on Macs in the above smart group, but only when the "autoupdate-Firefox" custom trigger is used. + + You can test this policy by running `sudo jamf policy -event "autoupdate-Firefox"` on a test Mac, if you like. + + + +#### Exercise 5c: Configure Macs to check for updates periodically + +1. Open the [Exercise5c](Exercise5c) folder. + +2. Edit the __auto_update_magic.sh__ script with a text editor. Make the following three changes: + - Un-comment line 26, where Firefox's recipe name is specified. + - Un-comment line 46, where Firefox's blocking applications are specified. + +3. Open Terminal and run the script (since `DEBUG_MODE` is on by default, nothing will actually be updated): + + ``` + cd ~/Downloads/auto-update-magic-master/Exercise5c/ + sudo ./auto_update_magic.sh + ``` + +4. You should see the script check whether Firefox is running. If Firefox isn't running, it will say `No apps are blocking the Firefox update.` + + If the script doesn't behave as described above, stop here and troubleshoot before proceeding. + +5. Open the __auto_update_magic.sh__ script in a text editor again, and change `DEBUG_MODE` to `false` on line 65. The script is now ready to deploy. + + :warning: Note: Keep in mind that you'll need to edit this script again if you add more "auto updated" apps in the future. You'll find instructions for doing that in the Adding More Apps section. + +6. Edit the __com.jamfsoftware.jamfnation.auto_update_magic.plist__ file with a text editor. Set the `StartInterval` as desired. (Default is 3600, which is one hour.) + +7. Create a package that you can use to deploy the script and LaunchDaemon. I've made this easy by including a script that does the work for you. Simply open Terminal and type the following: -1. In your RecipeOverrides folder, duplicate the `PolicyTemplate.xml` file. Name the copy `PolicyTemplate-SelfService.xml`. -2. Also duplicate the auto-update recipe override for the app you'd like to update in Self Service. Name the copy (for example) `Firefox-SelfService.jss.recipe`. -3. Edit the `PolicyTemplate-SelfService.xml` file: - 1. Change the `` of the recipe to `%PROD_NAME%`. - 2. Change the `` of the recipe to `selfservice-%PROD_NAME%`. - 3. In the `` section, add `true`. - 4. Expand the `` section as follows: ``` - - true - Install %VERSION% - %SELF_SERVICE_DESCRIPTION% - + sudo ./create_pkg.sh ``` -4. Edit the `Firefox-SelfService.jss.recipe` file: - 1. Make sure the `Identifier` key is unique. For example: `com.github.homebysix.jss.Firefox-SelfService` - 2. Set the `POLICY_CATEGORY` to the desired category. For example: `Web Browsers and Internet Utilities` - 3. Set the `POLICY_TEMPLATE` to the new template file you created: `%RECIPE_DIR%/PolicyTemplate-SelfService.xml` - 4. Remove the `GROUP_NAME` and `GROUP_TEMPLATE` keys. - 5. Also remove the `groups` array forom the `Arguments` section. -5. Open AutoPkgr and check the box for the new -SelfService recipe you created. -It may be useful to refer to the example `Firefox-SelfService.jss.recipe` and `PolicyTemplate-SelfService.xml` files provided in this repo. + Once the package is created, upload it to your JSS using Casper Admin or your JSS web interface. + +8. Create a policy on Casper that will deploy the Auto Update Magic script and LaunchDaemon to all managed computers. Here's an example: + + - __General__ + - Name: Auto Update Magic + - Category: Auto Update + - Enabled: Yes + - Trigger: Recurring check-in + - Execution Frequency: Once per week + - __Packages__ + - auto_update_magic-YYYYMMDD.pkg + (the one you generated in the previous step) + - __Scope__ + - Targets: All Computers + +9. Monitor the logs to ensure that the package is successfully installed on your org's Macs. Soon after their next check-in, they should automatically update Firefox if it isn't running. Hip hip hooray! + +  + +## Further enhancement and advanced workflows + +There are some additional things you can consider doing, if they fit well with your organization's needs. + + + +#### Exercise 6a: Adding More Apps + +Once you're confident the Firefox recipes are working well, you'll most likely want to add more apps to the Auto Update Magic workflow. + +If a [jss recipe](https://github.com/autopkg/jss-recipes) already exists for the app you want to add, this process is super simple. + +1. Create a __-testing.jss__ recipe override. Use the existing __Firefox-testing.jss__ recipe override as a template for this. + +2. Create a __-autoupdate.jss__ recipe override. Use the existing __Firefox-autoupdate.jss__ recipe override as a template for this. + + In most cases, simply changing the recipe Identifier and ParentIdentifier are sufficient, but more complex apps may require a custom smart group template or extension attribute template. + + I've included some examples in the [Exercise6a](Exercise6a) folder for Flash, Chrome, and Java. + +3. Modify the __auto_update_magic.sh__ script to include the trigger and blocking applications. Make sure that the list of triggers and list of blocking applications are in the same relative order. + +4. Use create_pkg.sh to create a new script/LaunchDaemon package for deployment, as you did in [Exercise 5c](#e5c). + +5. Swap the new package into the "Auto Update Magic" policy. If you need it to be deployed immediately, flush the "Auto Update Magic" policy logs. + + + +#### Exercise 6b: Organizing and customizing the testing recipes + +Once you get more familiar with the relationship between recipe overrides and JSSImporter templates, I'd recommend returning to the __-testing.jss__ recipes you created in [Exercise 3a](#e3a) and making some subtle changes: + +- Creation of a policy template called __PolicyTemplate-testing.xml__ with these customizations: + - Policy name is "Test Latest %PROD_NAME%" + This makes it clear to your trusted testers that this is a test policy, as opposed to a normal Self Service policy. + - Policy has a custom trigger called "test-%PROD_NAME%" + This makes it really easy to differentiate policies that are created by AutoPkg from policies that you created manually, when viewing the Policies page on the JSS. + - Policy scope is set to a specific group, using the group's `id` and `name`. + This means that you only need a single "Testing" group, rather than separate AppName-testing smart groups for each app. Greatly reduces smart group bloat. +- Adjusting the `POLICY_TEMPLATE` key in each -testing.jss recipe to point to the new __PolicyTemplate-testing.xml__ file you created. +- Removing keys from the __-testing.jss__ overrides that are not different than the parent recipe. (Only those keys that are different are necessary to include in overrides.) + +I have provided an example __PolicyTemplate-testing.xml__ file as well as modified __-testing.jss__ recipes in the [Exercise6b](Exercise6b) folder in this repo. + + + +#### Exercise 6c: Sending software directly to Self Service policies -If you'd like to add a Dock icon to your Self Service policy, you can do that manually after the first recipe run. Subsequent runs will preserve the Dock icon settings. +:warning: This is the workflow that's most likely to bite you later, because it's deploying directly to production. Proceed with caution. +For certain software, you may want to have updates available immediately in Self Service. This workflow is good for software which meets the following criteria: -## Notes and caveats +- The software is not mission-critical for your organization. +- You do not want to test the software prior to making it available in Self Service, and you understand the risks this introduces. -### Use at your own risk +I have included a policy template and two recipes that you can use as an example for this, in the [Exercise6c](Exercise6c) folder. They all contain `-selfservice`. -This method is on the bleeding edge, and you can bet that there are a few bugs that need squashing. In addition, you may find that not everything works as described in your specific environment. Test thoroughly on a sample Mac before deploying to everybody in your company. + -If you open an [issue](https://github.com/homebysix/auto-update-magic/issues) on this GitHub repo, I'll do my best to help you troubleshoot. But I take no responsibility for any harm caused by over-automation. +#### Exercise 6d: Create installation policies for site-licensed software +If you have a site license for software you'd like to automatically update, you might wonder what the best way to deploy both the app and the license. Here's what I've done: -### Run AutoPkgr on a Mac with access to all DPs +- AutoPkg recipes create a policy that installs the latest version of the app, just like the __-autoupdate.jss__ recipes we created earlier. However, this policy also calls a custom trigger "license-AppName." +- A manually created policy installs the license, and is only triggered by the "license-AppName" trigger. -It's a good idea to run AutoPkgr from a Mac that has network access to all distribution points. If no such Mac exists, you can omit non-accessible DPs by clicking Cancel when AutoPkgr prompts you for a specific DP's password. That DP will be skipped (which means you'll need to use Casper Admin to replicate it manually, or set up a system like rsync to replicate it automatically). +In the [Exercise6d](Exercise6d) folder of this repo, I have included an example of an __-selfservice.jss__ recipe override and policy template for TextExpander which illustrates this method. + -### JSSRecipeCreator +#### Exercise 6e: Store your -autoupdate.jss recipes outside the search path -Shea Craig has written a great tool called [JSSRecipeCreator](https://github.com/sheagcraig/JSSRecipeCreator) that makes it much simpler to create `.jss` recipes. Highly recommended. +For added safety, store your __-autoupdate.jss__ recipes outside of the AutoPkg search path. For example, you could create new folder at ~/Library/AutoPkg/AutoUpdateRecipes and keep them inside. Then when you run the recipe in Terminal, you'll need to refer to the full path, like this: +``` +autopkg run -v "~/Library/AutoPkg/AutoUpdateRecipes/Firefox-autoupdate.jss.recipe" +``` + +The benefit of this adjustment is that the __-autoupdate.jss__ recipes won't appear in AutoPkgr, and are therefore less likely to be executed accidentally or incorrectly included in scheduled AutoPkg runs. + +  + +## Operational workflow + +Once you have finished tweaking Auto Update Magic and are using it to deploy new updates, your standard everyday workflow will look something like the below. Feel free to copy/paste this into your corporate wiki or knowledge base so your IT department can refer to it as they step through the software deployment cycle. + +1. When new updates are issued by the developer, you will receive an email notification similar to the one below. This serves as your indication that new software is now available for testing. + + ![email-notification.png](README-images/email-notification.png) + +2. As soon as possible after receiving the email, log into your designated software testing Mac (on which you configured AutoPkgr to run "install" recipes in Exercise 2a). Launch the app and verify that it basically works. + - If it does not work, follow the [Rollback Plan](#rollback-plan) below. + - If it does work, proceed to step 3. + +3. Send an email to your "testers" group, letting them know that a new version of the software is available. Ask them to open Self Service and click on the Testing category, then install it and run it. Give them a deadline by which they should report the results of their testing to the IT department. + +4. Based on the feedback from the testers, determine whether or not you want to proceed and deploy the app to the rest of the company. + +5. If the decision is made to deploy, log into the Mac running AutoPkgr, open Terminal, and do three things: -### Don't forget to bring your parents + 1. `autopkg run -v "_____-testing.jss"` (substituting the app name) + This allows you to verify that the latest version of the software matches the one you just finished testing, and should prevent you from deploying last-minute surprise updates. + 2. `jss_helper promote` + This steps you through the process of promoting the existing Self Service policy to use the new package. + 3. `autopkg run -v "_____-autoupdate.jss"` (substituting the app name) + Makes the necessary changes to the Auto Update policy and smart group. After this, all Macs in your organization that have older versions of the app will update to the newest version upon their next check-in. -When you add a `.jss` recipe, be sure that you also add the AutoPkg repository of its parent recipe, if a parent recipe exists. AutoPkgr doesn't do this automatically. +And that's all there is to it. +  -### Open source pros and cons +## Rollback plan -Because AutoPkg, JSSImporter, and AutoPkgr all are open source, JAMF is not responsible for their upkeep or support. If you have questions, your JAMF rep will likely not be able to help. +Sometimes your testing reveals show-stopping bugs, or sometimes you simply need to put everything on pause to give you a chance to test further. Here's how to roll back to the last stable version in an orderly manner: -Fortunately, the developers of all the projects above have so far been very responsive to questions and advice-seekers. +- __Disable the app's -testing.jss recipe in AutoPkgr.__ + This will prevent new versions from showing up in Self Service for your testers. +- __Also disable the app's -selfservice.jss recipe, if it exists.__ + This will prevent new versions from automatically being placed into Self Service for everybody else. -### Automatically deploying plugins like Flash and Java + (Something to consider: If this app is the kind that produces show-stopping errors, you may want to include it in the __-testing.jss__ workflow rather than using a __-selfservice.jss__ recipe at all.) -For software like Adobe Flash Player that doesn't have an associated "app," you may want to create a separate FlashPolicyTemplate.xml file that uses `true` instead of `autoupdate-%PROD_NAME%`. See the files in this repo for an example of the Flash recipe override and policy template I use. (Note: This will not check whether web browsers are running, so update at your own risk.) +- __Manually adjust the policies and smart groups as necessary__ to deploy the old, stable version of the app to the people who need it. +- __Enable the app's pkg recipe.__ + This ensures you'll receive notification when a new (and hopefully more stable) version of the app is released, so that you can choose whether to resume testing. -### Always-on apps like Dropbox +Once the crisis has passed and a newer version of the app is available: -The methods above don't yet work for always-running apps like Dropbox, because it's impossible for Casper to launch apps with the current user's context. A LaunchAgent-based solution may be in the works, and we'd welcome your contribution if you'd like to help craft it. +- __Re-enable the -testing.jss recipe and disable the pkg recipe.__ + This will allow you to resume testing the app according to the [Operational Workflow](#operational-workflow) above. +  -### A few troubleshooting tips +## Troubleshooting -- Be sure Casper Admin and AutoPkgr are not running at the same time. Otherwise one or the other may fail to mount the distribution points. +No doubt you realize by now that this is a complex workflow with many moving parts. It's important to know what parts are involved, because it will make troubleshooting easier for everybody involved: +- __AutoPkg__ + The command-line tool that uses recipes to check for app updates and automatically package them for distribution. -## Acknowledgements +- __AutoPkgr__ + The Mac app that schedules AutoPkg recipe runs to occur periodically and notifies you of their results. It also allows you to easily manage the recipes, overrides, and repos. -Auto Update Magic stands on the shoulders of giants. Specifically, I'd like to thank [Eldon Ahrold](https://github.com/eahrold) and [James Barclay](https://github.com/futureimperfect) for their work on adding the new JSS integration features to AutoPkgr. +- __Recipes and overrides__ + The instructions that AutoPkg follows in order to download new software, create packages, and trigger JSSImporter. -And of course we couldn't have done that without significant help from [Shea Craig](https://github.com/sheagcraig), who built upon [Allister Banks](https://github.com/arubdesu/)'s original jss-autopkg-addon. +- __JSSImporter__ + The AutoPkg processor that uploads packages to your JSS and creates policies and groups based on XML templates. -And none of the above would have happened at all if not for AutoPkg, the amazing, stable, and infinitely useful packaging tool by [Greg Neagle](https://github.com/gregneagle), [Tim Sutton](https://github.com/timsutton), and [Per Olofsson](https://github.com/MagerValp). The Mac admin community owes them a huge thanks. +- __Casper API__ + The API for which JSSImporter templates are created. Pointing a browser at https://yourjss.pretendco.com:8443/api is a good idea when you're modifying JSSImporter template XML files. +Here are some general tips for troubleshooting common issues: -## Files included in this repo: +### Remove one layer and try again -In this repository, I've included copies of the files mentioned above. These should serve as useful starting points, but feel free to tweak and customize them for your own particular environment. And remember you can see the original unmodified files anytime at `~/Library/AutoPkg/RecipeRepos/com.github.sheagcraig.jss-recipes`, for comparison. +Getting an error while running a recipe in AutoPkgr? Run the recipe in Terminal instead, and see if the error persists. If it does, then it's not an AutoPkgr problem. +If you're having trouble running a jss recipe, try running its parent pkg recipe once. If the pkg recipe still fails, try running its parent download recipe. -### Scripts +It's not uncommon for recipes to produce errors as a result of upstream changes — for example, the software developer could have redesigned their website and therefore the direct download URL referenced in the download recipe is no longer correct. Alerting the recipe author by opening an issue on their repository's GitHub page is an excellent idea. Their repository is probably listed on [this page](https://github.com/autopkg/). -- **auto_update_magic.sh** policy script +### Check for bad recipe overrides -This is the script used by the "trigger" policy in order to determine whether apps that need updating are currently running. If the apps aren't running, the script calls the appropriate custom policy trigger for the app updater. +Whenever you finish editing a recipe or a recipe override, I recommend running a simple plist "linting" command to make sure that the recipe doesn't contain any major syntax errors. Here is the command you can use to lint all your overrides at once: +``` +find ~/Library/AutoPkg/RecipeOverrides/ -type f -iname "*.recipe" -exec plutil -lint "{}" \; +``` -### RecipeOverrides +### Check for missing parent recipes -- **Firefox.jss** recipe override +For recipes that have parent recipes (which all jss recipes do), you must also make sure that the repo that contains the parent recipe is present on disk. AutoPkgr attempts to warn you about recipes with missing parents by showing you a :warning: icon next to the recipe in the list. -This recipe determines what happens when autopkg runs the Firefox.jss recipe. It's a good one to use as a template for other apps. +However, the parent recipes sometimes _also_ have parent recipes. You may need to trace the chain backwards to ensure that all necessary repos are added. -Note that there is a ParentRecipe specified, so you should subscribe to the `github.com/autopkg/recipes` repo. +If you get an `EOF` error during recipe runs, the likelihood is high that you're missing a parent recipe somewhere. -- **Firefox-SelfService.jss** recipe override +### Test the LaunchDaemon and script pair -This recipe allows you to run a Firefox auto update policy side-by-side with another Firefox policy for Self Service. +If your AutoPkg recipes are working as expected but Macs still aren't automatically updating, dig into the client-side components to see what could be going on. This is pretty simple, since there are only two client-side components: the LaunchDaemon and the auto_update_magic.sh script. -- **PolicyTemplate.xml** policy template +On a managed Mac, open Terminal and run the following command to determine whether the LaunchDaemon is running: -This determines the parameters of the policy updated when a standard `.jss` recipe runs. You will modify this file if you need to change the trigger used, or add Self Service information to the policy, for example. +``` +sudo launchctl list | grep auto_update_magic +``` -- **PolicyTemplate-SelfService.xml** policy template +If everything is working normally, you'll see something like this: -This determines the parameters of the policy updated when a `_____-SelfService.jss` recipe runs. +``` +- 0 com.jamfsoftware.jamfnation.auto_update_magic +``` + +If not, try these two commands to unload and reload the LaunchDaemon: -- **SmartGroupTemplate.xml** smart group template +``` +sudo launchctl unload -w /Library/LaunchDaemons/com.jamfsoftware.jamfnation.auto_update_magic.plist +sudo launchctl load -w /Library/LaunchDaemons/com.jamfsoftware.jamfnation.auto_update_magic.plist +``` -This determines the criteria of the smart group updated when the `.jss` recipe runs. You will modify this file if you need to scope a policy all managed Macs, rather than just to the "Testing" static computer group. +If you've confirmed that the LaunchDaemon is running, but the updates still aren't happening, try running the following on a managed Mac: -- **AdobeFlashPlayer.jss.recipe** recipe override +``` +sudo time /Library/Scripts/auto_update_magic.sh +``` -This is an example recipe for Adobe Flash Player. This example updates Flash without quitting any browsers, which is only appropriate if the users in your environment unanimously use Google Chrome. +This will force the script to run immediately and check for updates, and install any it finds. It will also show you how long the process takes, for benchmarking against other Macs in your organization. -- **AdobeFlashPlayerPolicyTemplate.xml** policy template +### Find and fix loopers -This is an example policy template for Adobe Flash Player. (This template does not close browsers before updating Flash. I'll provide a policy template and script that does that in a future update.) +Under certain circumstances, computers will repeatedly execute the Auto Update policies every hour. This is because the computer still meets the smart group criteria associated with the policy. __This is fixable.__ +Here's how to find loopers: -## Comments and suggestions +1. Allow your Auto Update policies to run for at least 2-3 hours, to build up policy logs that can be used for investigation. -I'd love to hear your feedback! If you find a problem, feel free to open an [issue](https://github.com/lindegroup/autopkgr/issues) on our AutoPkgr Git repo, and we'll do our best to help troubleshoot. Or if you'd like to ask a general question or give some praise, feel free to join us on our [Google Group](https://groups.google.com/forum/#!aboutgroup/autopkgr-discuss) or in the [JAMFNation forums](https://jamfnation.jamfsoftware.com/discussion.html?id=12280). +2. Open the policy log for each of your Auto Update policies. + +3. Check to see whether the same computer is executing the policy multiple times in a row, as shown below: + + ![policy-looping-01.png](README-images/policy-looping-01.png) + +If you have a large fleet of Macs and it's difficult to see whether the same computer appears multiple times in the policy logs, try this instead: + +1. From one of the Auto Update policy logs, select a random sample of 10-20 Macs and open their individual policy histories. (Hold __Command__ while you click on each computer to open them in new background tabs.) +2. Filter for Auto Update to see whether they've executed the same Auto Update policy repeatedly, as shown below: + + ![policy-looping-02.png](README-images/policy-looping-02.png) + +If you see looping happening, here's how to fix it: + +1. __Force an inventory on the problem computers.__ + Sometimes it's as simple as a failed recon run. + +2. __Check the application's path.__ + If an old version of an application lives somewhere other than in the Applications folder, the installer won't overwrite it with the new version of the app. There are two solutions: + + - If the old version of the app that lives outside the Applications folder is no longer needed, delete it and run inventory again. + + - If the old version of the app is necessary, rename the app. For example, if a web developer needs to keep Firefox 34 for testing, simply have them rename the old app from `Firefox.app` to `Firefox 34.app`. + +3. __Check your smart group logic.__ + If you've tried both of the above and the policy is still looping, check the smart group template that the -autoupdate.jss recipe override is using. You might need to add another criterion. + +  + +## Getting help + +### Community support + +If you need help setting up "Auto Update Magic" in your organization, or if you're encountering a problem which the [Troubleshooting](#troubleshooting) steps above don't resolve, you'll find many knowledgeable people in the following locations: + +- In the #jamfnation and #autopkg rooms within the [MacAdmins Slack team](http://macadmins.org/) +- On the [JAMF Nation discussion boards](https://jamfnation.jamfsoftware.com/index.html) +- In the [#jamfnation IRC channel](https://webchat.freenode.net/?channels=%23jamfnation) on Freenode + +### Consulting services + +If you're in the San Francisco Bay Area and you'd rather just pay somebody to set this up properly, document it, and leave you instructions for maintaining it, give [the Linde Group](http://www.lindegroup.com/) a call. We've done that sort of thing for many companies. + +### Found a problem? + +If you've found a reproducible problem with the scripts or templates I've provided here, or if you have ideas for improving them, feel free to submit a [GitHub issue](https://github.com/homebysix/auto-update-magic/issues) on this repo, and I'll do my best to reply in a timely manner. + +  + +  -[Watch the original presentation on the JAMF website](http://www.jamfsoftware.com/resources/auto-update-magic-keep-mac-apps-current-with-the-casper-suite-and-autopkgr/). +P.S. Thanks for reading all the way to the end! You get a [:city_sunset:](https://www.youtube.com/watch?v=ZCbkUu2uykg). diff --git a/RecipeOverrides/AdobeFlashPlayer.jss.recipe b/RecipeOverrides/AdobeFlashPlayer.jss.recipe deleted file mode 100644 index d6f5704..0000000 --- a/RecipeOverrides/AdobeFlashPlayer.jss.recipe +++ /dev/null @@ -1,17 +0,0 @@ - - - - - Identifier - local.jss.AdobeFlashPlayer - Input - - POLICY_CATEGORY - Auto Update - POLICY_TEMPLATE - %RECIPE_DIR%/AdobeFlashPlayerPolicyTemplate.xml - - ParentRecipe - com.github.autopkg.jss.FlashPlayerExtractPackage - - diff --git a/RecipeOverrides/AdobeFlashPlayerPolicyTemplate.xml b/RecipeOverrides/AdobeFlashPlayerPolicyTemplate.xml deleted file mode 100755 index cbaa9f9..0000000 --- a/RecipeOverrides/AdobeFlashPlayerPolicyTemplate.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - Auto Update %PROD_NAME% - true - Ongoing - - %POLICY_CATEGORY% - - true - - - - - - - - - - - - - - true - - diff --git a/RecipeOverrides/Firefox-SelfService.jss.recipe b/RecipeOverrides/Firefox-SelfService.jss.recipe deleted file mode 100644 index f04e64c..0000000 --- a/RecipeOverrides/Firefox-SelfService.jss.recipe +++ /dev/null @@ -1,67 +0,0 @@ - - - - - Comment - -This AutoPkg recipe was created using JSSRecipeCreator: -https://github.com/sheagcraig/JSSRecipeCreator - -It is meant to be used with JSSImporter: -https://github.com/sheagcraig/JSSImporter - -For tips on integrating JSSImporter into your Casper environment, check out Auto Update Magic: -https://github.com/homebysix/auto-update-magic - Description - Downloads Firefox disk image and builds a package. -Values for RELEASE correspond to directories here: http://download-origin.cdn.mozilla.net/pub/mozilla.org/firefox/releases/ -Some useful values are: 'latest', 'latest-10.0esr', 'latest-esr', 'latest-3.6', 'latest-beta' -LOCALE corresponds to directories at http://download-origin.cdn.mozilla.net/pub/mozilla.org/firefox/releases/$RELEASE/mac/ -Examples include 'en-US', 'de', 'ja-JP-mac', 'sv-SE', and 'zh-TW' -No idea if all Firefox builds are available in all the same localizations, so you may need to verify that any particular -combination is offered. Then, uploads to the JSS. - Identifier - com.github.homebysix.jss.Firefox-SelfService - Input - - CATEGORY - Web Browsers and Internet Utilities - DESCRIPTION - Popular and flexible web browser from Mozilla. - ICON - %RECIPE_DIR%/Firefox.png - NAME - Firefox - POLICY_CATEGORY - Web Browsers and Internet Utilities - POLICY_TEMPLATE - %RECIPE_DIR%/PolicyTemplate-SelfService.xml - - MinimumVersion - 0.2.0 - ParentRecipe - com.github.autopkg.pkg.Firefox_EN - Process - - - Arguments - - category - %CATEGORY% - policy_category - %POLICY_CATEGORY% - policy_template - %POLICY_TEMPLATE% - prod_name - %NAME% - self_service_description - %DESCRIPTION% - self_service_icon - %ICON% - - Processor - JSSImporter - - - - diff --git a/RecipeOverrides/Firefox.jss.recipe b/RecipeOverrides/Firefox.jss.recipe deleted file mode 100644 index f222533..0000000 --- a/RecipeOverrides/Firefox.jss.recipe +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Identifier - local.jss.Firefox - Input - - POLICY_CATEGORY - Auto Update - GROUP_TEMPLATE - %RECIPE_DIR%/AutoUpdateSmartGroupTemplate.xml - POLICY_TEMPLATE - %RECIPE_DIR%/AutoUpdatePolicyTemplate.xml - - ParentRecipe - com.github.autopkg.jss.Firefox_EN - - diff --git a/doc-images/autopkgr-casper-integration.png b/doc-images/autopkgr-casper-integration.png deleted file mode 100644 index bdc2ab9..0000000 Binary files a/doc-images/autopkgr-casper-integration.png and /dev/null differ diff --git a/doc-images/magic-01.png b/doc-images/magic-01.png deleted file mode 100644 index 3780c3b..0000000 Binary files a/doc-images/magic-01.png and /dev/null differ diff --git a/doc-images/magic-02.png b/doc-images/magic-02.png deleted file mode 100644 index beecec1..0000000 Binary files a/doc-images/magic-02.png and /dev/null differ diff --git a/doc-images/magic-03.png b/doc-images/magic-03.png deleted file mode 100644 index 9dbe7af..0000000 Binary files a/doc-images/magic-03.png and /dev/null differ diff --git a/doc-images/magic-04.png b/doc-images/magic-04.png deleted file mode 100644 index 751a13c..0000000 Binary files a/doc-images/magic-04.png and /dev/null differ diff --git a/doc-images/screencast-thumbnail.png b/doc-images/screencast-thumbnail.png deleted file mode 100644 index 82696d5..0000000 Binary files a/doc-images/screencast-thumbnail.png and /dev/null differ diff --git a/scripts/auto_update_magic.sh b/scripts/auto_update_magic.sh deleted file mode 100755 index 27b6a08..0000000 --- a/scripts/auto_update_magic.sh +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env bash - -### -# -# Name: auto_update_magic.sh -# Description: A Casper script to assist in automatically updating apps, -# meant to be used in conjunction with autopkg, AutoPkgr, and -# JSSImporter. -# Author: Elliot Jordan -# Created: 2013-03-24 -# Last Modified: 2015-01-29 -# Version: 1.4.3 -# -### - - -################################### SETTINGS ################################### - -# Add a line here for each auto-update recipe name. Recipe names do not -# typically contain spaces. Some examples are included below: -RECIPE_NAME=( - - # "Firefox" - # "GoogleChrome" - # "Office2011Update" - # "AdobeFlashPlayer" - # "Evernote" - -) - -# For each recipe above, add a corresponding line here for each "blocking -# application" — apps/processes that must not be open if the app is to be -# updated automatically. You can add multiple comma-separated applications per -# line, as in the examples below: -BLOCKING_APPS=( - - # "Firefox" - # "Google Chrome" - # "Microsoft Word, Microsoft Excel, Microsoft PowerPoint, Microsoft Outlook, Google Chrome, Safari, Firefox" - # "Safari, Firefox" - # "Evernote$" # matches "Evernote" but not "EvernoteHelper" - -) - -# Set DEBUG_MODE to true if you wish to do a "dry run." This changes two things: -# - The auto update process will run every time, regardless of the -# presence of a LastAutoUpdate value. -# - The custom triggers that cause the apps to actually update will be -# logged, but not actually executed. -DEBUG_MODE=false - - -################################################################################ -######################### DO NOT EDIT BELOW THIS LINE ########################## -################################################################################ - - -######################## VALIDATION AND ERROR CHECKING ######################### - -APPNAME=$(basename "$0" | sed "s/\.sh$//") - -# Let's make sure we have the right numbers of settings above. -if [[ ${#RECIPE_NAME[@]} != ${#BLOCKING_APPS[@]} ]]; then - echo "[ERROR] Please carefully check the settings in the $APPNAME script. The number of parameters don't match." >&2 - exit 1001 -fi - -# Let's verify that DEBUG_MODE is set to true or false. -if [[ $DEBUG_MODE != true && $DEBUG_MODE != false ]]; then - echo "[ERROR] DEBUG_MODE should be set to either true or false." >&2 - exit 1002 -fi - -# Number of hours between auto updates is taken from parameter 4, or defaults to 1 -if [[ ! -z $4 && $(bc <<< "$4 > 0") == 1 ]]; then - HOURS=$4 -else - HOURS=1 -fi - - -################################## FUNCTIONS ################################### - -# This function checks whether the apps are running, and updates them if not -function fn_AutoUpdateMagic () { - - # Count how many recipes we need to process. - RECIPE_COUNT=${#RECIPE_NAME[@]} - - # Save the default internal field separator. - OLDIFS=IFS - - # Begin iterating through recipes. - for (( i = 0; i < RECIPE_COUNT; i++ )); do - - echo " " # for some visual separation between apps in the log - - # Iterate through each recipe's corresponding blocking apps. - echo "Checking for apps that would block the ${RECIPE_NAME[$i]} update..." - IFS="," - UPDATE_BLOCKED=false - - for APP in ${BLOCKING_APPS[$i]}; do - - # Strip leading spaces from app name. Save lowercase version. - APP_CLEAN="$(echo "$APP" | sed 's/^ *//')" - APP_CLEAN_LOWER="$(echo "$APP_CLEAN" | tr [:upper:] [:lower:])" - - # Check whether the app is running. - if pgrep "$APP_CLEAN" &> /dev/null || pgrep "$APP_CLEAN_LOWER" &> /dev/null; then - echo " $APP_CLEAN is running. Skipping auto update." - UPDATE_BLOCKED=true - break - else - echo " $APP_CLEAN is not running." - fi - - done - - # Only run the auto-update policy if no blocking apps are running. - if [[ $UPDATE_BLOCKED == false ]]; then - if [[ $DEBUG_MODE == false ]]; then - echo "No apps are blocking the ${RECIPE_NAME[$i]} update. Calling policy trigger autoupdate-${RECIPE_NAME[$i]}." - /usr/sbin/jamf policy -trigger "autoupdate-${RECIPE_NAME[$i]}" - else - echo "[DEBUG] No apps are blocking the ${RECIPE_NAME[$i]} update. This is the point where we would normally call the policy trigger autoupdate-${RECIPE_NAME[$i]}." - fi - fi - - done # End iterating through recipes. - - # Reset back to default internal field separator. - IFS=OLDIFS - - # Reset the LastAutoUpdate time. - if [[ $DEBUG_MODE == false ]]; then - /usr/bin/defaults write /Library/"Application Support"/JAMF/com.jamfsoftware.jamfnation LastAutoUpdate "$(date +%s)" - fi -} - -# This function calculates whether it's time to run the auto updates -function fn_AutoUpdateTimeCheck () { - SECONDS=$((60*60*HOURS)) - EPOCH=$(date +%s) - TIMEDIFF=$((EPOCH-lastAutoUpdateTime)) - - if [[ "$TIMEDIFF" -ge "$SECONDS" || $DEBUG_MODE == true ]]; then - fn_AutoUpdateMagic - else - if [[ "$TIMEDIFF" -lt "3600" ]]; then - /bin/echo "Auto updates not needed, last ran $((TIMEDIFF/60)) minutes ago. Will run again in $((HOURS*60-TIMEDIFF/60)) minutes." - else - /bin/echo "Auto updates not needed, last ran $((TIMEDIFF/60/60)) hours ago. Will run again in $((HOURS*60-TIMEDIFF/60)) minutes." - fi - fi -} - - -################################# MAIN PROCESS ################################# - -lastAutoUpdateTime=$(/usr/bin/defaults read /Library/"Application Support"/JAMF/com.jamfsoftware.jamfnation LastAutoUpdate 2> /dev/null) -if [[ "$?" -ne "0" ]]; then - echo "Auto Update Magic has never run before. Checking for updates now..." - fn_AutoUpdateMagic -else - fn_AutoUpdateTimeCheck -fi - -exit 0 \ No newline at end of file diff --git a/slides/auto_update_magic.pdf b/slides/auto_update_magic-1.0.pdf similarity index 100% rename from slides/auto_update_magic.pdf rename to slides/auto_update_magic-1.0.pdf