Posted on 01-15-2020 02:33 AM
Hello all,
Would anyone out there be able to provide me with a Script that on execution would delete all Users and/or User's home folder's with the exception of the user that is logged in and an option to specify specific (admin) users that need to stay on there?
It is likely that my Macs have a User Home folders that don't have a local user. So if the Local user doesn't exist, it still should wipe the Home folders of anyone but the current logged in user (and the specified admin user(s).
I would be tremendously gratefull!
Solved! Go to Solution.
Posted on 01-15-2020 06:23 AM
Relatively easy to fix, the previous was taken from code I had...
Users_Array=( `ls /Users | grep -v Shared | grep -v UserNotToDelete1 | grep -v UserNotToDelete2` )
for user in "${Users_Array[@]}"
do
if [ "${user}" == "${User_Name}" ]; then
echo "skip user ${user} as they are logged on."
else
dscl . -delete /Users/${user}
rm -fR /Users/${user}
fi
done
Posted on 01-15-2020 03:04 AM
Sounds like you want something like:
#!/bin/sh
User_Name=`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 + "
");'`
Users_Array=( `ls /Users | grep -v Shared` )
for user in "${Users_Array[@]}"
do
User_Local=`dscl . -list /Users | grep "^${user}"`
if [ "${user}" == "${User_Local}" ] || [ "${user}" == "${User_Name}" ]; then
echo "skip user ${user} as they are local or logged on."
else
rm -fR /Users/${user}
fi
done
exit 0;
Posted on 01-15-2020 05:33 AM
Hi there,
Thank you so much for your quick reply. I've tried your script, but It's not quite what I wanted.
"skip user ${user} as they are local or logged on."
What I mean is that I would need all local users to be deleted too (except for the user that is currently logged in). And in addition I would like to specify in the scrip itself a couple of user accounts that should always be skipped.
I do really appreciate the effort tho. Maybe someday I can return the favour for someone else!
Posted on 01-15-2020 06:23 AM
Relatively easy to fix, the previous was taken from code I had...
Users_Array=( `ls /Users | grep -v Shared | grep -v UserNotToDelete1 | grep -v UserNotToDelete2` )
for user in "${Users_Array[@]}"
do
if [ "${user}" == "${User_Name}" ]; then
echo "skip user ${user} as they are logged on."
else
dscl . -delete /Users/${user}
rm -fR /Users/${user}
fi
done
Posted on 01-15-2020 06:27 AM
Here is what we do (caveat, I had to sanitize this and pull in some stuff that we actually source from a library of our routines, so hopefully I didn't mess it up). We have a rolling delete so that if the machine crashes, or somebody forgets to save their stuff before they log out we don't have tears. You'd want to set homesToSave to 0 for your purpose. This is not necessarily a shining example of shell coding (I can say that since I wrote it). Also, we run this locally as part of a logouthook with the current user fed in as $1, so if you run it from Jamf you are probably going to need to change the way it gets the current user. It also somewhat depends on a reasonable local assumption that the home directory name is the same as the short user ID.
I don't know if this continues to work in Catalina, we're not taking the labs there until summer. It works fine for us in Mojave.
#!/bin/sh
#---------------------------------------------------------------------------------------------
#-- purgeoldhomes.sh
#---------------------------------------------------------------------------------------------
homesToSave=2
homesSaved=0
baseDirectory="/Users/"
CURRENTUSER="${1}"
ProtectedHomeFolders=( "${CURRENTUSER}" root ndadmin .localized Shared )
ProtectedHomeFolder()
{
for folder in ${ProtectedHomeFolders[@]}
do
if [ "${1}" == "$folder" ] ; then
return 0
fi
done
return 1
}
for homeFolder in `ls -t ${baseDirectory}`
do
# only process directories
if [ -d ${baseDirectory}${homeFolder} ]; then
#only process unprotected directories
if ! ProtectedHomeFolder "${homeFolder}" ; then
#pardon the newest homes
if [ $[homesSaved] -lt $[homesToSave] ] ; then
((homesSaved+=1))
else
# delete user
/usr/bin/dscl . delete "${baseDirectory}${homeFolder}" > /dev/null 2>&1
# delete home directory
/usr/bin/chflags -Rf nouchg "${baseDirectory}${homeFolder}"
/bin/rm -Rf "${baseDirectory}${homeFolder}"
fi
fi
fi
done
exit 0
Posted on 07-25-2024 05:54 AM
Hi and thank you for sharing.
I´m trying to protect the home folders of any admin home folders even they are not the last to sign in to the computer.
Is there any way to have the script skip admin users?
Posted on 01-15-2020 07:29 AM
@dsavageED
You are my Hero. This does exactly what I want it to do. I'm sure it might be nothing for you, but really you have made my day!
Thanks a lot!
Posted on 06-17-2020 01:45 PM
@dsavageED
Your script is still working on macOS Catalina 10.15.5!
Posted on 11-04-2021 08:15 AM
Now that JAMF has removed the logouthook, what are you doing to remove home folders?
Posted on 01-05-2024 11:40 AM
You can run a script at login (not with loginhook, obviously, but by using the normal launch agent architecture) and then watch for when it gets killed (which should be logout). Bing's AI actually came up with a pretty good answer for this, although I haven't tested its code:
## Bing
The logouthook feature has been deprecated for some time now and there is no obvious replacement for logout hooks in macOS. However, you can create a shell script that is launched on login and simply sleeps until a kill signal is received. Here's an example of how you can do this:
#!/bin/sh
onLogout () {
echo 'Logging out' >> ~/Logs/logout.sh.log
exit
}
trap 'onLogout' SIGINT SIGHUP SIGTERM
while true; do
sleep 86400 &
wait $!
done
This script will sleep until it receives one of the trapped signals, at which point it will execute the onLogout function. You can launch this script using a RunAtLoad launch agent or launch daemon and it will run at log-out or shutdown. Please note that tasks only have a limited amount of time to complete before they are killed, so this shouldn't be used to run anything that takes a long time, or requires a network connection that could be delayed.
For this to work, the shell scripts need to be executed directly by launchd, i.e., it shouldn't be invoked via sh. So if it were placed in ~/Library/Scripts/foo.sh your program arguments might look like:
<key>ProgramArguments</key>
<array>
<string>~/Library/Scripts/foo.sh</string>
<string>bar</string>
</array>
<key>EnableGlobbing</key>
<true/>
Posted on 01-05-2024 09:34 AM
I know this is old, but hopefully, someone can answer this. I can usually look at the script and figure out what I need to change even with my limited knowledge of the subject.
In this case, I can't figure out how to set the range of the users to keep based on when they last logged in. I can see the comment "#pardon the newest homes", but how do I change the timeframe? It seems like it's set to a month based on my testing.
And this does seem to work on Mac OS X Ventura and Sonoma.
Thanks!
Posted on 01-05-2024 11:30 AM
Greetings! That particular version of our script works on a count of remaining home directories rather than an age, as that was what the department wanted. So, we set a count (it is currently 2) and iterate on that. To do it based on age, you'd need to replace the
if [ $[homesSaved] -lt $[homesToSave] ] ; then
logic with logic based on the age of either the home directory folder or a semaphore file. I don't have code handy to illustrate that, but it should be fairly straightforward. Same kind of logic, just using the age rather than the number of directories.