Posted on 05-05-2022 01:29 AM
Hello!
At the school where I work we are planning to convert the mobile user accounts (connected to AD) to local user accounts, and make them admins.
I saw the fantastic script on rtrouton's GitHub.
I tested it on a test machine and works like a charm, though the issue I have is that it asks for user input, and trying to push it via policy in Jamf, it simply waits.
So the question is: is there a way for me to achieve this via Jamf Pro, without the use of Jamf Connect (we currently don't have it)?
Thank you
Solved! Go to Solution.
Posted on 05-05-2022 02:22 PM
Also I am using the same script as our devices are no longer bound to AD and no AD account on the device, instead we are using Kerboros SSO Extension. I had to adjust the script in a way that it doesn't ask user input. As admin, I can decide if the converted account should habe an admin right or not. Well it work like a charm.
Posted on 05-06-2022 03:19 AM
No worries @efil4xiN, I figured :-)
Thank you @MehdiYawari & @Tribruin .
I actually figured it out, confirming also what @MehdiYawari: I removed the user inputs ("select" menus) and now it works perfectly also from Jamf!
Posted on 05-05-2022 04:18 AM
As long as you have credentials for both accounts, it should be possible. I would start here with Rich's write up
Posted on 05-05-2022 04:54 AM
Thank you, though it's not exactly what I'm looking for.
When I test the script on a test machine, the scripts needs user input in order to run. If I run the script via Jamf (with a policy), I can't see any of the user input, hence the script doesn't run, it just waits.
Maybe I'm missing some detail?
Posted on 05-05-2022 09:53 AM
Since scripts run as Administrator when run from Jamf, you can't get user input via terminal. You would have to rework the script to prompt the user via another tool (such as AppleScript or, maybe, SwiftDialog).
Posted on 05-05-2022 02:22 PM
Also I am using the same script as our devices are no longer bound to AD and no AD account on the device, instead we are using Kerboros SSO Extension. I had to adjust the script in a way that it doesn't ask user input. As admin, I can decide if the converted account should habe an admin right or not. Well it work like a charm.
Posted on 05-06-2022 02:46 AM
@HariSeldon My apologies, I posted in the wrong chat
Posted on 05-06-2022 03:19 AM
No worries @efil4xiN, I figured :-)
Thank you @MehdiYawari & @Tribruin .
I actually figured it out, confirming also what @MehdiYawari: I removed the user inputs ("select" menus) and now it works perfectly also from Jamf!
Posted on 11-22-2023 01:27 AM
Im looking to do this for our exiting users through policy run script, by removing the input menus from the script will this just apply to the account running the script or all the mobile users it finds?
Posted on 11-27-2023 05:48 PM
@HariSeldon
can you share your version to skip the select options? I'm having trouble doing that, and I don't see why.
Posted on 11-28-2023 06:24 AM
Hey Malcolm,
What I did that worked for my case was to:
11-28-2023 03:52 PM - edited 11-28-2023 03:54 PM
Thanks, I ended up re-engineering script, it will process all mobile accounts and also then repeat and process all accounts as admin accounts for local accounts.
#!/bin/bash
active_directory_users=()
# Get all users
users="$(/usr/bin/dscl . list /Users UniqueID | awk '$2 > 1000 {print $1}') FINISHED"
# Filter users with "Active Directory" in their account information
for user in $users; do
# Check if "Active Directory" is present in the information
if [[ "$(/usr/bin/dscl . -read /Users/$user AuthenticationAuthority)" == *"Active Directory"* ]]; then
active_directory_users+=("$user")
fi
done
echo "Active Directory users:"
echo "${active_directory_users[@]}"
#force unbind of AD
/usr/sbin/dsconfigad -remove -force -u none -p none
# Deletes the Active Directory domain from the custom /Search
# and /Search/Contacts paths
/usr/bin/dscl /Search/Contacts -delete . CSPSearchPath "$searchPath"
/usr/bin/dscl /Search -delete . CSPSearchPath "$searchPath"
# Changes the /Search and /Search/Contacts path type from Custom to Automatic
/usr/bin/dscl /Search -change . SearchPolicy dsAttrTypeStandard:CSPSearchPath dsAttrTypeStandard:NSPSearchPath
/usr/bin/dscl /Search/Contacts -change . SearchPolicy dsAttrTypeStandard:CSPSearchPath dsAttrTypeStandard:NSPSearchPath
# macOS 10.14.4 will remove the the actual ShadowHashData key immediately
# if the AuthenticationAuthority array value which references the ShadowHash
# is removed from the AuthenticationAuthority array. To address this, the
# existing AuthenticationAuthority array will be modified to remove the Kerberos
# and LocalCachedUser user values.
AuthenticationAuthority=$(/usr/bin/dscl -plist . -read /Users/$user AuthenticationAuthority)
Kerberosv5=$(echo "${AuthenticationAuthority}" | xmllint --xpath 'string(//string[contains(text(),"Kerberosv5")])' -)
LocalCachedUser=$(echo "${AuthenticationAuthority}" | xmllint --xpath 'string(//string[contains(text(),"LocalCachedUser")])' -)
# Remove Kerberosv5 and LocalCachedUser
for user in "${active_directory_users[@]}"; do
# Retrieve the AuthenticationAuthority attribute for the current user
user_auth_authority=$(dscl . -plist /Users/$user AuthenticationAuthority)
# Check if Kerberosv5 is present in the AuthenticationAuthority attribute
if [[ ! -z "$(echo "$user_auth_authority" | xmllint --xpath 'string(//string[contains(text(),"Kerberosv5")])' -)" ]]; then
# Remove the Kerberosv5 value from the AuthenticationAuthority attribute
dscl . -plist /Users/$user AuthenticationAuthority "${Kerberosv5}"
fi
# Check if LocalCachedUser is present in the AuthenticationAuthority attribute
if [[ ! -z "$(echo "$user_auth_authority" | xmllint --xpath 'string(//string[contains(text(),"LocalCachedUser")])' -)" ]]; then
# Remove the LocalCachedUser value from the AuthenticationAuthority attribute
dscl . -plist /Users/$user AuthenticationAuthority "${LocalCachedUser}"
fi
done
for user in "${active_directory_users[@]}"; do
# Remove the cached_groups attribute
/usr/bin/dscl . -delete /Users/$user cached_groups
# Remove the cached_auth_policy attribute
/usr/bin/dscl . -delete /Users/$user cached_auth_policy
# Remove the CopyTimestamp attribute
/usr/bin/dscl . -delete /Users/$user CopyTimestamp
# Remove the AltSecurityIdentities attribute
/usr/bin/dscl . -delete /Users/$user AltSecurityIdentities
# Remove the SMBPrimaryGroupSID attribute
/usr/bin/dscl . -delete /Users/$user SMBPrimaryGroupSID
# Remove the OriginalAuthenticationAuthority attribute
/usr/bin/dscl . -delete /Users/$user OriginalAuthenticationAuthority
# Remove the OriginalNodeName attribute
/usr/bin/dscl . -delete /Users/$user OriginalNodeName
# Remove the SMBSID attribute
/usr/bin/dscl . -delete /Users/$user SMBSID
# Remove the SMBScriptPath attribute
/usr/bin/dscl . -delete /Users/$user SMBScriptPath
# Remove the SMBPasswordLastSet attribute
/usr/bin/dscl . -delete /Users/$user SMBPasswordLastSet
# Remove the SMBGroupRID attribute
/usr/bin/dscl . -delete /Users/$user SMBGroupRID
# Remove the PrimaryNTDomain attribute
/usr/bin/dscl . -delete /Users/$user PrimaryNTDomain
# Remove the AppleMetaRecordName attribute
/usr/bin/dscl . -delete /Users/$user AppleMetaRecordName
# Remove the MCXSettings attribute
/usr/bin/dscl . -delete /Users/$user MCXSettings
# Remove the MCXFlags attribute
/usr/bin/dscl . -delete /Users/$user MCXFlags
/usr/bin/killall DirectoryService
/usr/bin/killall opendirectoryd
sleep 20
homedir=`/usr/bin/dscl . -read /Users/"$user" NFSHomeDirectory | awk '{print $2}'`
if [[ "$homedir" != "" ]]; then
/bin/echo "Home directory location: $homedir"
/bin/echo "Updating home folder permissions for the $netusername account"
/usr/sbin/chown -R "$user" "$homedir"
fi
/bin/echo "Adding $user to the staff group on this Mac."
/usr/sbin/dseditgroup -o edit -a "$user" -t user staff
/bin/echo "Displaying user and group information for the $user account"
/usr/bin/id $user
/usr/sbin/dseditgroup -o edit -a "$user" -t user admin; /bin/echo "Admin rights given to this account"
done
# Collect all users again
allusers="$(/usr/bin/dscl . list /Users UniqueID | awk '$2 > 1000 {print $1}') FINISHED"
# Grant admin rights to all users
for alluser in $allusers; do
/usr/sbin/dseditgroup -o edit -a "$alluser" -t user admin
/bin/echo "Adding $alluser to the staff group on this Mac."
/usr/sbin/dseditgroup -o edit -a "$alluser" -t user staff
/bin/echo "Displaying user and group information for the $user account"
/usr/bin/id $alluser
/usr/sbin/dseditgroup -o edit -a "$alluser" -t user admin; /bin/echo "Admin rights given to this account"
done
In the original, it seemingly does follow up checks which seem unnecessary for the task at hand. The netuser seems unnecessary as it had already determined that the user was an Active Directory one when extracting the users.
I might need to check mine above, as I want to remove the Active Directory status as the very last step, so to confirm all previous steps have completed.
I also want to see if there's a section to check if an account is disabled, as demobilising an account while it is disabled, is not going to have a very good outcome I suspect.
Posted on 11-28-2023 06:20 PM
actually the script above is not quite right, so I will try your changes and see how I go
looked like it was working but the end user couldn't change their password.
Posted on 11-29-2023 02:04 AM
I could find the my updated version of the script, here you go:
#!/bin/bash
# Modified 5/8/2022
Version=1.5
# Original source is from MigrateUserHomeToDomainAcct.sh
# Written by Patrick Gallagher
#
# Guidance and inspiration from Lisa Davies:
# http://lisacherie.com/?p=239
#
# Modified by Rich Trouton
#
#
# Further modified by Lorenzo Fittarelli
#
# Version 1.0 - Migrates an Active Directory mobile account to a local account by the following process:
# 1. Detect if the Mac is bound to AD and offer to unbind the Mac from AD if desired
# 2. Display a list of the accounts with a UID greater than 1000
# 3. Remove the following attributes from the specified account:
#
# cached_groups
# cached_auth_policy
# CopyTimestamp - This attribute is used by the OS to determine if the account is a mobile account
# SMBPrimaryGroupSID
# OriginalAuthenticationAuthority
# OriginalNodeName
# SMBSID
# SMBScriptPath
# SMBPasswordLastSet
# SMBGroupRID
# PrimaryNTDomain
# AppleMetaRecordName
# MCXSettings
# MCXFlags
#
# 4. Selectively modify the account's AuthenticationAuthority attribute to remove AD-specific attributes.
# 5. Restart the directory services process
# 6. Check to see if the conversion process succeeded by checking the OriginalNodeName attribute for the value "Active Directory"
# 7. If the conversion process succeeded, update the permissions on the account's home folder.
# 8. Prompt if admin rights should be granted for the specified account
#
# Version 1.1
#
# Changes:
#
# 1. After conversion, the specified account is added to the staff group. All local accounts on this Mac are members of the staff group,
# but AD mobile accounts are not members of the staff group.
# 2. The "accounttype" variable is now checking the AuthenticationAuthority attribute instead of the OriginalNodeName attribute.
# The reason for Change 2's attributes change is that the AuthenticationAuthority attribute will exist following the conversion
# process while the OriginalNodeName attribute may not.
#
#
# Version 1.2
#
# Changes:
#
# Add RemoveAD function to handle the following tasks:
#
# 1. Force unbind the Mac from Active Directory
# 2. Deletes the Active Directory domain from the custom /Search and /Search/Contacts paths
# 3. Changes the /Search and /Search/Contacts path type from Custom to Automatic
#
# Thanks to Rick Lemmon for the suggested changes to the AD unbind process.
#
# Version 1.3
#
# Changes:
#
# Fix to account password backup and restore process. Previous versions
# of the script were adding extra quote marks to the account's plist
# file located in /var/db/dslocal/nodes/Default/users/.
#
# Version 1.4
#
# Changes:
#
# macOS 10.14.4 will remove the the actual ShadowHashData key immediately
# if the AuthenticationAuthority array value which references the ShadowHash
# is removed from the AuthenticationAuthority array. To address this, the
# existing AuthenticationAuthority array will be modified to remove the Kerberos
# and LocalCachedUser user values.
#
# Thanks to the anonymous reporter who provided the bug report and fix.
#
#
# Version 1.5
#
# Changes:
#
# Stripped the script of all the user inputs (Select menu) and prompts to user
# in order to facilitate an automatic execution via Jamf.
# The main Select menu where the user account is being converted from Mobile to Local,
# has been changed into a for loop, also facilitating automatic execution.
clear
listUsers="$(/usr/bin/dscl . list /Users UniqueID | awk '$2 > 1000 {print $1}') FINISHED"
FullScriptName=`basename "$0"`
ShowVersion="$FullScriptName $Version"
check4AD=`/usr/bin/dscl localhost -list . | grep "Active Directory"`
# Save current IFS state
OLDIFS=$IFS
IFS='.' read osvers_major osvers_minor osvers_dot_version <<< "$(/usr/bin/sw_vers -productVersion)"
# restore IFS to previous state
IFS=$OLDIFS
/bin/echo "********* Running $FullScriptName Version $Version *********"
RunAsRoot()
{
## Pass in the full path to the executable as $1
if [[ "${USER}" != "root" ]] ; then
/bin/echo
/bin/echo "*** This application must be run as root. Please authenticate below. ***"
/bin/echo
sudo "${1}" && exit 0
fi
}
RemoveAD(){
# This function force-unbinds the Mac from the existing Active Directory domain
# and updates the search path settings to remove references to Active Directory
searchPath=`/usr/bin/dscl /Search -read . CSPSearchPath | grep Active\ Directory | sed 's/^ //'`
# Force unbind from Active Directory
/usr/sbin/dsconfigad -remove -force -u none -p none
# Deletes the Active Directory domain from the custom /Search
# and /Search/Contacts paths
/usr/bin/dscl /Search/Contacts -delete . CSPSearchPath "$searchPath"
/usr/bin/dscl /Search -delete . CSPSearchPath "$searchPath"
# Changes the /Search and /Search/Contacts path type from Custom to Automatic
/usr/bin/dscl /Search -change . SearchPolicy dsAttrTypeStandard:CSPSearchPath dsAttrTypeStandard:NSPSearchPath
/usr/bin/dscl /Search/Contacts -change . SearchPolicy dsAttrTypeStandard:CSPSearchPath dsAttrTypeStandard:NSPSearchPath
}
PasswordMigration(){
# macOS 10.14.4 will remove the the actual ShadowHashData key immediately
# if the AuthenticationAuthority array value which references the ShadowHash
# is removed from the AuthenticationAuthority array. To address this, the
# existing AuthenticationAuthority array will be modified to remove the Kerberos
# and LocalCachedUser user values.
AuthenticationAuthority=$(/usr/bin/dscl -plist . -read /Users/$netname AuthenticationAuthority)
Kerberosv5=$(echo "${AuthenticationAuthority}" | xmllint --xpath 'string(//string[contains(text(),"Kerberosv5")])' -)
LocalCachedUser=$(echo "${AuthenticationAuthority}" | xmllint --xpath 'string(//string[contains(text(),"LocalCachedUser")])' -)
# Remove Kerberosv5 and LocalCachedUser
if [[ ! -z "${Kerberosv5}" ]]; then
/usr/bin/dscl -plist . -delete /Users/$netname AuthenticationAuthority "${Kerberosv5}"
fi
if [[ ! -z "${LocalCachedUser}" ]]; then
/usr/bin/dscl -plist . -delete /Users/$netname AuthenticationAuthority "${LocalCachedUser}"
fi
}
RunAsRoot "${0}"
# Check for AD binding and offer to unbind if found.
if [[ "${check4AD}" = "Active Directory" ]]; then
# Removed the Select menu, requesting user input in order to remove AD binding. Left only the command to remove the AD binding
RemoveAD; /bin/echo "AD binding has been removed.";
fi
until [ "$user" == "FINISHED" ]; do
# Changed the Select menu into a for loop, leaving all the commands inside unchanged.
# That way they get executed automatically without the need of user input
for netname in $listUsers; do
if [ "$netname" = "FINISHED" ]; then
/bin/echo "Finished converting users to local accounts"
exit 0
fi
accounttype=`/usr/bin/dscl . -read /Users/"$netname" AuthenticationAuthority | head -2 | awk -F'/' '{print $2}' | tr -d '\n'`
if [[ "$accounttype" = "Active Directory" ]]; then
mobileusercheck=`/usr/bin/dscl . -read /Users/"$netname" AuthenticationAuthority | head -2 | awk -F'/' '{print $1}' | tr -d '\n' | sed 's/^[^:]*: //' | sed s/\;/""/g`
if [[ "$mobileusercheck" = "LocalCachedUser" ]]; then
/usr/bin/printf "$netname has an AD mobile account.\nConverting to a local account with the same username and UID.\n"
else
/usr/bin/printf "The $netname account is not a AD mobile account\n"
break
fi
else
/usr/bin/printf "The $netname account is not a AD mobile account\n"
break
fi
# Remove the account attributes that identify it as an Active Directory mobile account
/usr/bin/dscl . -delete /users/$netname cached_groups
/usr/bin/dscl . -delete /users/$netname cached_auth_policy
/usr/bin/dscl . -delete /users/$netname CopyTimestamp
/usr/bin/dscl . -delete /users/$netname AltSecurityIdentities
/usr/bin/dscl . -delete /users/$netname SMBPrimaryGroupSID
/usr/bin/dscl . -delete /users/$netname OriginalAuthenticationAuthority
/usr/bin/dscl . -delete /users/$netname OriginalNodeName
/usr/bin/dscl . -delete /users/$netname SMBSID
/usr/bin/dscl . -delete /users/$netname SMBScriptPath
/usr/bin/dscl . -delete /users/$netname SMBPasswordLastSet
/usr/bin/dscl . -delete /users/$netname SMBGroupRID
/usr/bin/dscl . -delete /users/$netname PrimaryNTDomain
/usr/bin/dscl . -delete /users/$netname AppleMetaRecordName
/usr/bin/dscl . -delete /users/$netname PrimaryNTDomain
/usr/bin/dscl . -delete /users/$netname MCXSettings
/usr/bin/dscl . -delete /users/$netname MCXFlags
# Migrate password and remove AD-related attributes
PasswordMigration
# Refresh Directory Services
if [[ ( ${osvers_major} -eq 10 && ${osvers_minor} -lt 7 ) ]]; then
/usr/bin/killall DirectoryService
else
/usr/bin/killall opendirectoryd
fi
sleep 20
accounttype=`/usr/bin/dscl . -read /Users/"$netname" AuthenticationAuthority | head -2 | awk -F'/' '{print $2}' | tr -d '\n'`
if [[ "$accounttype" = "Active Directory" ]]; then
/usr/bin/printf "Something went wrong with the conversion process.\nThe $netname account is still an AD mobile account.\n"
exit 1
else
/usr/bin/printf "Conversion process was successful.\nThe $netname account is now a local account.\n"
fi
homedir=`/usr/bin/dscl . -read /Users/"$netname" NFSHomeDirectory | awk '{print $2}'`
if [[ "$homedir" != "" ]]; then
/bin/echo "Home directory location: $homedir"
/bin/echo "Updating home folder permissions for the $netname account"
/usr/sbin/chown -R "$netname" "$homedir"
fi
# Add user to the staff group on the Mac
/bin/echo "Adding $netname to the staff group on this Mac."
/usr/sbin/dseditgroup -o edit -a "$netname" -t user staff
/bin/echo "Displaying user and group information for the $netname account"
/usr/bin/id $netname
# Removed the two user inputs: 1) prompting the end-user to confirm whether the
# local account should be given admin rights, and 2) the Select menu
# to choose either yes or no. Left simply the command, that way
# it gets executed automatically, without the need of user input.
/usr/sbin/dseditgroup -o edit -a "$netname" -t user admin; /bin/echo "Admin rights given to this account";
done
done
Posted on 11-29-2023 04:29 PM
Thanks, it seems to collect non Active Directory Users, and loops on them in this section, post the script running.
/usr/bin/printf "The $netname account is not a AD mobile account
I think I can potentially fix it though.
Posted on 11-29-2023 06:07 PM
seemingly the until command was forcing it to recheck
I've changed
until [ "$user" == "FINISHED" ]; do
for netname in $listUsers; do
Not sure why at this point re running the script was collecting non active directory users post a successful run.
just a few more tests to be done this change and I thin I can pull the trigger on its use, for our exit process, and also to help migrate staff over to Jamf connect
Posted on 11-29-2023 06:07 PM
my best guess it is a cached variable from the first successful run.