Skip to main content

With the increasing trend to stop binding macs to AD, I put together a script to demote mobile accounts to local.

To re-iterate - this one is risky. Please test it carefully if you decide to try it out.

If you find additional attributes that your fleet needed - would be interested to hear.

#!/usr/bin/perl -w

#  mobiletolocal.sh
#  Created by LD
#  Appears safe to run whilst logged in - user keeps existing password :)

my $userlist = `dscl . list /Users`;

chomp $userlist;

my @excludedusers = split(" ","root daemon nobody _amavisd _appleevents _appowner _appserver _ard _assetcache _astris _atsserver _avbdeviced _calendar _ces _clamav _coreaudiod _coremediaiod _cvmsroot _cvs _cyrus _devdocs _devicemgr _displaypolicyd _distnote _dovecot _dovenull _dpaudio _eppc _ftp _gamecontrollerd _geod _iconservices _installassistant _installer _jabber _kadmin_admin _kadmin_changepw _krb_anonymous _krb_changepw _krb_kadmin _krb_kerberos _krb_krbtgt _krbfast _krbtgt _launchservicesd _lda _locationd _lp _mailman _mbsetupuser _mcxalr _mdnsresponder _mysql _netbios _netstatistics _networkd _nsurlsessiond _nsurlstoraged _ondemand _postfix _postgres _qtss _sandbox _screensaver _scsd _securityagent _serialnumberd _softwareupdate _spotlight _sshd _svn _taskgated _teamsserver _timezone _tokend _trustevaluationagent _unknown _update_sharing _usbmuxd _uucp _warmd _webauthserver _windowserver _www _wwwproxy _xserverdocs");

my @userslist = split("
", $userlist);
my @users;
my $result = "";

foreach my $u (@userslist) {

   my $match = 0;

   foreach my $e (@excludedusers) {
      if ("$u" eq "$e") {
         $match = 1;
      }
   }

   if ($match == 0) {
      push(@users, $u);
    }
}

my $dsconfigad = `/usr/sbin/dsconfigad -show`;
chomp $dsconfigad;

unless ($dsconfigad eq "") {
   printf "Removing AD bind
";
   system "/usr/sbin/dsconfigad -remove -force -u none -p none";
}

foreach my $username (@users) {

   printf "Username is: $username
";
   my $accounttype = `/usr/bin/dscl . -read /Users/$username OriginalNodeName`;

   unless ($accounttype =~ //Active Directory//) {
       printf "Next: $username is not a mobile account
";
       next;
   }

   printf "$username has an AD mobile account - converting to local
";

   #Get Hash of existing password

   my $shadowhash = `/usr/bin/dscl . -read /Users/$username AuthenticationAuthority | grep " ;ShadowHash;HASHLIST:<"`;
   chomp $shadowhash;

   #printf "AuthenticationAuthority is: $shadowhash
";

   system "/usr/bin/dscl . -delete /users/$username cached_groups";
   system "/usr/bin/dscl . -delete /users/$username SMBPrimaryGroupSID";
   system "/usr/bin/dscl . -delete /users/$username OriginalAuthenticationAuthority";
   system "/usr/bin/dscl . -delete /users/$username OriginalNodeName";
   system "/usr/bin/dscl . -delete /users/$username AuthenticationAuthority";
   system "/usr/bin/dscl . -create /users/$username AuthenticationAuthority '$shadowhash'";
   system "/usr/bin/dscl . -delete /users/$username SMBSID";
   system "/usr/bin/dscl . -delete /users/$username SMBScriptPath";
   system "/usr/bin/dscl . -delete /users/$username SMBPasswordLastSet";
   system "/usr/bin/dscl . -delete /users/$username SMBGroupRID";
   system "/usr/bin/dscl . -delete /users/$username PrimaryNTDomain";
   system "/usr/bin/dscl . -delete /users/$username AppleMetaRecordName";
   system "/usr/bin/dscl . -delete /users/$username PrimaryNTDomain";
   system "/usr/bin/dscl . -delete /users/$username MCXSettings";
   system "/usr/bin/dscl . -delete /users/$username MCXFlags";
   system "/usr/bin/dscl . -delete /users/$username AppleMetaRecordName";
   system "/usr/bin/dscl . -delete /users/$username dsAttrTypeNative:cached_auth_policy";
   system "/usr/bin/dscl . -delete /Users/$username dsAttrTypeStandard:CopyTimestamp";
   system "/usr/sbin/dseditgroup -o edit -a $username -t user admin";

}

exit 0;

@CardFlightIT - Afraid I don't have any Open LDAP accounts to test against, but if you're interested in testing here is another mobile to local project: https://github.com/BIG-RAT/mobile_to_local


Hi @lisacherie

Thanks for that script. I made it work with MacOS 10.13, but when I try it for the latest version of Mojave, for some reason the password of the user is not being stored, because when I try to login after a restart after the script ran, it doesn't allow me to login with the same password. I haven't been able to figure it out, but do you know if maybe the password hash storage path has been changed or if there is something I should modified for this to happen?

I am newbie in scripting so a help could be very useful here.

Thanks,
Hugo Quinte


I haven't actually needed to use this script since 10.13.something... it was working at that point.

Since I no longer have access to an active directory environment, I'd do a dscl output prior to the change, and then afterwards. Also compare dscl fields with a local user (that was never an AD mobile account). That will help see what fields might now be different. If you have that output, I can look quickly - however not much I can do without an AD environment.


Just wondering if anyone has gotten any variant of this to work with Catalina!


@arepko - Was the following not converting accounts?
https://github.com/BIG-RAT/mobile_to_local


@leslie It didn't do anything, though I was referring to the original script. I'll give that link (and app) you just linked a go!


@leslie The App seems to work like a champ! Thanks!


@rtrouton Has worked his magic, and made an interactive version with some extra features. https://derflounder.wordpress.com/2016/12/21/migrating-ad-mobile-accounts-to-local-user-accounts/

Can confirm that the Der Flounder script works with 10.14 and 10.15


@leslie This was an amazing find, THANK YOU! https://github.com/BIG-RAT/mobile_to_local


Running the Der Flounder script, I get this output:

Running mobileToLocalAccount.sh Version 1.4 **
This machine is bound to Active Directory.
Do you want to unbind this Mac from AD?
1) Yes
2) No

? 1

AD binding has been removed.

Select a user to convert or select FINISHED:
1) mdesmar5
2) FINISHED

? 1

mdesmar5 has an AD mobile account.
Converting to a local account with the same username and UID.
warning: failed to load external entity "–xpath"
warning: failed to load external entity "string(//string[contains(text(),"Kerberosv5")])"
warning: failed to load external entity "–"
warning: failed to load external entity "–xpath"
warning: failed to load external entity "string(//string[contains(text(),"LocalCachedUser")])"
warning: failed to load external entity "–"

Any ideas?


Update: I worked it out. I got the latest version from GitHub and modified it for the logged on user and then made it a self service policy. Works great now. Great script!

https://github.com/rtrouton/rtrouton_scripts/blob/master/rtrouton_scripts/migrate_ad_mobile_account_to_local_account/MigrateADMobileAccounttoLocalAccount.command


I tested the OP script on Big Sur 11.2.3 in my VM, which worked and converted from mobile to local and removed the AD bind, but it removed the user from Filevault and the password is changed. I can reset using my other local account, just FYI! I'm trying to work through it, if anyone has an idea on how to prevent that I'd appreciate it, until then it's still a great script that needs a little hands on work.


Just updated mobile_to_local to be universal. Tested (albeit minimally) on Big Sur with no issues. If you get a chance to test let me know how it goes/have any suggestions.


I tested the OP script on Big Sur 11.2.3 in my VM, which worked and converted from mobile to local and removed the AD bind, but it removed the user from Filevault and the password is changed. I can reset using my other local account, just FYI! I'm trying to work through it, if anyone has an idea on how to prevent that I'd appreciate it, until then it's still a great script that needs a little hands on work.


Did you ever figure out what was causing this.


Just updated mobile_to_local to be universal. Tested (albeit minimally) on Big Sur with no issues. If you get a chance to test let me know how it goes/have any suggestions.


Can this be run silently?  Our goal would be to use it without user interaction.


Can this be run silently?  Our goal would be to use it without user interaction.


Yes. Something like the following will run silently.

sudo /path/to/Mobile\\ to\\ Local.app/Contents/MacOS/Mobile\\ to\\ Local -mode silent

Yes. Something like the following will run silently.

sudo /path/to/Mobile\\ to\\ Local.app/Contents/MacOS/Mobile\\ to\\ Local -mode silent

Worked perfect!  The only issue we encountered is that it didn't unbind the machine but we'll use another script for that for now until we can figure out what is up.

Below is what we used:

sudo /Applications/Utilities/Mobile\\ to\\ Local.app/Contents/MacOS/Mobile\\ to\\ Local -unbind true -mode silent

Worked perfect!  The only issue we encountered is that it didn't unbind the machine but we'll use another script for that for now until we can figure out what is up.

Below is what we used:

sudo /Applications/Utilities/Mobile\\ to\\ Local.app/Contents/MacOS/Mobile\\ to\\ Local -unbind true -mode silent

-allowNewUsername: whether or not to allow the user to change their current shortname. Either true of false.
-userType: type of account to migrate to. Either standard or admin.
-unbind: whether or not to unbind after migrating. Either true or false.
-mode: whether or not to prompt the user for input. If mode is silent the user will not be prompted for input.
-allowNewUsername: whether or not to allow the user to change their current shortname. Either true of false.
-userType: type of account to migrate to. Either standard or admin.
-unbind: whether or not to unbind after migrating. Either true or false.
-mode: whether or not to prompt the user for input. If mode is silent the user will not be prompted for input.

Just noticed you did use the -unbind.  I'll have to look into that.


Just noticed you did use the -unbind.  I'll have to look into that.


Let me know what if anything I can do to help.  We got huge kudos for the effectiveness of this.


Did you ever figure out what was causing this.


Just ran it on 12.5.  Completely removed the user account from System Preferences > Accounts but the profile directory still existed in /Users.  It also changed the password and could not sign back in.

It did unbind the machine...


Is this the BIG-RAT still working?

I just tried using it, as we been tasked to convert our fleet to local profiles and non bind (YAY!) and it still shows as a mobile profile in preferences and will no longer give me the checkbox to change the name either is this working at all on 12.5?


I wouldn't know if this still works, and from the recent posts sounds like it's not. The work was originally done back in 2016, and it's been many years since I have worked on an AD environment, along with a number of OS changes since then.

If you manage to make changes to the code to get it to work again, I'm sure others will be appreciative to you. I have no environment to test or continue development.


Worked on my test machine, macOS 12.5.1.  My AD environment is a bit dated though, 2012, not sure if that's a factor.

Updated the logging, now logs to /var/log/mobile.to.local.log.  Reviewing that may shed some light on what's (or what's not) going on.  How did you launch the app, what switches.


Worked on my test machine, macOS 12.5.1.  My AD environment is a bit dated though, 2012, not sure if that's a factor.

Updated the logging, now logs to /var/log/mobile.to.local.log.  Reviewing that may shed some light on what's (or what's not) going on.  How did you launch the app, what switches.


sudo /Applications/Utilities/Mobile\\ to\\ Local.app/Contents/MacOS/Mobile\\ to\\ Local -unbind true -mode silent -userType admin -allowNewUsernamwe true