Enumerate The Remote Event Log with .NET
One of my favorite things to do as an administrator is to open Domain Controller Security Event Logs and manually thumb through them looking for evil doers… NOT! Opening, filtering, and sorting entries is as exciting as watching paint dry, well actually paint dries quicker…
PowerShell introduced a cool cmdlet called Get-EventLog… Hold on I know what you are thinking! You’ve used Get-EventLog and it only gathers information from the local computer, and your right! Because of this limitation some of you have opted to use WMI to connect to remote logs. Since PowerShell utilizes .NET, how do we use .NET to gather Event log info from a remote computer? If you would like to learn how to use PowerShell and .NET to remotely connect to your Domain Controller and gather information from the security log keep reading on…
Discover the .NET Class
First thing we want to do is discover which .NET class we will be working with. This is a simple step that you can do the “Get-Member” cmdlet.
The command above produces and table of Methods and Properties. Just above the table you should see an entry called TypeName : This is the .NET object we will be working with. In this example the .NET object is System.Diagnostics.EventLog.
Connecting to a remote computer using the .NET class
Run the command above, don’t forget to place your computer name within the quotes (string). Your output should be similar to this, a listing of all the Event Logs on the remote computer.
If you havent worked with .NET and PowerShell you may be wondering where I got the command above? There is no magic bullet for learning .NET. The best way is to download the Microsoft .NET Framework 2.0 SDK and go through the .NET Class Library documentation. What I did was look up Systems.Diagnostics -> EventLog Class. I found a method called GetEventLogs which “searches for all event logs on the given computer and creates an array of Event Log objects.”
Now that I know that i am working will an array I am going to run the command above and save the array to a variable called $Logs.
Verify the array entries in the $logs variable
Further investigating the System.Diagnostics.EventLog there is a property called Entries which “Gets the contents of the event log.”
Note: Here is the trick, we are working with an array, arrays index items begining with 0 (Zero). Remember that and the next example on which log to enumerate will make sense.
In the example I posted, my array index values would look like this:
0 - Application
1 - Directory Services
2 - DNS Server
3 - File Replication Service
4 - Internet Explorer
5 - Security
6 - System
Knowing that I want to work with the security log I use the following code to get all Security Log entries.
If there are a lot of entries then you are currently starting at a PowerShell console with information whizzing by!!! Use “Ctrl + C” to stop the execution.
That is the gist of how to use .NET to connect to a remote computer and enumerate Event Log files. If you want to enumerate the System log just change the code to $logs[6].entries (6 being the index number for the System log).
Script it and Filter it…
So now that you have a big amount of data its sill an administrative nightmare. I’m going to share a script with you that uses the foreach loop and the if conditional statement to enumerate the security log and only output events of interest.
Remember to input your computer name within “YourComputerName”
#
# Microsoft PowerShell Source File
#
# NAME: EvtLogReader.ps1
#
# AUTHOR: Jesse Hamrick
# DATE : 11/5/2008
# Web : www.powershellpro.com
# COMMENT: Script enumerates Security Log and Outputs Requested Results
#
# ======================================
# Enumerate Domain Controller Security Logs for the following entries
# Event ID 608 - User Right Assigned
# Event ID 609 - User Right Removed
# Event ID 626 - User Account Enabled
# Event ID 627 - Change Pass Attempt
# Event ID 628 - User Account Pass set
# Event ID 630 - User Account Delete
# Event ID 631 - Global Group Created
# Event ID 632 - Global Group Member Added
# Event ID 633 - Global Group Member Removed
# Event ID 634 - Global Group Deleted
# Event ID 635 - Local Group Created
# Event ID 636 - Local Group Member Added
# Event ID 637 - Local Group Member Removed
# Event ID 638 - Local Group Member Deleted
# Event ID 639 - Local Group Changed
# Event ID 641 - Global Group Changed
# Event ID 642 - User Account Changed
#Connect to Security Event Log.
$logs = [System.Diagnostics.EventLog]::GetEventLogs(”YourComputerName”)
$colItems = $logs[5].entries
foreach ($item in $colItems){
if(($item.EventID -eq 608)-or($item.EventID -eq 609)-or`
($item.EventID -eq 626)-or($item.EventID -eq 627)-or`
($item.EventID -eq 628)-or($item.EventID -eq 630)-or`
($item.EventID -eq 631)-or($item.EventID -eq 632)-or`
($item.EventID -eq 633)-or($item.EventID -eq 634)-or`
($item.EventID -eq 635)-or($item.EventID -eq 636)-or`
($item.EventID -eq 637)-or($item.EventID -eq 638)-or`
($item.EventID -eq 639)-or($item.EventID -eq 641)-or`
($item.EventID -eq 642)-or($item.EventID -eq 517)){
“DC Reporting : ” + $item.MachineName
“Event ID: ” + $item.EventID
“Time Written: ” + $item.TimeWritten
“Category: ” + $item.Category
“Entry Type: ” + $item.EntryType
“UserName: ” + $item.UserName
“Data: ” + $item.Data
“Source: ” + $item.Source
“Time Generated: ” + $item.TimeGenerated
“Message: ” + $item.Message
“====================================================”
” ”
}
}
# ===================================================
# End of script
# ===================================================
Cool… now we only get the information we want. Experiment with different EventIDs or other properties. To find which properties you can use, enter the trusty Get-Member cmdlet. Here’s how I found the EventID property:
Bonus Script (Email Results)
Next… I’m going to take the script above and convert it to a function. Then I’m going to insert the function into the body section of the email template in introduced in another article called “How to Send Alters to Your Mailbox using .NET.”
How the script works:
- Converted EvtLogReader.ps1 into a function called EvtReader.
- Added an option to clear event log when completed $logs[].Clear(). This is an option, the comment needs to be removed to use it. I use it only on the security log due to its rapid growth. Clearing the log allows for faster run times when running the script again.
- Call the function from the message body portion of the Email Template.
Important things to do:
- Add Computer name you wish to enumerate
- Make sure to verify array index numbers (basically make sure your getting the entries for the correct log).
- Go through the Mail portion of the script and add appropriate entries
Here is the script:
# uses authentication and full message.
# easy to extend for use with HTTP.
# EvtLogReader.ps1 script converted into a Function
Function EvtReader {
# ==================================================
#
# Microsoft PowerShell Source File
#
# NAME: EvtLogReader.ps1
#
# AUTHOR: Jesse Hamrick
# DATE : 11/5/2008
# Web : www.powershellpro.com
#
# ==================================================
# Enumerate Computer Security Logs for the following entries
# Event ID 608 - User Right Assigned
# Event ID 609 - User Right Removed
# Event ID 626 - User Account Enabled
# Event ID 627 - Change Pass Attempt
# Event ID 628 - User Account Pass set
# Event ID 630 - User Account Delete
# Event ID 631 - Global Group Created
# Event ID 632 - Global Group Member Added
# Event ID 633 - Global Group Member Removed
# Event ID 634 - Global Group Deleted
# Event ID 635 - Local Group Created
# Event ID 636 - Local Group Member Added
# Event ID 637 - Local Group Member Removed
# Event ID 638 - Local Group Member Deleted
# Event ID 639 - Local Group Changed
# Event ID 641 - Global Group Changed
# Event ID 642 - User Account Changed
#Connect to Computer Security Event Log.
$logs = [System.Diagnostics.EventLog]::GetEventLogs(’ComputeName’)
$colItems = $logs[5].entries
foreach ($item in $colItems){
if(($item.EventID -eq 608)-or($item.EventID -eq 609)-or`
($item.EventID -eq 626)-or($item.EventID -eq 627)-or`
($item.EventID -eq 628)-or($item.EventID -eq 630)-or`
($item.EventID -eq 631)-or($item.EventID -eq 632)-or`
($item.EventID -eq 633)-or($item.EventID -eq 634)-or`
($item.EventID -eq 635)-or($item.EventID -eq 636)-or`
($item.EventID -eq 637)-or($item.EventID -eq 638)-or`
($item.EventID -eq 639)-or($item.EventID -eq 641)-or`
($item.EventID -eq 642)-or($item.EventID -eq 517)){
“DC Reporting : ” + $item.MachineName
“Event ID: ” + $item.EventID
“Time Written: ” + $item.TimeWritten
“Category: ” + $item.Category
“Entry Type: ” + $item.EntryType
“UserName: ” + $item.UserName
“Data: ” + $item.Data
“Source: ” + $item.Source
“Time Generated: ” + $item.TimeGenerated
“Message: ” + $item.Message
“====================================================”
” ”
}
}
#Clear the Security Log - Uncomment line below to enable
# $logs[5].Clear()
}
# ====================================================
# End of Function
# ====================================================
# ====================================================
# Script Body
# ====================================================
# Create new .NET object and assign to variable
$mail = New-Object System.Net.Mail.MailMessage
# Set the addresses (FROM:)
$mail.From = New-Object System.Net.Mail.MailAddress(”user@domain.com”);
# Set the Recipient Address (TO:)
$mail.To.Add(”user@domain.com”);
# Email Subject
$mail.Subject = “DC Security Logs”;
# Message Body - Call Function Here
$mail.Body = EvtReader;
# Connect to your mail server
$smtp = new-object System.Net.Mail.SmtpClient(”yourdomain.com”);
# Uncomment line below if authentication is required
# $smtp.Credentials = New-Object System.Net.NetworkCredential(”username”, “passwd”);
# Send Mail
$smtp.Send($mail);
# ==========================================
# End of Script
# ==========================================
After configuring the script for you environment it will email the results. I use the script to send reports each hour. The email sizes are arount 7k (with the clear option enabled). To run the script every hour I use the Task Scheduler.
Happy Scripting…
Email This Post To A Friend
« PowerShell Big Hit at VMworld 2008 | Home | Learning PowerShell? RTFM! »







Comments
Great post! I’ve got something which will simplify the filter quite a bit.
$events = @( 608, 609, 626, 627 ) # and so on…
if ( $events -contains $item.EventID ) { doStuff }
Hal,
Excellent suggestion of using an array to simplify the filter.
Hi, this post it’s great, easy and simple to use!!
This script is great. Do you know of a way to add multiple host and filter by, say last 7 days?
Thanks
Great script… But I too would like to narrow down the results to 7 days or 24 hours..
Still new to PS
Create the following variables and add it as part of the filter:
$Now = Get-Date
$lastWrite = $Now.AddDays(-7)
#now place in filter
-and($_.TimeWritten -ge $lastWrite)
I haven’t tested it yet but this works in other scripts I’ve written which get all errors recorded within last 7 days…
Leave a Comment