Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I retrieve a list of unique users from the Security event log?

-- KM

SpacerHey, Scripting Guy! AnswerScript Center

Hey, KM. Before we tackle your question we should probably address a question sent in by another reader:

Hey, Scripting Guy! Whatever happened to Monday?

Having been gone on vacation all last week, I was combing through the Hey, Scripting Guy! archive, and I find that last week was only four days long.

I'm familiar with the adage "time flies when you're having fun," (and the frogger version "time's fun when you're having flies") but I hadn't realized there had been an anti-leap year calendar adjustment. There was no announcement in the newspapers. Maybe it was lost among all the stories about firing the Univ. of Nebraska A.D. (or as he's known in the Cornhusker State, "The Pope").

Even my favorite Internet search engine won't reveal the missing column.

What gives?

-- TP

Hey, TP. Ah, yes The Case of the Missing Monday. (Oh, by the way, nice letter. Although it is kind of sad when the letters about a column are funnier and better written than the column itself.) As it turns out, there actually was a column last Monday, albeit briefly. Shortly after the column appeared, however, we had to take it down. Why? Well, that particular column mentioned a third-party software company, and we were asked to “rework” the article by removing all references to that company.

Note. But hey, no big deal; after all, if you write 800+ columns you’re bound to write one sooner or later that someone takes issue with. Considering some of the other columns we’ve written, however, we’re just surprised that that one was the one someone took issue with!

And in case you’re wondering, no, the Scripting Guys did not make a lot of cruel and cutting remarks at the expense of that software company; in fact, we actually had a lot of nice things to say about this particular company. (After all, when you get in as much trouble as the Scripting Guys do you can’t afford to make even more enemies.) Nevertheless, we have complied with the request, removed everything from the column except the code (and an explanation of how that code works), and reposted the article. Which, in turn, means that not only did Monday actually happen, but we even have a Monday column to prove it.

So does that mean that you’re not going crazy, TP? Well, we’re not sure; after all, you do live in Nebraska.

Note. Which, we hasten to add, has always been the Scripting Guys’ favorite state.

Well, OK: it’s tied for our favorite state with all the other 49 states. What’s that? Even Delaware? You know what? We’ll have to get back to you on that one .…

Anyway, so much for The Case of the Missing Monday. If anyone out there saw the column before it was removed and was offended by the content, well, we sincerely apologize. The truth is, the Scripting Guys never intentionally set out to offend anyone; after all, if we did then today’s column would be all about the University of Nebraska’s football program.

But it’s not. Instead, it’s all about retrieving a list of unique users from the Security event log. (Which is really more a reminder to ourselves than to any of our readers.)

In addition, if any of you thought that Monday really had disappeared, well, we apologize for any inconvenience that might have caused. As we noted, the Scripting Guys did not make Monday disappear. It would have been a bit ironic if we had; after all, we’ve actually been working on a project to make the week longer, primarily by inserting a few extra Saturdays here and there. But now that we think about it, removing Monday might be a little easier. We’ll put that on to the to-do list.

But today’s column isn’t about messing with the space-time continuum, either. Instead, it’s all about retrieving a list of unique users from the Security event log:

On Error Resume Next

strComputer = "."

Set objWMIService = GetObject("winmgmts:{(Security)}\\" & strComputer & "\root\cimv2")

Set colEvents = objWMIService.ExecQuery _
    ("Select * from Win32_NTLogEvent Where Logfile = 'Security'")

Set objDictionary = CreateObject("Scripting.Dictionary")

For Each objEvent in colEvents
    If Not objDictionary.Exists(objEvent.User) Then
        objDictionary.Add objEvent.User, objEvent.User   
    End If
Next

For Each strKey in objDictionary.Keys
    Wscript.Echo strKey
Next

OK, let’s see if we can figure out how this script works. To begin with, we connect to the WMI service on the local computer; if we wanted to, however, we could just as easily run this script against a remote computer. (How? By assigning the name of the remote computer to the variable strComputer.) When you make the connection to the WMI service, make sure your GetObject call looks like this:

GetObject("winmgmts:{(Security)}\\" & strComputer & "\root\cimv2")

As you can see, we’ve included the Security privilege in this script, enclosing it in parentheses and curly braces, and tacking it on immediately after the winmgmts: moniker. Why? Well, unlike many of the things the Scripting Guys do, there’s actually a good reason for this: without this privilege the script will not return any data. (You won’t get an error message, but you won’t get back any information, either.) The Security privilege must be present any time you try to access the Security event log. If it isn’t, well, don’t say we didn’t warn you.

Note. Check that: don’t say that we did warn you; we don’t want to get in trouble for ordering people around, and for telling them what they can and cannot do in their script. But make sure you use the Security privilege anyway, OK? Pretty please? With sugar on it?

After we connect to the WMI service we then use this line of code to return a collection of all the events found in the Security event log:

Set colEvents = objWMIService.ExecQuery _
    ("Select * from Win32_NTLogEvent Where Logfile = 'Security'")

One thing to keep in mind here: depending on the number of records in your Security event log, this script could take a minute or two (or even more) to complete. The Scripting Guy who writes this column clears his event log about as often as he cleans his gutters; with over 51,000 events in his security event log, this script took about 90 seconds to finish.

The gutters will likely require a bit more time and effort.

Sooner or later, though, we will get back a collection of all the events in the Security event log. Once we do we next create an instance of the Scripting.Dictionary object; we’re going to use this object to keep track of the unique users found in the event log. And then we’re ready to roll up our sleeves and get to work.

To begin with, we set up a For Each loop that loops through all the events in our collection. Inside that loop, the first thing we do is run this line of code:

If Not objDictionary.Exists(objEvent.User) Then

What are we doing here? We’re simply checking to see if the user specified in the event’s User property already exists in the Dictionary. If he or she does, then we’re going to loop around and repeat this test with the next event in the collection; after all, because we’re interested only in unique users there’s no need to add this user a second time. (Besides, the Dictionary object doesn’t allow for duplicate items.) If the user isn’t in the Dictionary, then we use this line of code to add that user, specifying the value of the User property as both the Dictionary Item and Key:

objDictionary.Add objEvent.User, objEvent.User

And then it back to the top of the loop to try again with the next event in the collection.

After we exit the loop, we use this block of code to echo back our collection of unique users:

For Each strKey in objDictionary.Keys
    Wscript.Echo strKey
Next

That’s going to result in output similar to this:

NT AUTHORITY\NETWORK SERVICE
NT AUTHORITY\LOCAL SERVICE
NT AUTHORITY\SYSTEM
FABRIKAM\kmyer
NT AUTHORITY\ANONYMOUS LOGON
FABRIKAM\packerman

And then what? Well, to quote Porky Pig, that’s – well, maybe it’s best if we don’t go around quoting third-party cartoon animals. So let’s just say, “That’s all, uh … people.”

Before we go, however, yes, we know: you’re all dying to learn the name of the company mentioned in our original Monday article. As it turns out, that was – uh, well, never mind. We’re not going to slip up and tell you the name; after all, the Scripting Guys never make the same mistake twice. (Mainly because we make so many other mistakes that we never get around to making the same mistake twice.) So, no, we can’t – and won’t – tell you the name of the company. But you could always try visiting your favorite Internet search engine and figuring it out for yourself.