Detecting additional users via smart groups?

azimmer1984
New Contributor

Greetings! I'm trying to create an EA that detects when a user has added their own user to a device. We need an indicator of "setup-ed-ness" on laptops. A device that a user has never powered on, or has but never logged in to, needs to not run a couple policies, but once someone has their user account (John Doe), it should be in a "ready" state.

So I'm searching for "Machines with known accounts, plus more." 

We have two accounts fleet-wide, with predictable names. Once someone logs in with Jamf Connect, there should be a third account. But I can't write a one-size fits all for known1, known2, as well as unkonwn1, unkonwn2, unknownN in a Smart Group, at least not that I'm aware. 

I can create a smart group that checks for the presence of the expected users.

I was thinking I'd need to write an EA, but zsh is giving me a devil of a time taking dscl's output and putting it into an array I can cross-check.

Anyone have any guidance on a pre-existing EA that's close? A solid script or snippet or function for "get all users above ID 500 on this Mac?"  Is there a way to do it with Smart Group regexes?

Thanks in advance. 

1 ACCEPTED SOLUTION

AJPinto
Honored Contributor III

Seems like a very messy ask, but I'll take a stab. 

 

If we are going off UID's you will want to exclude 501, and 502. 501 and 502 are likely your local admin account and JSS account, macOS does not assign 500 as a user account. This script is far simpler, but if somehow a user gets 501 or 502 then it won't work as it will miss the account; this is not likely, but it is possible.

#!/bin/bash

# Get a list of user accounts with UID above 500
user_accounts=$(dscl . list /Users UniqueID | awk '$2 > 500 {print $1, $2}')

# Echo the user accounts
echo "User accounts with UID above 500:"
echo "$user_accounts"

# Check if any user account has a UID of 503 or greater
user_503_or_greater=$(echo "$user_accounts" | awk '$2 >= 503')

if [ -n "$user_503_or_greater" ]; then
    echo "user has logged in"
    exit 0
else
    echo "user has not logged in"
    exit 1
fi

 

The other option is specifying the usernames you don't want to report on. If the script sees something "unexpected" like a new user account, it will exit echoing it found the new account. Scripting this way would require you to specify each account you want to omit but would handle the chance a user got UID 501 or 502. 

#!/bin/bash

# Define the expected users
User1= #Replace with Account name of your local admin account
User2= #Replace with Account name of your local admin account
expected_users=("$User1" "$User2" "daemon" "nobody" "root")

# Function to check if a user exists on the system
user_exists() {
  id "$1" &>/dev/null
  return $?
}

# Check for the presence of User1 and User2
for user in "${expected_users[@]}"; do
  if ! user_exists "$user"; then
    echo "Missing account: $user"
    exit 1
  fi
done

# Get a list of all user accounts on the system
all_users=($(dscl . -list /Users | grep -v '^_'))

# Check for any additional user accounts beyond User1 and User2
for user in "${all_users[@]}"; do
  if [[ ! " ${expected_users[@]} " =~ " ${user} " ]]; then
    echo "Extra account found: $user"
    exit 0
  fi
done

# If no extra accounts are found
echo "Only $User1 and $User2 are present."
exit 0

  

Just some quick and dirty scripts for ideas. As far as telling if the user has logged in, I did not attack that one. You would likely be looking for the user setup done flag which is somewhere in var if I remember correctly.

View solution in original post

5 REPLIES 5

AJPinto
Honored Contributor III

Seems like a very messy ask, but I'll take a stab. 

 

If we are going off UID's you will want to exclude 501, and 502. 501 and 502 are likely your local admin account and JSS account, macOS does not assign 500 as a user account. This script is far simpler, but if somehow a user gets 501 or 502 then it won't work as it will miss the account; this is not likely, but it is possible.

#!/bin/bash

# Get a list of user accounts with UID above 500
user_accounts=$(dscl . list /Users UniqueID | awk '$2 > 500 {print $1, $2}')

# Echo the user accounts
echo "User accounts with UID above 500:"
echo "$user_accounts"

# Check if any user account has a UID of 503 or greater
user_503_or_greater=$(echo "$user_accounts" | awk '$2 >= 503')

if [ -n "$user_503_or_greater" ]; then
    echo "user has logged in"
    exit 0
else
    echo "user has not logged in"
    exit 1
fi

 

The other option is specifying the usernames you don't want to report on. If the script sees something "unexpected" like a new user account, it will exit echoing it found the new account. Scripting this way would require you to specify each account you want to omit but would handle the chance a user got UID 501 or 502. 

#!/bin/bash

# Define the expected users
User1= #Replace with Account name of your local admin account
User2= #Replace with Account name of your local admin account
expected_users=("$User1" "$User2" "daemon" "nobody" "root")

# Function to check if a user exists on the system
user_exists() {
  id "$1" &>/dev/null
  return $?
}

# Check for the presence of User1 and User2
for user in "${expected_users[@]}"; do
  if ! user_exists "$user"; then
    echo "Missing account: $user"
    exit 1
  fi
done

# Get a list of all user accounts on the system
all_users=($(dscl . -list /Users | grep -v '^_'))

# Check for any additional user accounts beyond User1 and User2
for user in "${all_users[@]}"; do
  if [[ ! " ${expected_users[@]} " =~ " ${user} " ]]; then
    echo "Extra account found: $user"
    exit 0
  fi
done

# If no extra accounts are found
echo "Only $User1 and $User2 are present."
exit 0

  

Just some quick and dirty scripts for ideas. As far as telling if the user has logged in, I did not attack that one. You would likely be looking for the user setup done flag which is somewhere in var if I remember correctly.

This gets me started. I'd written multiple variants doing the dscl check, but kept getting the strings arranged in ways later functions and for loops wouldn't play with.

Don't know what voodoo you have that I don't, but I'm glad you do! 

As for telling if the user's ever logged in, you make a good point. Fortunately we're early enough in the process that we can mostly say "this is correct, if not the device does not match this, reimage". The account's presence would be proof they did--the account is created by Jamf Connect, as part of first login. And any situation where JC died or the laptop lost power midway through, creating a home directory but not getting to desktop would be a ticket to us anyway...

Have a great one!

Just so you have the snippet if you need it in your workflow, here is how we make sure that our enrollment script does not run until the user arrives at the desktop.

# Check if Setup Assistance Process is Still Running.
# If yes, wait till it finishes so this script will NOT proceed while running the Setup Assistant (Location Settings..etc)


SetupAssistance_process=$(/bin/ps auxww | grep -q "[S]etup Assistant.app")
while [ $? -eq 0 ]
do
    /bin/echo "Setup Assistant Still Running... Sleep for 2 seconds..."
    /bin/sleep 2
    SetupAssistance_process=$(/bin/ps auxww | grep -q "[S]etup Assistant.app")
done

 

AJPinto
Honored Contributor III

Checking for accounts generated by Jamf Connect is pretty easy. Jamf Connect drops a plist with the IDP information on the device, its /Users/{user}/Library/Preferences/com.jamf.connect.state.plist. You can just grep information out of it for anything specific, and just the existence of the file means the user logged in successfully with Jamf Connect at some point. On a side note, this is a really useful file to get information from like homedrive paths, and when the PW expires and put it in Jamf with Extension Attributes. 

 

Looks like @mickgrant had some magic sauce for checking for setup assistant to ensure that part is not running. Monitoring setup assistant is a very good trick to figure out.

 

That was my thought exactly! Adding a function after the existing check for the user to check that user's folder for the PLIST.

Great minds and all that.