Exchange Health Check – Event Logs

Most companies I work with have some sort of monitoring software in place for their enterprise applications like Exchange. They might use SCOM or Splunk! or Netwrix to provide an insight into their servers health at any given moment. For an Exchange consultant these tool can provide some instant ‘health status’ information on the servers, however sometimes we like to dig in manually to see what might have been missed. One of my first checks on an Exchange server is the event logs. When it comes to Event Logs and manual, I don’t mean that you need to open up the Event Viewer on each server and look at each individual log. PowerShell is your friend.

Criteria

  • All Critical events
  • All Error events
  • All Warning events
  • Major logs – Application, System, Security
  • Create a report with all results
  • Events reported – count of how many times event occurred
  • Most recent occurrence of the event logged


Script
The script starts off by asking a few questions, it then queries the computers you’ve told it to look at and finally generate one report per server. The script as written will look at the Application, Security, System, Directory Service, Fire Replication Service and DNS logs. If the log does not exist, the script will skip that log.

<#  
.SYNOPSIS
   	Analyzes server event logs for Error, Warning and Critical events.

.DESCRIPTION  
    Analyzes server event logs for Error, Warning and Critical events for mulptile servers and skps unneded log file types.

.NOTES  
    Version      		: 1.4
    Change Log:			: 1.4 - added log check, if log name is valid, proceed, otherwise ignore
				: 1.3 - added warning and critical events to the get-eventlog commands
				: 1.2 - Added support for multiple event logs other than thre standard 3
				: 1.1 - Added support for couting events and last occured
				: 1.0 - Created script for with basic event log screening
    Wish list			: 
    Rights Required		: Local admin on server
    Sched Task Req'd		: No
    Exchange Version		: 2013
    Author       		: Damian Scoles
    Email/Blog/Twitter	        : 
    Dedicated Blog		: 
    Disclaimer   		: You are on your own.  This was not written by, support by, or endorsed by Microsoft.

.LINK  
[TBD]

.EXAMPLE
	.\EventLogs.ps1

.INPUTS
	None. You cannot pipe objects to this script.
#>


$servers = @()
$allinfo = @()
cls
write-host "Where do you want to store the generated Event Log Reports? [c:\temp\] " -foregroundcolor cyan -nonewline
$path = read-host
write-host " "
write-host "How many servers will need to have their Event Logs examined? " -foregroundcolor green -nonewline
$num = read-host
write-host " "
$counter = 0
do {
    $SNo = $counter+1
    $server = read-host "What is the name of server $SNo"
    $servers += ,@($server)
    $counter++
}
while ($counter -ne $num) 

foreach ($line in $servers) {
    $server = [string]$line
    write-host " "
    write-host "Analyzing event logs for server $line" -ForegroundColor white
    write-host " "
    write-host "PROCESSING" -foregroundcolor yellow
    write-host " "
    # Get a list of Critical Events
    # Application Log
    $info = $null
    
    # Application Log
    $log = "application"
    $logcheck = get-winevent -ListLog $log -ComputerName $server -erroraction SilentlyContinue
    if ($logcheck -ne $null) {
        write-host "Application Log Analysis"  -foregroundcolor cyan
        $events = get-eventlog -computername $line -logname $log | where {($_.entrytype -eq "error") -or ($_.entrytype -eq "warning") -or ($_.entrytype -eq "critical")} | sort-object eventid | group-object eventid
        $app = foreach ($line2 in $events) {
            $evt = $line2.name
            $Info2 = get-winevent -computername $server -FilterHashtable @{Logname=$log;ID=$evt} -MaxEvents 1 -erroraction silentlycontinue 
                New-Object PSObject -Property @{
                LastOccured = ($info2.timecreated).datetime
                Count = $line2.count
                Name = $info2.providername
                Event = $evt
                # message = $info.message
            }
        }
        if ($app -eq $null) {
            $Application = $app | ConvertTo-Html -Fragment -PreContent '<h2>Security Log</h2><BR>No critical events were found in the Application Log'
        } else {
            $Application = $app | ConvertTo-Html -Fragment -PreContent '<h2>Application Log</h2>'
        }
    } else {
        $Application = $null
    }
    
    # System Log
    $log = "system"
    $logcheck = get-winevent -ListLog $log -ComputerName $server -erroraction SilentlyContinue
    if ($logcheck -ne $null) {
        write-host "System Log Analysis"  -foregroundcolor cyan
        $events = get-eventlog -computername $line -logname $log | where {($_.entrytype -eq "error") -or ($_.entrytype -eq "warning") -or ($_.entrytype -eq "critical")} | sort-object eventid | group-object eventid
        $sys = foreach ($line2 in $events) {
            $evt = $line2.name
            $Info2 = get-winevent -computername $server -FilterHashtable @{Logname=$log;ID=$evt} -MaxEvents 1 -erroraction silentlycontinue 
            New-Object PSObject -Property @{
                LastOccured = ($info2.timecreated).datetime
                Count = $line2.count
                Name = $info2.providername
                Event = $evt
                # message = $info.message
            }
        }
        if ($sys -eq $null) {
            $System = $sys | ConvertTo-Html -Fragment -PreContent '<h2>System Log</h2><BR>No critical events were found in the Systemn Log'
        } else {
            $System = $sys  | ConvertTo-Html -Fragment -PreContent '<h2>System Log</h2>'
        }
    } else {
        $System = $null
    }
    
    # DNS Server
    $log = "DNS Server"
    $logcheck = get-winevent -ListLog $log -ComputerName $server -erroraction SilentlyContinue
    if ($logcheck -ne $null) {
        write-host "DNS Server Log Analysis"  -foregroundcolor cyan
        $events = get-eventlog -computername $line -logname $log | where {($_.entrytype -eq "error") -or ($_.entrytype -eq "warning") -or ($_.entrytype -eq "critical")} | sort-object eventid | group-object eventid
        $dns = foreach ($line2 in $events) {
            $evt = $line2.name
         $Info2 = get-winevent -computername $server -FilterHashtable @{Logname=$log;ID=$evt} -MaxEvents 1 -erroraction silentlycontinue 
         New-Object PSObject -Property @{
            LastOccured = ($info2.timecreated).datetime
             Count = $line2.count
            Name = $info2.providername
            Event = $evt
             # message = $info.message
            }
        }
        if ($dns -eq $null) {
            $DNSlog = $dns | ConvertTo-Html -Fragment -PreContent '<h2>DNS Server Log</h2><BR>No critical events were found in the DNS Server Log'
        } else {
            $DNSlog = $dns  | ConvertTo-Html -Fragment -PreContent '<h2>DNS Server Log</h2>'
        }
    } else {
        $DNSlog = $null
    }
    
    # File Replication Service
    $log = "File Replication Service"
    $logcheck = get-winevent -ListLog $log -ComputerName $server -erroraction SilentlyContinue
    if ($logcheck -ne $null) {
        write-host "FRS Log Analysis" -foregroundcolor cyan
        $events = get-eventlog -computername $line -logname $log | where {($_.entrytype -eq "error") -or ($_.entrytype -eq "warning") -or ($_.entrytype -eq "critical")} | sort-object eventid | group-object eventid
        $frs = foreach ($line2 in $events) {
            $evt = $line2.name
            $Info2 = get-winevent -computername $server -FilterHashtable @{Logname=$log;ID=$evt} -MaxEvents 1 -erroraction silentlycontinue 
            New-Object PSObject -Property @{
                LastOccured = ($info2.timecreated).datetime
                Count = $line2.count
                Name = $info2.providername
                Event = $evt
                # message = $info.message
            }
        }
        if ($frs -eq $null) {
            $FRSLog = $frs | ConvertTo-Html -Fragment -PreContent '<h2>File Replication Service Log</h2><BR>No critical events were found in the FRS Log'
        } else {
            $FRSLog = $frs | ConvertTo-Html -Fragment -PreContent '<h2>File Replication Service Log</h2>'
        }
    } else {
        $FRSlog = $null
    }

    # Security
    $log = "Security"
    $logcheck = get-winevent -ListLog $log -ComputerName $server -erroraction SilentlyContinue
    if ($logcheck -ne $null) {
        write-host "Security Log Analysis" -foregroundcolor cyan
        $events = get-eventlog -computername $line -logname $log | where {($_.entrytype -eq "error") -or ($_.entrytype -eq "warning") -or ($_.entrytype -eq "critical")} | sort-object eventid | group-object eventid
        $sec = foreach ($line2 in $events) {
            $evt = $line2.name
            $Info2 = get-winevent -computername $server -FilterHashtable @{Logname=$log;ID=$evt} -MaxEvents 1 -erroraction silentlycontinue 
            New-Object PSObject -Property @{
                LastOccured = ($info2.timecreated).datetime
                Count = $line2.count
                Name = $info2.providername
                Event = $evt
                # message = $info.message
            }
        }
        if ($sec -eq $null) {
            $Security = $sec | ConvertTo-Html -Fragment -PreContent '<h2>Security Log</h2><BR>No critical events were found in the Security Log'
        } else {
        $Security = $sec | ConvertTo-Html -Fragment -PreContent '<h2>Security Log</h2>'
        }
    } else {
        $Security = $null
    }

    # Directory Service
    $log = "Directory Service"
    $logcheck = get-winevent -ListLog $log -ComputerName $server -erroraction SilentlyContinue
    if ($logcheck -ne $null) {
        write-host "Directory Service Log Analysis" -foregroundcolor cyan
        $events = get-eventlog -computername $line -logname $log | where {($_.entrytype -eq "error") -or ($_.entrytype -eq "warning") -or ($_.entrytype -eq "critical")} | sort-object eventid | group-object eventid
        $dir = foreach ($line2 in $events) {
            $evt = $line2.name
            $Info2 = get-winevent -computername $server -FilterHashtable @{Logname=$log;ID=$evt} -MaxEvents 1 -erroraction silentlycontinue 
            New-Object PSObject -Property @{
                LastOccured = ($info2.timecreated).datetime
                Count = $line2.count
                Name = $info2.providername
                Event = $evt
                # message = $info.message
            }
        }
        if ($dir -eq $null) {
            $Directory = $dir | ConvertTo-Html -Fragment -PreContent '<h2>Security Log</h2><BR>No critical events were found in the Directory Service Log'
        } else {
            $Directory = $dir | ConvertTo-Html -Fragment -PreContent '<h2>Directory Service Log</h2>'
        }
    } else {
        $Directory = $null
    }

    # Format HTML
    $Header = @"
    <style>
    TABLE {border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
    TH {border-width: 1px;padding: 3px;border-style: solid;border-color: black;background-color: #FF0000;}
    TD {border-width: 1px;padding: 3px;border-style: solid;border-color: black;}
    .odd  { background-color:#ffffff; }
    .even { background-color:#dddddd; }
    </style>
    <title>
    Critical Events Report for $server
    </title>
"@
    $Pre = "Critical Events Report in the Application Log for "+$line
    $name = $path+"CriticalEvents-"+$line+".html"
    # $allinfo | ConvertTo-HTML -Head $Header -PreContent $Pre | out-file $name
    # $info | ConvertTo-HTML -Head $Header -PreContent $Pre | out-file $name

    ConvertTo-HTML -head $header -Body "$application $system $DNSLog $FRSLog $Security $Directory" -Title "Critical Events in Event Logs Logs" |  Out-File $name

    write-host "Generated an Event log report for " -nonewline
    write-host $line -foregroundcolor green
    $info = $null
}

In Operation
The script process is relatively simple. Specify where you want to generate log files, how many servers to examine and the names of the servers. In the below example I am examining a lab server for testing purposes. However the script will process as many servers as you specify and generate one HTML results file per server processed.

Exchange-Processing

Results
The results of the file are produced in the form of an HTML file. Notice the separation between Logs as well as a report on the Security log that no issues were found. The example below was from a lab based Exchange Server:
ExchangeServer-EventReport
Further Information
With a slight modification, the script could even email this file to IT personnel or a consultant to review and look for problems in the environment.

Get-EventLog
Get-WinEvent

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s