Here's a quick script I wrote to delete all classes — based on your snippet, I'm assuming that's what you're looking to do, rather than just delete classes that were imported by ASM (which is doable, but less straightforward). Works in my instance of Jamf Pro.
https://github.com/MatthewPrins/Jamf/blob/main/Delete_Classes.sh
Here's a quick script I wrote to delete all classes — based on your snippet, I'm assuming that's what you're looking to do, rather than just delete classes that were imported by ASM (which is doable, but less straightforward). Works in my instance of Jamf Pro.
https://github.com/MatthewPrins/Jamf/blob/main/Delete_Classes.sh
I got this error
Failed conversion of ``<stdin>: Unexpected character { at line 1'' using format ``%Y-%m-%dT%T''
date: illegal time format
usage: date e-jnRu] ]-d dst] ]-r seconds] ]-t west] ]-v-+|-]valaymwdHMS]] ...
n-f fmt date | | [mm]dd]HH]MMMMcc]yy]y.ss]] ]+format]
I got this error
Failed conversion of ``<stdin>: Unexpected character { at line 1'' using format ``%Y-%m-%dT%T''
date: illegal time format
usage: date [-jnRu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ...
[-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]
I've seen that error before — it's usually what I get when I forget to change or incorrectly enter the Jamf username/password/URL variables. Check that info (lines 11-13) to make sure it's entered in right.
Edit: After some testing, it's most likely the URL — that's the exact error I get with an incorrect URL, while the UN/PW error is slightly different
Hey. This code did it for me. Hopefully it is equally as successful for you as well. Oh a note: If on Apple's TextEditor, be sure to "Convert to Plain Text" and ensure the extension is .sh. Be well and have a great day!:
#!/bin/bash
####################################################################################################
#
# THIS SCRIPT IS NOT AN OFFICIAL PRODUCT OF JAMF SOFTWARE
# AS SUCH IT IS PROVIDED WITHOUT WARRANTY OR SUPPORT
#
# BY USING THIS SCRIPT, YOU AGREE THAT JAMF SOFTWARE
# IS UNDER NO OBLIGATION TO SUPPORT, DEBUG, OR OTHERWISE
# MAINTAIN THIS SCRIPT
#
####################################################################################################
#
# DESCRIPTION
# This script retrieves class information from the JAMF Pro RESTful API, saves it as an XML file,
# and then uses that XML file to delete the classes.
# Requires a user that has READ and DELETE privileges for Classes.
#
####################################################################################################
#
# DEFINE VARIABLES & READ IN PARAMETERS
#
####################################################################################################
echo "#####################"
echo "###!!! WARNING !!!###"
echo "#####################"
echo "This script will retrieve class information from the JAMF Pro server and delete all classes."
echo "Please ensure you have a database backup."
echo "There is no magic undo button other than restoring to a backup when the classes were in existence."
read -p "Are you sure you want to continue? [ y | n ] " answer
if [[ $answer != 'y' ]]; then
echo "Exiting script!"
exit 1
fi
read -p "Jamf Pro URL: " server
read -p "Jamf Pro Username: " username
read -s -p "Jamf Pro Password: " password
echo ""
# Trim the trailing slash off if necessary
if [ "${server: -1}" == "/" ]; then
server="${server%?}"
fi
# Add protocol and specify port 443
server="https://${server}:443"
# Base64 encode the username and password for basic authentication
auth=$(echo -n "$username:$password" | base64)
# Filename for the XML file
xmlFile="classes.xml"
echo "Retrieving class information..."
curl -s -H "Authorization: Basic $auth" -H "Accept: application/xml" "$server/JSSResource/classes" -o "$xmlFile"
echo "Deleting classes..."
classIDs=$(xmllint --xpath "//id/text()" "$xmlFile")
for classID in $classIDs; do
echo "Deleting class with ID: $classID"
curl -s -H "Authorization: Basic $auth" -H "Content-type: application/xml" -X DELETE "$server/JSSResource/classes/id/$classID"
done
echo "All classes have been deleted."
# Clean up XML file
rm "$xmlFile"
Hey. This code did it for me. Hopefully it is equally as successful for you as well. Oh a note: If on Apple's TextEditor, be sure to "Convert to Plain Text" and ensure the extension is .sh. Be well and have a great day!:
#!/bin/bash
####################################################################################################
#
# THIS SCRIPT IS NOT AN OFFICIAL PRODUCT OF JAMF SOFTWARE
# AS SUCH IT IS PROVIDED WITHOUT WARRANTY OR SUPPORT
#
# BY USING THIS SCRIPT, YOU AGREE THAT JAMF SOFTWARE
# IS UNDER NO OBLIGATION TO SUPPORT, DEBUG, OR OTHERWISE
# MAINTAIN THIS SCRIPT
#
####################################################################################################
#
# DESCRIPTION
# This script retrieves class information from the JAMF Pro RESTful API, saves it as an XML file,
# and then uses that XML file to delete the classes.
# Requires a user that has READ and DELETE privileges for Classes.
#
####################################################################################################
#
# DEFINE VARIABLES & READ IN PARAMETERS
#
####################################################################################################
echo "#####################"
echo "###!!! WARNING !!!###"
echo "#####################"
echo "This script will retrieve class information from the JAMF Pro server and delete all classes."
echo "Please ensure you have a database backup."
echo "There is no magic undo button other than restoring to a backup when the classes were in existence."
read -p "Are you sure you want to continue? [ y | n ] " answer
if [[ $answer != 'y' ]]; then
echo "Exiting script!"
exit 1
fi
read -p "Jamf Pro URL: " server
read -p "Jamf Pro Username: " username
read -s -p "Jamf Pro Password: " password
echo ""
# Trim the trailing slash off if necessary
if [ "${server: -1}" == "/" ]; then
server="${server%?}"
fi
# Add protocol and specify port 443
server="https://${server}:443"
# Base64 encode the username and password for basic authentication
auth=$(echo -n "$username:$password" | base64)
# Filename for the XML file
xmlFile="classes.xml"
echo "Retrieving class information..."
curl -s -H "Authorization: Basic $auth" -H "Accept: application/xml" "$server/JSSResource/classes" -o "$xmlFile"
echo "Deleting classes..."
classIDs=$(xmllint --xpath "//id/text()" "$xmlFile")
for classID in $classIDs; do
echo "Deleting class with ID: $classID"
curl -s -H "Authorization: Basic $auth" -H "Content-type: application/xml" -X DELETE "$server/JSSResource/classes/id/$classID"
done
echo "All classes have been deleted."
# Clean up XML file
rm "$xmlFile"
I have a script will delete only the "Manual" classes if anyone would like. It will skip ASM classes and delete only manual. I use this a lot because , we have tons of rotations at our district and they become inactive and clog up Apple classroom and Jamf teacher for our staff.
echo "Downloading list of class IDs..."
ids+=($(curl -X GET -s -k -u ${jssUser}:${jssPass} ${jssURL}/JSSResource/classes | xmllint --format - | awk -F'>|<' '/<id>/{print $3}' | sort -n))
for n in "${ids[@]}"; do
source=$(curl -X GET -s -k -u ${jssUser}:${jssPass} ${jssURL}/JSSResource/classes/id/${n} | xmllint --format - | awk -F'>|<' '/<source>/{print $3}')
if [[ $source = "N/A" ]] ; then
echo "Class $n manually created, deleting..."
curl -s -k -u ${jssUser}:${jssPass} ${jssURL}/JSSResource/classes/id/${n} -X DELETE
elif [[ $source = "Apple School Manager" ]] ; then
echo "Class $n created by ASM, skipping..."
fi
done
exit 0
I have a script will delete only the "Manual" classes if anyone would like. It will skip ASM classes and delete only manual. I use this a lot because , we have tons of rotations at our district and they become inactive and clog up Apple classroom and Jamf teacher for our staff.
echo "Downloading list of class IDs..."
ids+=($(curl -X GET -s -k -u ${jssUser}:${jssPass} ${jssURL}/JSSResource/classes | xmllint --format - | awk -F'>|<' '/<id>/{print $3}' | sort -n))
for n in "${ids[@]}"; do
source=$(curl -X GET -s -k -u ${jssUser}:${jssPass} ${jssURL}/JSSResource/classes/id/${n} | xmllint --format - | awk -F'>|<' '/<source>/{print $3}')
if [[ $source = "N/A" ]] ; then
echo "Class $n manually created, deleting..."
curl -s -k -u ${jssUser}:${jssPass} ${jssURL}/JSSResource/classes/id/${n} -X DELETE
elif [[ $source = "Apple School Manager" ]] ; then
echo "Class $n created by ASM, skipping..."
fi
done
exit 0
I still kept getting errors when trying this. What I did find was this script that worked like a charm! https://raw.githubusercontent.com/MatthewPrins/Jamf/main/Delete_Classes.sh
The only modification I made to the script was adding the port to the end of the URL.
url="https://xxxxxx.jamfcloud.com:443"
Open text edit, change it to plain text, paste the script into it, save it as a .sh
Open terminal, type in sudo chmod u+x /path/to/file
Hit Return
Drag the .sh file into terminal (or type in the path) and hit return again, you should see the classes start to delete.
Keep in mind this will delete ALL classes, imported or manually created. I hope this helps someone because I was pulling my hair out trying to find a script that still worked!
Anybody have this in PowerShell?
Hey all. Each year I have to renovate this script to work. I don't know why.
This year I had to create a virtual environment in Terminal (macOS) to get/install needed packages, running a python script to call out to JAMF to pull classes and then run a command to purge them. It is a pain and I wish was easier to do inside the JAMF console.
I used CoPilot AI to assist in coding-related headaches. I very much suggest the same. CoPilot was actually a better assist than GPT in this scenario. Would recommend.
I've seen that error before — it's usually what I get when I forget to change or incorrectly enter the Jamf username/password/URL variables. Check that info (lines 11-13) to make sure it's entered in right.
Edit: After some testing, it's most likely the URL — that's the exact error I get with an incorrect URL, while the UN/PW error is slightly different
Hi Matthew - thanks so much for this! My old PowerShell scripts don't work any more, thanks to the bearer token stuff, that I don't know how to fix.
Anyway, I am running your script and getting:
-:1 parser error : StartTag: Invalid element name
<!doctype html><html lang="en"><head><title>HTTP Status 404 - Not Found</title
^
-:1 parser error : StartTag: Invalid element name
<!doctype html><html lang="en"><head><title>HTTP Status 404 - Not Found</title
^
0 Classes
0/0
All classes deleted
I made sure the variables are correct by adding a piece of code:
echo Token $bearerToken received.
right after getBearerToken is called, and I see the token in the output.
Any help is much appreciated!
Hi Matthew - thanks so much for this! My old PowerShell scripts don't work any more, thanks to the bearer token stuff, that I don't know how to fix.
Anyway, I am running your script and getting:
-:1 parser error : StartTag: Invalid element name
<!doctype html><html lang="en"><head><title>HTTP Status 404 - Not Found</title
^
-:1 parser error : StartTag: Invalid element name
<!doctype html><html lang="en"><head><title>HTTP Status 404 - Not Found</title
^
0 Classes
0/0
All classes deleted
I made sure the variables are correct by adding a piece of code:
echo Token $bearerToken received.
right after getBearerToken is called, and I see the token in the output.
Any help is much appreciated!
Ask CoPilot AI, it does a good job working through syntax B.S. and might be able to get you through the roadblock quick. Be well!
Ask CoPilot AI, it does a good job working through syntax B.S. and might be able to get you through the roadblock quick. Be well!
@cbrewer's PowerShell script worked effortlessly!
Just a note. I noticed that the ps script will exit if it hits a manually created class(not one generated by asm). deleting the class in JAMF manually is the only way to help the script proceed along at lease in our case.