How to remove a Mobile Device from All Groups with an API Call?

Hugonaut
Valued Contributor II

Background information: I need to mass remove all devices from all groups via api

I've been reading through all the API Calls available from jamfs /api page, i've come to the conclusion if it would be anywhere, it would be here

[https://ENTERJSS.URLHERE] :8443/api/#!/mobiledevicecommands/createMobileDeviceCommandURL_post

but via "Delete" (assuming a Remove From Groups Option is an available command) instead of "Post" but "Post" is all that's available. Am I missing something?

Does anyone know of a way to remove an iOS Device from all static groups via API Call?

Thank you

________________
Looking for a Jamf Managed Service Provider? Look no further than Rocketman
________________


Virtual MacAdmins Monthly Meetup - First Friday, Every Month
1 ACCEPTED SOLUTION

ryan_ball
Valued Contributor

@Hugonaut I came up with a script for you that will take a mobile device ID and remove it from any static groups it is a member of. You really need a good XML parser to make this easier, I prefer xmlstarlet and this script leverages that. To install xmlstarlet you can install homebrew using this command:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Then install xmlstarlet with this command:

brew install xmlstarlet

Here is the script:

#!/bin/bash
# written by Ryan Ball

loggedInUser=$(/usr/bin/python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");')
jssURL=$(defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url | sed s'/.$//')
outputDir="/Users/$loggedInUser/Documents/Export_$(date +%m-%d-%Y)"

# Make sure xmlstarlet is installed
if ! which xmlstarlet ; then
    echo "You must install xmlstarlet before using this script."
    echo "Try "brew install xmlstarlet""
    exit 1
fi

clear
echo -n "Enter JSS Username: "
read -r jssUser
clear

echo -n "Enter $jssUser's Pass: "
read -r -s jssPass
clear

echo -n "Enter the Mobile Device ID that you want to remove from Static Groups: "
read -r deviceID

read -r -p "Are you sure you want to remove Mobile Device with ID $deviceID from all Static Groups? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]
then
    echo "Continuing..."
else
    echo "Done!"
    exit 0
fi

mkdir -p "$outputDir"

echo "Getting list of groups for device with ID $deviceID..."
deviceGroupIDs=($(curl -X GET -s -u "$jssUser:$jssPass" "$jssURL/JSSResource/mobiledevices/id/$deviceID" | xmlstarlet sel -t -v '//mobile_device/mobile_device_groups/mobile_device_group/id')) # | xmlstarlet sel -t -m "/mobile_device_groups/mobile_device_group[is_smart='false']" -v id -n))


echo "Getting list of Static mobile device groups..."
staticGroupIDs+=($(curl -X GET -s -u "$jssUser:$jssPass" "$jssURL/JSSResource/mobiledevicegroups" | xmlstarlet sel -t -m "/mobile_device_groups/mobile_device_group[is_smart='false']" -v id -n))

echo "Determining Group membership..."
staticGroupsTheDeviceIsIn=($(echo "${staticGroupIDs[@]}" "${deviceGroupIDs[@]}" | tr ' ' '
' | sort | uniq -d))
echo "Device ID $deviceID is in ${#deviceGroupIDs[@]} groups total; ${#staticGroupsTheDeviceIsIn[@]} of which are Static."
sleep 3

for id in "${staticGroupsTheDeviceIsIn[@]}"; do
    echo "Obtaining name of mobile device Static Group with ID: $id"
    groupName=$(curl -X GET -s -u "$jssUser:$jssPass" "$jssURL/JSSResource/mobiledevicegroups/id/$id" | xmlstarlet sel -t -v '//mobile_device_group/name')
    if [[ -n "$groupName" ]]; then
        echo "Writing XML of mobile device Static Group "$groupName" to the output file..."
        curl -X GET -s -u "$jssUser:$jssPass" "$jssURL/JSSResource/mobiledevicegroups/id/$id" -o "${outputDir}/Backup_${id}_${groupName}.xml"
        if [[ -f "${outputDir}/Backup_${id}_${groupName}.xml" ]]; then
            modifiedXML=$(xmlstarlet ed -d '//mobile_device[id='"$deviceID"']' "${outputDir}/Backup_${id}_${groupName}.xml")
            putXML=$(curl -X PUT -s -u "$jssUser:$jssPass" "$jssURL/JSSResource/mobiledevicegroups/id/$id" -H "Content-Type: text/xml" -d "$modifiedXML" 2> /dev/null)
            if [[ -n "$putXML" ]]; then
                echo "Success; Static Group "$groupName" (ID $id) was successfully modified."
            else
                echo "Error; failed to modify Static Group "$groupName" (ID $id)."
                sleep 1
            fi
        else
            echo "Error; could not write XML data locally."
            sleep 1
        fi
    else
        echo "Error; can't GET name of Static Group with ID: $id"
        sleep 1
    fi
done

echo "Done!"

exit 0

Enjoy!

View solution in original post

9 REPLIES 9

ryan_ball
Valued Contributor

If you are referring to smart groups, you would not be able to do that as smart groups are populated dynamically based on attributes of the device; i.e. apps installed, username, building, etc.

To remove a device from all static groups, you'd need to get the ID of the device, loop through all the static groups and check to see if the device is in each group, get the xml of the static group if the device's ID is detected in the group, remove it from the XML, then PUT the new XML for the static group.

Hugonaut
Valued Contributor II

@ryan.ball brilliant, you're good man! so, i dont need to check against it, BUT I will go ahead and overwrite the xml with a blank slate. I will test this, thank you!

________________
Looking for a Jamf Managed Service Provider? Look no further than Rocketman
________________


Virtual MacAdmins Monthly Meetup - First Friday, Every Month

ryan_ball
Valued Contributor

I would assume the XML you'd need to modify would be the static group's XML, not the device's.

Hugonaut
Valued Contributor II

@ryan.ball really appreciate it, outside of the box thinking, you always come through with great solutions.

________________
Looking for a Jamf Managed Service Provider? Look no further than Rocketman
________________


Virtual MacAdmins Monthly Meetup - First Friday, Every Month

Hugonaut
Valued Contributor II

@ryan.ball any idea where a static groups xml sheet would be located?! I'm having trouble locating it

________________
Looking for a Jamf Managed Service Provider? Look no further than Rocketman
________________


Virtual MacAdmins Monthly Meetup - First Friday, Every Month

exno
Contributor

@Hugonaut you can do a GET call to pull down an xml file of the static groups. or go to https://yourjamfproserver.company.com:8443/api and run the Try Out process to get the XML response. You would need the name or ID for this though.

/JSSResource/mobiledevicegroups/id/{id}
/JSSResource/mobiledevicegroups/name/{name}

If you don't have a list of all static group names or IDs you could use

/JSSResource/mobiledevicegroups

and look for

<is_smart>false</is_smart>

could be useful to feed your script the static groups that you are trying to zero out.

Also if you are in the macadmins Slack workspace, you can check #jss-api channel for help as well.

- I am @exno or @exnozero on almost everything that exists.

Hugonaut
Valued Contributor II

Thank you @exno i'm familiar with that part and know where to look as far as the url goes - :8443/JSSResource/mobiledevicegroups/id/## -

I just want to know where that darn sheet lives! and if it doesn't "live" somewhere accessible, how to replace it with a blank slate and containing no devices

________________
Looking for a Jamf Managed Service Provider? Look no further than Rocketman
________________


Virtual MacAdmins Monthly Meetup - First Friday, Every Month

ryan_ball
Valued Contributor

@Hugonaut I came up with a script for you that will take a mobile device ID and remove it from any static groups it is a member of. You really need a good XML parser to make this easier, I prefer xmlstarlet and this script leverages that. To install xmlstarlet you can install homebrew using this command:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Then install xmlstarlet with this command:

brew install xmlstarlet

Here is the script:

#!/bin/bash
# written by Ryan Ball

loggedInUser=$(/usr/bin/python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");')
jssURL=$(defaults read /Library/Preferences/com.jamfsoftware.jamf.plist jss_url | sed s'/.$//')
outputDir="/Users/$loggedInUser/Documents/Export_$(date +%m-%d-%Y)"

# Make sure xmlstarlet is installed
if ! which xmlstarlet ; then
    echo "You must install xmlstarlet before using this script."
    echo "Try "brew install xmlstarlet""
    exit 1
fi

clear
echo -n "Enter JSS Username: "
read -r jssUser
clear

echo -n "Enter $jssUser's Pass: "
read -r -s jssPass
clear

echo -n "Enter the Mobile Device ID that you want to remove from Static Groups: "
read -r deviceID

read -r -p "Are you sure you want to remove Mobile Device with ID $deviceID from all Static Groups? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]
then
    echo "Continuing..."
else
    echo "Done!"
    exit 0
fi

mkdir -p "$outputDir"

echo "Getting list of groups for device with ID $deviceID..."
deviceGroupIDs=($(curl -X GET -s -u "$jssUser:$jssPass" "$jssURL/JSSResource/mobiledevices/id/$deviceID" | xmlstarlet sel -t -v '//mobile_device/mobile_device_groups/mobile_device_group/id')) # | xmlstarlet sel -t -m "/mobile_device_groups/mobile_device_group[is_smart='false']" -v id -n))


echo "Getting list of Static mobile device groups..."
staticGroupIDs+=($(curl -X GET -s -u "$jssUser:$jssPass" "$jssURL/JSSResource/mobiledevicegroups" | xmlstarlet sel -t -m "/mobile_device_groups/mobile_device_group[is_smart='false']" -v id -n))

echo "Determining Group membership..."
staticGroupsTheDeviceIsIn=($(echo "${staticGroupIDs[@]}" "${deviceGroupIDs[@]}" | tr ' ' '
' | sort | uniq -d))
echo "Device ID $deviceID is in ${#deviceGroupIDs[@]} groups total; ${#staticGroupsTheDeviceIsIn[@]} of which are Static."
sleep 3

for id in "${staticGroupsTheDeviceIsIn[@]}"; do
    echo "Obtaining name of mobile device Static Group with ID: $id"
    groupName=$(curl -X GET -s -u "$jssUser:$jssPass" "$jssURL/JSSResource/mobiledevicegroups/id/$id" | xmlstarlet sel -t -v '//mobile_device_group/name')
    if [[ -n "$groupName" ]]; then
        echo "Writing XML of mobile device Static Group "$groupName" to the output file..."
        curl -X GET -s -u "$jssUser:$jssPass" "$jssURL/JSSResource/mobiledevicegroups/id/$id" -o "${outputDir}/Backup_${id}_${groupName}.xml"
        if [[ -f "${outputDir}/Backup_${id}_${groupName}.xml" ]]; then
            modifiedXML=$(xmlstarlet ed -d '//mobile_device[id='"$deviceID"']' "${outputDir}/Backup_${id}_${groupName}.xml")
            putXML=$(curl -X PUT -s -u "$jssUser:$jssPass" "$jssURL/JSSResource/mobiledevicegroups/id/$id" -H "Content-Type: text/xml" -d "$modifiedXML" 2> /dev/null)
            if [[ -n "$putXML" ]]; then
                echo "Success; Static Group "$groupName" (ID $id) was successfully modified."
            else
                echo "Error; failed to modify Static Group "$groupName" (ID $id)."
                sleep 1
            fi
        else
            echo "Error; could not write XML data locally."
            sleep 1
        fi
    else
        echo "Error; can't GET name of Static Group with ID: $id"
        sleep 1
    fi
done

echo "Done!"

exit 0

Enjoy!

Hugonaut
Valued Contributor II

@ryan.ball

Thank you very much! You're the man, Jamf really needs some kind of point system on the forum! haha

Gonna put this to work.

________________
Looking for a Jamf Managed Service Provider? Look no further than Rocketman
________________


Virtual MacAdmins Monthly Meetup - First Friday, Every Month