mirror of
https://github.com/MLBZ521/MacAdmin.git
synced 2026-03-03 17:12:02 +00:00
233 lines
9.5 KiB
Bash
233 lines
9.5 KiB
Bash
#!/bin/bash
|
|
|
|
###################################################################################################
|
|
# Script Name: jamf_verifyVPPApps.sh
|
|
# By: Zack Thompson / Created: 6/13/2018
|
|
# Version: 1.0 / Updated: 10/8/2018 / By: ZT
|
|
#
|
|
# Description: Gets details on all of the Mobile Device VPP Apps from the JSS and checks the iTunes API to see if they are available, update to date, and 32bit only, and exports results to a csv file.
|
|
#
|
|
# Inspired by:
|
|
# https://github.com/dnikles/Check32bitOnlyApps/blob/master/check32bit.sh
|
|
# https://github.com/bumbletech/JSS_API_scripts/blob/master/JSS_API_check_stale_and_32bit_apps.sh
|
|
# https://www.jamf.com/jamf-nation/discussions/28035/identifying-32-bit-apps-for-ios-before-vpp-purchase
|
|
#
|
|
###################################################################################################
|
|
|
|
echo "***** verifyVPPApps process: START *****"
|
|
|
|
##################################################
|
|
# Define Variables
|
|
# Either hard code or prompt for credentials
|
|
# jamfAPIUser="APIUsername"
|
|
# jamfAPIPassword="APIPassword"
|
|
jamfAPIUser=$(/usr/bin/osascript -e 'set userInput to the text returned of (display dialog "Enter your Jamf Username:" default answer "")' 2>/dev/null)
|
|
jamfAPIPassword=$(/usr/bin/osascript -e 'set userInput to the text returned of (display dialog "Enter your Jamf Password:" default answer "" with hidden answer)' 2>/dev/null)
|
|
|
|
jamfPS="https://newjss.company.com:8443"
|
|
mobileApps="${jamfPS}/JSSResource/mobiledeviceapplications"
|
|
mobileAppsByID="${mobileApps}/id"
|
|
# Add -k (--insecure) to disable SSL verification
|
|
curlJamfAPI=(--silent --show-error --fail --user "${jamfAPIUser}:${jamfAPIPassword}" --write-out "statusCode:%{http_code}" --output - --header "Accept: application/xml" --request)
|
|
|
|
iTunesAPI="https://uclient-api.itunes.apple.com/WebObjects/MZStorePlatform.woa/wa/lookup?version=1&p=mdm-lockup&caller=MDM&platform=itunes&cc=us&l=en&id="
|
|
curliTunesAPI=(--silent --show-error --fail --write-out "statusCode:%{http_code}" --output - --header "Accept: application/JSON" --request)
|
|
|
|
# Either use CLI arguments or prompt for choice
|
|
if [[ "${4}" == "Jamf" ]]; then
|
|
action=$(/usr/bin/osascript -e 'tell application (path to frontmost application as text)' -e 'set availableActions to {"Get VPP Apps", "Assign VPP Apps"}' -e 'set Action to choose from list availableActions with prompt "Select action:" default items {"Get VPP Apps"}' -e 'end tell' 2>/dev/null)
|
|
ranBy="Jamf"
|
|
else
|
|
action="${1}"
|
|
switch1="${2}"
|
|
ranBy="CLI"
|
|
fi
|
|
|
|
##################################################
|
|
# Setup Functions
|
|
|
|
getHelp() {
|
|
echo "
|
|
usage: jamf_verifyVPPApps.sh [-run | -r] [/path/to/file.csv] [-help]
|
|
|
|
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:
|
|
--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
|
|
"
|
|
}
|
|
|
|
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}" | /usr/bin/awk -F statusCode: '{print $2}' | /usr/bin/xargs )
|
|
checkStatusCode $curlCode $appID
|
|
|
|
numberOfApps=$(echo "${curlReturn}" | /usr/bin/sed -e 's/statusCode\:.*//g' | /usr/bin/xmllint --format - | /usr/bin/xpath /mobile_device_applications/size 2>/dev/null | LANG=C /usr/bin/sed -e 's/<[^/>]*>//g' | LANG=C /usr/bin/sed -e 's/<[^>]*>/\'$'\n/g')
|
|
echo "Total Number of Apps: $numberOfApps"
|
|
|
|
# Set the ulimit as a large number of apps will start causing steps to error out because of "cannot make pipe for command substitution: Too many open files"
|
|
ulimitSize=$((numberOfApps + 256))
|
|
ulimit -n $ulimitSize
|
|
|
|
# Regex down to just the ID numbers
|
|
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}" | /usr/bin/awk -F statusCode: '{print $2}' | /usr/bin/xargs )
|
|
checkStatusCode $curlCode $appID
|
|
|
|
# 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/version | /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 jssVersion 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})"
|
|
|
|
# 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
|
|
|
|
# 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
|
|
|
|
objects = json.load(sys.stdin)
|
|
|
|
if not objects.get('results'):
|
|
print('No')
|
|
else:
|
|
print('Yes')")
|
|
|
|
# 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/,//')
|
|
|
|
# Extract the Version from iTunes
|
|
iTunesVersion=$(echo "${iTunesCurlReturn}" | /usr/bin/sed -e 's/statusCode\:.*//g' | /usr/bin/python -mjson.tool | /usr/bin/awk -F "\"display\":" '{print $2}' | /usr/bin/xargs | /usr/bin/sed 's/,//')
|
|
|
|
# echo "iTunes: ${iTunesVersion} and JSS: ${jssVersion}"
|
|
# Check if the jssVersion is Out of Date
|
|
if [[ -n "${iTunesVersion}" && "${iTunesVersion}" == "${jssVersion}" ]]; then
|
|
outOfDate="No"
|
|
else
|
|
outOfDate="Yes"
|
|
fi
|
|
|
|
# Output to File
|
|
echo -e "${appInfo}\t${appExists}\t${outOfDate}\t${iTunesVersion}\t${bitness32}" >> "${outFile}"
|
|
|
|
# Clear variable for next loop item
|
|
unset appInfo
|
|
|
|
done < <(/usr/bin/printf '%s\n' "${appInfo}")
|
|
done
|
|
|
|
informBy "List has been saved to: ${outFile}"
|
|
}
|
|
|
|
checkStatusCode() {
|
|
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\tJSS Version\tiTunes Store URL\tJamf Site\tAvailable\tOut Of Date\tiTunes Version\t32Bit"
|
|
echo -e $header >> "${outFile}"
|
|
elif [[ ! -e "${1}" && $2 == "trip" ]]; then
|
|
informBy "ERROR: Unable to find the input file!"
|
|
echo "***** verifyVPPApps process: FAILED *****"
|
|
exit 3
|
|
fi
|
|
}
|
|
|
|
informBy() {
|
|
case $ranBy in
|
|
Jamf )
|
|
/usr/bin/osascript -e 'tell application (path to frontmost application as text) to display dialog "'"${1}"'" buttons {"OK"}' > /dev/null
|
|
;;
|
|
CLI )
|
|
echo "${1}"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
##################################################
|
|
# Bits Staged
|
|
|
|
# Verify credentials were provided.
|
|
if [[ -z "${jamfAPIUser}" && -z "${jamfAPIPassword}" ]]; then
|
|
informBy "Jamf credentials are required!"
|
|
exit 1
|
|
else
|
|
# Verify credentials that were provided by doing an API call and checking the result to verify permissions.
|
|
echo "Verifying API credentials..."
|
|
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" | /usr/bin/awk -F statusCode: '{print $2}')
|
|
if [[ $curlCode != *"200"* ]]; then
|
|
informBy "ERROR: Invalid API credentials provided!"
|
|
echo "***** verifyVPPApps process: FAILED *****"
|
|
exit 2
|
|
fi
|
|
|
|
echo "API Credentials Valid -- continuing..."
|
|
fi
|
|
|
|
# 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 *****"
|
|
exit 0 |