Best Practice for Removing a OSX device from Inventory.

Andy_McCaskill
Contributor

Hello Everyone,

I would like to first off thank everyone ahead of time for any advice and/or information.
I work at a private school that has implemented a macbook program to our students. They receive the device their freshman year and get to keep it once they graduate our school. Once they graduate, we will need to start the process to transfer ownership of the device to them.

The question is, what is the best practices for removing all casper related apps, configs, and framework from the device?
As of right now, I have a self service policy that has a configuration that removes the apps, admin account, unbinds from AD, and then runs the sudo jamf removeframework. Problem is the app package removal is specific, is there a way to make it dynamic to remove all Casper installed Apps?

1 ACCEPTED SOLUTION

Chris_Hafner
Valued Contributor II

Ahhh, thanks for pointing me in this direction Mike! WARNING - I.T. STREAM OF CONSCIOUSNESS TO FOLLOW)

Over the past few years I've developed a really quick and simple method to "De-Brewsterize" students computers once they leave our campus and I promise you it's not that tricky at all. Now, each deployment could vary however we all have at least the following:

1) Applications and files that the students get to keep. We get to ignore these.
2) Applications and files that the students DON'T get to keep
3) Accounts that need to be elevated (Standard or AD accounts that need to be moved to local adminsitrators)
4) Accounts that need to be removed (JAMF management accounts and or other administrative accounts)
5) The JAMF Binary that needs to be removed
6) The JSS record that needs to be purged.

Fortunately, through some really creative thinking and scripts borrowed and modified from the most intelligent folks here on JAMF Nation we've been successfully accomplishing what you're asking, in production quickly and efficiently. There is ONE and only ONE difference that needs to be mentioned. You are using AD mobile accounts that will need to be converted into standard accounts first. It sounds like you've got a solution for that? If not there are folks here on JAMF Nation that have written up scripts to accomplish that. We avoid AD accounts due to this and other complications.

So. Since I was going to write this up as a white paper for JAMF anyways I may as well vet the content here.

Just as some quick background Brewster Academy is an international Private Boarding school in Wolfeboro NH that has the distinction of being the first and longest continually operational 1:1 laptop school that we’ve ever found. Our program started it’s pilot in 1991 and had full implementation in 1993. In short, we’ve seen just about everything. For the past 4-5 years we’ve been BYOD with basic requirements (All OS X, with the ability to run the latest OS with minimum storage and RAM requirements).

All students image their own computers on the first day of orientation and are de-brewsterized at the end of each year unless they leave early. Each process takes about 4-6 min.

—————— THE PROCESS —————
1) Applications and files that the students get to keep. We get to ignore these. - For example, we put a variety of software applications like Firefox, Google Chrome, flash, f.lux, etc.. that are either open source or otherwise free. We happily let the student keep these and hence they are ignored during “De-Brewsterization”

2) Applications and files that the students DON'T get to keep - So things like, Microsoft Office, Sophos AV, Adobe CC apps, etc. (It’s a long list)

This can get a little tricky until you come to one conclusion. Fall in love with Composer! I create every software installer I can using composer, saving out as a .dmg which I index using Casper Admin. When you index your .dmg Casper gives you the ability to uninstall via policy in the same way that you would install any .dmg or .pkg as a policy. Since I’ve spent my time putting together composer packages I simply need a policy that “Un-installs” those apps. No big. Some things get a bit trickier. I’m thinking things like Adobe Photoshop and the like. The good news is that Adobe’s tools for packaging those installers also allow you to create uninstaller which I cache on students computers when any of the adobe CC apps are installed (Either via configuration or Self-Service policy). In my De-Brewsterization policy I ask it to run all cached packages since I only permanently cache uninstaller on students computers). There are a few others that have to be installed as .pkg’s and hence will not be available for indexed uninstallation via policy. For these I put together a cleaner script that not only removes anything like that, but also cleans up any left over directories or other small files my uninstaller didn’t get (I’m looking at you Adobe!)

3) Accounts that need to be elevated (Standard or AD accounts that need to be moved to local adminsitrators) - I include a very simple script to elevate the students standard account to administrative privileges. I admit, since I use standard accounts and NOT AD, this is very very simple bash command in a before script

/usr/sbin/dseditgroup -o edit -a student -t user admin

You are going to have a very different circumstance given that you’re using AD accounts, but as I said, you may already have a solution and others exist here on the forums.

4-5) Accounts that need to be removed (JAMF management accounts and or other administrative accounts) along with the JAMF Binary I include the following commands in my after script

killall "Self Service"
killall "SophosUIServer"
rm -r /Applications/Self Service.app
rm -r /Library/Preferences/com.apple.SoftwareUpdate.plist
/usr/sbin/jamf deleteAccount -username admin -deleteHomeDirectory
/usr/sbin/jamf -removeFramework

These should be pretty obvious. This stops the Sophos processes that aren’t automatically quit with the un-installer, quits Self-Service before moving it. This is critical as the students run this policy from Self-Service. Then it deletes our adminisitrative user.

5) The JSS record that needs to be purged. Now, loaded into a .tmp director during this process is another script that I borrowed from the forums here. It logs into the JSS using an account I created specifically for they purpose. This allows the computer itself to contact the JSS and remove delete itself based on either UDID or HW address, whichever comes first.

#!/bin/csh
## It has to be a csh script
# getting UUID
set UUID=`ioreg -rd1 -c IOPlatformExpertDevice | awk '/IOPlatformUUID/ { split($0, line, """); printf("%s
", line[4]); }'`

# deleting computer from casper with UUID
curl -k -v -u Delete:PASSWORD https://JSS-URL:8443/JSSResource/computers/udid/$UUID -X DELETE

set CAM=`networksetup -getmacaddress en1 | cut -c18-35 |sed 's/:/./g'`

curl -k -v -u Delete:PASSWORD https://JSS-URL:8443/JSSResource/computers/macaddress/$CAM -X DELETE

set JAM=`networksetup -getmacaddress en0 | cut -c18-35 |sed 's/:/./g'`

curl -k -v -u Delete:PASSWORD https://JSS-URL:8443/JSSResource/computers/macaddress/$JAM -X DELETE

echo
ioreg -c "IOPlatformExpertDevice" | awk -F '"' '/IOPlatformSerialNumber/ {print $4}'
echo

exit 0

and then finally reboots the unit leaving it all nice and clean for the user. It’s now free of our policies and licensed software, with their applications and files all left intact. They even keep the same username and password. The process is extremely quick. Just a few minuets depending on optional software installed and whether or not the unit has an SSD.

Are there improvements I could make… sure. I’m, also always open to suggestions but I’d have to write the process up more formally as I’ve pretty much taken 5 minuets to dump this into the thread and haven’t checked anything for continuity. I sure hope this makes sense. Regardless, please ask questions and poke holes in anything I’ve mentioned. I’ll be formalizing this later when I have a few moments. Hell, I hope I don't have too many grammatical/spelling errors.

;-)

Boy I love working in education!

View solution in original post

8 REPLIES 8

mm2270
Legendary Contributor III

Calling @Chris_Hafner! If Chris is around (and he has the time), he can elaborate on his "De-Brewsterization" process he uses at Brewster Academy to transfer ownership back to students once they graduate. What he's doing may be a good fit for your school as well. I don't know if his process actually removes any installed apps though. He'l have to chime in on that, or anyone else that has something similar in place.

davidacland
Honored Contributor II
Honored Contributor II

Hi, that sounds pretty generous!

That would be a bit tricky as you would need to be sure not to delete any apps that they may have purchased or installed themselves. jamf removeFramework is definitely the way to go to get rid of the management on the client side. Getting the Casper deployed apps off the machine would be the hard bit.

A simple route would be to erase and install the Mac, but I guess you wouldn't get many taking you up on that offer.

Depending on how far down the process you are, I would possibly consider adding some kind of local receipt file attached to the end of any software deployment policies. I would have it keep a record in a single file, appending the app path whenever a new one is added. When it comes time to remove the Mac, you could either have a script that deletes each app it finds in the text file. It would leave stuff behind in App support and preferences etc but would at least achieve the goal with relatively little development.

Another option would be to tie it into the uninstall feature of Casper (I haven't used that myself so not sure if it works or not). For each install policy you would want to (again probably with a local receipt text file), note which apps have been installed, and then have an equivalent uninstall policy that can be run automatically. Again quite a lot of work.

We did a project last year with a customer using AirWatch and Munki that could remove all corporate deployed apps if the Mac was un-enrolled, but it did take quite a few weeks of development to get it right.

So I'm not sure if there is a quick / easy way to achieve this. Perhaps someone else has a different approach that is a little less labour intensive.

Andy_McCaskill
Contributor

Originally we wanted to just wipe the device but issue with that is majority of the students have personal items across the device. Plus this process will take more time than i want when dealing with hundreds of these things at the end of the school year.

mm2270
Legendary Contributor III

The removing of Casper installed apps or tools could prove to be a little tricky, if that's something you really aim to do.
The /Library/Application Support/JAMF/Receipts/ directory contains a list of anything that was installed directly by Casper Suite using the built in Casper Suite installation method (pkg or dmg) Anything that might have been installed manually by an end user or technician, or items installed using command line installer directly in a scripted method won't drop a receipt into that folder.
One issue is that the "receipts" in that directory aren't true receipts, at least from OS X's point of view. They are more like stub files that are named the same as the pkg or dmg that was installed. So they can't, for example, be used as uninstall packages.
Still, this list could be a place to start in determining what you may want to target for uninstallation through regular policies. Those same receipts are viewable in a Mac's record in the JSS under the package Receipts section, and under the "Casper Suite" tab.

Chris_Hafner
Valued Contributor II

Ahhh, thanks for pointing me in this direction Mike! WARNING - I.T. STREAM OF CONSCIOUSNESS TO FOLLOW)

Over the past few years I've developed a really quick and simple method to "De-Brewsterize" students computers once they leave our campus and I promise you it's not that tricky at all. Now, each deployment could vary however we all have at least the following:

1) Applications and files that the students get to keep. We get to ignore these.
2) Applications and files that the students DON'T get to keep
3) Accounts that need to be elevated (Standard or AD accounts that need to be moved to local adminsitrators)
4) Accounts that need to be removed (JAMF management accounts and or other administrative accounts)
5) The JAMF Binary that needs to be removed
6) The JSS record that needs to be purged.

Fortunately, through some really creative thinking and scripts borrowed and modified from the most intelligent folks here on JAMF Nation we've been successfully accomplishing what you're asking, in production quickly and efficiently. There is ONE and only ONE difference that needs to be mentioned. You are using AD mobile accounts that will need to be converted into standard accounts first. It sounds like you've got a solution for that? If not there are folks here on JAMF Nation that have written up scripts to accomplish that. We avoid AD accounts due to this and other complications.

So. Since I was going to write this up as a white paper for JAMF anyways I may as well vet the content here.

Just as some quick background Brewster Academy is an international Private Boarding school in Wolfeboro NH that has the distinction of being the first and longest continually operational 1:1 laptop school that we’ve ever found. Our program started it’s pilot in 1991 and had full implementation in 1993. In short, we’ve seen just about everything. For the past 4-5 years we’ve been BYOD with basic requirements (All OS X, with the ability to run the latest OS with minimum storage and RAM requirements).

All students image their own computers on the first day of orientation and are de-brewsterized at the end of each year unless they leave early. Each process takes about 4-6 min.

—————— THE PROCESS —————
1) Applications and files that the students get to keep. We get to ignore these. - For example, we put a variety of software applications like Firefox, Google Chrome, flash, f.lux, etc.. that are either open source or otherwise free. We happily let the student keep these and hence they are ignored during “De-Brewsterization”

2) Applications and files that the students DON'T get to keep - So things like, Microsoft Office, Sophos AV, Adobe CC apps, etc. (It’s a long list)

This can get a little tricky until you come to one conclusion. Fall in love with Composer! I create every software installer I can using composer, saving out as a .dmg which I index using Casper Admin. When you index your .dmg Casper gives you the ability to uninstall via policy in the same way that you would install any .dmg or .pkg as a policy. Since I’ve spent my time putting together composer packages I simply need a policy that “Un-installs” those apps. No big. Some things get a bit trickier. I’m thinking things like Adobe Photoshop and the like. The good news is that Adobe’s tools for packaging those installers also allow you to create uninstaller which I cache on students computers when any of the adobe CC apps are installed (Either via configuration or Self-Service policy). In my De-Brewsterization policy I ask it to run all cached packages since I only permanently cache uninstaller on students computers). There are a few others that have to be installed as .pkg’s and hence will not be available for indexed uninstallation via policy. For these I put together a cleaner script that not only removes anything like that, but also cleans up any left over directories or other small files my uninstaller didn’t get (I’m looking at you Adobe!)

3) Accounts that need to be elevated (Standard or AD accounts that need to be moved to local adminsitrators) - I include a very simple script to elevate the students standard account to administrative privileges. I admit, since I use standard accounts and NOT AD, this is very very simple bash command in a before script

/usr/sbin/dseditgroup -o edit -a student -t user admin

You are going to have a very different circumstance given that you’re using AD accounts, but as I said, you may already have a solution and others exist here on the forums.

4-5) Accounts that need to be removed (JAMF management accounts and or other administrative accounts) along with the JAMF Binary I include the following commands in my after script

killall "Self Service"
killall "SophosUIServer"
rm -r /Applications/Self Service.app
rm -r /Library/Preferences/com.apple.SoftwareUpdate.plist
/usr/sbin/jamf deleteAccount -username admin -deleteHomeDirectory
/usr/sbin/jamf -removeFramework

These should be pretty obvious. This stops the Sophos processes that aren’t automatically quit with the un-installer, quits Self-Service before moving it. This is critical as the students run this policy from Self-Service. Then it deletes our adminisitrative user.

5) The JSS record that needs to be purged. Now, loaded into a .tmp director during this process is another script that I borrowed from the forums here. It logs into the JSS using an account I created specifically for they purpose. This allows the computer itself to contact the JSS and remove delete itself based on either UDID or HW address, whichever comes first.

#!/bin/csh
## It has to be a csh script
# getting UUID
set UUID=`ioreg -rd1 -c IOPlatformExpertDevice | awk '/IOPlatformUUID/ { split($0, line, """); printf("%s
", line[4]); }'`

# deleting computer from casper with UUID
curl -k -v -u Delete:PASSWORD https://JSS-URL:8443/JSSResource/computers/udid/$UUID -X DELETE

set CAM=`networksetup -getmacaddress en1 | cut -c18-35 |sed 's/:/./g'`

curl -k -v -u Delete:PASSWORD https://JSS-URL:8443/JSSResource/computers/macaddress/$CAM -X DELETE

set JAM=`networksetup -getmacaddress en0 | cut -c18-35 |sed 's/:/./g'`

curl -k -v -u Delete:PASSWORD https://JSS-URL:8443/JSSResource/computers/macaddress/$JAM -X DELETE

echo
ioreg -c "IOPlatformExpertDevice" | awk -F '"' '/IOPlatformSerialNumber/ {print $4}'
echo

exit 0

and then finally reboots the unit leaving it all nice and clean for the user. It’s now free of our policies and licensed software, with their applications and files all left intact. They even keep the same username and password. The process is extremely quick. Just a few minuets depending on optional software installed and whether or not the unit has an SSD.

Are there improvements I could make… sure. I’m, also always open to suggestions but I’d have to write the process up more formally as I’ve pretty much taken 5 minuets to dump this into the thread and haven’t checked anything for continuity. I sure hope this makes sense. Regardless, please ask questions and poke holes in anything I’ve mentioned. I’ll be formalizing this later when I have a few moments. Hell, I hope I don't have too many grammatical/spelling errors.

;-)

Boy I love working in education!

Chris_Hafner
Valued Contributor II

Wow, sorry that this was so poorly written. @immaculateheart does this help you? I know it's marked solved but feel free to contact me here or @ chris_hafner@brewsteracademy.org with any questions. At some point I'll still end up cleaning up this description and including full scripts.

Andy_McCaskill
Contributor

Here is another good script I found from this forum post, https://jamfnation.jamfsoftware.com/discussion.html?id=12462

It checks the mobile account and creates a local account then prompts the user to input the password for the account. This is going to save many headaches for our first batch of Macbooks that we configured with mobile accounts. Moving forward I am not going to use that. It seems to only be a good choice for our devices that get checked out.

#!/bin/bash

#  Recreate account.sh
#
#  This script is designed to remove a mobile user account and re-create
#  a local account with the same username and the password from user-input.
#  It will also give read/write permissions to the user's home folder.

#Gets the short name of the currently logged in user
loggedInUser=$3

#Get loggedInUser UID
UserUID=`dscl . read /Users/"$loggedInUser" UniqueID | grep UniqueID: | cut -c 11-`

#Exit if UID is under 1000 (local account)
if [[ "$UserUID" -lt 1000 ]]; then
echo "Not a mobile account, exiting"
exit 2
else

#Gets the real name of the currently logged in user
userRealName=`dscl . -read /Users/$loggedInUser | grep RealName: | cut -c11-`
if [[ -z $userRealName ]]; then
userRealName=`dscl . -read /Users/$loggedInUser | awk '/^RealName:/,/^RecordName:/' | sed -n 2p | cut -c 2-`
fi

#Prompts user to enter their login password
loginPassword=`/usr/bin/osascript <<EOT
tell application "System Events"
activate
set myReply to text returned of (display dialog "Please enter your login password." ¬
default answer "" ¬
with title "Ruyton IT" ¬
buttons {"Continue."} ¬
default button 1 ¬
with hidden answer)
end tell
EOT`

#Confirm password.
confirmPassword=`/usr/bin/osascript <<EOT
tell application "System Events"
activate
set myReply to text returned of (display dialog "Please confirm your password" ¬
default answer "" ¬
with title "Ruyton IT" ¬
buttons {"Continue."} ¬
default button 1 ¬
with hidden answer)
end tell
EOT`

defaultPasswordAttempts=1

#Checks to make sure passwords match, if they don't displays an error and prompts again.
while [ $loginPassword != $confirmPassword ] || [ -z $loginPassword ]; do
`/usr/bin/osascript <<EOT
tell application "System Events"
activate
display dialog "Passwords do not match. Please try again." ¬
with title "Ruyton IT" ¬
buttons {"Continue."} ¬
default button 1
end tell
EOT`

loginPassword=`/usr/bin/osascript <<EOT
tell application "System Events"
activate
set myReply to text returned of (display dialog "Please enter your login password." ¬
default answer "" ¬
with title "Ruyton IT" ¬
buttons {"Continue."} ¬
default button 1 ¬
with hidden answer)
end tell
EOT`

confirmPassword=`/usr/bin/osascript <<EOT
tell application "System Events"
activate
set myReply to text returned of (display dialog "Please confirm your password" ¬
default answer "" ¬
with title "Ruyton IT" ¬
buttons {"Continue."} ¬
default button 1 ¬
with hidden answer)
end tell
EOT`

defaultPasswordAttempts=$((defaultPasswordAttempts+1))

if [[ $defaultPasswordAttempts -ge 5 ]]; then
`/usr/bin/osascript <<EOT
tell application "System Events"
activate
display dialog "You have entered mis-matching passwords five times. Please come to the IT desk for assistance." ¬
with title "Ruyton IT" ¬
buttons {"Continue."} ¬
default button 1
end tell
EOT`
echo "Entered mis-matching passwords too many times."
exit 1
fi

done

#This will delete the currently logged in user
dscl . delete /Users/$loggedInUser

#Gets the current highest user UID
maxid=$(dscl . -list /Users UniqueID | awk '{print $2}' | sort -ug | tail -1)

#New UID for the user
newid=$((maxid+1))

#Creating the new user
dscl . -create /Users/"$loggedInUser"
dscl . -create /Users/"$loggedInUser" UserShell /bin/bash
dscl . -create /Users/"$loggedInUser" RealName "$userRealName"
dscl . -create /Users/"$loggedInUser" UniqueID "$newid"
dscl . -create /Users/"$loggedInUser" PrimaryGroupID 80

#Set the user's password to the one entered prior
dscl . -passwd /Users/"$loggedInUser" "$loginPassword"

#Makes the user an admin
dscl . -append /Groups/admin GroupMembership "$loggedInUser"

#Reset ownership on home directory and append location
chown -R "$loggedInUser":staff /Users/"$loggedInUser"
dscl . -append /Users/"$loggedInUser" NFSHomeDirectory /Users/"$loggedInUser"/

#Delete the user's keychain folder.
rm -Rf /Users/$loggedInUser/Library/Keychains/*

echo "Script successful."

fi

sleep 3

ps -Ajc | grep loginwindow | awk '{print $2}' | xargs kill -9

Andy_McCaskill
Contributor

@Chris_Hafner, Yes your information was very useful. The principle taskflow is very useful. I have created a policy that is very similar. The JSS purge is a great addition that I didn't have, thank you!