Last time in Episode #43, Ed presented a challenge to list all groups and the user names that were in each group. But as I was working on Ed's challenge, I realized that there was another way to look at this data. What if instead of a list of "users per group", you wanted to get a list of "groups per user"?
This is actually straightforward in Unix:
$ for u in `cut -f1 -d: /etc/passwd`; do echo -n $u:; groups $u; done | sort
avahi-autoipd:avahi-autoipd
avahi:avahi
backup:backup
bin:bin
bind:bind
daemon:daemon
games:games
gdm:gdm
gnats:gnats
haldaemon:haldaemon
hal:hal adm dialout cdrom plugdev lpadmin admin sambashare
[...]
Here we're using "cut" to pull all the user names from /etc/passwd and then running a loop over them. Inside we output the user name and a trailing colon, but use the "-n" option on the "echo" statement so the we don't output a newline. This means that the output of the "groups $u" command will appear on the same line as the username, immediately after the colon. Finally we're piping the output of the entire loop into "sort", so we get the information sorted by the user names.
I wonder if Ed's going to have to go to as much trouble answering my challenge as I went through answering his...
Ed responds:
When I first read your challenge, Hal, I was thinking, "Uh-oh... Windows is gonna make this hard." My gut told me that while mapping groups to users was easy ("net localgroup
But, whenever I need to find something out about users on a Windows box, I almost always start out by running "net user [username]
I stopped in my tracks. The "net user" command does this really annoying thing where it puts the user names in columns, as follows:
C:\> net userSure, I could parse those columns with Yet Another FOR Loop (YAFL), but that would be annoying and tiresome. I decided to go for a cleaner way to get a list of users than "net user", solving the challenge as follows:
User accounts for \\MYCOMPUTER
-------------------------------------------------------------------------
Administrator cheetah Guest
jane tarzan
C:\> for /F "skip=1" %i in ('wmic useraccount get name') do @echo. & echo %i &My command here is simply running "wmic useraccount get name", which is a clean way to get a list of account names from the local box. I use a FOR /F loop to iterate over the output of this command, skipping the first line (which contains the "Name" column header from the wmic output). At each iteration through the loop, I skip a line (echo.) to make our output prettier. Then, I display the username (echo %i) and run the "net user [username]" command to get all of the details associated with that account. Now, I pipe the output of the "net user [username]" command through the find command to locate lines that have a * in them. Yes, that annoying little * that I was complaining about in Episode #43. But, here, I'm using it as a selector to grab the group names. If Windows annoyingly puts *'s in front of group names, darnit, I'm gonna use them to my advantage. No sense trying to pee against the wind.... er... Windows, that is.
net user %i | find "*"
Administrator
Local Group Memberships *Administrators
Global Group memberships *None
cheetah
Local Group Memberships *Users
Global Group memberships *None
Guest
Local Group Memberships *Guests
Global Group memberships *None
jane
Local Group Memberships *Administrators *Backup Operators
Global Group memberships *None
tarzan
Local Group Memberships *Users *HelpServicesGroup
Global Group memberships *None
Sure, sure, we could parse this output further to remove out the text that says "Local Group Memberships" and "Global Group memberships" (btw, didja note the inconsistency in the capitalization of Membership and membership? Gee, thanks, Microsoft). If I really needed to, I'd parse that stuff out using another FOR /F loop with a delimiter of *. But, that would make the command unnecessarily complicated and ugly, for it already has the information we want, in a relatively useful form.
I also like this solution, because it shows a useful mixture of "wmic useraccount" with "net user". It's not every day that you get to use the two of them together in a convenient fashion like this. So, I'm happy, and that's really what command line kung fu is all about... making people happy.