From c9de090fee53797ee9a421ebaed1a7df32936172 Mon Sep 17 00:00:00 2001 From: Zack T Date: Thu, 14 Jun 2018 21:24:40 -0700 Subject: [PATCH] v0.3 = Completed all desired logic and tidied up code + Added check to see if the app exists in the iTunes API + Cleaned up code + Finished supporting logic --- Jamf Pro/Admin Tools/jamf_verifyVPPApps.sh | 184 +++++++++------------ 1 file changed, 76 insertions(+), 108 deletions(-) diff --git a/Jamf Pro/Admin Tools/jamf_verifyVPPApps.sh b/Jamf Pro/Admin Tools/jamf_verifyVPPApps.sh index aa4ea0a..56ebff5 100644 --- a/Jamf Pro/Admin Tools/jamf_verifyVPPApps.sh +++ b/Jamf Pro/Admin Tools/jamf_verifyVPPApps.sh @@ -3,9 +3,9 @@ ################################################################################################### # Script Name: jamf_verifyVPPApps.sh # By: Zack Thompson / Created: 6/13/2018 -# Version: 0.2 / Updated: 6/13/2018 / By: ZT +# Version: 0.3 / Updated: 6/14/2018 / By: ZT # -# Description: This script is used to scope groups to VPP Apps. +# Description: Gets details on all of the VPP Apps from the JSS and checks iTunes to see if they are 32bit and exports results to a csv file # ################################################################################################### @@ -43,123 +43,105 @@ echo "***** verifyVPPApps process: START *****" getHelp() { echo " -usage: jamf_verifyVPPApps.sh [-get | -assign] [/path/to/file.txt] [-help] +usage: jamf_verifyVPPApps.sh [-run | -r] [/path/to/file.csv] [-help] -Info: Get a list of VPP Apps or assign VPP Apps to groups. +Info: Gets details on all of the VPP Apps from the JSS and checks iTunes to see if they are 32bit and exports results to a csv file. Actions: - -get Gets all the VPP Apps from the JSS and exports them to a txt file. - Example: jamf_verifyVPPApps.sh -get output.txt - - -assign Read the provide file and assigns (scopes) VPP Apps to a Group. - Example: jamf_verifyVPPApps.sh -assign input.txt + -run | -r Run the report and output to a csv file. + Example: jamf_verifyVPPApps.sh -run output.csv -help Displays this help section. Example: jamf_verifyVPPApps.sh -help " } -# Build a list of Mobile Device Apps from the JSS. getAppInfo() { echo "Requesting list of all App IDs..." # GET list of App IDs from the JSS. curlReturn="$(/usr/bin/curl "${curlJamfAPI[@]}" GET $mobileApps)" # Check if the API call was successful or not. - curlCode=$(echo "${curlReturn}" | awk -F statusCode: '{print $2}') - if [[ $curlCode != "200" ]]; then - informBy "ERROR: API call failed with error: ${curlCode}!" - echo "***** verifyVPPApps process: FAILED *****" - exit 4 - fi + curlCode=$(echo "${curlReturn}" | /usr/bin/awk -F statusCode: '{print $2}' | /usr/bin/xargs ) # Regex down to just the ID numbers - appIDs=$(echo "${curlReturn}" | sed -e 's/statusCode\:.*//g' | xmllint --format - | xpath /mobile_device_applications/mobile_device_application/id 2>/dev/null | LANG=C sed -e 's/<[^/>]*>//g' | LANG=C sed -e 's/<[^>]*>/\'$'\n/g') - + appIDs=$(echo "${curlReturn}" | /usr/bin/sed -e 's/statusCode\:.*//g' | /usr/bin/xmllint --format - | /usr/bin/xpath /mobile_device_applications/mobile_device_application/id 2>/dev/null | LANG=C /usr/bin/sed -e 's/<[^/>]*>//g' | LANG=C /usr/bin/sed -e 's/<[^>]*>/\'$'\n/g') + informBy "Getting info for each App from the JSS..." + # For Each ID, get additional information. for appID in $appIDs; do + + # Get each info for each AppID curlReturn="$(/usr/bin/curl "${curlJamfAPI[@]}" GET ${mobileAppsByID}/${appID}/subset/General)" # Check if the API call was successful or not. - curlCode=$(echo "${curlReturn}" | awk -F statusCode: '{print $2}') + curlCode=$(echo "${curlReturn}" | /usr/bin/awk -F statusCode: '{print $2}' | /usr/bin/xargs ) checkStatusCode $curlCode $appID - # Regex down to the info we want and output to a tab delimited file - appInfo="$(printf "${curlReturn}" | sed -e 's/statusCode\:.*//g' | xmllint --format - | xpath '/mobile_device_application/general/id | /mobile_device_application/general/name | /mobile_device_application/general/site/name | /mobile_device_application/general/bundle_id | /mobile_device_application/general/itunes_store_url' 2>/dev/null | LANG=C sed -e 's/<[^/>]*>//g' | LANG=C sed -e 's/<[^>]*>/\'$'\t/g' | LANG=C sed -e 's/\'$'\t[^\t]*$//')" #>> "${outFile}" + # Regex down to the info we want. + appInfo="$(echo "${curlReturn}" | /usr/bin/sed -e 's/statusCode\:.*//g' | /usr/bin/xmllint --format - | /usr/bin/xpath '/mobile_device_application/general/id | /mobile_device_application/general/name | /mobile_device_application/general/site/name | /mobile_device_application/general/bundle_id | /mobile_device_application/general/itunes_store_url' 2>/dev/null | LANG=C /usr/bin/sed -e 's/<[^/>]*>//g' | LANG=C /usr/bin/sed -e 's/<[^>]*>/\'$'\t/g' | LANG=C /usr/bin/sed -e 's/\'$'\t[^\t]*$//')" + # Read in the App Info and assign to variables + while IFS=$'\t' read appID appName bundle_id itunes_store_url appSite; do - # Read in the file and assign to variables - while IFS=$'\t' read appID appName bundle_id itunes_store_url appSite; do + # Get the Adam ID which is needed for the iTunes API + appAdamID=$(echo "${itunes_store_url}" | /usr/bin/sed -e 's/.*\/id\(.*\)?.*/\1/') + # Get App info from iTunes + iTunesCurlReturn="$(/usr/bin/curl "${curliTunesAPI[@]}" GET ${iTunesAPI}${appAdamID})" - #printf "${#appInfo[@]}" + # Check if the API call was successful or not. + curlCode=$(echo "${iTunesCurlReturn}" | /usr/bin/awk -F statusCode: '{print $2}' | /usr/bin/xargs ) + checkStatusCode $curlCode $appID "iTunes" $appAdamID - printf '%s\n' "itunes_store_url: ${itunes_store_url}" - appAdamID=$(printf "${itunes_store_url}" | sed -e 's/.*\/id\(.*\)?.*/\1/') - printf '%s\n' "AdamID: ${appAdamID}" - # - #echo "${iTunesAPI}/${appAdamID}" - iTunesCurlReturn="$(/usr/bin/curl "${curliTunesAPI[@]}" GET ${iTunesAPI}${appAdamID})" + # echo "AppID: ${appID} AdamID: ${appAdamID}" + # Check if the App still exists on iTunes + appExists=$(echo "${iTunesCurlReturn}" | /usr/bin/sed -e 's/statusCode\:.*//g' | /usr/bin/python -c " +import sys, json - # Check if the API call was successful or not. - curlCode=$(printf "${iTunesCurlReturn}" | awk -F statusCode: '{print $2}') - checkStatusCode $curlCode $appID +objects = json.load(sys.stdin) - printf '%s\t' "${appInfo}" - #32bitness=$( - printf "${iTunesCurlReturn}" | sed -e 's/statusCode\:.*//g' | python -mjson.tool | awk -F "is32bitOnly\": " '{print $2}' | xargs | sed 's/,//' #) +if not objects.get('results'): + print('No') +else: + print('Yes')") - unset appInfo + # echo "App Exists: ${appExists}" - # echo "Adding header to output file..." - # header="App ID\tApp Name\tBundle ID\tiTunes Store URL\tJamf Site\t\t32Bit" - # echo -e $header >> "${outFile}" + # Extract if the App is 32bit Only + bitness32=$(echo "${iTunesCurlReturn}" | /usr/bin/sed -e 's/statusCode\:.*//g' | /usr/bin/python -mjson.tool | /usr/bin/awk -F "is32bitOnly\": " '{print $2}' | /usr/bin/xargs | /usr/bin/sed 's/,//') + # Output to File + echo -e "${appInfo}\t${appExists}\t${bitness32}" >> "${outFile}" - done < <(printf '%s\n' "${appInfo}") + # Clear variable for next loop item + unset appInfo - + done < <(/usr/bin/printf '%s\n' "${appInfo}") done -# informBy "List has been saved to: ${outFile}" + informBy "List has been saved to: ${outFile}" } checkStatusCode() { - case $1 in - 200 ) - # Turn off success notifications - # informBy " -> Request successful" - ;; - 201) - # Turn off success notifications - # informBy "App ID: ${appID} -> Request to create or update object successful" - ;; - 400) - informBy "App ID: ${appID} -> Bad request. Verify the syntax of the request specifically the XML body." - ;; - 401) - informBy "App ID: ${appID} -> Authentication failed. Verify the credentials being used for the request." - ;; - 403) - informBy "App ID: ${appID} -> Invalid permissions. Verify the account being used has the proper permissions for the object/resource you are trying to access." - ;; - 404) - informBy "App ID: ${appID} -> Object/resource not found. Verify the URL path is correct." - ;; - 409) - informBy "App ID: ${appID} -> Conflict" - ;; - 500) - informBy "App ID: ${appID} -> Internal server error. Retry the request or contact Jamf support if the error is persistent." - ;; - esac + if [[ $1 != "200" ]]; then + informBy "ERROR: API call failed for ${2} with error: ${1}!" + + if [[ $3 == "iTunes" ]]; then + informBy "AdamID is: ${4}" + fi + fi } fileExists() { if [[ ! -e "${1}" && $2 == "create" ]]; then echo "Creating output file at location: ${1}" /usr/bin/touch "${1}" + + echo "Adding header to output file..." + header="App ID\tApp Name\tBundle ID\tiTunes Store URL\tJamf Site\tAvailable\t32Bit" + echo -e $header >> "${outFile}" elif [[ ! -e "${1}" && $2 == "trip" ]]; then informBy "ERROR: Unable to find the input file!" echo "***** verifyVPPApps process: FAILED *****" @@ -191,7 +173,7 @@ else curlReturn="$(/usr/bin/curl $jamfPS/JSSResource/jssuser -i --silent --show-error --fail --user "${jamfAPIUser}:${jamfAPIPassword}" --write-out "statusCode:%{http_code}")" # Check if the API call was successful or not. - curlCode=$(echo "$curlReturn" | awk -F statusCode: '{print $2}') + curlCode=$(echo "$curlReturn" | /usr/bin/awk -F statusCode: '{print $2}') if [[ $curlCode != *"200"* ]]; then informBy "ERROR: Invalid API credentials provided!" echo "***** verifyVPPApps process: FAILED *****" @@ -201,42 +183,28 @@ else echo "API Credentials Valid -- continuing..." fi -getAppInfo - -# case $action in -# --get | -g | "Get VPP Apps" ) -# if [[ -n "${switch1}" ]]; then -# outFile="${switch1}" -# # Function getApps -# getApps -# else -# outFile=$(/usr/bin/osascript -e 'tell application (path to frontmost application as text)' -e 'return POSIX path of (choose file name with prompt "Provide a file name and location to save the configuration file:")' -e 'end tell' 2>/dev/null) -# # Function fileExists -# fileExists "${outFile}" create -# # Function getApps -# getApps -# fi -# ;; -# --assign | -a | "Assign VPP Apps" ) -# if [[ -n "${switch1}" ]]; then -# inputFile="${switch1}" -# # Function fileExists -# fileExists "${inputFile}" trip -# # Function assignApps -# assignApps -# else -# inputFile=$(/usr/bin/osascript -e 'tell application (path to frontmost application as text)' -e 'return POSIX path of(choose file with prompt "Select configuration file to process:" of type {"txt"})' -e 'end tell' 2>/dev/null) -# # Function fileExists -# fileExists "${inputFile}" trip -# # Function assignApps -# assignApps -# fi -# ;; -# -help | -h | * ) -# # Function getHelp -# getHelp -# ;; -# esac +# Perform the request action. +case $action in + --run | -r ) + if [[ -n "${switch1}" ]]; then + outFile="${switch1}" + # Function fileExists + fileExists "${outFile}" create + # Function getAppInfo + getAppInfo + else + outFile=$(/usr/bin/osascript -e 'tell application (path to frontmost application as text)' -e 'return POSIX path of (choose file name with prompt "Provide a file name and location to save the configuration file:")' -e 'end tell' 2>/dev/null) + # Function fileExists + fileExists "${outFile}" create + # Function getAppInfo + getAppInfo + fi + ;; + -help | -h | * ) + # Function getHelp + getHelp + ;; +esac informBy "Script successfully completed!" echo "***** verifyVPPApps process: COMPLETE *****"