Skip to content

Instantly share code, notes, and snippets.

@zaneGittins
Created January 26, 2021 03:41
Show Gist options
  • Select an option

  • Save zaneGittins/b3ea4d9ae2f69d91dc272fae50c20fb2 to your computer and use it in GitHub Desktop.

Select an option

Save zaneGittins/b3ea4d9ae2f69d91dc272fae50c20fb2 to your computer and use it in GitHub Desktop.
Get Event Log Report
# GetEventLogReport
# This is a modified version of the script provided by IBM-Security, this version also estimates EPS of Sysmon.
# Credits - IBM Security (Jamie Wheaton // William Delong)
function Get-EventLogInfo { param($Agent, $LogName, $RemoteComputer, $OS)
$LogInfo = @{}
try {
# Just localhost
If (!$RemoteComputer) {
$TotalLogEvents = (Get-WinEvent -ListLog $LogName).RecordCount
$LogSize = (Get-WinEvent -ListLog $LogName).FileSize / 1000000 # Set to MB
$LogSize = [math]::Round(($LogSize), 1)
$OldestEventTime = (Get-WinEvent $LogName -Oldest -maxevents 1).TimeCreated
$NewestEventTime = (Get-WinEvent $LogName -maxevents 1).TimeCreated
$TotalTime = (Get-Date).Subtract($OldestEventTime).TotalSeconds
$AvgEventsPerSecond = $TotalLogEvents / $TotalTime
$AvgEventsPerSecond = [math]::Round($AvgEventsPerSecond, 5)
}
# Remote box
Else {
if ($OS -like "*Server 2003*" -or $OS -like "*Windows XP*"){
Write-Host "$OS is an old Operating System, Collecting $LogName Event Log Information via WMI, this may take some time"
$wmi_eventlogsummary = Get-WmiObject -Class Win32_NTEventLogFile -computername $Agent -Credential $Global:Cred -filter "LogFileName = '$LogName'"
$TotalLogEvents = $wmi_eventlogsummary.NumberOfRecords
$LogSize = ($wmi_eventlogsummary.FileSize / 1MB)
$wmi_eventlogdata = Get-WMIobject -ComputerName $computer -Credential $cred -query "Select * from Win32_NTLogEvent Where Logfile = 'application'"
$getwmioldevent = $wmi_eventlogdata| select -last 1
$getwminewest = $wmi_eventlogdata | select -first 1
$OldestEventTime = [management.managementDateTimeConverter]::ToDateTime($getwmioldevent.TimeGenerated)
$NewestEventTime = [management.managementDateTimeConverter]::ToDateTime($getwminewest.TimeGenerated)
}
else {
$TotalLogEvents = (Get-WinEvent -ListLog $LogName -ComputerName $Agent -Credential $Global:Cred).RecordCount
$LogSize = ((Get-WinEvent -ListLog $LogName -ComputerName $Agent -Credential $Global:Cred).FileSize / 1MB) # Set to MB
#$LogSize = [math]::Round(($LogSize), 1)
if ($TotalLogEvents -eq 0) {
Write-Log $ERROR_LOG "There are 0 $LogName Events"
$OldestEventTime = 0
$NewestEventTime = 0
$TotalTime = 0
$AvgEventsPerSecond = 0
$AvgEventsPerSecond = 0
}
else {
$OldestEventTime = (Get-WinEvent $LogName -ComputerName $Agent -Credential $Global:Cred -Oldest -Maxevents 1).TimeCreated
$NewestEventTime = (Get-WinEvent $LogName -ComputerName $Agent -Credential $Global:Cred -Maxevents 1).TimeCreated
$TotalTime = (Get-Date).Subtract($OldestEventTime).TotalSeconds
$AvgEventsPerSecond = $TotalLogEvents / $TotalTime
$AvgEventsPerSecond = [math]::Round($AvgEventsPerSecond, 5)
}
}
}
$LogInfo.Add("StartTime", $OldestEventTime)
$LogInfo.Add("EndTime", $NewestEventTime)
$LogInfo.Add("LogSize", $LogSize)
#$LogInfo.Add("OSVersion", $OSVersion)
$LogInfo.Add("TotalEvents", $TotalLogEvents)
$LogInfo.Add("AverageEvents", $AvgEventsPerSecond)
Return $LogInfo
}
catch {
Write-Log $ERROR_LOG "Unable to scan $Agent event logs"
Write-Log $ERROR_LOG $Error[0]
$ErrorLineNumber = $Error[0].InvocationInfo.scriptlinenumber
Write-Log $ERROR_LOG "Caught on line number: $ErrorLineNumber"
continue
}
}
#################################################################################################
#Function will generate output info for the given log events per second
#@param $TotalLogEvents -> The total # of events for the given log
#################################################################################################
function Get-ProfileSuggestion { param($AvgEventsPerSecond)
try {
#Profile sugestion
$LogStatsAndInfo = ""
If ($AvgEventsPerSecond -GE 0 -and $AvgEventsPerSecond -LE 100) {
$LogStatsAndInfo += "MSRPC (0-100) EPS or WinCollect Default (Endpoint) (0-50) EPS`n"
}
# Above High Hate
If ($AvgEventsPerSecond -GT 625) {
$LogStatsAndInfo += "Suggested Profile: High Event Rate Server (251-625) EPS"
#$LogStatsAndInfo += "NOTE: Log Event Rate Higher Then Profile Range`n"
}
#- High Event Rate Server 1250-1875 (416-625)
ElseIf ($AvgEventsPerSecond -GE 250) {
$LogStatsAndInfo += "High Event Rate Server (251-625) EPS"
}
#- Typical Server 500-750 (166-250)
ElseIf ($AvgEventsPerSecond -GE 50) {
$LogStatsAndInfo += "Typical Server (51-250) EPS"
}
#- Default (Endpoint) 100-150 (33-50)
ElseIf ($AvgEventsPerSecond -GE 0) {
$LogStatsAndInfo += "WinCollect Default (Endpoint) (0-50) EPS"
}
# Negitive or unreadble and cant be determined
Else {
Write-Log $ERROR_LOG "Unable to Suggest Profile"
exit
}
$LogStatsAndInfo
}
catch {
Write-Log $ERROR_LOG "Unable to get profile suggestion"
Write-Log $ERROR_LOG $Error[0]
$ErrorLineNumber = $Error[0].InvocationInfo.scriptlinenumber
Write-Log $ERROR_LOG "Caught on line number: $ErrorLineNumber"
exit
}
}
#################################################################################################
#Function will test connection
#@param $Cred -> The Event Log
#@param $Computer -> The avg events per second for the given log
#################################################################################################
function Test-HostConnection { param($Computer)
try {
if ((Test-Connection -ComputerName $Computer -count 1 -quiet)) {
return $true
}
else {
Write-Log $ERROR_LOG "Unable to contact $Computer. Please verify its network connectivity and try again"
$Global:ConnectionIssues = $Global:ConnectionIssues + 1
return $false
}
}
catch {
Write-Log $ERROR_LOG "Unable conect to Host"
Write-Log $ERROR_LOG $Error[0]
$ErrorLineNumber = $Error[0].InvocationInfo.scriptlinenumber
Write-Log $ERROR_LOG "Caught on line number: $ErrorLineNumber"
exit
}
}
#################################################################################################
#Function Create a log report for the each computer in the computer list
#@param $LogName -> The Event Log
#@param $AvgEventsPerSecond -> The avg events per second for the given log
#@param $TotalLogEvents -> The total # of events for the given log
#################################################################################################
function Create-LogReport { param($Computerlist, $ComputerCount, $ComputerListType, $OS)
try {
$Report = @{}
$ProgressCount = 0;
if ($ComputerListType -NE $LOCALHOST_OPT) {
$Global:Cred = Get-Credential -Message "Enter an account which has access to the Windows Event Logs"
}
ForEach ($Computer in $Computerlist) {
$ProgressCount = $ProgressCount + 1
$RemoteComputer = $false
if($ProgressCount -EQ 1) {
Write-Log $INFO_LOG "Calculating & Processing Log EPS For Computer List"
}
if ($ComputerListType -NE $LOCALHOST_OPT) {
$RemoteComputer = $true
$Login = Test-HostConnection $Computer
if (!$Login) {
continue
}
}
# Get Server OS if not already gathered
if ($ComputerListType -eq $FILE_OPT) {
Write-Log $INFO_LOG "Getting OS Information for $Computer"
$OS = (Get-WmiObject Win32_OperatingSystem -computername $Computer -Credential $Global:Cred).Caption
Write-Log $INFO_LOG "$OS"
}
if ($ComputerListType -eq $LOCALHOST_OPT) {
Write-Log $INFO_LOG "Getting OS Information for $Computer"
$OS = (Get-WmiObject Win32_OperatingSystem).Caption
Write-Log $INFO_LOG "$OS"
}
if ($ComputerListType -eq $DOMAIN_OPT) {
Write-Log $INFO_LOG "Getting OS Information for $Computer"
#$OS = (Get-WmiObject Win32_OperatingSystem -computername $Computer -Credential $Global:Cred).Caption
$GetADComputerList = Get-ADComputer -Credential $Global:Cred -Filter {enabled -eq "true"} -Properties OperatingSystem | Select DNSHostname, OperatingSystem
#$GetADOS = Get-ADComputer -Credential $Global:Cred -Filter {enabled -eq "true"} -Properties OperatingSystem | Select
#$ComputerList = $GetADComputerList.DNSHostName
$OS = ($GetADComputerList -match $Computer).OperatingSystem
Write-Log $INFO_LOG "$OS"
}
# Retrieve the Application Event log info
$ApplicationInfo = Get-EventLogInfo $Computer Application $RemoteComputer $OS
$ApplicationEPS = $ApplicationInfo.AverageEvents
$ApplicationFirstEventTime = $ApplicationInfo.StartTime
$ApplicationLastEventTime = $ApplicationInfo.EndTime
$ApplicationTotalEvents = $ApplicationInfo.TotalEvents
$ApplicationEventLogSize = $ApplicationInfo.LogSize
# Retrieve the Security Event log info
$SecurityInfo = Get-EventLogInfo $Computer Security $RemoteComputer $OS
$SecurityEPS = $SecurityInfo.AverageEvents
$SecurityFirstEventTime = $SecurityInfo.StartTime
$SecurityLastEventTime = $SecurityInfo.EndTime
$SecurityTotalEvents = $SecurityInfo.TotalEvents
$SecurityEventLogSize = $SecurityInfo.LogSize
# Retrieve the System Event log info
$SystemInfo = Get-EventLogInfo $Computer System $RemoteComputer $OS
$SystemEPS = $SystemInfo.AverageEvents
$SystemFirstEventTime = $SystemInfo.StartTime
$SystemLastEventTime = $SystemInfo.EndTime
$SystemTotalEvents = $SystemInfo.TotalEvents
$SystemEventLogSize = $SystemInfo.LogSize
# Retrieve the Sysmon Event log info
$SysmonInfo = Get-EventLogInfo $Computer Microsoft-Windows-Sysmon/Operational $RemoteComputer $OS
$SysmonEPS = $SysmonInfo.AverageEvents
$SysmonFirstEventTime = $SysmonInfo.StartTime
$SysmonLastEventTime = $SysmonInfo.EndTime
$SysmonTotalEvents = $SysmonInfo.TotalEvents
$SysmonEventLogSize = $SysmonInfo.LogSize
$TotalEPS = [math]::Round(($ApplicationEPS + $SecurityEPS + $SystemEPS + $SysmonEPS), 5)
$ProfileSuggestion = Get-ProfileSuggestion $TotalEPS
#$ComputerOS = (Get-ADComputer -Filter *).OperatingSystem
$ComputerOS = "$OS"
$Box = @{"ProfileSuggestion" = $ProfileSuggestion; "TotalEPS" = $TotalEPS; "OSVersion" = $ComputerOS;
"ApplicationEPS" = $ApplicationEPS; "ApplicationFirstEventTime" = $ApplicationFirstEventTime; "ApplicationLastEventTime" = $ApplicationLastEventTime; "ApplicationTotalEvents" = $ApplicationTotalEvents; "ApplicationEventLogSize" = $ApplicationEventLogSize;
"SecurityEPS" = $SecurityEPS; "SecurityFirstEventTime" = $SecurityFirstEventTime; "SecurityLastEventTime" = $SecurityLastEventTime; "SecurityTotalEvents" = $SecurityTotalEvents; "SecurityEventLogSize" = $SecurityEventLogSize;
"SystemEPS" = $SystemEPS; "SystemFirstEventTime" = $SystemFirstEventTime; "SystemLastEventTime" = $SystemLastEventTime; "SystemTotalEvents" = $SystemTotalEvents; "SystemEventLogSize" = $SystemEventLogSize;
"SysmonEPS" = $SysmonEPS; "SysmonFirstEventTime" = $SysmonFirstEventTime; "SysmonLastEventTime" = $SysmonLastEventTime; "SysmonTotalEvents" = $SysmonTotalEvents; "SysmonEventLogSize" = $SysmonEventLogSize;}
$Report.Add($Computer, $Box)
$PercentComplete = $ProgressCount / $ComputerCount * 100
$PercentComplete = [math]::Round($PercentComplete, 0)
Write-Progress -Activity "Processing Computer List - $PercentComplete% Complete" -status "Calculating EPS for Computer: $Computer" -percentComplete $PercentComplete
}
Write-Log $INFO_LOG "Event Log ESP Report Calculations Complete"
Return $Report
}
catch {
Write-Log $ERROR_LOG "Unable to Create Log Report"
Write-Log $ERROR_LOG $Error[0]
$ErrorLineNumber = $Error[0].InvocationInfo.scriptlinenumber
Write-Log $ERROR_LOG "Caught on line number: $ErrorLineNumber"
exit
}
}
#################################################################################################
#Function will generate output info for the given log. Avg, Suggested Profile, etc...
#@param $LogName -> The Event Log
#@param $AvgEventsPerSecond -> The avg events per second for the given log
#@param $TotalLogEvents -> The total # of events for the given log
#################################################################################################
function Export-LogReport { param($Computerlist, $ComputerCount, $ComputerListType)
try {
$Report = Create-LogReport $Computerlist $ComputerCount $ComputerListType
$OutputTable = foreach ($box in $Report.GetEnumerator()) {
New-Object PSObject -Property ([ordered]@{
"Server" = $box.Name; "OS Version" = $box.Value.OSVersion;
"Application (EPS)" = $box.Value.ApplicationEPS; "Application 1st Event" = $box.Value.ApplicationFirstEventTime; "Application last Event" = $box.Value.ApplicationLastEventTime; "Application total events" = $box.Value.ApplicationTotalEvents; "Application Log Size (MB)" = $box.Value.ApplicationEventLogSize;
"Security (EPS)" = $box.Value.SecurityEPS; "Security 1st Event" = $box.Value.SecurityFirstEventTime; "Security last Event" = $box.Value.SecurityLastEventTime; "Security total events" = $box.Value.SecurityTotalEvents; "Security Log Size (MB)" = $box.Value.SecurityEventLogSize;
"System (EPS)" = $box.Value.SystemEPS; "System 1st Event" = $box.Value.SystemFirstEventTime; "System last Event" = $box.Value.SystemLastEventTime; "System total events" = $box.Value.SystemTotalEvents; "System Log Size (MB)" = $box.Value.SystemEventLogSize;
"Sysmon (EPS)" = $box.Value.SysmonEPS; "Sysmon 1st Event" = $box.Value.SysmonFirstEventTime; "Sysmon last Event" = $box.Value.SysmonLastEventTime; "Sysmon total events" = $box.Value.SysmonTotalEvents; "Sysmon Log Size (MB)" = $box.Value.SysmonEventLogSize;
"Total (EPS)" = $box.Value.TotalEPS; "Profile Suggestion (3 Sec Polling Interval)" = $box.Value.ProfileSuggestion;})
}
Write-Log $INPUT_LOG "Select Event Log Export Location..."
$ExportFolder = Select-ExportLocation "Event Log Summary Report Export Location" "Desktop"
$ExportLocation = $ExportFolder + "\Event-Log-Summary-Report-" + $(get-date -f yyyyMMddhhmmss) + ".csv"
Write-Log $INFO_LOG "Exporting Log Events to: $ExportLocation"
$OutputTable | Export-CSV $ExportLocation -NoTypeInformation -Force
}
catch {
Write-Log $ERROR_LOG "Unable to Export Log Report"
Write-Log $ERROR_LOG $Error[0]
$ErrorLineNumber = $Error[0].InvocationInfo.scriptlinenumber
Write-Log $ERROR_LOG "Caught on line number: $ErrorLineNumber"
exit
}
}
#################################################################################################
#Function will generate a Folder Select Dialog
#@param $Description -> The Description of the Dialog
#@param $RootFolder -> The location that the folder selection begins
#################################################################################################
function Get-FileName { param($RootFolder)
try {
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $RootFolder
$OpenFileDialog.Title = "Select Computer List"
$OpenFileDialog.filter = "All files (*.*)| *.*"
$OpenFileDialog.ShowDialog() | Out-Null
$OpenFileDialog.filename
}
catch {
Write-Log $ERROR_LOG "Unable to Select File"
Write-Log $ERROR_LOG $Error[0]
$ErrorLineNumber = $Error[0].InvocationInfo.scriptlinenumber
Write-Log $ERROR_LOG "Caught on line number: $ErrorLineNumber"
exit
}
}
#################################################################################################
#Function will generate a Folder Select Dialog
#@param $Description -> The Description of the Dialog
#@param $RootFolder -> The location that the folder selection begins
#################################################################################################
function Select-ExportLocation { param($Description, $RootFolder)
try {
$objForm = New-Object System.Windows.Forms.FolderBrowserDialog
$objForm.Rootfolder = $RootFolder
$objForm.Description = $Description
$Show = $objForm.ShowDialog()
if ($Show -EQ "OK") {
return $objForm.SelectedPath
}
else {
Write-Log $ERROR_LOG "Operation cancelled by user"
Write-Log $ERROR_LOG $Error[0]
$ErrorLineNumber = $Error[0].InvocationInfo.scriptlinenumber
Write-Log $ERROR_LOG "Caught on line number: $ErrorLineNumber"
exit
}
}
catch {
Write-Log $ERROR_LOG "Unable to Select Folder"
Write-Log $ERROR_LOG $Error[0]
$ErrorLineNumber = $Error[0].InvocationInfo.scriptlinenumber
Write-Log $ERROR_LOG "Caught on line number: $ErrorLineNumber"
exit
}
}
#################################################################################################
#Function will generate a Drop Down Menu based on the given Drop Down Options
#@param $DropDownOptions -> The Event Log that will be evaluated (Security, Application, System)
#@param $Title -> The Title of the Drop Down Menu
#################################################################################################
function Get-InputFromDropDown { param($DropDownOptions, $Title)
try {
function Return-DropDown {
$script:Choice = $DropDown.SelectedItem.ToString()
$Form.Close()
}
$Form = New-Object System.Windows.Forms.Form
$Form.width = 300
$Form.height = 150
$Form.Text = "Select $Title"
$DropDown = new-object System.Windows.Forms.ComboBox
$DropDown.Location = new-object System.Drawing.Size(100,10)
$DropDown.Size = new-object System.Drawing.Size(130,30)
ForEach ($Item in $DropDownOptions) {
[void] $DropDown.Items.Add($Item)
}
$Form.Controls.Add($DropDown)
$DropDownLabel = new-object System.Windows.Forms.Label
$DropDownLabel.Location = new-object System.Drawing.Size(10,10)
$DropDownLabel.size = new-object System.Drawing.Size(100,20)
$DropDownLabel.Text = "Options:"
$Form.Controls.Add($DropDownLabel)
$Button = new-object System.Windows.Forms.Button
$Button.Location = new-object System.Drawing.Size(100,50)
$Button.Size = new-object System.Drawing.Size(100,20)
$Button.Text = "Submit"
$Button.Add_Click({Return-DropDown})
$form.Controls.Add($Button)
$DropDown.SelectedIndex = 0
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()
$Choice
}
catch {
Write-Log $ERROR_LOG "Unable to generate input drop down"
Write-Log $ERROR_LOG $Error[0]
$ErrorLineNumber = $Error[0].InvocationInfo.scriptlinenumber
Write-Log $ERROR_LOG "Caught on line number: $ErrorLineNumber"
exit
}
}
#########################################################################################
#Function will get the list of computers based on the users selected list type
#@param $ComputerListType -> The type of computer list
#########################################################################################
function Get-ComputerList { param($ComputerListType)
try {
$ComputerList = @{};
switch($ComputerListType) {
$DOMAIN_OPT {
$GetADComputerList = Get-ADComputer -Credential $Global:Cred -Filter {enabled -eq "true"} -Properties OperatingSystem | Select DNSHostname, OperatingSystem
$ComputerList = $GetADComputerList.DNSHostName
break
}
$FILE_OPT {
$ComputerList = Get-FileName "Desktop"
$ComputerList = Get-Content $ComputerList
break
}
$LOCALHOST_OPT {
$ComputerList = "localhost"
break
}
}
Return $ComputerList
}
catch {
Write-Log $ERROR_LOG "Unable to determine computer list"
Write-Log $ERROR_LOG $Error[0]
$ErrorLineNumber = $Error[0].InvocationInfo.scriptlinenumber
Write-Log $ERROR_LOG "Caught on line number: $ErrorLineNumber"
exit
}
}
#########################################################################################
#Function will log messages throughout the script execution
#@param $severity -> How severe of the input message to log
#@param $logMessage -> The message that will be logged cast to a string
#########################################################################################
function Write-Log { param($severity, [string]$logMessage)
try {
if ($logMessage.length -GT 200) {
$logMessage = $logMessage.Substring(0,200) + "..."
}
$output = $logMessage + "`n"
switch($Severity) {
$INFO_LOG {Write-Host $output -Fore Green; break}
$INPUT_LOG {Write-Host $output -Fore Cyan; break}
$WARN_LOG {Write-Host $output -Fore Cyan; break}
$ERROR_LOG {Write-Host $output -Fore Red; break}
Default {Write-Host "Unable to log based on sererity: $Severity" -Fore Cyan; break}
}
}
catch {
Write-Host "Unable to log`n" -Fore Red
Write-Host $Error[0] -Fore Red
$ErrorLineNumber = $Error[0].InvocationInfo.scriptlinenumber
Write-Host "Caught on line number: $ErrorLineNumber" -Fore Red
exit
}
}
# Imports the forms
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") | Out-Null
#Set severities
$INFO_LOG = "Info"
$INPUT_LOG = "Input"
$WARN_LOG = "Warn"
$ERROR_LOG = "Error"
#Set Computer List Options
#$hostdomain = (Get-ADDomain).DNSRoot
$FILE_OPT = "IP List"
$DOMAIN_OPT = "Domain"
$LOCALHOST_OPT = "Local Host"
Write-Log $INFO_LOG "Starting Script"
# Drop Down Options
[array]$ComputerListTypeOptions = $FILE_OPT, $LOCALHOST_OPT, $DOMAIN_OPT
#Set the function variables
$ComputerListType = Get-InputFromDropDown $ComputerListTypeOptions "IP List Type"
#Set the function variables
Write-Log $INPUT_LOG "Select Computer List..."
$ComputerList = Get-ComputerList $ComputerListType
$ComputerCount = $ComputerList.Count
$Global:Cred = $Null
$Global:ConnectionIssues = 0
#Set all errors to terminating
$ErrorActionPreference = "Stop"
Write-Log $INFO_LOG "Selected: $ComputerListType ($ComputerCount Computer(s) Found)"
#Call function
$Time = Measure-Command -Expression {
$LogReport = Export-LogReport $Computerlist $ComputerCount $ComputerListType
}
$Time = [math]::Round($Time.TotalMinutes, 1)
Write-Log $INFO_LOG "Event Log Report Successfully Calculated & Exported - $ComputerCount Computers - $Time Minutes - $Global:ConnectionIssues Connection Issue(s)"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment