User groups are easy, right? A user is either a member or they are not.
Once you start thinking about the details and want or need to automate some of the aspects of user and group management on macOS, there is a lot of devil in those details.
You can easily list all groups a given user is a member of. The
id command will show all the groups the current user is a member of.
id -Gn will list just the groups. Add a username to the
id command to see the information for a different user. The
groups command does the same as
You can also run a command to check if a given user is a member of a group:
$ dseditgroup -o checkmember -m user staff yes user is a member of staff $ dseditgroup -o checkmember -m user wheel no user is NOT a member of wheel
So far, so good.
A user is a member of a group when one of these applies:
- the user’s
PrimaryGroupIDattribute matches the
PrimaryGroupIDof the group
- the user’s UUID is listed in the group’s
GroupMembersattribute and the user’s shortname is listed in the group’s
- the user is a member of a group nested in the group
Note: you should not attempt to manipulate the
GroupMembershipattributes directly. Use the
dseditgroup -o editcommand to manage group membership instead.
dseditgroupsyntax is weird, but it is a really useful tool. Study its
Listing Group Members
Sometimes (mainly for security audits) you need to list all the members of a group. With the above information, it is easy enough to build a script that checks the
GroupMembership attribute and the recursively loops through the
This is confused by the fact that
PrimaryGroupID stores the numeric User ID,
GroupMembership uses the shortname and
NestedGroups uses UUIDs. Nevertheless, you can sort through it.
I have written exactly such a script here:
In most cases this script will work fine. But, (and you knew there would be a “but”) macOS has a very nasty wrench to throw in our wheels.
There are a few groups on macOS, that have neither
NestedGroups, but still have members. This is because the system calculates membership dynamically. This is similar to Smart Playlists in iTunes, Smart Folders in Finder, or Smart Groups in Jamf Pro.
You can list all calculated groups on macOS with:
$ dscl . list /Groups Comment | grep "calc"
The most interesting calculated groups are
These groups can be very useful in certain environments. For example in a DEP setup you could add
everyone to the
_developer groups, before the user has even created their standard account. That way any user created on that Mac will can manage printers and use the developer tools.
However, since these groups are calculated magically, a script cannot list all the members of any of these groups. (My script above will show a warning, when it encounters one of these groups.)
While it would probably not be wise to nest the
everybody group in the
admin group, a malicious user could do that and hide from detection with the above script (or similar methods).
Instead of recursively listing all users, we can loop through all user accounts and check their member status with
dseditgroup -checkmember. This script is actually much simpler and
dseditgroup can deal with calculated groups.
This works well enough when run against all local users.
I strongly recommend against running this for all users in a large directory infrastructure. It’ll be very slow and generate a lot of requests to the directory server. Because of this the script above runs only on the local directory node by default.
- on macOS users can be assigned to groups thorugh different means
- you can check membership with
dseditgroup -o checkmember
- you can edit group membership with
dseditgroup -o edit
- macOS has a few groups which are dynamically calculated and difficult to process in scripts