This post details a technique and a proper sequence for installing hotfixes on top of AEM 6.1 General Availability (GA) which is version 6.1.0.20150507. Until the Service Pack 1 for AEM 6.1 drops, with a target of Q1 2016, this is a good method for quickly deploying all relevant hotfixes on top of the GA version. Your instance is now up to date, with the latest security patches, bug fixes, and feature packs added on.

The source data is this article on the Adobe CQ Help site. There's some work involved in understanding the list of hotfixes on that article, and correctly ordering them for installation. What I have done is order the hotfixes chronologically, while also taking into consideration the dependencies for the Touch UI Feature Pack. Note that we're excluding hotfixes for AEM Forms. Here's the same data, but reprinted chronologically:

  • May 28th, 2015 - Hot fix 6500 - Security - XSS vulnerability in the Assets user interface
  • June 2nd, 2015 - Hot fix 6446 - Security - Webdav security fix
  • June 5th, 2015 - Hot fix 6640 - Miscellaneous - Installing packages with ResourceProviders can cause installation to fail
  • June 8th, 2015 - Hot fix 6680- Miscellaneous - The web console sometimes becomes unusable after package installation
  • June 20th, 2015 - Version 1.7.199 - Communities - This fix pack contains the latest set of fixes for AEM Communities 6.1 features.
  • June 24th, 2015 - Hot fix 6570 - Integrations - Hot fix pack for various Adobe Target Integration fixes.
  • June 25th, 2015 - Hot fix 6972 - Workflow - SegmentNotFoundException in workflow processing
  • July 15th, 2015 Hot fix 7085 - Security - XSS vulnerability
  • July 23th, 2015 - Hot fix 7285 - Sites - Toolbar buttons on Websites Search do not consider the ACL on all selected Rows.
  • August 22nd, 2015 - Hot fix 6449 - Security - Vulnerability in the Apache POI Library
  • September 1st, 2015 - Feature Pack 6563 - Sites - This Update Pack addresses some bugs and improvements reported by customers.
  • October 6th, 2015 - Hot fix 7700 -- CRX/OAK - Oak 1.2.7

All of the hotfix packages are available on Package Share. I downloaded each package and placed them in logical folders based on the AEM product or section. Then I listed them out in a file packages.cfg, to be used by our script later.

security/cq-6.1.0-hotfix-6500-1.0.zip
security/cq-6.1.0-hotfix-6446-1.0.zip
miscellaneous/cq-6.1.0-hotfix-6640-1.2.zip
miscellaneous/cq-6.1.0-hotfix-6680-1.2.zip
communities/AEM-6.1-Communities-HotFix-1.7.199.zip
integrations/cq-6.1.0-hotfix-6570-1.2.zip
workflow/cq-6.1.0-hotfix-6972-1.0.zip
security/cq-6.1.0-hotfix-7085-1.0.zip
sites/cq-6.1.0-hotfix-7285-1.0.zip
security/cq-6.1.0-hotfix-6449-1.2.zip
sites/cq-6.1.0-featurepack-6563-1.0.0.zip
crx-oak/cq-6.1.0-hotfix-7700-2.2.zip

Deploying the hotfixes efficiently is simply a matter of scripting curl calls to an AEM instance. First, we define in a file settings.cfg the connection settings to the instance:

# -----------------------------------------------
# AEM instance settings

LOCAL_HOST="localhost"
LOCAL_PORT="4502"
LOCAL_ADMIN_USER="admin"
LOCAL_ADMIN_PASS="admin"

# -----------------------------------------------
# Path to the root directory holding the hotfixes

PACKAGES_ROOT="/path/the/hotfixes"

Then, in our bash script, we read these settings, and iterate over each of the packages.cfg file above. The script will upload and install to the Package Manager each zip file. The script will evaluate if the installation succeeded by checking for the status code 200 in the curl response. After each success, a pause of 60 seconds is taken. I've found that this gives time for the instance to ingest the package, install it, and let applicable OSGI bundles restart and reactivate themselves. Should a package installation fail, the script will abort and not install any further packages.

#!/bin/bash

# ----------------------------------------------------------------
# Read in the config file

source settings.cfg

echo -e "Local AEM instance:\n  Host: $LOCAL_HOST\n  Port: $LOCAL_PORT\n"

PACKAGES_FILE="packages.cfg"

# ----------------------------------------------------------------
# The heavy lifting
while IFS='' read -r line || [[ -n "$line" ]]; do

    # split the string on "/"
    arrLine=(${line//// })
    FOLDER=${arrLine[0]}
    ZIP=${arrLine[1]}

    FILE=$PACKAGES_ROOT/$FOLDER/$ZIP
    echo "Installing package $FILE on Local AEM..."
    OUTPUT=$(curl --silent -u $LOCAL_ADMIN_USER:$LOCAL_ADMIN_PASS -F file=@"$FILE" -F name="$ZIP" -F force=true -F install=true http://$LOCAL_HOST:$LOCAL_PORT/crx/packmgr/service.jsp)

    if [[ $OUTPUT == *"<status code=\"200\">ok</status>"* ]]
    then
        echo -e "... success! One minute nap...\n";
        sleep 60s
    else
        echo -e "... failed! Exiting...\n";
        break # get outta here!
    fi

done < "$PACKAGES_FILE"

I hope this article is helpful for your AEM deployments and maintenance.