Adding AD user in Terminal

JefferyAnderson
Contributor

Is there a way to add an Active Directory user account using a Terminal command? Our normal workflow when on site is to:
- log in as admin
- bind the Mac to AD
- log out of the admin account
- have the user sign into their AD account at the macOS login screen, thus creating their user account and user profile.

If we have a computer outside of our local network and need to add a network user account to a Mac, we have no way to do it. If we connect to the VPN logged into the admin account, we can hit our AD servers. But as soon as we log out of the admin account, or if we try to switch users or go to "login window..." the VPN connection drops and then we cannot add the network user account to the Mac.

So my question is, is there a way to add an AD user account from Terminal? Is there a way we could log in as admin, connect to VPN, bind to AD and then add the user somehow without logging out of the admin account.

We are looking at getting away from AD binding with Jamf connect, but we are not there yet and are trying to find a solution in the meantime.

1 ACCEPTED SOLUTION

JefferyAnderson
Contributor

I figured it out. While logged into the admin account, connect to VPN. Open Terminal and run the following commmand:

sudo /System/Library/CoreServices/ManagedClient.app/Contents/Resources/createmobileaccount -n [AD_username]

This creates the mobile user account. Now we need to cache the user's password. Back in Terminal:

login

When prompted, enter the AD username and password.

View solution in original post

13 REPLIES 13

JefferyAnderson
Contributor

I figured it out. While logged into the admin account, connect to VPN. Open Terminal and run the following commmand:

sudo /System/Library/CoreServices/ManagedClient.app/Contents/Resources/createmobileaccount -n [AD_username]

This creates the mobile user account. Now we need to cache the user's password. Back in Terminal:

login

When prompted, enter the AD username and password.

Thanks @JefferyAnderson 

Used this to resolve an issue we were having.  Tested on macOS 12.3.  Adding here for others to reference if needs be.

We are domain joined in our student labs.  The issue we were/are having is that students sometimes login to a workstation before our technicians login to the workstation.  The first account to login gets the SecureToken and therefore can't be deleted from the system when no other account has a SecureToken and/or the bootstrap hasn't been escrowed. This gives an active directory service account a SecureToken and resolved our problem.  We have a script that runs at login that deletes previous active directory accounts (students) which is where the problem started, unable to delete student accounts when they had a SecureToken.  Note, these lab machines are not encrypted.

Script to create mobile account and "login" while the workstation is till at a login prompt.

#!/bin/zsh

username=$4
password=$5

# Create mobile account
result=$(expect -c "
    spawn /System/Library/CoreServices/ManagedClient.app/Contents/Resources/createmobileaccount -n $username
    expect \"SecureToken\"
    send -- \"\r\"
    expect eof
    ")
echo $result
# Login to mobile account to grant it a secureToken (First user to login)
result=$(expect -c "
    spawn /usr/bin/login
    expect \"login:\"
    send -- \"$username\"
    send -- \"\r\"
    expect \"password:\"
    send -- \"$password\"
    send -- \"\r\"
    expect eof
    ")
echo $result
# Jamf inventory (more for testing)
/usr/local/bin/jamf recon

Script for account deletes at login and information gathering about SecureToken. Some logic in here was borrowed from Jamf Nation, thanks!

#!/bin/zsh

#set -x
clear

# Get the current logged in user
currentLoggedInUser=$(ls -l /dev/console | cut -d " " -f 4)
# List of users that we want to exclude from deletion
usersToKeep=( $currentLoggedInUser $4 )

function secureTokengodmode {
  secureToken=$(/usr/bin/dscl . read /Users/godmode | grep "SecureToken")
  if [[ "$secureToken" == *"SecureToken"* ]]; then
    echo "User: godmode SecureToken status: Enabled"
  else
    echo "User: godmode SecureToken status: Disabled"
  fi
}

function removeAccount {
    removeAccountHome=$(dscl . read /Users/$1 | grep "NFSHomeDirectory" | awk '{print $2}')
    echo "Removing home folder for $1."
    log "Removing home folder for $1."
    rm -rf "$removeAccountHome"
    sleep 3
    if [[ -d "$removeAccountHome" ]]; then
        echo "$removeAccountHome failed to delete, skipping."
        log "$removeAccountHome failed to delete, skipping."
    else
        echo "Removing user account for $1."
        log "Removing user account for $1."
        dscl . -delete "/Users/$1"
        sleep 3
    fi
}

function log {
   timeStamp=$(date)
   echo "$timeStamp - $1" >> "/Library/Logs/deleted user accounts.log"
}

# cleanup!
function cleanup {
    if [[ -f "$outFile"1 ]]; then
        rm "$outFile"1
    fi
}

# Logic

secureTokengodmode

# Get a list of all the users with a UniqueID of greater than 1000 and save to a file
outFile=/var/tmp/output
/usr/bin/dscl . list /Users UniqueID | grep -v "^_" | awk '{if($2>1000)print $1}' > "$outFile"1

echo "List of Users to keep: $usersToKeep"
for usersToDelete in $usersToKeep ; do
    # Use grep to search for an exact match and if found, remove it from the file
    grep -v -Fx "$usersToDelete" "$outFile"1 > "$outFile"2 & mv "$outFile"2 "$outFile"1
done
# Check if the file is empty or not
if [[ -s "$outFile"1 ]]; then
    # Read the output file to an array for processing
    eval "array=($(<"$outFile"1))"
    # Remove the user account and home directory
    for removeUser in $array ; do
        removeAccount $removeUser
    done
    cleanup
else
    echo "No users to delete at this time."
    cleanup
fi

# List remaining users on the workstation
remainingUsers=$(/usr/bin/dscl . list /Users UniqueID | grep -v "^_")
echo "Remaining users:"
echo "$remainingUsers"
log "Remaining users: $remainingUsers"

echo " "
### Secure Token users ###
declare -a secureTokens
declare -a delete
secureTokens=($(fdesetup list -extended | awk '{print $4}'))
#echo ${secureTokens[@]}
delete+=(USER)
delete+=(Record)
#echo ${delete[@]}
for i in ${delete[@]}; do
secureTokens=( "${secureTokens[@]/$i}" )
done
#echo ${secureTokens[@]}
function join { local IFS="$1"; shift; echo "$*"; }
result=$(join , ${secureTokens[@]})
echo "Remaining Secure Token Users: $result"
log "Remaining Secure Token Users: $result"

echo " "
bootstrap=$(profiles status -type bootstraptoken)
if [[ $bootstrap == *"escrowed to server: YES"* ]]; then
    echo "Bootstrap Status: Escrowed"
    log "Bootstrap Status: Escrowed"
else
    echo "Bootstrap Status: Not Escrowed"
    log "Bootstrap Status: Not Escrowed"
fi

exit

 Perhaps this can be of use to others.

AdamCraig
Contributor III

I ran into a similar problem. I ended up using the command dscacheutil -q user -a name USERNAME to cache the user's password. I'll have to try the Login option next time I need to do this.

smitty1923
New Contributor II

@Jeffery_Anderson Thanks for the info on this. Have you seen an issue where the user who was created by this command can't log into their account after restart? I'm having that issue now and have tried multiple steps to resolve. I've followed your steps to a T and it hasn't prevented that issue so far. I can create the account fine, but the user can't login after restart. I have to login via local admin first, log out, then log into the user and it works. But not after restart or shutdown. Any thoughts?

AdamCraig
Contributor III

@smitty1923 Do you have Filevault Enabled? because that could cause some of those issues.
I ended up setting up this as a Self Service policy to add a remote user.
https://github.com/theadamcraig/jamf-scripts/blob/master/remote_AD_user_creation.sh

ageevarughese
New Contributor II

@Jeffery_Anderson This didn't work for me in 10.14.6. I receive the following error message when using my user name in the admin account;

* user name "[username]" was not found: 0 ((null))

Switchfly_IT
New Contributor III

Have the same issue as Jeffrey. Curious if anyone has preferences on this workaround? I've not tried the Terminal command that @Jeffery_Anderson has cited. Machine is AD bound and we have a ethernet connection that is supposedly hardwired to the network but no dice on logging in the AD user..or any AD user. Stuck with AD for the time being so have to find a workaround vs adding as a "local" user independent of AD credentials.

AdamCraig
Contributor III

@Switchfly_IT It's linked above. but this script is set up as a self service policy and scoped to computers that are being provisioned. Our IT team uses this both on prem and remotely to create mobile AD user accounts. We are transitioning to local accounts with jamf connect, but this has worked great for us in the mean time.
There is a bit in there that adds the account to filevault. remove that if you aren't using FV
https://github.com/theadamcraig/jamf-scripts/blob/master/remote_AD_user_creation.sh

sk0303
New Contributor

@AdamCraig 

Hi AdamCraig, do you know if the script is updated?  i keep getting an endless spinning in self-service?

thank you

I haven't used that in production in awhile. But I'm not aware of any OS changes that would break it off the top of my head. I'd try running it locally and see if it works there.
The way I wrote the display dialog prompt may wait on a "Jamf would like to access system events" prompt. but other than that I'm not sure what could be happening.

I updated the Display Dialog function in case that was causing the infinite spinning

sk0303
New Contributor

@AdamCraig 

thank you for getting back to me.

is there any modification needed within the script?  

getting this error message:

AD User failed to add. \nVerify GlobalProtect is Connected. \nRecommend restarting the computer and trying this install again. \nIf issues continue run 'Rebind to Domain' from Self Service and then try install again.

 

So that means the script couldn't add the user, and most likely the computer could not contact the domain controller. If you're remote and using VPN you'll want to make sure VPN is connected before trying this.