- Choose to scan all Domain Controllers – added option
- Choose to scan all Exchange Servers – added option
- Use a CSV file – added option
- Menu added for ease of use
- Speed – the old script could take days, now it takes hours (looking to trim this in the next version)
Changes and Explanation
The most important change above was simply the speed of the script was too slow. In an environment with 8+ sites and 4+ servers per site, the script took 2-3 days to run. What was happening is that the source machine (a laptop) was talking back and forth with the remote Exchange server which was sometimes in the same region, sometimes across a WAN link. The Servers over the WAN link were VERY slow. This increased the run time dramatically:
Now, in order to improve the speed of the script, I used the invoke-command so that the processing would take place on the remote server and save the results locally. Then the file would be copied back to the local machine.:
This reduced the run time to 2.5 hours for 50+ servers.
The Script
Here is the new menu:
<# .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.7 Change Log: : 1.7 - Added remote connection running of the script : 1.6 - Fixed some bugs, added menu, added choice for Exchange servers to be scanned, added check for no results found, cleaned up some formatting : 1.5 - Added choice for all DCs, CSV file or manual entry : 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 the standard 3 : 1.1 - Added support for couting events and last occured : 1.0 - Created script for with basic event log screening Wish list : Schedule each scan as a job to run all servers simultaneously : Write to the event log or alert the administrator that jobs are done : Email a link to the files or the files themselves in emails Rights Required : Local admin on server Sched Task Req'd : No Exchange Version : N/A Author : Damian Scoles Email/Blog/Twitter : https://justaucguy.wordpress.com/ Disclaimer : You are on your own. This was not written by, support by, or endorsed by Microsoft. .LINK [TBD] .EXAMPLE .\EventLogs-1.6.ps1 .INPUTS None. You cannot pipe objects to this script. #> $servers = @() $servers = $null $allinfo = @() cls write-host "Where do you want to store the generated Event Log Reports? [c:\temp\] " -foregroundcolor cyan -nonewline $path2 = read-host write-host " " write-host "*******************************************" -foregroundcolor cyan write-host "* Choose an option for Event Log Scanning *" -foregroundcolor cyan write-host "* *" -foregroundcolor cyan write-host "* (1) Query for all Domain Controllers *" -foregroundcolor cyan write-host "* (2) Query for all Exchange Servers *" -foregroundcolor cyan write-host "* (3) manually enter server names *" -foregroundcolor cyan write-host "* (4) use a CSV File *" -foregroundcolor cyan write-host "*******************************************" -foregroundcolor cyan write-host " " write-host "Choose 1-4: " -nonewline $choice = read-host write-host " " # Look for Domain Controllers in AD if ($choice -eq "1") { import-module activedirectory $servers2 = Get-ADDomainController -filter * write-host " " write-host "Here is the list of Domain Controllers to be checked:" -foregroundcolor yellow write-host " " foreach ($line in $servers2) { $servers += ,@($line.name) } $servers } # Look for Exchange Servers in AD if ($choice -eq "2") { $servers2 = Get-ADComputer -filter * write-host " " write-host "Here is the list of Exchange Servers to be checked:" -foregroundcolor cyan write-host " " foreach ($line in $servers2) { $memberof = (Get-ADComputer $line |Get-ADObject -Properties memberof).memberof if ($memberof -match "Exchange Install Domain Servers") { $name = [string]$line.name $servers += ,@($name) } } $servers } # Manually enter server names if ($choice -eq "3") { 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" $server = [string]$server $servers += ,@($server) $counter++ } while ($counter -ne $num) } # Use a CSV file to create a server list if ($choice -eq "4") { write-host " " write-host "enter the full path for the csv file [i.e. c:\temp\servers.csv " -foregroundcolor cyan -nonewline $csvname = read-host write-host " " $servers = import-csv $csvname } $script = { # foreach ($line in $servers) { # $server=$line.name $server = $args[0] # $path - $args[1] # $server = [string]$line write-host " " write-host "Analyzing event logs for server $server" -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 $server -logname $log | where {($_.entrytype -eq "error") -or ($_.entrytype -eq "warning") -or ($_.entrytype -eq "critical")} | sort-object eventid | group-object eventid if ($events -ne $null) { $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>Application Log</h2><BR>No critical events were found in the Application Log' | out-string } else { $Application = $app | ConvertTo-Html -Fragment -PreContent '<h2>Application Log</h2>' | out-string } } 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 $server -logname $log | where {($_.entrytype -eq "error") -or ($_.entrytype -eq "warning") -or ($_.entrytype -eq "critical")} | sort-object eventid | group-object eventid if ($events -ne $null) { $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' | out-string } else { $System = $sys | ConvertTo-Html -Fragment -PreContent '<h2>System Log</h2>' | out-string } } 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 $server -logname $log | where {($_.entrytype -eq "error") -or ($_.entrytype -eq "warning") -or ($_.entrytype -eq "critical")} | sort-object eventid | group-object eventid if ($events -ne $null) { $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' | out-string } else { $DNSlog = $dns | ConvertTo-Html -Fragment -PreContent '<h2>DNS Server Log</h2>' | out-string } } 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 $server -logname $log | where {($_.entrytype -eq "error") -or ($_.entrytype -eq "warning") -or ($_.entrytype -eq "critical")} | sort-object eventid | group-object eventid if ($events -ne $null) { $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' | out-string } else { $FRSLog = $frs | ConvertTo-Html -Fragment -PreContent '<h2>File Replication Service Log</h2>' | out-string } } 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 $server -logname $log | where {($_.entrytype -eq "error") -or ($_.entrytype -eq "warning") -or ($_.entrytype -eq "critical")} | sort-object eventid | group-object eventid if ($events -ne $null) { $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' | out-string } else { $Security = $sec | ConvertTo-Html -Fragment -PreContent '<h2>Security Log</h2>' | out-string } } 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 $server -logname $log | where {($_.entrytype -eq "error") -or ($_.entrytype -eq "warning") -or ($_.entrytype -eq "critical")} | sort-object eventid | group-object eventid if ($events -ne $null) { $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>Directory Service Log</h2><BR>No critical events were found in the Directory Service Log' | out-string } else { $Directory = $dir | ConvertTo-Html -Fragment -PreContent '<h2>Directory Service Log</h2>' | out-string } } else { $Directory = $null } $path = "c:\temp\" # 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 "+$server $dircheck = Get-Item c:\temp -erroraction silentlycontinue if ($dircheck -eq $null) {md "c:\temp"} $path = "c:\temp\" $name = $path+"CriticalEvents-"+$server+".html" # OLD CODE # # $allinfo | ConvertTo-HTML -Head $Header -PreContent $Pre | out-file $name # $info | ConvertTo-HTML -Head $Header -PreContent $Pre | out-file $name # $body = $application+$system+$DNSLog+$FRSLog+$Security+$Directory # ConvertTo-HTML -head $header -Body $body -Title "Critical Events in Event Logs" | Out-File $name # ConvertTo-HTML -head $header -Body $application -Title "Critical Events in Event Logs" | Out-File $name # ConvertTo-HTML -head $header -Body "$application $system $DNSLog $FRSLog $Security $Directory" -Title "Critical Events in Event Logs Logs" | Out-File $name ConvertTo-HTML -head $header -Body "$application $system $DNSLog $FRSLog $Security $Directory" -Title "Critical Events in Event Logs" | Out-File $name write-host "Generated an Event log report for " -nonewline write-host $server -foregroundcolor green $info = $null } # } foreach ($line in $servers) { $computer = [string]$line Invoke-Command -ComputerName $computer -ScriptBlock $script -Args $computer $localhost = $env:computername $LOCATION = "\\localhost\c$\netrix\evtlogs2" write-host "Placing HTML in $LOCATION." copy "\\$computer\c$\temp\CriticalEvents-$computer.html" "\\localhost\c$\netrix\evtlogs2" del "\\$computer\c$\temp\CriticalEvents-$computer.html" }
The run through is exactly the same as my Exchange Health Check – Event Logs. Please review that article to see what it does.
Further Reading
Invoke-Command