Posted on 08-28-2013 04:17 PM
Basically this is related to the context of migrating to an Active Directory account using Centrify Direct Control
Yet, Centrify DC only migrates from an existing user's local OS X account (linking with the accompanying user's local home folder).
Is there a tool, terminal commands, procedure, etc. that will convert the OD account to an OS X local account.
I am aware that I can create an OS X local account manually and then "move" / mv the contents into this new home folder, and then do a chown -R.
I undertand this is related to UID's, and that the actual OD user account is stored on the OD server.
We then use Centrify Account Migration Tool to "Link" this home folder to an AD user account name. It Links, and successfully logs in using AD creds, but the user profile / permissions are whacked. For example, do not see docs on the desktop, desktop picture, etc.
thanks in advance,
john k
Solved! Go to Solution.
Posted on 08-29-2013 12:10 PM
Reply to my own post....
Apparently all one has to do is create a local OS X account, with the same exact name as the OD user's home folder.
OS X will ask to use the Existing Home Folder (and auto fix all permissions).
Since I am testing this for a remote site, and do not have direct access to this machine and OD user home folder, I do not know for sure, if the user's profile prefs come over. It seems like it does not.
Not sure if the user's profile prefs (desktop picture, dock, etc) is located in that local home folder, or if it is stored in some folder on the OS X / OD server, it very well could be.
I am aware of the path for a local users profile:
/var/db/dslocal/nodes/Default/users
And I am guessing it is, username.plist
jk
Posted on 08-29-2013 12:10 PM
Reply to my own post....
Apparently all one has to do is create a local OS X account, with the same exact name as the OD user's home folder.
OS X will ask to use the Existing Home Folder (and auto fix all permissions).
Since I am testing this for a remote site, and do not have direct access to this machine and OD user home folder, I do not know for sure, if the user's profile prefs come over. It seems like it does not.
Not sure if the user's profile prefs (desktop picture, dock, etc) is located in that local home folder, or if it is stored in some folder on the OS X / OD server, it very well could be.
I am aware of the path for a local users profile:
/var/db/dslocal/nodes/Default/users
And I am guessing it is, username.plist
jk
Posted on 08-04-2016 10:23 AM
Heads up on this. You need to go remove the (deleted) off of the user folder to make this work.
Posted on 08-04-2016 10:42 AM
@johnklimeck Here's what we're using to convert Mobile AD accounts to local accounts:
function convertAccount() { # Convert account from mobile to local
ScriptLog "* Convert account ..."
if [ "${loginPassword}" == "${confirmPassword}" ] && [ "${dblchk}" == 1 ]; then # The passwords match and the user has acknowldged they have a backup
ScriptLog "* Convert account from mobile to local ..."
# Delete the currently logged-in user account
ScriptLog "* Deleting ${loggedInUser} account from client-side directory ..."
/usr/bin/dscl . delete /Users/"${loggedInUser}"
# Determine the current highest user UID, in the 500 range
maxid=$(/usr/bin/dscl . -list /Users UniqueID | /usr/bin/awk '{print $2}' | /usr/bin/grep -Ex '5[0-9][0-9]' | /usr/bin/sort -ug | /usr/bin/tail -1)
if [ -z ${maxid} ]; then
newid=501 # There aren't any user accounts in the 5nn range; use 501
else
newid=$((maxid+1)) # There are user accounts in the 5nn range; add one to the hightest
fi
# Create local user account ...
ScriptLog "* Create ${loggedInUser} local account in client-side directory ..."
/usr/sbin/sysadminctl -addUser "${loggedInUser}" -fullName "${userRealName}" -UID "${newid}" -password "${confirmPassword}" -home "/Users/${loggedInUser}" "${adminStatus}"
# Reset ownership on home directory and append location
ScriptLog "* Correct permissions for ${loggedInUser} ..."
/usr/sbin/chown -R "${loggedInUser}":staff /Users/"${loggedInUser}"
/usr/bin/dscl . -append /Users/"${loggedInUser}" NFSHomeDirectory /Users/"${loggedInUser}"/
ScriptLog "* Sleep for five seconds ..."
/bin/sleep 5
# Force logout
ScriptLog "* Force logout ..."
/bin/ps -Ajc | /usr/bin/grep loginwindow | /usr/bin/awk '{print $2}' | /usr/bin/xargs /bin/kill -9
ScriptLog "---"
ScriptLog "- $loggedInUser account converted from Mobile to Local"
ScriptLog "---"
# Re-direct logging to the JSS
exec 1>&3 2>&4
/bin/echo >&1 "$loggedInUser account converted from Mobile to Local."
else # Password don't match; inform user and exit
ScriptLog "* Error: Either passwords don't match, the user didn't authorize the change, or both; inform user and exit ... dblchk='${dblchk}'"
# The user has failed to match the password three consecutive times.
/usr/local/jamf/bin/jamf displayMessage -message "Error -397; exiting."
ScriptLog "* Error -397: The user failed to confirm the password three consecutive times."
# Re-direct logging to the JSS
exec 1>&3 2>&4
/bin/echo >&1 "Error -397"
exit 2 # exit with an error status
fi
}
Posted on 08-04-2016 11:52 AM
@johnklimeck You are correct that making an account with the same short name will override the OD account. While windows users need to prepend DOMAIN before the user account (DOMAINusername), Macs instead will search domains in order so you don't need to tell it where the account exists. The local computer domain is always searched first.
Posted on 01-04-2017 01:36 PM
@dan.snelson Can you explain more how you have setup this script in your JAMF environment?
Posted on 01-04-2017 05:56 PM
@perrinbw My previous post was only a single function from a larger script, which we make available via Self Service.
I recommend reviewing @lisacherie's recent post, Converting AD Mobile Accounts to Local.
Posted on 01-04-2017 06:05 PM
@perrinbw Here's our complete script, which relies on client-side functions (i.e., "source /path/to/client-side/functions/functions.sh") for logging and Pashua.
#!/bin/sh
####################################################################################################
#
# ABOUT
#
# Convert Mobile Account to Local Account
# Based on: https://jamfnation.jamfsoftware.com/discussion.html?id=12462#responseChild73117
#
# This script is designed to remove a mobile user account and re-create
# a local account with the same username and the password from user-input.
# It will also give read/write permissions to the user's home folder.
#
####################################################################################################
#
# HISTORY
#
# Version 1.0, 28-Apr-2016, Dan K. Snelson
# Version 1.1, 02-May-2016, Dan K. Snelson
# Removed code and verbiage about the user's keychain
# Version 1.2, 03-May-2016, Dan K. Snelson
# Fixed error when no users with 5nn UID existed
#
####################################################################################################
# Import general functions
source /path/to/client-side/functions/functions.sh
####################################################################################################
ScriptLog "###############################################"
ScriptLog "### Convert Mobile Account to Local Account ###"
ScriptLog "###############################################"
### Variables
loggedInUser=`/usr/bin/stat -f%Su /dev/console`
UserUID=`/usr/bin/dscl . read /Users/"${loggedInUser}" UniqueID | grep UniqueID: | cut -c 11-`
userRealName=`/usr/bin/dscl . -read /Users/"${loggedInUser}" | /usr/bin/grep RealName: | cut -c11-`
if [[ -z "${userRealName}" ]]; then
userRealName=`/usr/bin/dscl . -read /Users/"${loggedInUser}" | awk '/^RealName:/,/^RecordName:/' | sed -n 2p | cut -c 2-`
fi
if [[ $(/usr/bin/dsmemberutil checkmembership -U "${loggedInUser}" -G admin) != *not* ]]; then
adminStatus="-admin" # User is a member of the admin group; retain admin rights
userIsAdmin="Yes"
else
adminStatus="" # User is not a member of the admin group
userIsAdmin="No"
fi
# Echo variables
ScriptLog "Variables ..."
ScriptLog "* loggedInUser=${loggedInUser}"
ScriptLog "* UserUID=${UserUID}"
ScriptLog "* userRealName=${userRealName}"
ScriptLog "* adminStatus=${userIsAdmin}"
### Define the functions
function validateCurrentUserID() { # Exit if UID is under 1000 (local account)
ScriptLog "* Validate Current UserID ..."
if [[ "${UserUID}" -lt 1000 ]]; then
ScriptLog "* Error: The account '${loggedInUser}' is already a local account (${UserUID})."
# Re-direct logging to the JSS
exec 1>&3 2>&4
/bin/echo >&1 "Error: The account '${loggedInUser}' is already a local account (${UserUID})."
# Inform user of the error
/usr/local/jamf/bin/jamf displayMessage -message "Error: The account '${loggedInUser}' is already a local account (${UserUID})."
exit 2
else
ScriptLog "* The '${loggedInUser}' account is a mobile account (${UserUID}); proceeding ..."
fi
}
function checkCancel() { # Check for cancel button
#ScriptLog "* Check for cancel button ..."
if [ "${cb}" == 1 ]; then
# The user clicked Cancel
ScriptLog "* Cancelled by user."
# Re-direct logging to the JSS
exec 1>&3 2>&4
/bin/echo >&1 "Cancelled by user."
exit 2 # exit with an error status
fi
}
function promptLoginPassword() { # Prompt for login password
ScriptLog "* Prompt for Login Password ..."
pashuaDialog="
# Set window title
*.title = Convert Mobile Account to Local Account
*.floating = 1
# Specify image
img.type = image
img.path = /System/Library/CoreServices/Certificate Assistant.app/Contents/Resources/AppIcon.icns
img.maxwidth = 64
img.rely = 110
# Introductory text
txt.type = text
txt.default = This script converts your Mobile Account, ${loggedInUser}, to a Local Account.[return][return]Click Cancel to exit without making any changes.[return][return]To continue, save your work -- you will be logged out -- enter your current login password and click Confirm Password ...
#txt.height = 276
txt.width = 350
txt.x = 80
txt.y = 135
#txt.tooltip = Your current login password is the one you use to login to your computer.
# Add a password field
loginPassword.type = password
loginPassword.label = Current Login Password
loginPassword.mandatory = true
loginPassword.width = 350
loginPassword.x = 80
loginPassword.y = 80
loginPassword.tooltip = Your current login password is the one you use to login to your computer or unlock the screensaver.
# Add checkboxes
chk.rely = -10
chk.relx = 80
chk.type = checkbox
chk.label = I have a current, known-working backup of my data.
chk.tooltip = By checking this box, I acknowledge I have a known-working backup of my data.
chk.default = 0
chk.mandatory = true
# Add a cancel button with default label
cb.type = cancelbutton
cb.tooltip = Cancel without saving changes.
db.type = defaultbutton
db.label = Confirm Password ...
db.tooltip = Enter your current login password and click Confirm Password ...
"
pashua_run "${pashuaDialog}"
}
function confirmLoginPassword() { # Confirm login password
ScriptLog "* Confirm Login Password ..."
pashuaDialog="
# Set window title
*.title = Convert Mobile Account to Local Account
*.floating = 1
# Specify image
img.type = image
img.path = /System/Library/CoreServices/Certificate Assistant.app/Contents/Resources/AppIcon.icns
img.maxwidth = 64
img.rely = 30
# Introductory text
txt.type = text
txt.default = Please confirm your current login password and click Continue ...
#txt.height = 276
txt.width = 350
txt.x = 80
txt.y = 135
#txt.tooltip = Confirm your current login password (the one you use to login to your computer).
# Add a password field
confirmPassword.type = password
confirmPassword.label = Confirm Login Password
confirmPassword.mandatory = true
confirmPassword.width = 350
confirmPassword.x = 80
confirmPassword.y = 80
confirmPassword.tooltip = Confirm your current login password (the one you use to login to your computer or unlock the screensaver).
# Add checkboxes
chk.rely = -10
chk.relx = 80
chk.type = checkbox
chk.label = I have a current, known-working backup of my data.
chk.tooltip = I acknowledge I have a known working backup of my data.
chk.default = 1
chk.disabled = 1
chk.mandatory = true
# Add a cancel button with default label
cb.type = cancelbutton
cb.tooltip = Cancel without saving changes.
db.type = defaultbutton
db.label = Continue ...
db.tooltip = Confirm your current login password and click Continue ...
"
pashua_run "${pashuaDialog}"
}
function validateDataBackup() { # Ensure the user has selected the checkbox for data backup
ScriptLog "* Validate Data Backup ..."
while [ "${chk}" == 0 ]; do
pashuaDialog="
# Set window title
*.title = Convert Mobile Account to Local Account — Error
*.floating = 1
# Specify image
img.type = image
img.path = /System/Library/CoreServices/Problem Reporter.app/Contents/Resources/ProblemReporter.icns
img.maxwidth = 64
# Introductory text
txt.type = text
txt.default = You must check the box to indicate you have a current, known-working backup of your data.
txt.height = 276
txt.x = 80
txt.y = 64
"
pashua_run "${pashuaDialog}"
promptLoginPassword # Prompt for login password
checkCancel # Check if the cancel button was clicked; if so, exit.
done
}
function validateAuthorization() { # Ensure the user has selected the checkbox for data backup
ScriptLog "* Validate Authorization to Convert Account ..."
while [ "${dblchk}" == 0 ]; do
pashuaDialog="
# Set window title
*.title = Convert Mobile Account to Local Account — Error
*.floating = 1
# Specify image
img.type = image
img.path = /System/Library/CoreServices/Problem Reporter.app/Contents/Resources/ProblemReporter.icns
img.maxwidth = 64
# Introductory text
txt.type = text
txt.default = You must check the box to indicate you have a current, known-working backup of your data.
txt.height = 276
txt.x = 80
txt.y = 64
"
pashua_run "${pashuaDialog}"
return # Return to the calling function
done
}
function passwordMismatch() { # Inform user the passwords don't match
ScriptLog "* Passwords Mismatch ..."
if [ "${loginPassword}" != "${confirmPassword}" ]; then
pashuaDialog="
# Set window title
*.title = Convert Mobile Account to Local Account — Error
*.floating = 1
# Specify image
img.type = image
img.path = /System/Library/CoreServices/Problem Reporter.app/Contents/Resources/ProblemReporter.icns
img.maxwidth = 64
# Introductory text
txt.type = text
txt.default = Passwords do not match; please try again.[return](Attempt "${defaultPasswordAttempts}" of 3.)
txt.height = 276
txt.x = 80
txt.y = 64
"
pashua_run "${pashuaDialog}"
fi
}
function validatePasswords() { # Validate the passwords are identical
ScriptLog "* Validate the passwords are identical ..."
passwordMismatch # Inform user the passwords don't match
confirmLoginPassword # Confirm login password
checkCancel # Check if the cancel button was clicked; if so, exit.
}
function authorizeConversion() { # Authorize account conversion
ScriptLog "* Authorize Account Conversion ..."
if [ "${loginPassword}" == "${confirmPassword}" ]; then # Double-check the passwords match before authorizing conversion
pashuaDialog="
# Set window title
*.title = Convert Mobile Account to Local Account
*.floating = 1
# Specify image
img.type = image
img.path = /System/Library/CoreServices/Problem Reporter.app/Contents/Resources/ProblemReporter.icns
img.maxwidth = 64
img.rely = 135
# Introductory text
txt.type = text
txt.default = By clicking Proceed, you acknowledge the following:[return]• You have a current, known-working backup[return]• You will be logged out[return]• Your Mobile Account, ${loggedInUser}, will be permanently converted to a Local Account[return][return]Click Cancel to exit without making any changes.[return][return]If you are certain you want to permanently convert your account, check the box to acknowledge you have a current, known-working backup of your data and click Permanently convert ${loggedInUser}.
txt.width = 350
txt.x = 80
txt.y = 64
# Add checkboxes
dblchk.rely = -10
dblchk.relx = 80
dblchk.type = checkbox
dblchk.label = I have a current, known-working backup of my data.
dblchk.tooltip = I acknowledge I have a known working backup of my data.
dblchk.default = 0
#dblchk.disabled = 1
dblchk.mandatory = true
# Add a cancel button with default label
cb.type = cancelbutton
cb.tooltip = Cancel without saving changes.
db.type = defaultbutton
db.label = Permanently convert ${loggedInUser}
db.tooltip = Click to convert your Mobile Account to a Local Account
"
pashua_run "${pashuaDialog}"
checkCancel # Check if the cancel button was clicked; if so, exit.
fi
}
function convertAccount() { # Convert account from mobile to local
ScriptLog "* Convert account ..."
if [ "${loginPassword}" == "${confirmPassword}" ] && [ "${dblchk}" == 1 ]; then # The passwords match and the user has acknowldged they have a backup
ScriptLog "* Convert account from mobile to local ..."
# Delete the currently logged-in user account
ScriptLog "* Deleting ${loggedInUser} account from client-side directory ..."
/usr/bin/dscl . delete /Users/"${loggedInUser}"
# Determine the current highest user UID, in the 500 range
maxid=$(/usr/bin/dscl . -list /Users UniqueID | /usr/bin/awk '{print $2}' | /usr/bin/grep -Ex '5[0-9][0-9]' | /usr/bin/sort -ug | /usr/bin/tail -1)
if [ -z ${maxid} ]; then
newid=501 # There aren't any user accounts in the 5nn range; use 501
else
newid=$((maxid+1)) # There are user accounts in the 5nn range; add one to the hightest
fi
# Create local user account ...
ScriptLog "* Create ${loggedInUser} local account in client-side directory ..."
/usr/sbin/sysadminctl -addUser "${loggedInUser}" -fullName "${userRealName}" -UID "${newid}" -password "${confirmPassword}" -home "/Users/${loggedInUser}" "${adminStatus}"
# Reset ownership on home directory and append location
ScriptLog "* Correct permissions for ${loggedInUser} ..."
/usr/sbin/chown -R "${loggedInUser}":staff /Users/"${loggedInUser}"
/usr/bin/dscl . -append /Users/"${loggedInUser}" NFSHomeDirectory /Users/"${loggedInUser}"/
#Delete the user's keychain folder.
# ScriptLog "* Delete ${loggedInUser} keychain ..."
# /bin/rm -Rf /Users/"${loggedInUser}"/Library/Keychains/*
ScriptLog "* Sleep for five seconds ..."
/bin/sleep 5
# Force logout
ScriptLog "* Force logout ..."
/bin/ps -Ajc | /usr/bin/grep loginwindow | /usr/bin/awk '{print $2}' | /usr/bin/xargs /bin/kill -9
ScriptLog "---"
ScriptLog "- $loggedInUser account converted from Mobile to Local"
ScriptLog "---"
# Re-direct logging to the JSS
exec 1>&3 2>&4
/bin/echo >&1 "$loggedInUser account converted from Mobile to Local."
else # Password don't match; inform user and exit
ScriptLog "* Error: Either passwords don't match, the user didn't authorize the change, or both; inform user and exit ... dblchk='${dblchk}'"
# The user has failed to match the password three consecutive times.
/usr/local/jamf/bin/jamf displayMessage -message "Error -397; exiting."
ScriptLog "* Error -397: The user failed to confirm the password three consecutive times."
# Re-direct logging to the JSS
exec 1>&3 2>&4
/bin/echo >&1 "Error -397"
exit 2 # exit with an error status
fi
}
### Call the functions
validateCurrentUserID # Exit if UID is under 1000 (local account)
promptLoginPassword # Prompt for login password
checkCancel # Check if the cancel button was clicked; if so, exit.
validateDataBackup # Ensure the user has selected the checkbox
confirmLoginPassword # Prompt for login password
checkCancel # Check if the cancel button was clicked; if so, exit.
# Ensure passwords match; if not, display an error and prompt to re-enter.
defaultPasswordAttempts=0
while [[ "${loginPassword}" != "${confirmPassword}" ]]; do
defaultPasswordAttempts="$((defaultPasswordAttempts+1))"
validatePasswords # Validate the passwords are identical
if [[ "${defaultPasswordAttempts}" -ge 3 ]]; then
# The user has failed to match the password three consecutive times.
/usr/local/jamf/bin/jamf displayMessage -message "Too many failed attempts to confirm password; exiting."
ScriptLog "* Error: The user failed to confirm the password three consecutive times. defaultPasswordAttempts='${defaultPasswordAttempts}'"
# Re-direct logging to the JSS
exec 1>&3 2>&4
/bin/echo >&1 "Error: The user failed to confirm the password three consecutive times."
exit 2 # exit with an error status
fi
done
# Authorize conversion
dblchk=0
while [ "${loginPassword}" == "${confirmPassword}" ] && [ "${dblchk}" == 0 ]; do
authorizeConversion # Authorize conversion
validateAuthorization # Ensure the user has selected the checkbox to authorize conversion
checkCancel # Check if the cancel button was clicked; if so, exit.
done
convertAccount # Convert account from mobile to local
exit 0
Posted on 01-04-2017 06:09 PM
@perrinbw Here's our client-side functions, which we source
into our scripts:
#!/bin/sh
####################################################################################################
#
# ABOUT
#
# Standard functions which are imported into other scripts
#
####################################################################################################
#
# HISTORY
#
# Version 1.1, 30-Nov-2016, Dan K. Snelson
#
####################################################################################################
#
# LOGGING
#
####################################################################################################
# Variables
logFile="/var/log/com.company.division.log"
# Check for / create logFile
if [ ! -f "${logFile}" ]; then
# logFile not found; Create logFile
/usr/bin/touch "${logFile}"
fi
exec 3>&1 4>&2 # Save standard output and standard error
exec 1>>"${logFile}" # Redirect standard output to logFile
exec 2>>"${logFile}" # Redirect standard error to logFile
#set -xv; exec 1>>"${logFile}" 2>&1 # Enable all logging from this point forward
# Logging Functions
# Version 1
alias now="date '+%Y-%m-%d %H:%M:%S'"
function ScriptLog() { # Re-direct logging to the log file ...
NOW=`date +%Y-%m-%d %H:%M:%S`
/bin/echo "${NOW}" " ${1}" >> ${logFile}
}
function jssLog() { # Re-direct logging to the JSS
ScriptLog "${1}"
exec 1>&3 2>&4
/bin/echo >&1 ${1}
}
####################################################################################################
#
# Pashua
#
####################################################################################################
function pashua_run() {
# Write config file
local pashua_configfile=`/usr/bin/mktemp /tmp/pashua_XXXXXXXXX`
echo "$1" > "$pashua_configfile"
pashuapath='/usr/local/ics/scripts/Pashua.app/Contents/MacOS/Pashua'
# Get result
local result=$("$pashuapath" "$pashua_configfile")
# Remove config file
rm "$pashua_configfile"
oldIFS="$IFS"
IFS=$'
'
# Parse result
for line in $result; do
local name=$(echo $line | sed 's/^([^=]*)=.*$/1/')
local value=$(echo $line | sed 's/^[^=]*=(.*)$/1/')
eval $name='$value'
done
IFS="$oldIFS"
}
####################################################################################################
#
# JAMF Display Message
#
####################################################################################################
function jamfDisplayMessage() {
ScriptLog "${1}"
/usr/local/jamf/bin/jamf displayMessage -message "${1}" &
}
####################################################################################################
#
# Decrypt Password
#
####################################################################################################
function decryptPassword () {
/bin/echo "${1}" | /usr/bin/openssl enc -aes256 -d -a -A -S "${2}" -k "${3}"
}
####################################################################################################
#
# Reveal File in Finder
#
####################################################################################################
function revealMe() {
/usr/bin/su - "`/bin/ls -l /dev/console | cut -d " " -f4`" -c "/usr/bin/open -R ${1}"
}
Posted on 01-05-2017 05:59 AM
@dan.snelson thank you so much. Going to investigate which route works best for us.
Posted on 04-07-2017 12:03 PM
This one works for current logged in user and checks if they're in our "Teachers and others" AD group.
#!/bin/bash #Get the logged in user theUser=$(ls -l /dev/console | awk -F " " '{print $3}') if [[ $(/usr/bin/dsmemberutil checkmembership -U "${theUser}" -G "Teachers and others") != not ]]; then dseditgroup -v -o edit -n /Local/Default -a $theUser -t user admin echo "Added $theUser to the local admin group" else echo "$theUser not local admin" fi exit 0
This one looks at all users on the machine. Elevates them if they match the AD group, demotes them otherwise.
#!/bin/bash userList=$(/usr/bin/dscl . list /Users UniqueID | /usr/bin/awk '$2 > 510 { print $1 }') for u in ${userList} ; do /usr/bin/dsmemberutil checkmembership -U ${u} -G "Teachers and others" if [[ $(/usr/bin/dsmemberutil checkmembership -U ${u} -G "Teachers and others") != not ]]; then dseditgroup -v -o edit -n /Local/Default -a ${u} -t user admin logger -t makeAdmin "${u} is local admin" echo "Added ${u} to the local admin group" else dseditgroup -v -o edit -n /Local/Default -d ${u} -t user admin echo "${u} not local admin" fi done exit 0
Posted on 11-29-2022 02:40 AM
This content helped me a lot thank you for sharing.