I had occasion recently to need to remotely delete a user — let’s call him “George” — on a Mac OS X box that is running the Client version of Tiger. I have ssh access to that machine and, since I keep meaning to learn how to do it, I decided to take the time to make a few notes on the process for the next such occasion.
What I needed to do was, first, remove him from any groups he was in and then delete his account. On OS X, this is usually handled by the NetInfo database, so I needed a way to manipulate it without using the GUI
/Applications/Utilities/NetInfo Manager that I’d probably use were I physically sitting at the machine.
The command I’ll use is
/usr/bin/dscl — the Directory Service command line utility. If you’re familiar with CLI utilities, the syntax of
dscl won’t be problematic for you. It is a truly powerful program, bringing pretty much anything involved with NetInfo under your control. This is a good thing, but it is also dangerous. Which brings us to this warning:
Do not start doing this if you don’t know what you’re doing or are disconcerted by the idea of telling your computer what to do by typing. You can damage your system, not to mention possibly leaving you unable to have children. ¡Cuidado!
Before you make any changes to NetInfo, you should back its database up. That Apple article has a couple of methods. Use one of them. For the children.
With that out of the way, let’s talk about NetInfo domains. Assuming you didn’t RTFA at the link above, the basic idea is that there is a hierarchical database that handles all the user and group data (just to mention a couple of things) for Mac systems. NetInfo has been around since the NeXT days.
The NetInfo hierarchy starts with what it calls Domains. (This is a mite confusing at first since it doesn’t refer to Internet domain names.) Under each Domain there are Directories, and they can have Properties with accompanying Values, as well as contain other Directories. We’ll cover these ideas in practice as we go along.
Here’s an applicable example: like every Mac, my remote server has a
/users directory under the local domain.
It’s important to differentiate here that this is not referring to the
/Users folder in the filesystem where a user’s home folder usually is. This can be somewhat bewildering for NetInfo neophytes.
Now, inside the NetInfo
/users Directory are a bunch of other Directories corresponding to all the users on the machine — human accounts (like my own and the one I’ll be deleting), but also system “users” like daemon, mysql, nobody, root, and www. In fact, here’s a command to give us a list of all the users on the machine:
dscl . list /users
Breaking it down: there’s
dscl, a period “.” representing the local machine, the
list command, and then the directory we want a listing of. This is also the basic syntax we’ll be dealing with throughout our exercise.
So, I run that on my remote machine and get a long list of users, including the about-to-be-deleted George. To see what NetInfo has to say about good old Georgie:
dscl . read /users/george
Pretty much the same idea as before, except we’re using the
read command rather than
list. Using the Finder as an analogy,
list is like viewing a list of text files in a folder, and
read is like viewing the contents of one of those files.
Here’s some (though not all) of what I got in response to my
RealName: George Costanza
This can get overwhelming with all kinds of unfamiliar text flying by, so it can be useful to focus in on one value, e.g. where their home folder is. We find that out by examining
NFSHomeDirectory, which is a users Property. Other such Properties include
UniqueID, and the rest of
Much like a variable in algebra, a Property has a corresponding Value. To ask for George’s home directory only, we use:
dscl . read /users/george NFSHomeDirectory
Which returns this line:
So, for the Property
NFSHomeDirectory the Value is
Again, to keep it straight, that’s the
/Users/george home folder in the Finder.
Now I have George in my sights, and I’m almost ready to get rid of him. But first, let’s deal with the groups he’s a member of. Similarly to getting a list of users on the local machine, we can do the same thing for groups:
dscl . list /groups
Long list there, but it includes the two groups I need to deal with. I happen to know that George is in only two groups:
george (a user is by default a member of a group with the same name).
Just for our edification, let’s get a list of the users in
handmodels. We can do this by zeroing in on one Property like we did above,
dscl . read /groups/handmodels GroupMembership
GroupMembership: grady mia ramon mike george
A-ha! There he is, along with a few other folks. To kick him out of there, I’ll need to use
sudo because you need admin access to make this kind of change to the database:
sudo dscl . delete /groups/handmodels GroupMembership george
A password prompt appears. Enter the admin password, hit Return, and George is gone from handmodels. Let’s just make sure:
dscl . read /groups/handmodels GroupMembership
And we get back:
GroupMembership: grady mia ramon mike
If George were HAL, he would be feeling his mind going right about now.
Getting rid of the
george group is handled a bit differently since it’s a whole Directory and not the Value of a Property. To delete his group completely:
sudo dscl . delete /groups/george
And that’s it for George’s groups. George/HAL is singing “Bicycle Built For Two.”
For safety’s sake, please note the similarity between this last command and the one above that deleted his name from handmodels. Imagine how easy it could be to really screw things up by deleting something accidentally. Have you backed up lately?
Finally, we’re ready to delete George himself. The syntax is much the same as the last command:
sudo dscl . delete /users/george
Poof! George has ceased to be. He has expired and gone to meet his maker. He is an ex-user.
Now all that’s left is to remove the vestiges of George scattered around the filesystem, starting with his home folder
/Users/george. Just to play it safe, you might want to archive George’s stuff. You know, if he happens to re-enter your good graces.
Maybe when you’re feeling magnanimous around Festivus time. ;)