RDS Server Event Logs

Hello everyone. This is my first post and my first question in the marvelous world of Powershell. I am quite new to the shell, with under a month of experience in my belt, but I’m getting the hang of things. I have bought and read Don Jones Month of Lunches and I’m offically on my first real world work project.

My boss wants me to create a script that scans the event viewers of rdp servers and gives a list of logins both failed and successful. It is really important for me to do this mostly on my own, however, with being so new to the shell, I need to be pointed in the right direction. If someone could send me on the right path, or give me examples on how to do this, it would be most appreciated.

I’m assuming I’m going to be needing the cmdlet Get-Eventlog with some filters that only give me the information I need, while exporting that information to a .csv file.

I apologize ahead of time if asking for assistance with work related matters on this forum is inapropiate and against the rules. If you have gotten this far thank you sincerely for your time and effort. I hope to hear from you guys!

As a tip, try to keep your post subjects related to what you’re asking about - helps the right folks look at your question. I’ve edited this one.

Yep, Get-EventLog is where you would probably start. It has a number of parameters to help filter what you get back, and Export-CSV can convert the output to a CSV file. The help files for both commands include numerous examples - run “Help Get-EventLog -Full” to see them.

The man himself! Thank you, Don! Love your book!

In general, you’ll have a much better experience if you set up a log shipping solution first, and then run your queries against the location where all of the accumulated logs are stored. This functionality has been built into Windows for some time now (since 2008, if I remember correctly) with the Forwarded Event Logs feature, or you could use a third-party tool; that’s up to you.

The performance of querying the log collection database is much better than having to go out to each individual machine over the network each time a report is run.

As far as PowerShell goes, there are two built-in cmdlets for reading event logs. Get-EventLog is older, and has some missing features (such as no ability to specify alternate credentials when connecting to a remote machine.) The newer Get-WinEvent cmdlet can be a useful alternative, if you’re finding that Get-EventLog isn’t working for you.

If you do choose to use Get-EventLog, I’ll share one quick “gotcha”. To filter events by ID, Get-EventLog wants you to pass in an Instance ID. This is not always the same “event ID” you see in the event viewer; there are actually 4 possible Instance ID values for each Event ID (based on the values of a pair of binary flags.) I wrote a quick utility function to help with this a while back, translating Event IDs into each of the possible Instance IDs:

function Get-InstanceID
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]

        foreach ($id in $EventID)
            $maskedId = $id -band 0x3FFFFFFF

            $maskedId -bor 0x40000000L
            $maskedId -bor 0x80000000L
            $maskedId -bor 0xC0000000L

Say you wanted to search the System event log for event IDs 4000 and 4002; to use the Get-InstanceID command, you could just do something like this:

$instanceID = 4000, 4002 | Get-InstanceID

Get-EventLog -Logname System -InstanceId $instanceID

Dave, this InstanceID is great stuff. Question, and excuse me if you already explained this, but I am curious. Out of all the possible InstanceID’s returned, how do you easily find which ones you are looking for quickly? Thanks again, great post.

Do you mean, “how to you figure out which instance IDs you are about?”

If that’s the question, the answer is, “experience.” There’s no master list of what they all are or what they all mean; it’s a matter of browsing through them until you find likely-looking ones.

As long as you know the Event ID you’re interested in, you don’t need to be concerned with which of the Instance IDs are actually being used under the hood. It’s a little weird that Get-EventLog even exposed the concept of an “Instance ID” at all; every other event logging command I can think of just takes care of this for you, and only exposes the Event ID.

Here is a clipping of the code I have written so far. It’s ugly, it’s defiantly wrong, but I’m a month in. So be nice! If anyone out there has the time to take a look at it and tell me why it’s wrong it would greatly help this learning process.

$s = “Remote,Alpha,Delta,Gamma,Epsilon,Zeta,Kappa”
Foreach ($Server in $S)
{$Server; Get-WinEvent -Listlog 4634,4624,4648 -Computername $Server}

“-Listlog 4634,4624,4648” looks wrong. Well I know it’s wrong because I just ran it. What am I missing? To me it makes sense to put it there. I fear I’m missing a cmdlet or perhaps a parameter that pulls the ID’s I want from Get-WinEvent.

The -ListLog parameter is for getting information about the event logs, but not the events themselves. Get-WinEvent is a bit tricky to master. You can start by looking at the examples in “Get-Help Get-WinEvent -Full”, but even that’s not terribly complete. As I mentioned earlier, I tend to find that I wind up using -FilterXPath or -FilterXml just about every time, which is the same syntax used to create custom filters in the Event Viewer. You can find lots of examples and documentation on that topic online, such as at http://blogs.technet.com/b/askds/archive/2011/09/26/advanced-xml-filtering-in-the-windows-event-viewer.aspx

In this case, I assume you’re looking for events from the Security log. For that, you’d do something like this:

Get-WinEvent -ComputerName $Server -LogName Security -FilterXPath '*[System[EventID = 4634 or EventID = 4624 or EventID = 4648]]'

The cool thing is, you can use the Event Viewer to build some of these simple queries for you, even if you forget the syntax. Open up Event Viewer, right click on the Security log, and choose Filter Current Log. In the filter tab, type “4634, 4624, 4648” into the text box for Event IDs, and then just click the XML tab. You’ll see something like the attached screenshot, and you can just copy and paste the contents of that “Select” node right into the value you’re passing to -FilterXPath. (Or you can copy the entire XML code and pass it to -FilterXml instead; in that case, you’d also get rid of the -LogName parameter.)

Whoa! This is some seriously awesome stuff. I knew I was missing something! Don would probably tell me to use that help feature! I can’t believe I didn’t see -FilterXPath I also learned that everything in my server list needed quotes after running it. My code is pretty much perfect now and I want to thank both of you for getting my brain into shell mode! Here is what it looks like. I’m having errors still but they are more then likely on our end via permissions. Thanks again guys for helping out a new guy! Dave your informative answers were amazing!

$s = “Remote”,“Alpha”,“Delta”,“Gamma”,“Epsilon”,“Zeta”,“Kappa”
Foreach ($Server in $S)
{$Server; Get-WinEvent -LogName Security -Computername $Server -FilterXPath ‘*[System[EventID = 4634 or EventID = 4624 or EventID = 4648]]’}

I just wanted to post a follow up showing you that the time you guys spend here is NOT wasted!
See, the problem was, some of our servers are 2003, and some are 2008. WinEvent worked, and I was all excited, but then I had to go back, and use Dave’s suggestion about using his function. After trial and error, your help, and using my brain, I finally got it to work. Now I just have to make a else statement for my WinEvent command for the 2008 servers and I’m up and running. You guys are amazing.

Check it out.

$instanceID = 4634, 4624,4648 | Get-InstanceID
$s = “Remote”,“Alpha”,“Delta”,“Gamma”

Foreach ($Server in $S)

{$Server; Get-EventLog -Logname Security -Computername $Server -InstanceId $instanceID}

And it works! Thank you, I have learned SOOOOO much these two days. I’ll be back for sure!