Posted on 03-01-2016 09:40 AM
I have a script that runs and deletes the home directories of users
userList=find /Users -type d -maxdepth 1 -mindepth 1 -not -name "." -not -name "admin" -not -name "testuser" -not -name "Shared" -not -name "Guest" -mtime +7 | awk -F'/' '{print $NF}'
for a in $userList ;
do
rm -r /Users/"$a"; #delete the home directory
echo "$a has been deleted"
let counter=counter+1
done
it deletes the home directories correctly, but when i check the System Preferences --> Users & Groups
all the deleted users names are still listed here. How do I also get those user names cleared ?
Solved! Go to Solution.
Posted on 03-01-2016 09:54 AM
You have to remove the user using dscl. Just deleting the home folder does not remove the account from the local directory services, and it will still be listed in Users & Groups as a result.
#!/bin/sh
userList=find /Users -type d -maxdepth 1 -mindepth 1 -not -name "." -not -name "admin" -not -name "testuser" -not -name "Shared" -not -name "Guest" -mtime +7 | awk -F'/' '{print $NF}'
for a in $userList ; do
rm -r /Users/"$a"; #delete the home directory
dscl . delete /Users/"$a" # Deleting the entry from dir services
echo "$a has been deleted"
let counter=$((counter+1))
done
I'm thinking that first line pulling the usernames could also be simplified a bit, but I don't want to get too off the topic with this post, so I'll leave it at that.
Posted on 03-01-2016 09:54 AM
You have to remove the user using dscl. Just deleting the home folder does not remove the account from the local directory services, and it will still be listed in Users & Groups as a result.
#!/bin/sh
userList=find /Users -type d -maxdepth 1 -mindepth 1 -not -name "." -not -name "admin" -not -name "testuser" -not -name "Shared" -not -name "Guest" -mtime +7 | awk -F'/' '{print $NF}'
for a in $userList ; do
rm -r /Users/"$a"; #delete the home directory
dscl . delete /Users/"$a" # Deleting the entry from dir services
echo "$a has been deleted"
let counter=$((counter+1))
done
I'm thinking that first line pulling the usernames could also be simplified a bit, but I don't want to get too off the topic with this post, so I'll leave it at that.
Posted on 03-01-2016 10:02 AM
@mm2270 I added the 'dscl' line you provided.
even though let counter=counter+1 was working for me, I changed it to let counter=$((counter+1))
after the 'do' loop runs, i added jamf recon
I'll test and get back.
Posted on 03-01-2016 10:47 AM
You are only deleting the home directory, not the user account.
If you want to use the jamf command, first take a look at the jamf command help page
/usr/local/bin/jamf help deleteAccount
You would likely use something like this:
/usr/local/bin/jamf deleteAccount -username $LocalUserName -deleteHomeDirectory
If you want to use a native OS X (10.10+) command first take a look at the sysadminctl command help page.
/usr/sbin/sysadminctl -help
You would likely use something like this:
/usr/sbin/sysadminctl -deleteUser $LocalUserName
Posted on 03-02-2016 12:04 PM
which one of these 3 methods is the preferred method ?
jamf deleteAccount
sysadminctl - deleteUser
dscl . delete
Posted on 03-02-2016 12:19 PM
@tcandela That's a very good question. Here's what I can say about them.
jamf deleteAccount - this should work on all systems that are under management. As far as I know, there shouldn't be any problems with using this and the syntax is fairly simple to use. OTOH, since its a built in jamf binary command, there's always a possibility of it breaking at some point due to changes from Apple. But, I'd imaging JAMF would update their binary to accommodate any such changes.
sysadminctl -deleteUser - this (sysadminctl) is a relatively new binary that only came about as of 10.10 Yosemite. If you have a need to delete accounts on any Macs running older OSes, this isn't going to work. Its a good binary and is likely the one Apple engineers would recommend if asked, but again, keep in mind what your target OSes are with this one.
dscl . delete - an oldie but goodie. As of 10.11, this still should work just fine to remove an account from the Mac. As far as I've seen dscl has not been deprecated by Apple... yet. I say yet, because they do have a tendency to deprecate things as time goes on and they add new binaries, like sysadminctl.
I don't recommend using dscl for changing account records, like adding/removing accounts from the admin group. For that, either dseditgroup
or sysadminctl
are better tools, but for simply deleting an account, it should be OK to use dscl. To anyone out there, if I'm way off on that, feel free to let me know that I'm wrong.
Posted on 03-02-2016 12:20 PM
sysadminctl is newer so it would work on 10.10 or higher. and i believe specifically on local accounts (not sure if it works on mobile accounts).
jamf deleteAccount is probably making use of dscl and other tools to remove the account.
i'd test and go with whatever works best for you. just know that if something changes with a newer OS you would have to rely on jamf to update that particular command which they may or may not do right away whereas apple would most likely definitely make sure that sysadminctl is up to date and working on the latest OS.
Posted on 03-02-2016 01:21 PM
I added the dscl . delete /Users/"$a" line, just like above. I then add some test local accounts
test1, test2, test3
and then using Casper Remote I target the script to the test computer and 0 home directories get deleted.
all 3 test accounts do not get touched.
I then just added into the do loop jamf deleteAccount -userName $a -deleteHomeDirectory
and also nothing happened, all home folders and Users were not touched.
The comments inside the DO LOOP never even echoed
Posted on 03-02-2016 01:38 PM
Then something is wrong with the script in how its pulling the accounts to remove or passing them to the loop. It can't be that dscl and jamf deleteAccount are both broken.
try removing the double quotes around the $a variable. It generally shouldn't be needed since having spaces in a short user name is difficult (almost impossible actually, though not 100% impossible) so quoting the variable there shouldn't be needed.
Posted on 03-02-2016 01:43 PM
Ugh. I see the issue. Its the first line. No idea why I didn't see that, but it needs to be:
userList=$(find /Users -type d -maxdepth 1 -mindepth 1 -not -name "." -not -name "admin" -not -name "testuser" -not -name "Shared" -not -name "Guest" -mtime +7 | awk -F'/' '{print $NF}')
The way you have it its not creating a variable at all to loop over since its not contained in $() syntax or with backticks.
one other thing. I would change the rm -r
to be rm -Rfd
The "f" flag does a force removal and "d" tells it to also delete the directory its operating on, meaning the top level home folder. It may not be strictly necessary, but it should work a little better like that.
Posted on 03-02-2016 06:45 PM
@mm2270 - I'll add the ( ) to the first line tomorrow and test it, with both the .dscl and jamf deleteAccount.
I put the jamf deleteAccount -userName $a -deleteHomeDirectory inside the Do Loop and just # comment out the rm -r and dscl lines.
in my original post it did not have the $() and went through the DO LOOP deleting the home directories, why now since adding the 'dscl . delete or jamf deleteAccount' does it need the $() ?
Posted on 03-03-2016 08:13 AM
@mm2270 adding the $() made no difference
Posted on 03-03-2016 08:32 AM
I could be mistaken here, but your userList variable is getting a list of all folders under /Users. But just because a folder exists there, does not mean that an account exists in the local directory service.
This command should give you a list of all users:
dscl . -list /Users
But you probably want to omit the OS specific accounts. Quick and dirty way:
dscl . -list /Users | grep -v "_" | grep -v "daemon" | grep -v "nobody" | grep -v "root"
And then once you have those user names you can get their home directories with the following command:
dscl . read /Users/USERNAME_GOES_HERE NFSHomeDirectory | cut -d " " -f 2
Keep in mind I'm not sure if NFSHomeDirectory is the correct key to look at. It seems like the right value though as it reports the proper info on a local and mobile account on my computer.
Anyways, I realize this may not exactly help with specific the issue, but it might be a more accurate way to determine which accounts are actually on the command (and if you want to determine the account's home directory assuming you don't want to use the jamf command or sysadminctl).
Posted on 03-03-2016 08:37 AM
@mm2270 my original post did not show the back ticks, but did have them in the script. I've added the dscl . delete /Users/$a
it works, but only deletes users that have accounts created when logged in through an AD account.
If i specifically create a local account from the Users & Groups pane, those users do not get deleted. Why would these accounts I create locally (standard accounts) not get deleted?
Here is the script.
echo "Deleting home directory for the following users…"
userList=find /Users -type d -maxdepth 1 -mindepth 1 -not -name "." -not -name "admin" -not -name "user1" -not -name "Shared" -not -name "Guest" -mtime +7 | awk -F'/' '{print $NF}'
counter=0
for a in $userList ;
do
# jamf deleteAccount -userName $a -deleteHomeDirectory
#rm -r /Users/"$a" ; #delete the home directory
rm -Rfd /Users/"$a" ; #delete the home directory
dscl . delete /Users/"$a" # Deleting the entry from dir services
echo "$a has been deleted"
let counter=counter+1
done
echo "Finished Deleting $counter home directories"
jamf recon
exit $?
Posted on 03-03-2016 08:39 AM
when posting scripts make sure to select all your code and then use the button that has ">_" so that it preserves the code.
Posted on 03-03-2016 08:52 AM
@bpavlov thanks, i was wondering how to do that. I then add my code between those ticks ?
#!/bin/sh
Posted on 03-03-2016 08:59 AM
Correct. You can edit your previous posts.
Posted on 03-03-2016 09:09 AM
I only want AD mobile accounts to be deleted/removed, but why does the script only remove those AD mobile accounts and not any test accounts that are created locally through the System Preferences --> Users & Groups pane ?
I don't see anything in the script that singles out AD mobile accounts
Posted on 03-03-2016 09:23 AM
I figured out what was preventing my test accounts from also not being deleted.
it is that -mtime +7 that is toward the end of the script, once I removed this -mtime +7 (Primaries)
my 5 test accounts (home directories and entry in User & groups pane) were removed.
I read the -mtime _ definition under 'man find' but do not understand it.
Posted on 03-31-2016 08:36 AM
Quick post of an edited version of mm2270's script from everyone's input. This is the best one that worked for me. Tested on 10.10 so far:
#!/bin/sh
#Add more | grep -v "" for users to keep at end of userList
userList=$(dscl . -list /Users | grep -v "_" | grep -v "daemon" | grep -v "nobody" | grep -v "root" | awk -F '/' '{print $NF}')
#Deleting Users and Directories
for a in $userList ; do
/usr/local/bin/jamf deleteAccount -username "$a" -deleteHomeDirectory
echo "$a has been deleted"
let counter=$((counter+1))
done
Posted on 03-31-2016 09:27 AM
Had a bit of fun with the script to integrate into Casper, still learning to script so critique away!
#!/bin/sh
#Last tested on 10.10 make sure you add any users to list below or it WILL DELETE user and files.
#If logic for variable username entries in Casper arugments
if [ -z "$4" ]; then
userList=$(dscl . -list /Users | grep -v "_" | grep -v "daemon" | grep -v "nobody" | grep -v "root" | awk -F '/' '{print $NF}')
#Deleting User and userfiles
for a in $userList ; do
/usr/local/bin/jamf deleteAccount -username "$a" -deleteHomeDirectory
echo "$a has been deleted"
let counter=$((counter+1))
done
exit 0
else
if [ -z "$5" ]; then
#Deletes Users including populated argument 4
userList=$(dscl . -list /Users | grep -v "_" | grep -v "daemon" | grep -v "nobody" | grep -v "root" | grep -v "$4" | awk -F '/' '{print $NF}')
#Deleting User and userfiles
for a in $userList ; do
/usr/local/bin/jamf deleteAccount -username "$a" -deleteHomeDirectory
echo "$a has been deleted"
let counter=$((counter+1))
done
exit 0
else
if [ -z "$6" ]; then
#Deletes users including populated argument 5
userList=$(dscl . -list /Users | grep -v "_" | grep -v "daemon" | grep -v "nobody" | grep -v "root" | grep -v "$4" | grep -v "$5" | awk -F '/' '{print $NF}')
#Deleting User and userfiles
for a in $userList ; do
/usr/local/bin/jamf deleteAccount -username "$a" -deleteHomeDirectory
echo "$a has been deleted"
let counter=$((counter+1))
done
exit 0
else
#Deletes users including populated argument 6
userList=$(dscl . -list /Users | grep -v "_" | grep -v "daemon" | grep -v "nobody" | grep -v "root" | grep -v "$4" | grep -v "$5" | grep -v "$6" | awk -F '/' '{print $NF}')
#Deleting User and userfiles
for a in $userList ; do
/usr/local/bin/jamf deleteAccount -username "$a" -deleteHomeDirectory
echo "$a has been deleted"
let counter=$((counter+1))
done
exit 0
fi
fi
fi
exit 0
Posted on 03-31-2016 01:45 PM
On the assumption that you don't have admin accounts that need preserving with home accounts located in /Users, you can just run through the user list and check for existence of file. This removes the need for any exception list that can change over time.
#!/bin/bash
dscl . list /Users | grep -v ^"_" | while read line
do
if [ -e /Users/$line ]
then
echo "Deleting: $line"
/usr/local/bin/jamf deleteAccount -username "$line" -deleteHomeDirectory
echo "Account $line deleted: "$?
fi
done
exit 0
If you do require to preserve any accounts then perhaps something akin to:
#!/bin/bash
dscl . list /Users | grep -v ^"_" | while read line
do
if [ -e /Users/$line ]
then
case $line in
# Add as many OR as required for local admin with home accounts in /Users
admin_user1|admin_user2)
echo "admin user: $line"
;;
*)
echo "Deleting: $line"
/usr/local/bin/jamf deleteAccount -username "$line" -deleteHomeDirectory
echo "Account $line deleted: "$?
;;
esac
fi
done
exit 0
Alternatively, you could use dscl to return the home directory and use that as your basis for deletion. Either way you aren't managing a potentially changeable exclusion list.
#!/bin/bash
home_dir="/Users/"
dscl . list /Users | grep -v ^"_" | while read line
do
home_account=`dscl . read /Users/$line NFSHomeDirectory | awk '{print $NF}'`
if [[ "$home_account" =~ ^"$home_dir" ]]
then
echo "Deleting: $line"
/usr/local/bin/jamf deleteAccount -username "$line" -deleteHomeDirectory
echo "Account $line deleted: "$?
fi
done
exit 0
Again, add in the case statement if you have accounts to preserve.
The first will run faster, but I'd suggest the alternative is the better way to do it.
I would politely suggest that you remove the solution on @mm2270 post. This is a dangerous script to run. It will remove all of the hidden folders
find /Users -type d -maxdepth 1 -mindepth 1 -not -name "." -not -name "admin" -not -name "testuser" -not -name "Shared" -not -name "Guest" -mtime +7 | awk -F'/' '{print $NF}'
.DocumentRevisions-V100
.IABootFiles
.PKInstallSandboxManager
.Spotlight-V100
.Trashes
Posted on 03-13-2017 08:35 AM
Did anyone find a simplified version of this script that just deletes the home folders for network accounts (AD) that don't have dscl entries to match? We switched from using mobilized AD accounts to using network AD accounts due to a problem that cropped up last year with how many accounts could be created without creating startup problems for the macOS. I'm not having too much luck with the one below from @mm2270 :
#!/bin/sh
userList=find /Users -type d -maxdepth 1 -mindepth 1 -not -name "." -not -name "admin" -not -name "testuser" -not -name "Shared" -not -name "Guest" -mtime +7 | awk -F'/' '{print $NF}'
for a in $userList ; do
rm -r /Users/"$a"; #delete the home directory
dscl . delete /Users/"$a" # Deleting the entry from dir services
echo "$a has been deleted"
let counter=$((counter+1))
done
Update - this older-than-7-day clear out ended up working for me for removing accounts that do not have a dscl entry, in case it helps anyone else:
#!/bin/sh
echo "Deleting home directory for the following users…"
userList=`find /Users -type d -maxdepth 1 -mindepth 1 -not -name "AdminAcct" -not -name "Shared" -mtime +7 | awk -F'/' '{print $NF}'`
for a in $userList ; do
rm -r /Users/"$a"; #delete the home directory
done
Posted on 08-01-2018 09:10 PM
Ok, dragging up an old discussion.
Trying to delete users that haven't logged in for n+ days but leaving some users exempt from deletion.
Have been getting different results depending on what command to delete is used, script below:
#!/bin/sh
userList=`find /Users -type d -maxdepth 1 -mindepth 1 -not -name "*.*" -mtime +7d | awk -F'/' '{print $NF}'`
LocalUsers=`dscl localhost -list /Local/Default/Users`
exempt=( itsadmin Shared Guest .localized )
for a in $userList ; do
DeleteUser=1
# for b in $LocalUsers ; do
for b in $exempt ; do
if [[ "$a" = "$b" ]]; then
# $a is a current user - don’t delete
DeleteUser=0
fi;
done;
if [[ "$DeleteUser" = "0" ]] || [[ "$a" = "Shared" ]] ; then
echo "NO NOT DELETE $a"
else
echo "DELETE $a"
rm -rf /Users/"$a";
# sysadminctl -deleteUser /Users/"$a";
# jamf -deleteAccount /Users/"$a";
fi;
done
Results:
using:
rm -rf /Users/"$a";
removes the account locally but still lists the deleted accounts in the JSS Inventory.
using:
sysadminctl -deleteUser /Users/"$a";
returns an error:
Failed to authenticate with SystemAdministration framework
using:
jamf -deleteAccount /Users/"$a";
returns an error:
No user name was specified. Use the -username flag
Using the command that deletes the accounts, how can the same account be removed from the Inventory, or is another command a better choice?