-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathUpdateReporting
More file actions
137 lines (117 loc) · 6.09 KB
/
UpdateReporting
File metadata and controls
137 lines (117 loc) · 6.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/bin/bash
#A tool to help admins quickly see the latest update status for all devices in their fleet.
#As always, test in test servers, not in prod.
#File path for exported CSV
finalCSVOutput="/$HOME/Downloads/new.csv"
jsonFilePathTemp="/tmp/Update_Reporting/AllUpdates.json"
jsonFilePath="/tmp/Update_Reporting/AllUpdatesFinal.json"
jsonScratchpad="/tmp/Update_Reporting/scratchpad.json"
csvFilePath="/tmp/Update_Reporting/preliminaryCSV.csv"
#############################################################################
#API Creds
#Get these right first or you could lock yourself out as it loops through, still need to add smart logic for token, otherwise it can run for 401 pages since it sees that as the max page count
username="username"
password="password"
url="https://server.jamfcloud.com"
#############################################################################
#Bearer Token Auth
#Variable declarations
bearerToken=""
tokenExpirationEpoch="0"
getBearerToken() {
response=$(curl -s -u "$username":"$password" "$url"/api/v1/auth/token -X POST)
bearerToken=$(echo "$response" | plutil -extract token raw -)
tokenExpiration=$(echo "$response" | plutil -extract expires raw - | awk -F . '{print $1}')
tokenExpirationEpoch=$(date -j -f "%Y-%m-%dT%T" "$tokenExpiration" +"%s")
}
checkTokenExpiration() {
nowEpochUTC=$(date -j -f "%Y-%m-%dT%T" "$(date -u +"%Y-%m-%dT%T")" +"%s")
if [[ tokenExpirationEpoch -gt nowEpochUTC ]]
then
echo "Token valid until the following epoch time: " "$tokenExpirationEpoch"
else
echo "No valid token available, getting new token"
getBearerToken
fi
}
invalidateToken() {
responseCode=$(curl -w "%{http_code}" -H "Authorization: Bearer ${bearerToken}" $url/api/v1/auth/invalidate-token -X POST -s -o /dev/null)
if [[ ${responseCode} == 204 ]]
then
echo "Token successfully invalidated"
bearerToken=""
tokenExpirationEpoch="0"
elif [[ ${responseCode} == 401 ]]
then
echo "Token already invalid"
else
echo "An unknown error occurred invalidating the token"
fi
}
#############################################################################
#Cleanuup from previous runs
rm -rf /tmp/Update_Reporting/
mkdir /tmp/Update_Reporting/
#############################################################################
#Get Bearer Token
getBearerToken
#############################################################################
pageSize="100"
page="0"
#Pull all devices plans from newest to oldest
initialUpdatePlanCheck=$(curl -X 'GET' \
"$url/api/v1/managed-software-updates/plans?page=$page&page-size=$pageSize&sort=planUuid%3Adesc" \
-H 'accept: application/json' \
-H "Authorization: Bearer $bearerToken")
#echo $initialUpdatePlanCheck
echo $initialUpdatePlanCheck > $jsonFilePath
#JQ Filter Function on output json from API calls, Device_ID must always be first for the cursed CSV array to run. If you don't care about that then go nuts.
#the first [] sets the column headers and the second [] pulls from the json and sets under each header in order that the columns were specified. If you change this, also change line 116 to match
jq -r '["Device_ID","Computer_or_Mobile_Device","updateAction","status","Error_Reason"], (.results[] | [.device.deviceId, .device.objectType, .updateAction, .status.state, .status.errorReasons[0]]) | @csv' "$jsonFilePath" > $csvFilePath
jq -r '.' "$jsonFilePath" > $jsonFilePathTemp && mv $jsonFilePathTemp $jsonFilePath
getCountOfResults=$(jq -r -c '.[]' <<< "$initialUpdatePlanCheck" | awk '{print $1}')
filterGetCountOfResults=$(awk -F, 'NR==1{print $1}' <<<"$getCountOfResults")
#Do some math to check if we need to keep going up from page size
#if pagesize/filtergetcountofresults le=1 then +1 page
#WARNING 'expr' will round to nearest whole number
realPageNumber=$(expr $page + 1)
#echo $realPageNumber
totalPossibleResults=$(expr $pageSize \* $realPageNumber)
#echo $totalPossibleResults
#Make a for loop that goes through multiple pages if found and get next page if needed
while [ $totalPossibleResults -lt $filterGetCountOfResults ]; do
#Testing reporting, can comment out if not desired
echo "more update results pending, fetching now"
((page++))
realPageNumber=$(expr $page + 1)
#Testing reporting, can comment out if not desired, should always start at 2 since page 1 already ran
echo "current real page number is $realPageNumber"
totalPossibleResults=$(expr $pageSize \* $realPageNumber)
#Testing reporting, can comment out if not desired, your page * real page should be less than this value if it's still running
echo "total possible results are $filterGetCountOfResults"
checkTokenExpiration
UpdatePlanCheck=$(curl -X 'GET' \
"$url/api/v1/managed-software-updates/plans?page=$page&page-size=$pageSize&sort=planUuid%3Adesc" \
-H 'accept: application/json' \
-H "Authorization: Bearer $bearerToken")
echo $UpdatePlanCheck > $jsonScratchpad
#JQ Filter Function on output json from API calls, then adds it to the existing CSV from the first call. Updates to the JQ filter here should match line 81
#Don't make column headers here or it'll create more entries as the CSV builds, just the data should be mimicked
jq -r '.results[] | [.device.deviceId, .device.objectType, .updateAction, .status.state, .status.errorReasons[0]] | @csv' "$jsonScratchpad" >> $csvFilePath
done
#A cursed for loop where Bash edits a CSV file. There's got to be a better way to do this, but it's not something I can figure out currently.
#Since the pages of results return by most recent to least recent, the function loops through the initial CSV and skips anything that's already been reported into it so you can just get the latest status.
#Could be problematic if admins send multiple plans out with overlapping scope as the "existing plan in progress" could be the latest report.
readCSVFile=$(cat $csvFilePath)
for line in $readCSVFile;
do
printCurrentDeviceID=$(grep -Eiow '^"[0-9]+"' <<< "${line}")
checkForId=$(cat "/tmp/Update_Reporting/deviceIdList.txt")
checkForIDAlreadyRan=$(grep "$printCurrentDeviceID" <<< $checkForId)
if [[ $checkForIDAlreadyRan != "" ]]; then
break
else
echo $printCurrentDeviceID >> /tmp/Update_Reporting/deviceIdList.txt
echo $line >> $finalCSVOutput
fi
done