Jamf Pro Policy Editor Lite

dan-snelson
Valued Contributor II

Edit a policy's version number via the API


About

Since Jamf Pro PI-005903, I’ve been thinking of a faster way to update policies.

Last week, Adobe released six updates which — outside of building new packages via Adobe's admin console — effectively required only incrementing a version number four places in each policy (please don't tell @talkingmoose):
- Adobe After Effects CC 15.1.1 was update to: Adobe After Effects CC 15.1.2
- Adobe Media Encoder CC 12.1.1 was update to: Adobe Media Encoder CC 12.1.2
- Adobe Bridge CC 8.0.1 was update to: Adobe Bridge CC 8.1
- Adobe Premiere Pro CC 12.1.1 was update to: Adobe Premiere Pro CC 12.1.2
- Adobe Prelude CC 7.1 was update to: Adobe Prelude CC 7.1.1
- Adobe XD CC 9.1.12 was updated to: Adobe XD CC 10.0.12

With inspiration from @mm2270's API scripts, and lots of feedback from @Leslie, Jamf Pro Policy Editor Lite was born.


Requirements

API

To utilize this script, the API account must have the following privileges:
- Policies: CREATE, READ, UPDATE
- Because of the need to use API credentials with Create privileges, the script allows you to interactively enter the credentials so they don't need to be stored within the script. (Thanks, mm2270)
- The script performs only minor error checking; please ensure proper API credentials or you will encounter errors

Policies

If policies include the version number in parenthesis, for example: "Adobe Prelude CC 2018 (7.1.1)", the script will automatically parse the version number, for example: "7.1.1"; otherwise, you will be prompted for the version number.

Packages

The updated package must be present before running this script.


Usage

This script was designed to be run interactively in Terminal and allows you to use the API (along with valid API credentials) to update a policy's version number.

This script uses some BASH specific items; please first make the script executable: chmod +x /path/to/Jamf Pro Policy Editor Lite.sh

To use the script:
/path/to/path/to/Jamf Pro Policy Editor Lite.sh


Warning

While the script does backup a policy's XML before performing updates, please thoroughly test before using in production.


Special Thanks


Script

Latest version on GitHub.

#!/bin/bash
####################################################################################################
#
# ABOUT
#
#   Jamf Pro Policy Editor Lite: Edit a policy's version number via the API
#
####################################################################################################
#
# HISTORY
#
#     Version 1.0, 23-Jul-2018, Dan K. Snelson
#           Original Version
#       With inspiration from mm2270
#       https://github.com/mm2270/Casper-API/blob/master/Convert-SG-Search-Search-SG.sh
#
####################################################################################################



####################################################################################################
#
# Global Variables
#
####################################################################################################

# Values for API connection; if left blank, you will be prompted to interactively enter
apiURL=""
apiUser=""
apiPassword=""

# Debug mode [ true | false ]
debug="false"



# ------------------------------ No edits required below this line --------------------------------



###################################################################################################
#
# Define the Functions
#
####################################################################################################

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Create Working Diretory and Log file
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function createWorkingDirectory() {

    # Currently logged-in user
    loggedInUser=$( /usr/bin/stat -f%Su /dev/console )

    # Time stamp for log file
    timestamp=$( /bin/date '+%Y-%m-%d-%H%M%S' )

    # Working Directory
    workingDirectory="/Users/${loggedInUser}/Documents/Jamf_Pro_Policy_Editor_Lite"
    logDirectory="${workingDirectory}/Logs/"
    logFile="${logDirectory}/Jamf_Pro_Policy_Editor_Lite-${timestamp}.log"

    # Ensure Working Directory exists
    if [[ ! -d ${workingDirectory} ]]; then
        /bin/mkdir -p ${workingDirectory}
    fi

    # Ensure Log Directory exists
    if [[ ! -d ${logDirectory} ]]; then
        /bin/mkdir -p ${logDirectory}
    fi

    # Ensure Log File exists
    if [[ ! -d ${logFile} ]]; then
        /usr/bin/touch ${logFile}
        echo "Log file created `date`" >> ${logFile}
    fi

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Logging
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function ScriptLog() { # Re-direct logging to the log file ...

    NOW=`date +%Y-%m-%d %H:%M:%S`
    /bin/echo "${NOW}" " ${1}" >> "${logFile}"

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Reveal File in Finder
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function revealMe() {

    /usr/bin/open -R "${1}"

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# API Connection
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function apiConnectionSettings() {

    printf "
-------------------------------------------------------------------------------------------------------"
    printf "

###
"
    echo "# Step 1 of 6: API Connection Settings"
    printf "###
"

    promptAPIurl

    promptAPIusername

    promptAPIpassword

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Prompt user for API URL
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function promptAPIurl() {

    if [[ -z "$apiURL" ]]; then
        ScriptLog "API URL is blank; attempt to read from JAMF plist ..."
        # Read the API URL from the JAMF preferences
        if [[ -e "/Library/Preferences/com.jamfsoftware.jamf.plist" ]]; then
            ScriptLog "Found JAMF plist; read its URL ..."
            apiURL=$( defaults read "/Library/Preferences/com.jamfsoftware.jamf.plist" jss_url | sed 's|/$||' )
            echo "
Use this URL? ${apiURL}

[y] Yes - Use the URL presented above
[n] No - Enter the API URL at the next prompt
[x] Exit"

            read -n 1 -r -p "`echo $'
> '`" urlResponse
            ScriptLog "Use this URL: ${apiURL}? ${urlResponse}"

            case "$urlResponse" in

                y|Y)

                    apiURL="$apiURL"
                    ;;

                n|N)

                    printf "

Enter the API URL:"
                    read -r -p "`echo $'
> '`" newURLResponse
                    if [[ -z "$newURLResponse" ]]; then
                        ScriptLog "No API URL provided; exiting."
                        printf "
No API URL provided; exiting.

"
                        exit 0
                    fi
                    apiURL="${newURLResponse}"
                    ScriptLog "API URL: ${apiURL}"
                    ;;

                x|X)

                    ScriptLog "Exiting. Goodbye!"
                    printf "

Exiting. Goodbye!

"
                    exit 0
                    ;;

                *)

                    ScriptLog "ERROR: Invalid response: ${urlResponse}; exiting."
                    printf "

ERROR: Invalid response; exiting.

"
                    exit 1
                    ;;

            esac

        else

            ScriptLog "No API URL is specified in the script; prompt user ..."

            echo "
No API URL is specified in the script. Enter it now?

[y] Yes - Enter the URL at the next prompt
[n] No - Exit the script"

            read -n 1 -r -p "`echo $'
> '`" urlResponse

            case "$urlResponse" in

                y|Y)

                    printf "

Enter the API URL:"
                    read -r -p "`echo $'
> '`"  userURLResponse
                    if [[ -z "$userURLResponse" ]]; then
                        ScriptLog "No API URL provided; exiting."
                        printf "
No API URL provided; exiting.

"
                        exit 0
                    fi
                    apiURL="$userURLResponse"
                    ScriptLog "API URL: ${apiURL}"
                    ;;

                n|N)

                    ScriptLog "Exiting. Goodbye!"
                    printf "

Exiting. Goodbye!

"
                    exit 0
                    ;;

                *)

                    ScriptLog "ERROR: Invalid response ${urlResponse}; exiting."
                    printf "

ERROR: Invalid response; exiting.

"
                    exit 1
                    ;;

            esac
        fi
    fi

    apiURL=$( echo "$apiURL" | sed 's|/$||' )

    ScriptLog "Using the API URL of: ${apiURL}"
    printf "
• Using the API URL of: ${apiURL}"

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Prompt user for API Username
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function promptAPIusername() {

    if [[ -z "${apiUser}" ]]; then
        ScriptLog "API username is blank; attempt to read from JAMF plist ..."
        printf "

No API Username has been supplied. Enter it now?

[y] Yes - Enter the Username at the next prompt
[n] No/Exit
"

        read -n 1 -r -p "`echo $'
> '`" apiUsernameResponse

        case "$apiUsernameResponse" in

            y|Y)

                printf "

API Username:"
                read -r -p "`echo $'
> '`" apiUserName
                if [[ -z "${apiUserName}" ]]; then
                    printf "
No API Username provided; exiting.

"
                    exit 0
                fi
                apiUser="${apiUserName}"
                ;;

            n|N)

                printf "

Exiting. Goodbye!

"
                exit 0
                ;;

            *)

                printf "

Invalid response! Please try again."
                promptAPIusername
                ;;

        esac

    fi

    ScriptLog "Using the API Username of: ${apiUser}"
    printf "
• Using the API Username of: ${apiUser}"

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Prompt user for API Password
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function promptAPIpassword() {

    if [[ -z "${apiPassword}" ]]; then

        printf "

No API Password has been supplied. Enter it now?

[y] Yes - Enter the password at the next prompt
[n] No/Exit
"

        read -n 1 -r -p "`echo $'
> '`" apiPasswordEntryResponse

        case "$apiPasswordEntryResponse" in

            y|Y)

                printf "

API Password:
>"
                read -s apiPasswordEntry
                if [[ -z "${apiPasswordEntry}" ]]; then
                    printf "
No API Password provided; exiting.

"
                    exit 0
                fi
                apiPassword="${apiPasswordEntry}"
                ;;

            n|N)

                printf "

Exiting. Goodbye!

"
                exit 0
                ;;

            *)

                printf "

Invalid response! Please try again."
                promptAPIpassword
                ;;

        esac

    fi

    if [[ ${debug} ==  "true" ]]; then
        ScriptLog "Using the API Password of: ${apiPassword}"
        printf "
• Using the API Password of: ${apiPassword}
"
    else
        printf "
• Using the supplied API password
"
    fi

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Select Policy to Update (Thanks, mm2270!)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function selectPolicy() {

    # Reset Variables
    ScriptLog "Reset variables ..."
    unset policyNames policyIDs policyName policyNamesArray policyID policyIDsArray policyChoice

    printf "
-------------------------------------------------------------------------------------------------------"
    printf "

###
"
    echo "# Step 2 of 6: Select Policy to Update"
    printf "###

"

    # Build two lists via the API: One for Policy names; the other for their respective IDs.
    ScriptLog "Build list of policy names via API ..."
    policyNames=$( /usr/bin/curl -H "Accept: text/xml" -sfku "${apiUser}:${apiPassword}" "${apiURL}/JSSResource/policies" | xmllint --format - | awk -F'>|<' '/<name>/{print $3}')

    ScriptLog "Build list of policy IDs via API ..."
    policyIDs=$( /usr/bin/curl -H "Accept: text/xml" -sfku "${apiUser}:${apiPassword}" "${apiURL}/JSSResource/policies" | xmllint --format - | awk -F'>|<' '/<id>/{print $3}')

    # Create array for Policy names
    ScriptLog "Create array for Policy names ..."
    while read policyName; do
        policyNamesArray+=("$policyName")
    done < <( printf '%s
' "$policyNames" )

    # Create array for Policy IDs
    ScriptLog "Create array for Policy IDs ..."
    while read policyID; do
        policyIDsArray+=("$policyID")
    done < <( printf '%s
' "$policyIDs" )

    # Display Policy names with index labels
    ScriptLog "Display Policy names with index labels ..."
    for i in "${!policyNamesArray[@]}"; do
      printf "%s	%s
" "[$i]" "${policyNamesArray[$i]}"
    done

    echo "
    Choose the Policy to update by entering its index number:"

    read -r -p "`echo $'
> '`" policyChoice

    if [ "${policyChoice}" -eq "${policyChoice}" ] 2>/dev/null; then
      ScriptLog "Policy index: ${policyChoice}"
    else
      printf "

ERROR: "${policyChoice}" is not an index number; exiting.

"
        ScriptLog "ERROR: "${policyChoice}" is not an index number; exiting."
        exit 1
    fi

    echo " "
    echo "Policy Name: ${policyNamesArray[$policyChoice]}"
    echo "  Policy ID: ${policyIDsArray[$policyChoice]}"
    echo " "

    # Assign Policy ID to variable
    policyID="${policyIDsArray[$policyChoice]}"
    ScriptLog "User selected: Policy ID ${policyID} ${policyNamesArray[$policyChoice]}"

    promptToContinue

}


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Download and backup the Policy XML
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function downloadBackupXML() {

    printf "


-------------------------------------------------------------------------------------------------------"
    printf "

###
"
    echo "# Step 3 of 6: Download and Backup Policy XML"
    printf "###

"

    echo "• Downloading XML for Policy ID ${policyID} ..."
    ScriptLog "Downloading XML for Policy ID ${policyID} ..."

    # Backup Directory
    backupDirectory="${workingDirectory}/Backups/${timestamp}"

    # Ensure Backup Directory exists
    if [[ ! -d ${backupDirectory} ]]; then
        /bin/mkdir -p ${backupDirectory}
        ScriptLog "Created backup directory: ${backupDirectory}"
    fi

    # Updates Directory
    updatesDirectory="${workingDirectory}/Updates/${timestamp}"

    # Ensure Update Directory exists
    if [[ ! -d ${updatesDirectory} ]]; then
        /bin/mkdir -p ${updatesDirectory}
        ScriptLog "Created update directory: ${updatesDirectory}"
    fi

    # Download policy XML
    if [[ ${debug} ==  "true" ]]; then
        /usr/bin/curl -u "$apiUser":"$apiPassword" $apiURL/JSSResource/policies/id/${policyID} -H "Accept: application/xml" -X GET -o ${backupDirectory}/policy-${policyID}.xml
    else
        /usr/bin/curl -s -u "$apiUser":"$apiPassword" $apiURL/JSSResource/policies/id/${policyID} -H "Accept: application/xml" -X GET -o ${backupDirectory}/policy-${policyID}.xml
    fi
    echo "• Downloaded to: ${backupDirectory}/policy-${policyID}.xml ..."
    ScriptLog "Downloaded to: ${backupDirectory}/policy-${policyID}.xml"

    # Copy downloaded XML to Updates directory
    echo "• Copying ../Backups/policy-${policyID}.xml to ../Updates/policy-${policyID}.xml"
    ScriptLog "Copying ../Backups/policy-${policyID}.xml to ../Updates/policy-${policyID}.xml"
    if [[ ${debug} ==  "true" ]]; then
        /bin/cp -v ${backupDirectory}/policy-${policyID}.xml ${updatesDirectory}/policy-${policyID}.xml
    else
        /bin/cp ${backupDirectory}/policy-${policyID}.xml ${updatesDirectory}/policy-${policyID}.xml
    fi
    echo "• Copied to ../Updates/policy-${policyID}.xml"
    ScriptLog "Copied to ../Updates/policy-${policyID}.xml"

    # Exit if update file does not exist
    if [[ ! -f "${updatesDirectory}/policy-${policyID}.xml" ]]; then
        echo "ERROR: Policy file "../Updates/policy-${policyID}.xml" does NOT exist; exiting"
        ScriptLog "ERROR: Policy file "../Updates/policy-${policyID}.xml" does NOT exist; exiting"
        exit 1
    fi

    printf "
-------------------------------------------------------------------------------------------------------
"

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Prompt the user for the new version number
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function promptNewVersion() {

    printf "
###
"
    echo "# Step 4 of 6: Specify new version number"
    printf "###

"

    # Lookup policy name
    policyName=$( /usr/bin/xmllint --xpath "/policy/general/name/text()" ${updatesDirectory}/policy-${policyID}.xml )
    printf "• Policy Name: ${policyName}
"
    ScriptLog "Policy Name: ${policyName}"

    # Determine current version
    currentVersion=$( echo $policyName | /usr/bin/awk -F"[()]" '{print $2}' )
    if [[ -z ${currentVersion} ]]; then
        # Prompt user for current version
        printf "• Current version: UNKOWN

"

        read -p "Please specify the current version number: `echo $'
> '`" currentVersion
        ScriptLog "Current version number: ${currentVersion}"
        echo " "

    fi

    printf "• Current version: ${currentVersion}

"
    ScriptLog "Current version: ${currentVersion}"

    read -p "Please specify the new version number: `echo $'
> '`" newVersion
    ScriptLog "New version number: ${newVersion}"
    echo " "

    read -n 1 -r -p "Are you sure you want to update version "${currentVersion}" to version "${newVersion}"? [y]es or [n]o: `echo $'
> '`" confirmUpdate
    ScriptLog "Are you sure you want to update version "${currentVersion}" to version "${newVersion}"?: ${confirmUpdate}"

    case "${confirmUpdate}" in

        y|Y )

            updatePolicyVersion

            updatePackageID

            ;;

     n|N )

            printf "

No; exiting

"
            exit 0
            ;;

     *)

            printf "

ERROR: Did not recognize response: ${confirmUpdate}; exiting.

"
            exit 1
            ;;

    esac

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Update Policy Version
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function updatePolicyVersion() {

    printf "

-------------------------------------------------------------------------------------------------------
"
    printf "
###
"
    echo "# Step 5 of 6: Update Policy"
    printf "###

"

    echo "• Replacing "${currentVersion}" with "${newVersion}" ..."
    ScriptLog "Replacing "${currentVersion}" with "${newVersion}" ..."
    /usr/bin/sed -i.bak1 "s|${currentVersion}|${newVersion}|g" ${updatesDirectory}/policy-${policyID}.xml

    echo "• Done."

    newpolicyName=$( /usr/bin/xmllint --xpath "/policy/general/name/text()" ${updatesDirectory}/policy-${policyID}.xml )
    printf "• New Policy version: ${newpolicyName}
"
    ScriptLog "New Policy version: ${newpolicyName}"

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Update Package ID
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function updatePackageID() {

    echo "• Updating Package ID for "${newpolicyName}" ..."
    ScriptLog "Updating Package ID for  "${newpolicyName}" ..."

    currentPackageID=$( /usr/bin/xmllint --xpath "/policy/package_configuration/packages/package/id/text()"  ${updatesDirectory}/policy-${policyID}.xml )
    echo "• The "${policyName}" policy has a Package ID of: ${currentPackageID}"

    newPackageName=$( /usr/bin/xmllint --xpath "/policy/package_configuration/packages/package/name/text()"  ${updatesDirectory}/policy-${policyID}.xml )
    echo "• Determining Package ID for "${newPackageName}" ..."

    newPackageNameScrubbed=$( echo ${newPackageName} | sed 's| |%20|g' )

    newPackageID=$( /usr/bin/curl -H "Accept: text/xml" -sfku "${apiUser}:${apiPassword}" "${apiURL}/JSSResource/packages/name/${newPackageNameScrubbed}" | xmllint --format - | awk -F'>|<' '/<id>/{print $3}')

    echo "• Package "${newPackageName}" has an ID of: ${newPackageID} ..."

    echo "• Updating Package ID from "${currentPackageID}" to "${newPackageID}" ..."

    /usr/bin/sed -i.bak2 "s|<package><id>${currentPackageID}|<package><id>${newPackageID}|" ${updatesDirectory}/policy-${policyID}.xml

    echo "• Done."

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Prompt Upload New Policy
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function promptUploadNewPolicy() {

    printf "
-------------------------------------------------------------------------------------------------------
"
    printf "
###
"
    echo "# Step 6 of 6: Upload New Policy"
    printf "###

"

    printf "• New Policy Name: ${newpolicyName}

"

    # Prompt user for permission to proceed
    read -n 1 -r -p "Would you like to upload this policy? [y]es or [n]o: `echo $'
> '`" uploadChoice
    ScriptLog "Would you like to upload this policy?: ${uploadChoice}"

    case "${uploadChoice}" in

     y|Y )

            uploadNewPolicy

            ;;

     n|N )

            ScriptLog "Upload canceled; exiting."
            printf "

Upload canceled; exiting.

"
            exit 0
            ;;

     *)

            ScriptLog "ERROR: Did not recognize response: $choice; exiting."
            printf "
ERROR: Did not recognize response: $choice; exiting."
            exit 1
            ;;

    esac

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Upload New Policy
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function uploadNewPolicy() {

    ScriptLog "Uploading ${newpolicyName} ..."
    printf "

• Uploading "${newpolicyName}" ...
"

    if [[ ${debug} ==  "true" ]]; then
        /usr/bin/curl -u "$apiUser":"$apiPassword" $apiURL/JSSResource/policies/id/${policyID} -H "Content-Type: application/xml" -X PUT -T ${updatesDirectory}/policy-${policyID}.xml
    else
        /usr/bin/curl -s -u "$apiUser":"$apiPassword" $apiURL/JSSResource/policies/id/${policyID} -H "Content-Type: application/xml" -X PUT -T ${updatesDirectory}/policy-${policyID}.xml
    fi

    ScriptLog "Uploaded ${newpolicyName} ..."
    printf "• Uploaded "${newpolicyName}" ...

"

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# View New Policy
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function viewNewPolicy() {

    printf "
-------------------------------------------------------------------------------------------------------
"
    printf "
###
"
    echo "# Complete: View New Policy"
    printf "###

"

    ScriptLog "Launching browser to view "${newpolicyName}" policy ..."
    printf "
• Launching browser to view "${newpolicyName}" policy ...
"
    /usr/bin/open $apiURL/policies.html?id=${policyID}

    printf "• Policy ID "${policyID}" has been updated to "${newpolicyName}."

To revert Policy ID "${policyID}" to "${policyName}," use the following Terminal command:

	"
    if [[ ${debug} ==  "true" ]]; then
        echo "/usr/bin/curl -k -u ${apiUser}:${apiPassword} ${apiURL}/JSSResource/policies/id/${policyID} -H "Content-Type: application/xml" -X PUT -T ${backupDirectory}/policy-${policyID}.xml ; /usr/bin/open $apiURL/policies.html?id=${policyID}"
    else
        echo "/usr/bin/curl -k -u ${apiUser}:API_PASSWORD_GOES_HERE ${apiURL}/JSSResource/policies/id/${policyID} -H "Content-Type: application/xml" -X PUT -T ${backupDirectory}/policy-${policyID}.xml"
    fi

    printf "


***************************************** Policy Updated *****************************************


"

}



# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Prompt to Continue
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

function promptToContinue(){

    unset choice

    # Prompt user for permission to proceed
    read -n 1 -r -p "Would you like to update this policy? [y]es or [n]o: `echo $'
> '`" choice
    ScriptLog "Would you like to update this policy?: ${choice}"

    case "${choice}" in

     y|Y )

            ScriptLog "Updating policy ..."

            downloadBackupXML               # Download and backup the XML

            promptNewVersion                # Prompt the user for the new version

            promptUploadNewPolicy       # Prompt to upload the new policy using the supplied API password

            ;;

     n|N )

            ScriptLog "Prompting user to select a different policy ..."
            /usr/bin/clear
            selectPolicy
            ;;

     *)

            ScriptLog "ERROR: Did not recognize response: $choice; exiting."
            printf "
ERROR: Did not recognize response: $choice; exiting."
            exit 1
            ;;

    esac

}



####################################################################################################
#
# Main Program
#
####################################################################################################

# Clear the user's Terminal session
/usr/bin/clear

createWorkingDirectory

echo "#####################################"
echo "# Jamf Pro Policy Editor Lite, v1.0 #"
echo "#####################################"
echo " "
echo "This script updates a selected policy's version number. For example, the policy for
"Adobe Prelude CC 2018 (7.1.1)" would be updated to: "Adobe Prelude CC 2018 (7.1.2).""

if [[ ${debug} ==  "true" ]]; then
    printf "

###
# DEBUG MODE ENABLED
###

"
    ScriptLog "DEBUG MODE ENABLED"
    /usr/bin/open "${logFile}"
    /usr/bin/osascript -e 'tell application "Console" to activate'
fi

apiConnectionSettings

selectPolicy

viewNewPolicy

exit 0
4 REPLIES 4

dan-snelson
Valued Contributor II

Jamf Pro Policy Viewer.sh is a slimmed-down version which launches a browser to view the selected policy, bypassing the slow-as-molasses ../policy.html page.

dan-snelson
Valued Contributor II

Here's a link to the presentation given at the October 2019 U of U MacAdmins meeting.

dan-snelson
Valued Contributor II

Version 1.4.2 is now available on GitHub.

  • Greatly enhanced error-checking for missing packages
  • Row highlighting in policy list
  • General updates and performance improvements

dan-snelson
Valued Contributor II

Version 1.4.4 is now available on GitHub

Inspired by @grahamrpugh's erase-install, Jamf Pro Policy Editor Lite, version 1.4.4, now includes the following flags:

bash ./policy-editor-lite.bash --help

Jamf Pro Policy Editor Lite, 1.4.4
by Dan K. Snelson (@dan-snelson)

    Usage:
    bash ./policy-editor-lite.bash [--filter] [--auto] [--version] [--debug]

    [no flags]    Displays all polcies
                  If API variables are left blank, you will be prompted to interactively enter.
                  If you have multiple lanes, fill-in variables in the "laneSelection" function.

    --filter ...  Filters policy names

    --auto        Auto-answers "yes" to prompt Nos. 2, 5 and 6

    --version     Specifies the new version number

    --debug       Enables debug mode

    --help        Displays this message and exits

For example, the following command will filter policies names containing foundry, auto-answer Y to prompt numbers 2, 5 and 6, and pre-populate 7.2.0 for the version number for prompt number 4.

bash ./policy-editor-lite.bash --filter foundry --auto --version 7.2.0