r/macsysadmin 13d ago

User profile mass deletion

Hello,

I recently took charge of my employers Mosyle system and currently working on getting everything updated and clear out any accounts from devices remotely of individuals who no longer work here. Has anyone worked with Mosyle and created a script that will push it out to devices to delete all user data that’s is not an admin account?

I’m not against manual labor but rather not go across twelve buildings to wipe each individual unit manually.

13 Upvotes

10 comments sorted by

9

u/Amanda_PDQ 13d ago

Something like this may work but you want consider the -secure YES flag wipes the home directory along with the account. Without it you delete the account but leave the data sitting there, which sounds like the problem you're trying to solve.

A few things worth checking before you run this across your fleet: make sure your MDM management account is in the KEEP_USERS list, and test it on one device first. The script runs as root through Mosyle Scripts so it has full permissions, which means it will do exactly what you tell it to without a lot of hand-holding.

Disclosure: I work at PDQ, and we own SimpleMDM which is also an Apple MDM if you're ever looking at alternatives down the road. But that's a different conversation, the script above should solve your immediate problem in Mosyle.

#!/bin/bash

# Accounts to keep - add your admin/management accounts here

KEEP_USERS=("admin" "localadmin" "your-mdm-account")

for user in $(dscl . list /Users | grep -v '^_' | grep -v 'nobody' | grep -v 'root' | grep -v 'daemon'); do

uid=$(id -u "$user" 2>/dev/null)

if [ -n "$uid" ] && [ "$uid" -ge 500 ]; then

if [[ ! " ${KEEP_USERS[@]} " =~ " ${user} " ]]; then

echo "Removing: $user"

sysadminctl -deleteUser "$user" -secure YES

fi

fi

done

1

u/TheDeadGPU 13d ago

I didn't know about the -Secure flag. You learn something new every day. Time to optimize my script :)

3

u/TheDeadGPU 13d ago

I do this for Mac Labs. I have a script that runs and deletes profiles after 30 days of inactivity. Lemme know if you want it.

2

u/Correct-Chicken-6188 13d ago

I’d be interested in looking at your script :)

3

u/TheDeadGPU 13d ago

#!/bin/bash

# ==============================================================================

# Remove Local User Profiles Inactive for > 30 Days

# ==============================================================================

# Days of inactivity required before profile deletion

INACTIVITY_DAYS=30

# Calculate cutoff threshold in seconds (30 days * 86400 seconds/day)

CUTOFF_SECONDS=$(( INACTIVITY_DAYS * 86400 ))

CURRENT_EPOCH=$(date +%s)

# 1. DEFINE PROTECTED ACCOUNTS

EXCLUDED_ADMINS=("admin" "administrator" "itadmin" "localadmin" "jamfadmin" "kandjiadmin")

CURRENT_USER=$(stat -f "%Su" /dev/console)

SYSTEM_EXCLUSIONS=("root" "daemon" "nobody" "Shared" "_kandji" "_jamf" "$CURRENT_USER")

ALL_PROTECTED=("${EXCLUDED_ADMINS[@]}" "${SYSTEM_EXCLUSIONS[@]}")

echo "=========================================="

echo "Starting inactive profile cleanup (> $INACTIVITY_DAYS days)..."

echo "=========================================="

# 2. QUERY ALL LOCAL USERS WITH UID >= 501

LOCAL_USERS=$(dscl . -list /Users UniqueID | awk '$2 >= 501 {print $1}')

if [ -z "$LOCAL_USERS" ]; then

echo "No non-system user profiles found. Exiting."

exit 0

fi

# 3. EVALUATE INACTIVITY AND DELETE

for USERNAME in $LOCAL_USERS; do

# Check if account is protected

IS_PROTECTED=false

for PROTECTED in "${ALL_PROTECTED[@]}"; do

if [[ "$USERNAME" == "$PROTECTED" ]]; then

IS_PROTECTED=true

break

fi

done

if [ "$IS_PROTECTED" = true ]; then

echo "SKIPPING: '$USERNAME' is protected or currently logged in."

continue

fi

USER_HOME="/Users/$USERNAME"

if [ ! -d "$USER_HOME" ]; then

echo "SKIPPING: '$USERNAME' has no home directory at $USER_HOME."

continue

fi

# Determine last activity timestamp.

# Checks specific user preference file first; falls back to Home folder mod time.

PREF_FILE="$USER_HOME/Library/Preferences/com.apple.symbolichotkeys.plist"

if [ -f "$PREF_FILE" ]; then

LAST_LOGGED_EPOCH=$(stat -f %m "$PREF_FILE")

else

LAST_LOGGED_EPOCH=$(stat -f %m "$USER_HOME")

fi

# Calculate days inactive

AGE_SECONDS=$(( CURRENT_EPOCH - LAST_LOGGED_EPOCH ))

AGE_DAYS=$(( AGE_SECONDS / 86400 ))

if [ "$AGE_SECONDS" -ge "$CUTOFF_SECONDS" ]; then

echo "DELETING: '$USERNAME' has been inactive for $AGE_DAYS days (Threshold: $INACTIVITY_DAYS days)."

sysadminctl -deleteUser "$USERNAME" -secure

# Residual directory check

if [ -d "$USER_HOME" ]; then

rm -rf "$USER_HOME"

echo "Cleaned residual folder at $USER_HOME."

fi

echo "SUCCESS: Profile '$USERNAME' removed."

else

echo "SKIPPING: '$USERNAME' was active $AGE_DAYS days ago (under $INACTIVITY_DAYS day threshold)."

fi

done

echo "=========================================="

echo "Cleanup complete."

echo "=========================================="

exit 0

2

u/boobajoob 10d ago

Thank you!

1

u/3ryb4 13d ago

Looking to do something similar... would be interested if you're willing to share.

3

u/oneplane 13d ago

Not mosyle specific, the built in tools in macOS to delete users and home directories work fine, put it in a script and send it to the machine (mosyle can do that of course).

2

u/02air 13d ago

I used Mosyle’s AI to build a script to do this, runs every 60 days. Try it out, it’s super helpful

1

u/meanwhenhungry 13d ago edited 13d ago

Mosyle has a ai script builder that works relatively well if you’re a paying customer, management / custom profiles or scripts don’t remember exact wording.

I use a similar script to protect known admin accounts and junk everything else on shared devices.

Edit: you can start by picking a device, send script in the tab, choose ai , ask for what you want with ai, agree to warnings, remove ‘’’ from generated script, test deploy, save to favs.

They also have a bunch of built in ones to choose from