Adding macOS Users Remotely from the Command Line

Published · Updated · System Administration

There was a time when adding a Mac OS X user from the command line meant talking directly to NetInfo with nicl, copying a user template with ditto, and hoping you did not fat-finger a UID. That was useful knowledge in 2007. It is also very much not how I would tell someone to manage macOS users today.

Modern macOS stores local users through Directory Services, and the command-line tools have changed. If you are administering a Mac over SSH now, the practical tools to know are sysadminctl, dscl, createhomedir, passwd, and the usual Unix permissions commands.

This article keeps the original spirit of the old post: sometimes you only have remote shell access, and you still need to create a working account. The details are updated for modern macOS.

Before You Create the User

Remote user creation is one of those tasks where a little caution saves a lot of cleanup. Before touching account records, answer a few questions:

  • Do you need a local account, or should this Mac be bound to a directory service or managed by MDM?
  • Should the user be a standard user or an administrator?
  • Does the account need GUI login, SSH access, or both?
  • Is FileVault enabled?
  • Does the account need a Secure Token?
  • Are you about to put a password in shell history, logs, or automation output?

For one-off administration, a local account may be fine. For fleets, use MDM. Hand-building local accounts over SSH does not scale well, and it is easy to end up with inconsistent state across machines.

Also, do not pass real passwords on the command line if you can avoid it. Some macOS tools support - or interactive prompting so the password is not exposed in shell history or process listings. Use that whenever practical.

Option 1: Use sysadminctl

For most modern macOS systems, sysadminctl is the friendliest command-line tool for creating a local user.

Here is the shape of the command:

sudo sysadminctl \
  -addUser buildadmin \
  -fullName "Build Admin" \
  -shell /bin/zsh \
  -home /Users/buildadmin \
  -password -

The -password - form prompts for the password instead of putting it directly in your command. That is the version you want when you are typing this by hand.

If the account should be an administrator, add -admin:

sudo sysadminctl \
  -addUser buildadmin \
  -fullName "Build Admin" \
  -shell /bin/zsh \
  -home /Users/buildadmin \
  -admin \
  -password -

That is intentionally boring, which is what I want from account creation. The older NetInfo process required you to manually create records, set attributes, copy a home directory, change ownership, and then set a password. sysadminctl packages that into a command that is harder to get partially wrong.

There are still reasons to understand the lower-level tools, though. When something looks strange, dscl is how you inspect what actually exists.

Inspect the Account with dscl

dscl is the Directory Service command-line utility. The local directory node is represented by ..

After creating the account, inspect it:

dscl . -read /Users/buildadmin

For a tighter check:

dscl . -read /Users/buildadmin UniqueID PrimaryGroupID NFSHomeDirectory UserShell

You can list local users with:

dscl . -list /Users

And you can check group membership with:

dscl . -read /Groups/admin GroupMembership

This is the modern replacement for the old nidump and nicl workflow. The mental model is similar: user and group records have attributes. The tooling and backing directory system changed.

Option 2: Build the Account with dscl

I prefer sysadminctl for normal account creation, but dscl is useful when you need more explicit control or when you are repairing a system with unusual state.

First, choose a username and a UID. On a single Mac, you can inspect existing UIDs like this:

dscl . -list /Users UniqueID | sort -nk2

Then create the user record:

sudo dscl . -create /Users/buildadmin
sudo dscl . -create /Users/buildadmin UserShell /bin/zsh
sudo dscl . -create /Users/buildadmin RealName "Build Admin"
sudo dscl . -create /Users/buildadmin UniqueID 505
sudo dscl . -create /Users/buildadmin PrimaryGroupID 20
sudo dscl . -create /Users/buildadmin NFSHomeDirectory /Users/buildadmin

On macOS, PrimaryGroupID 20 is commonly the staff group. Do not blindly copy UIDs or group IDs from a blog post into a production machine. Check the target system first.

Set the password:

sudo passwd buildadmin

Create and populate the home directory:

sudo createhomedir -c -u buildadmin
sudo chown -R buildadmin:staff /Users/buildadmin

If the user needs administrator rights:

sudo dseditgroup -o edit -a buildadmin -t user admin

Then verify:

id buildadmin
dscl . -read /Users/buildadmin UniqueID PrimaryGroupID NFSHomeDirectory UserShell
dscl . -read /Groups/admin GroupMembership | grep buildadmin

This is more verbose than sysadminctl, but it teaches you what is actually being created. That is still valuable when you are debugging broken accounts, migration leftovers, or automation that failed halfway through.

SSH Access Is a Separate Question

Creating a local user does not automatically mean that account can SSH into the Mac. Remote Login has to be enabled, and access may be restricted.

Check whether SSH is enabled:

sudo systemsetup -getremotelogin

Enable it if appropriate:

sudo systemsetup -setremotelogin on

On managed Macs, this may be controlled by configuration profile or MDM policy. Do not fight the management layer from the shell unless you are deliberately repairing a machine and understand what policy will do next.

If SSH is slow or strange between Macs, the issue may not be the account at all. The companion guide on macOS SSH slow connections walks through the network side of the problem: IPv4 versus IPv6, .local name resolution, Remote Login, and server-side SSH daemon checks. Keep those layers separate from user creation and account state.

Secure Token and FileVault Caveats

Modern macOS account administration has one complication the old NetInfo days did not: Secure Token.

If FileVault is enabled, a user may need a Secure Token to unlock the disk at boot. Creating an account from SSH does not guarantee that the account can unlock FileVault or perform every local security operation.

Check token status:

sysadminctl -secureTokenStatus buildadmin

Granting a Secure Token generally requires credentials from an existing token-enabled administrator:

sudo sysadminctl \
  -secureTokenOn buildadmin \
  -password - \
  -adminUser existingadmin \
  -adminPassword -

This is an area where fleet management tooling is much better than artisanal SSH commands. If you are doing this often, the right answer is probably MDM, Bootstrap Token, and a documented onboarding flow rather than clever shell snippets.

Cleanup and Removal

If you create the wrong account, clean it up deliberately.

With sysadminctl:

sudo sysadminctl -deleteUser buildadmin -secure

If you want to keep the home directory:

sudo sysadminctl -deleteUser buildadmin -keepHome

Before deleting anything, verify that you are on the right host:

hostname
scutil --get ComputerName
whoami

That sounds insultingly basic until the day you have SSH sessions open to three similar machines. Good operators build habits that protect them when attention is split.

Practical Recommendations

For a modern macOS system, my default approach is:

  • Use MDM for repeatable fleet account policy.
  • Use sysadminctl for one-off local user creation.
  • Use dscl to inspect and repair Directory Services records.
  • Use createhomedir when you need to explicitly create a home directory.
  • Avoid passwords in command history.
  • Verify SSH access separately from account creation.
  • Treat Secure Token and FileVault as first-class requirements, not afterthoughts.

The command line is still perfectly capable of creating a macOS user remotely, but the surrounding security model matters. A local admin account that cannot unlock FileVault, receive policy, or satisfy your audit requirements is not a finished account. It is just a record in the directory.

Conclusion

The old nicl recipe was useful in its time, but NetInfo is ancient history. Modern macOS administration is cleaner in some ways and more security-aware in others. sysadminctl gives you the high-level path. dscl gives you visibility underneath it. createhomedir, passwd, and dseditgroup fill in the system administration details when you need them.

Use the high-level tool when it does the job. Understand the lower-level records well enough to verify the result. And if you are doing this across more than a few machines, stop hand-rolling it over SSH and put the policy in your management system.

For more practical system administration notes, visit Slaptijack.

Slaptijack's Koding Kraken