Yule Logging

brockwalters
Contributor II

As it is the holiday season, I wanted to offer up a little gratitude in the form of boilerplate code related to topics that come up in the macadmins #scripting & #bash channels again & again. I hope people find it here & find it useful.

1) Logging is always a hot topic. "How do I create a log for my script?" "Where should I write log output?" etc. Without saying this solution is definitive, the script below has a pattern that I have used over & over. In fact, I paste this block exactly into any script I create that needs logging. It uses tee along with exec & with a named pipe. Why? Well, I find this works in all situations to capture all foreground & background processes executed by the script & it creates a dedicated stream / file for the log output regardless of what the script is trying to do.

2) Jamf API. I said in an earlier post I had come up with the shortest, bestest version of making an API call with token auth. I was wrong. I made it shorter & betterer.

This script does not do anything remarkable - it removes Network Segments at their endpoint by name. This is also something that seems to come up repeatedly as the Jamf API docs could be a bit clearer on this subject. Using the object ID is straight forward but I think having a good example of using name as the identifier should be useful to some of you. Happy Whatever!

 

 

#!/bin/zsh

# api.delete.network.segments @2023
# author: brock_walters@blah.com
# created: 2023-11-07 
# version: 9


# NOTE: This script is currently set in "test mode". To execute actual deletions the line in the script below starting with:
#
# 	/usr/bin/curl -LSs -X DELETE ...
#
# must be uncommented.


# environment & data

network_data_csv='/Users/Shared/building.subnet.data.csv'
jamf_environment='https://server.blah.com:8443'


###########################
### DO NOT MODIFY BELOW ###
###########################


# logging

cpuname="$(/usr/sbin/scutil --get ComputerName)"
srlnmbr="$(/usr/libexec/PlistBuddy -c 'print 0:serial-number' /dev/stdin <<< "$(/usr/sbin/ioreg -ar -d 1 -k 'IOPlatformSerialNumber')")"
usrcrnt="$(/usr/bin/stat -f %Su /dev/console)"
logexec="$(/usr/bin/basename "$0")"
logpath="/private/tmp/${logexec%.*}.log"
logpipe="/private/tmp/${logexec%.*}.pipe"

/usr/bin/mkfifo "$logpipe"
/usr/bin/tee -a < "$logpipe" "$logpath" &
exec &> "$logpipe"
printf "$(/bin/date "+%Y-%m-%dT%H:%M:%S") [START] logging %s\ncomputer name: %s\nserial number: %s\ncurrent user: %s\n" "$logexec" "$cpuname" "$srlnmbr" "$usrcrnt"  >> "$logpath"

logalrt(){
>&2 printf "$(/bin/date "+%Y-%m-%dT%H:%M:%S") [ALERT] %s\n" "$1" >> "$logpath"
}

logexit(){
>&2 printf "$(/bin/date "+%Y-%m-%dT%H:%M:%S") [STOP] logging %s\n" "$logexec" >> "$logpath"
/bin/rm -rf "$logpipe"; /usr/bin/pkill -ail tee > /dev/null; exit
}

loginfo(){
>&2 printf "$(/bin/date "+%Y-%m-%dT%H:%M:%S") [INFO] %s\n" "$1" >> "$logpath"
}


# jamf api

jamfurl="$jamf_environment"
jamfapi="$jamfurl/api/v1"
jamfchk="$jamfurl/healthCheck.html"
jamfrsc="$jamfurl/JSSResource"
osaauth='Jamf Pro Authentication'
osapswd='Please enter your Jamf API password:'
osauser='Please enter your Jamf API username:'
apiuser="$(/usr/bin/sudo -u "$usrcrnt" /usr/bin/osascript -e "display dialog \"$osauser\" default answer \"\" buttons {\"Ok\"} default button 1 with Title \"$osaauth\"" -e 'set theName to text returned of result')"
apipswd="$(/usr/bin/sudo -u "$usrcrnt" /usr/bin/osascript -e "display dialog \"$osapswd\" default answer \"\" buttons {\"Ok\"} default button 1 with Title \"$osaauth\" with hidden answer" -e 'set thePswd to text returned of result')"
b64auth="$(printf "%s" "$apiuser:$apipswd" | /usr/bin/iconv -t ISO-8859-1 | /usr/bin/base64)"
tknauth="$(/usr/bin/plutil -extract 'token' raw - <<< "$(/usr/bin/curl -LSs -X POST -H 'Accept: application/json' -H "Authorization: Basic $b64auth" "$jamfapi/auth/token")")"; /bin/sleep 1.5

api_chk(){ printf "\nChecking jamf api...\n" ; }
api_no(){ printf "The jamf server may not be available. Please try again. Exiting...\n" ; }
api_yes(){ printf "OK.\n" ; }
auth_chk(){ printf "\nValidating jamf api credentials...\njamf url: %s\njamf api user: %s\n" "$jamfurl" "$apiuser" ; }
auth_no(){ printf "Please ensure that your credentials are correct & try again. Exiting...\n\n" ; }
delete_no(){ printf "%s Network Segment Not Found.\n\n" "$ntwkstr" ; }
delete_yes(){ printf "Deleting:\n" ; }
mtch_req(){ printf 'The server has not found anything matching the request.' ; }
ntwk_csv(){ printf "\nReading Network Segment names from %s\n\n" "$network_data_csv" ; }
ops_done(){ printf "Operations complete.\nInvalidating jamf api token...\n" ; }
token_no(){ printf "jamf api token status: UNAUTHORIZED\n" ; }
token_yes(){ printf "jamf api token status: OK\n" ; }

tknchk(){
tknhttp="$(/usr/bin/curl -LSs -X GET -H 'Accept: application/json' -H "Authorization: Bearer $tknauth" "$jamfapi/auth" -o '/dev/null' -w "%{http_code}")"; /bin/sleep 1.5

case "$tknhttp" in
	'200' ) token_yes ;;
	'401' ) token_no ;;
		* ) echo "$tknhttp" ;;
esac
}

api_chk
if /usr/bin/curl -LSs "$jamfchk" --connect-timeout 60 | /usr/bin/grep -q '\[\]'
then
	api_yes
else
	api_no; logexit
fi

auth_chk; tknchk
if [ "$tknhttp" != '200' ]
then
	logalrt; auth_no; logexit
fi


# operations

IFS=$'\n'; arrdata=($(/bin/cat "$network_data_csv"))

ntwk_csv
for i in "${arrdata[@]}"
do
	ntwkstr="$(echo "$i" | /usr/bin/sed 's/,//g')"
	ntwkurl="$(echo "$i" | /usr/bin/sed 's/ /%20/g;s/,//g')"
	ntwkvar="$(/usr/bin/curl -LSs -X GET -H 'Accept: application/json' -H "Authorization: Bearer $tknauth" "$jamfrsc/networksegments/name/$ntwkurl"; /bin/sleep 1.5; echo)"

	if echo "$ntwkvar" | /usr/bin/grep -q "\"name\":\"$ntwkstr\""
	then
		logalrt; delete_yes; echo "$ntwkvar" | /usr/bin/json_pp -t json
		#/usr/bin/curl -LSs -X DELETE -H 'Accept: application/json' -H "Authorization: Bearer $tknauth" "$jamfrsc/networksegments/name/$ntwkurl"; /bin/sleep 1.5; echo >> "$logpath"
		unset ntwkstr ntwkurl ntwkvar
	elif echo "$ntwkvar" | /usr/bin/grep -q "$(mtch_req)"
	then
		loginfo; delete_no
		unset ntwkstr ntwkurl ntwkvar; continue
	else
		logalrt 'Error.'; echo >> "$logpath"
		unset ntwkstr ntwkurl ntwkvar; continue
	fi
done

ops_done
/usr/bin/curl -LSs -X POST -H 'Accept: application/json' -H "Authorization: Bearer $tknauth" "$jamfapi/auth/invalidate-token"; /bin/sleep 1.5; tknchk; echo; logexit

 

 

1 REPLY 1

brockwalters
Contributor II

PS. I failed to mention the input should just be a single column ".csv" file of single quoted Network Segment names & you put the path to that file in the network_data_csv variable at the top pf the script.