Remove old mobile accounts.

AndyBeaver
Contributor II

I am needing a script that can be added to our summer update configuration that will delete every user with the exception of admins. Anyone had any luck doing this? I have tried using Tom Larkin's script and it seems to remove the home directories from /Users how ever the accounts are still populated in SystemPreferences>Accounts. Any ideas?

https://discussions.apple.com/message/12165862#12165862

dscl . -delete /Users/


dscl . list /Users | grep -v "_"


#!/bin/bash

UserList=`/bin/ls /Users | /usr/bin/grep -v "Shared"`

for u in $UserList ; do

if [[ `/usr/bin/dscl . read /Groups/admin GroupMembership | /usr/bin/grep $u -c` == 1 ]]

then /bin/echo "Admin account detected skipping..."

else /usr/bin/dscl . delete /Users/$u && /bin/rm -rf /Users/$u

fi

done
1 ACCEPTED SOLUTION

cbrewer
Valued Contributor II

The "dscl . delete /Users/username" command should remove it from the Accounts prefpane.

My script builds a list of users with UniqueID's higher than 1000 (this way it's only looking at cached AD users). It then checks for home directories older than 21 days and then removes the account and home directory for that user. It also only deletes users who are members of our students group in AD.

#!/bin/sh

userList=`dscl . list /Users UniqueID | awk '$2 > 1000 {print $1}'`

echo "Deleting account and home directory for the following users..."

for a in $userList ; do
    if [[ "$(id $a | tr '[:upper:]' '[:lower:]')" =~ "your student AD group" ]]; then
        find /Users -type d -maxdepth 1 -mindepth 1 -not -name "*.*" -mtime +21 | grep "$a"
        if [[ $? == 0 ]]; then
            dscl . delete /Users/"$a"  #delete the account
            rm -r /Users/"$a"  #delete the home directory
        fi
    fi
done

View solution in original post

63 REPLIES 63

TJ78620
New Contributor

Can anyone help me? I work for a school district that allows teachers to checkout laptops from the library when needed. As a result I have several accounts on computers that do not need to be there. So I am trying to find a script that will delete mobile accounts even if they are an admin accounts except for a specified list. Example I want to keep the local admin and esteacher ( mobile admin) and esstudent ( mobile managed account) . Thanks for any help you can give I am VERY NEW to scripting.

ryan_ball
Valued Contributor

@TJ78620 The solution in this thread might work for you.

You'd modify the "KEEP" section with something like this:

KEEP=("/Users/Shared" "/Users/esteacher" "/Users/esstudent" "/Users/[LOCALADMIN]")

As well as the age of the accounts in this section:

AGE=122 # Delete /Users/ folders inactive longer than this many days

TJ78620
New Contributor

Thanks Ryan I will give it a try

cbrewer
Valued Contributor II

5 year old thread, but since it's still active I will add the latest version of what I'm using. I think it's a little more robust than what I first posted. I've also considered moving the home directories to an archive directory instead of nuking them.

#!/bin/bash

userList=`dscl . list /Users UniqueID | awk '$2 > 1000 {print $1}'`

echo "Deleting account and home directory for the following users..."

for user in $userList ; do
    if [[ "$(id $user | tr '[:upper:]' '[:lower:]')" =~ "my student group" ]]; then
        if [[ "$(find /Users -type d -maxdepth 1 -mindepth 1 -not -name "*.*" -mtime +21 | grep "$user")" =~ "$user" ]]; then
            dscl . delete /Users/"$user"  #delete the account
            rm -r /Users/"$user"  #delete the home directory
            echo "$user"
        fi
    fi
done

OR if you don't want the AD group lookup part...

#!/bin/bash

userList=`dscl . list /Users UniqueID | awk '$2 > 1000 {print $1}'`

echo "Deleting account and home directory for the following users..."

for user in $userList ; do
    if [[ "$(find /Users -type d -maxdepth 1 -mindepth 1 -not -name "*.*" -mtime +21 | grep "$user")" =~ "$user" ]]; then
        dscl . delete /Users/"$user"  #delete the account
        rm -r /Users/"$user"  #delete the home directory
        echo "$user"
    fi
done

KCH080208
New Contributor II

This could be useful for a situation where we need keep our loaner computers cleaned up. If i simply didnt want to search for a student group or a specific name would i simply remove "=~ "my student group" and =~ "my student group"

all id be looking to do is delete any account older than x amount of days old.

Acousmatic
New Contributor

Running this...

find /Users -type d -maxdepth 1 -mindepth 1 -mtime +1

... does not return the proper list of users whose accounts are older than 24 hours. Running "ls -l /Users" returns a confirmation that the folders have not been modified for several days. After bashing my head against my desk as well as some research, it looks like -mmin is better at this. So this works for our scenario...

#!/bin/sh
# Remove Mobile Accounts.sh
# Removes all mobile accounts from the system

userList=`dscl . list /Users UniqueID | awk '$2 > 1000 {print $1}'`

echo "Deleting account and home directory for the following users..."

for a in $userList ; do
        find /Users -type d -maxdepth 1 -mindepth 1 -mmin +$((60*24)) | grep "$a"
        if [[ $? == 0 ]]; then
            dscl . delete /Users/"$a"  #delete the account
            rm -r /Users/"$a"  #delete the home directory
        fi
done

sdagley
Esteemed Contributor II

Here's the script I use to clean AD accounts. It started life as something to just delete all AD accounts. When we switched from classroom sets of MacBook Airs to a truer 1-to-1 model of students being assigned a laptop they could take home I modified the script so a student could run it from Self Service and delete any AD account but theirs (we had some teachers that didn't bother to have regular laptop assignments with their class sets resulting in some machines having over 70 users created).

Note that my environment is all >= macOS 10.10, so I use sysadminctl rather than dscl and rm to delete the user accounts.

#!/bin/bash
################################################################################
# DeleteADUsers.sh
#
# Requires Mac OS X 10.10 or newer
# If run as root, deletes all AD accounts
# If user is logged in, asks to verify login ID and will not delete that account
################################################################################

adusers=$(dscl . list /Users UniqueID | awk '$2 > 1000 {print $1}')
currentuser=$(stat -f "%Su" /dev/console)
response="2" # Presume confirmation failure

if [[ "$currentuser" != "root" ]]; then
    # If we're not root, ask user to verify their login ID
    response=$(/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType utility -title "Verify login ID" -heading "Verify login ID" -description "Please verify that $currentuser is your login ID" -button1 "That's Me" -button2 "Not Me")
    if [ "$response" != "0" ]; then
       echo "Did not get confirmation from user, no accounts will be deleted"
    fi
else
    echo "Running as root, so all AD accounts will be deleted"
    response="0" # Always set confirmation response when root
fi

if [ "$response" == "0" ]; then
    echo "Deleting AD user accounts..."

    for user in $adusers ; do
        if [ "$user" != "$currentuser" ]; then
            /usr/sbin/sysadminctl -deleteUser "$user"
            echo "$user deleted"
        fi
    done
fi

rlegge
New Contributor

I want to use the above script to delete AD users older than "X" days. I've tried modifying it, but my scripting skills could use a bit more work. The script works pretty well, but I noticed a couple strange behaviors that maybe someone with more knowledge could explain? I ran this script on one of our student lab computers with about 75 accounts. We use AD accounts that create a mobile account on login. Most of these accounts do NOT end up in the Users & Groups pref pane, however about 8 or 9 DID. In summary, if you look at /Users/ there are 75 folders, but only 8 or 9 of them are in U&G list.
All accounts that were in /Users/ but NOT in the U&G pref pane were deleted (except one.... weird part). I could not see anything about that one account that would explain it being left alone (not logged in, etc.)

I ran the script again and this time ALL accounts (except admin, shared) were deleted, the only accounts left were the ones in the U&G, and the straggler that didn't go away the first time... Not sure why this didn't happen on the first run, but did the second.

tl;dr
I want to modify the above script to ONLY delete AD accounts OLDER than "X" days

Thanks in advance!!!

mm13
New Contributor II

@cbrewer

I feel like an absolute newb here, but I'm trying to make your script delete any mobile accounts; regardless of age. I've changed -mtime +21 to -mtime 0; but still not getting the desired results. We're looking to scope this to loaners for once they are checked in; it will completely wipe the mobile accounts.

Any help would be much appreciated!

Edit: Scratch that. Took out the "-not" flag, and things are nice and dandy. Thanks!

ChrisCox
New Contributor III

We are running a script similar to the ones above, and it is working as intended. It logs when it ignores a user due to it not being a student account, ignores the current user, ignores a user due to recent activity, and removes a user due to no recent activity. However, I am running into a bizarre problem where sometimes some of my users' home folders are not updating with a modification date/time upon login. During some troubleshooting we have determined that some users' home folders have a modification date/time that is older than their last login when viewed from the last command. Has anyone else seen anything like this before?

cbrewer
Valued Contributor II

@ChrisCox

I've seen what you're seeing, but haven't looked into it too much. For now, we aren't removing user accounts and home directories with this method.

ChrisCox
New Contributor III

Did you find a more reliable method, or are you just avoiding it altogether for now?

cbrewer
Valued Contributor II

Just avoiding at the moment. I think the answer is going to be to look recursively through all files in the home directory, find the newest one and use that date.

This may be a start:
https://stackoverflow.com/questions/4561895/how-to-recursively-find-the-latest-modified-file-in-a-di...

ChrisCox
New Contributor III

Anyone reason you can think of not to just ignore those home folders that contain a file less than 30 days since last modification? Check out the third if statement with the find command.

#!/bin/bash

for home in /Users/*; do
    username=`basename $home`
    if [[ `echo $username | cut -c -1` =~ ^[0-9]+$ ]]; then
        if [[ `stat -f "%Su" /dev/console` == $username ]]; then
            echo "Skipping due to being currently logged in: $username"
        else
            if [[ `find $home -type f -mtime -30` ]]; then
                echo "Skipping due to recent activity: $username"
            else
                dscl . -delete /Users/$username && echo "Removed user account: $username"
                rm -rf $home && echo "Removed home folder: $home"
            fi
        fi
    else
        echo "Skipping non-student: $username"
    fi
done

Edit: By the way, in our environment we are only trying to delete student users that have not been used in the last 30 days. All student usernames and only student usernames start with a number.

GabeShack
Valued Contributor III

@cbrewer Trying to work with your script below and changing the mtime to 15 or 10 but it seems it doesn't delete any user accounts either way.
Wondering if 10.12.6 is not working the same way.

#!/bin/bash

userList=`dscl . list /Users UniqueID | awk '$2 > 1000 {print $1}'`

echo "Deleting account and home directory for the following users..."

for user in $userList ; do
    if [[ "$(find /Users -type d -maxdepth 1 -mindepth 1 -not -name "*.*" -mtime +21 | grep "$user")" =~ "$user" ]]; then
        dscl . delete /Users/"$user"  #delete the account
        rm -r /Users/"$user"  #delete the home directory
        echo "$user"
    fi
done

Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

cbrewer
Valued Contributor II

@gshackney Read a few posts up. I've found that running find on just the home directory with mtime is not reliable. I personally wouldn't delete any home directories based on that logic alone.

GabeShack
Valued Contributor III

Ah, missed that. Guess I'm back to just deleting all users (minus my needed ones) once its 80% full

Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

millersc
Valued Contributor

@gshackney I have a Self Service policy that will show for our Media Lab teachers when there is "more than X accounts" and they can remove all accounts except for our local admin and jamf account. Usually if they start seeing space issues (we have 120 SSDs) they go right to this now.

GabeShack
Valued Contributor III

Well since I stopped creating system user accounts with the bind, I just have to delete the home folders.
So Now I just run this when the drive hits 80% full or more(just edit the grep's with the accounts you want to save):

#!/bin/sh

for home in $(ls /Users | grep -v localadmin | grep -v Shared | grep -v admin | grep -v username | grep -v username | grep -v username | grep -v username | grep -v username | grep -v $3)
do
sudo rm -rf /Users/$home
done

Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

tdilossi
Contributor

@gshackney Where do you run this? In self service or as a policy based on a smart group?

GabeShack
Valued Contributor III

@tdilossi Policy that runs automagically base on a Smart Group targeting specific heavy use machines and also machines over 80% full:
a3642a392f1c430db92b5191227e754a

Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

tdilossi
Contributor

@gshackney excellent! thanks for the prompt response!!

hodgesji
Contributor

We were looking at implementing this recently, but one caveat we ran into was if you push packages in Jamf with the Fill Existing Users option checked, it will modify files in the users home folders, effectively making the find command with mtime inaccurate.

We are still looking for a trusted source for last login time/activity that can be used.

On a side note, there is a configuration profile payload for Mobility that lets you set deleting user accounts after x days of login, but it was unreliable for us. Deleting users too early.

cbrewer
Valued Contributor II

I've found it more reliable to get mtime on the user's Preferences folder versus their entire home directory.

if [[ $(find /Users/$user/Library/Preferences -type d -maxdepth 1 -mindepth 1 -mtime +30) ]]; then
  echo "Deleting $user"
  sysadminctl -deleteUser $user
fi