To search the Windows Event Logs using PowerShell you can use the following PowerShell CmdLets and WMI class:
Table of Contents
Get Windows Event Logs Details Using PowerShell – Solutions
Here are few solutions for the local machine, remote computers and writing own PowerShell CmdLet.
Solution 1 – Get Windows Event Logs Details Using PowerShell On Local Machine
There are so many options to call Get-WinEvent CmdLet and get so many different information from Windows Event Logs and it is difficult to write about all of them.
I give you an example to list Critical and Error (Level = 1, 2) events from two Event Logs (Application, System) for the past 7 days.
Get-WinEvent -FilterHashTable @{LogName = "Application", "System"; Level=1,2; StartTime=((Get-Date).AddDays(-7))} | Out-GridView
IMPORTANT: It is very important to mention performance when running Get-WinEvent CmdLet. In my tests, I have found that using the FilterHashTable parameter was performing the best.
Here is the result:
Solution 2 – Get Windows Event Logs Details Using PowerShell On Remote Computers
For the list of computers, we can use the same call as for the previous solution only to use the ComputerName parameter and add the list of servers as a txt file.
Create the list of servers in the text file and save in, for example, C:\Temp folder. We basically load the content of the text file using Get-Content CmdLet and PowerShell will go through the list and run the same command as in the previous solution for each server on the list.
INFO: the ComputerName parameter of Get-WinEvent CmdLet accepts a single string as a computer name and doesn’t accept pipelining so we had to use ForEach-Object CmdLet while processing each server name for txt file.
(Get-Content -Path 'C:\Temp\Servers.txt') | ForEach-Object { Get-WinEvent -FilterHashTable @{LogName = "Application", "System"; Level=1,2; StartTime=((Get-Date).AddDays(-7))} -ComputerName $_} | Out-GridView
Here is the resultset:
I do not have servers in my home network so in order to simulate one I have created a very simple input list of servers in a text file just copying the localhost value several times.
Solution 3 – Write Own PowerShell CmdLet (Get-ErrorFromEventLog)
I have written my own Get-ErrorFromEventLog CmdLet that I will explain in the minute.
This approach takes a little bit longer time but gives us more benefits in the long run so it is my preferred way and we can combine this CmdLet with the library of CmdLets in Efficiency Booster PowerShell Project.
Here is a sample call to Get-ErrorFromEventLog CmdLet:
Get-ErrorFromEventLog -computers localhost -errorlog -client "OK" -solution "FIN" -days 3 -Verbose | Out-GridView
Here is the resultset of a call to Get-ErrorFromEventLog CmdLet:
Get-ErrorFromEventLog CmdLet – Explained
Get-ErrorFromEventLog CmdLet shows Critical and Error events from all Windows Event Logs for the list of servers and this CmdLet belongs to Efficiency Booster PowerShell Project. This project is the library of different CmdLets that can help us IT personal to do our everyday tasks more efficiently and accurately.
Source code for Get-ErrorFromEventLog CmdLet can be downloaded from this zip file so please feel free to download it and it would be easier for you to follow me along.
Get-ErrorFromEventLog CmdLet is part of Maintenance module and if you have downloaded the source code it can be found in the folder …\[My] Documents\WindowsPowerShell\Modules\04maintenance
INFO: If you want to know how to install and configure Efficiency Booster PowerShell Project files please read the following article: How To Install And Configure PowerShell: CmdLets, Modules, Profiles.
Get-ErrorFromEventLog CmdLet – Input Parameters
As input parameters we have:
- computers – it is a list of servers passed as input parameter with default value ‘localhost’ and accepts both pipeline options. Parameter belongs to the “ServerNames” parameter set. The “ServerNames” parameter set is the default parameter set.
- filename – it is the name of the text file with the list of servers and represents an alternative option to the “computers” parameter. The parameter belongs to the “FileName” parameter set.
- errorlog – switch datatype and when turned on it will write errors into an external error log file using Write-ErrorLog CmdLet. The error log file is located in the PSLogs folder of [My] Documents.
- client – it is a mandatory input parameter and by convention, I use two letters for client shortcode (for example, OK = O client, BK = B client, etc.). This parameter value is part of the filename parameter naming convention.
- solution – it is a mandatory input parameter and by convention, I use two-three letters for solution shortcode (for example, FIN = Financial solution, HR = HR solution, etc.).
- days – how many days back we want event log details in the resultset. Usually, we were using 30 days since we had maintenance once a month.
The naming convention for the filename parameter is as follows: Client + Solution + Text.txt. The text file should be located in …[My] Documents\WindowsPowerShell\Modules\01servers folder.
For example:
- OKFINTestServers.txt – List of test environment servers for OK client and FIN solution.
- OKFINProdServers.txt – List of production environment servers for OK client and FIN solution.
- OKFINAllServers.txt – List of all servers for OK client and FIN solution.
INFO: To get a deeper explanation about client and solution input parameters please read these two sections Parameter client, Parameter solution.
INFO: In order to customize the installation of CmdLet to your needs and set up necessary CSV file please read the following article How To Install And Configure PowerShell: CmdLets, Modules, Profiles
Here is the parameters definition code:
Function Get-ErrorFromEventLog {
[CmdletBinding(DefaultParametersetName="ServerNames")]
param (
[Parameter( ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ParameterSetName="ServerNames",
HelpMessage="List of computer names separated by commas.")]
[Alias('hosts')]
[string[]]$computers = 'localhost',
[Parameter( ParameterSetName="FileName",
HelpMessage="Name of txt file with list of servers. Txt file should be in 01servers folder.")]
[string]$filename,
[Parameter( Mandatory=$false,
HelpMessage="Write to error log file or not.")]
[switch]$errorlog,
[Parameter(Mandatory=$true,
HelpMessage="Client for example OK = O client, BK = B client")]
[string]$client,
[Parameter(Mandatory=$true,
HelpMessage="Solution, for example FIN = Financial, HR = Human Resource")]
[string]$solution,
[Parameter(Mandatory=$true,
HelpMessage="How many days in the past to look for error.")]
#[ValidateRange(0,100)]
[int]$days
)
}
INFO: To know more about PowerShell Parameters and Parameter Sets with some awesome examples please read the following articles How To Create Parameters In PowerShell and How To Use Parameter Sets In PowerShell Functions.
INFO: PowerShell Pipelining is a very important concept and I highly recommend you to read the article written on the subject. How PowerShell Pipeline Works. Here I have shown in many examples the real power of PowerShell using the Pipelining.
BEGIN Block
In the BEGIN block we:
- If the FileName parameter set has been used we test if text file with a list of servers exists.
- If the file exists read the file and create the list of servers as a string array in the $computers variable.
- … and if not write a warning with information to the caller to create the file.
BEGIN {
if ( $PsCmdlet.ParameterSetName -eq "FileName") {
if ( Test-Path -Path "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" -PathType Leaf ) {
Write-Verbose "Read content from file: $filename"
$computers = Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" )
} else {
Write-Warning "This file path does NOT exist: $home\Documents\WindowsPowerShell\Modules\01servers\$filename"
Write-Warning "Create file $filename in folder $home\Documents\WindowsPowerShell\Modules\01servers with list of server names."
break;
}
}
}
PROCESS Block
In the PROCESS block we run this block of code for each server passed into the pipeline or read from the text file:
- We replace the localhost default value for the local server with the actual name of the local machine.
- We use Get-ComputerInfo CmdLet to read additional data about each server (name, environment, logical name, IP address).
- We implement Error Handling using try-catch blocks and writing errors in an external text file using Write-ErrorLog CmdLet.
- IMPORTANT: My Cultural settings are NO (Norwegian). In order to avoid empty message string in the resultset, we switch temporarily to English culture settings.
- IMPORTANT: LogName parameter has the limitation of 256 logs so we will look only into non-empty logs for critical and error events.
- IMPORTANT: Make sure that the user running the script has enough permissions on all Windows Event Logs especially the Security log.
- We use PowerShell splatting to prepare the input parameters for the next call of Get-WinEvent CmdLet.
- IMPORTANT: As I have already mention use of the FilterHashtable parameter was the fastest method to get the result. Test different parameters to find the best solution for your environment.
- We collect all filtered events in $events variable
- Return Cultural settings to the original value.
- We process each collected event.
- We prepare resultset of Get-WinEvent CmdLet.
Please notice these features in the PROCESS block.
Splatting
We have used splatting several times. First when we prepare the call to Get-WinEvent CmdLet, and second when we prepare the resultset.
Splatting helps us to have a more neat and understandable code.
Here is a call to Get-WinEvent CmdLet and use of splatting:
$params = @{ 'ComputerName'=$computer;
'ErrorAction'='Stop';
'FilterHashtable'=@{ LogName = $logs; StartTime = ((Get-Date).AddDays(-1*[int]$days)); Level=1,2}
}
$events = Get-WinEvent @params |
Select-Object LogName,
Level,
LevelDisplayName,
TimeCreated,
ProviderName,
MachineName,
Id,
RecordId,
UserId,
Message |
Sort-Object TimeCreated
Here is the second use of splatting when creating the resultset.
$properties = @{ 'Environment'=$env;
'Logical name'=$logicalname;
'Computer name'=$computer;
'Log name'=$event.LogName;
'Message'=$event.Message;
'Level'=$event.Level;
'Level description'=$event.LevelDisplayName;
'Logged'=$event.TimeCreated;
'Source'=$event.ProviderName;
'Event ID'=$event.Id;
'Event record ID'=$event.RecordId;
'Server'=$event.MachineName;
'User'=$event.UserId;
'IP'=$ip;
'Collected'=(Get-Date -UFormat %Y.%m.%d' '%H:%M:%S)}
$obj = New-Object -TypeName PSObject -Property $properties
$obj.PSObject.TypeNames.Insert(0,'Report.ErrorFromEventLog')
Type Name Of The Resultset Objects
Notice the name of the resultset (Report.ErrorFromEventLog).
$obj.PSObject.TypeNames.Insert(0,'Report.ErrorFromEventLog')
So if we call PowerShell Get-Member CmdLet to get the type of resultset for Get-ErrorFromEventLog CmdLet we will get Report.ErrorFromEventLog type and not standard PowerShell PSObject type.
Get-ErrorFromEventLog -computers localhost -errorlog -client "OK" -solution "FIN" -days 3 -Verbose | Get-Member
Here is the resultset:
Type Name of resultset gives us a possibility to further expend the use of resultset. For example, we can use MS SQL Database and create table ErrorFromEventLog based on resultset type name ( Report.ErrorFromEventLog) where we can record the resultset and use MS SQL Reporting Services to show the results collected over a certain period of time.
Here is the PROCESS block source code:
PROCESS {
foreach ($computer in $computers ) {
if ( $computer -eq 'localhost' ) {
$computer = $env:COMPUTERNAME
Write-Verbose "Replace localhost with real name of the server."
}
$computerinfo = Get-ComputerInfo -computername $computer -client $client -solution $solution
$hostname = $computerinfo.hostname
$env = $computerinfo.environment
$logicalname = $computerinfo.logicalname
$ip = $computerinfo.ipaddress
try {
Write-Verbose "Start processing: $computer - $env - $logicalname"
Write-Verbose "Start Get-WinEvent processing..."
$events = $null
$event = $null
$obj = $null
#THIS SOLVES PROBLEM WITH EMPTY MESSAGE PROPERTY IN PS v3.0
$orgCulture = Get-Culture
[System.Threading.Thread]::CurrentThread.CurrentCulture = New-Object "System.Globalization.CultureInfo" "en-US"
#Use this to avoid Invalid data error due to limitation of 256 logs searching if used LogName = "*" with wildcard
#We will look only into logs that have records
$logs = Get-WinEvent -ListLog * | Where-Object {$_.RecordCount} | Select-Object -ExpandProperty LogName
$params = @{ 'ComputerName'=$computer;
'ErrorAction'='Stop';
'FilterHashtable'=@{ LogName = $logs; StartTime = ((Get-Date).AddDays(-1*[int]$days)); Level=1,2}
}
#'FilterHashtable'=@{ LogName = "Security", "Application", "System"; StartTime = ((Get-Date).AddDays(-1*[int]$days)); Level=1,2}
#LogName = "*" return us Invalid Data error if you have more than 256 logs in your Event Viewer
#'FilterHashtable'=@{ LogName = "*"; StartTime = ((Get-Date).AddDays(-1*[int]$days)); Level=1,2}
$events = Get-WinEvent @params |
Select-Object LogName,
Level,
LevelDisplayName,
TimeCreated,
ProviderName,
MachineName,
Id,
RecordId,
UserId,
Message |
Sort-Object TimeCreated
#Return to the original culture settings
[System.Threading.Thread]::CurrentThread.CurrentCulture = $orgCulture
Write-Verbose "Finish Get-WinEvent processing..."
foreach ( $event in $events ) {
Write-Verbose "Start processing event: $event"
$properties = @{ 'Environment'=$env;
'Logical name'=$logicalname;
'Computer name'=$computer;
'Log name'=$event.LogName;
'Message'=$event.Message;
'Level'=$event.Level;
'Level description'=$event.LevelDisplayName;
'Logged'=$event.TimeCreated;
'Source'=$event.ProviderName;
'Event ID'=$event.Id;
'Event record ID'=$event.RecordId;
'Server'=$event.MachineName;
'User'=$event.UserId;
'IP'=$ip;
'Collected'=(Get-Date -UFormat %Y.%m.%d' '%H:%M:%S)}
$obj = New-Object -TypeName PSObject -Property $properties
$obj.PSObject.TypeNames.Insert(0,'Report.ErrorFromEventLog')
Write-Output $obj
Write-Verbose "Finish processing event: $event"
}
Write-Verbose "Computer processed: $computer - $env - $logicalname"
} catch {
Write-Warning "Computer failed: $computer - $env - $logicalname Event failed: $event"
Write-Warning "Error message: $_"
if ( $errorlog ) {
$errormsg = $_.ToString()
$exception = $_.Exception
$stacktrace = $_.ScriptStackTrace
$failingline = $_.InvocationInfo.Line
$positionmsg = $_.InvocationInfo.PositionMessage
$pscommandpath = $_.InvocationInfo.PSCommandPath
$failinglinenumber = $_.InvocationInfo.ScriptLineNumber
$scriptname = $_.InvocationInfo.ScriptName
Write-Verbose "Start writing to Error log."
Write-ErrorLog -hostname $computer -env $env -logicalname $logicalname -errormsg $errormsg -exception $exception -scriptname $scriptname -failinglinenumber $failinglinenumber -failingline $failingline -pscommandpath $pscommandpath -positionmsg $pscommandpath -stacktrace $stacktrace
Write-Verbose "Finish writing to Error log."
}
}
}
}
INFO: To learn about PowerShell Error Handling and code debugging please read the following articles: How To Log PowerShell Errors And Much More and How To Debug PowerShell Scripts.
END Block
END block is empty.
INFO: To understand BEGIN, PROCESS and END blocks in PowerShell please read PowerShell Function Begin Process End Blocks Explained With Examples.
Comment-Based Help Section
For every one of my own CmdLets, I write Comment-Based help as well.
INFO: If you want to learn how to write comment-based Help for your own PowerShell Functions and Scripts please read these articles How To Write PowerShell Help (Step by Step). In this article How To Write PowerShell Function’s Or CmdLet’s Help (Fast), I explain the PowerShell Add-on that helps us to be fast with writing help content.
How To Use Get-ErrorFromEventLog CmdLet – Tips
In my experience, the best use of Get-ErrorFromEventLog CmdLet is to use it as part of a monthly maintenance routine and checking all the Windows Event Logs on all servers for Critical and Error events. Especially, all the events related to the critical applications for the solution, in my case that have been Agresso ERP Solution and all integrations with it.
I have this CmdLet scheduled and receive the email with an Excel sheet attachment that I will review and fix all the errors during the maintenance evening.
In the example below we look for all the critical and error events for the last seven days in all the Windows Event Logs that have events.
We can PowerShell pipeline result from Get-ErrorFromEventLog CmdLet into Save-ToExcel CmdLet and get resultset as an Excel Sheet:
Get-ErrorFromEventLog -errorlog -client "OK" -solution "FIN" -days 7 -Verbose | Save-ToExcel -errorlog -ExcelFileName "Get-ErrorFromEventLog" -title "Get errors from servers in Financial solution for " -author "Improve Scripting" -WorkSheetName "Errors from Event logs" -client "OK" -solution "FIN"
Here is the Excel Sheet result:
TIP: Please open the screenshot below in a separate tab in order to clearly see the result.
REMINDER: If your windows culture setting is not English like mine is Norwegian. We change settings in the code as I have shown to avoid empty message property of the resultset.
REMINDER: There is a limitation with a maximum of 256 logs to read with Get-WinEvent CmdLet so we read only logs with some events in them.
REMINDER: It is important to have the best performance while running Get-WinEvent CmdLet since we are reading lots of event logs which takes time. We used the FilterHashtable parameter since this one performed the best.
Useful PowerShell Windows Event Logs Articles
Here are some useful articles and resources:
- Get-EventLog
- Get-WinEvent
- Creating Get-WinEvent queries with FilterHashtable
- New-EventLog
- Write-EventLog
- Show-EventLog
- Clear-EventLog
- Remove-EventLog
- Limit-EventLog
- Win32_NTEventlogFile class [Legacy]
- Get-WinEvent Maximum Number of Logs
- PowerShell – Everything you wanted to know about Event Logs and then some
- PSEventViewer Module
Get-ErrorFromEventLog CmdLet Source Code
DISCLAIMER: Get-ErrorFromEventLog function is part of the Efficiency Booster PowerShell Project and as such utilize other CmdLets that are part of the same project. So the best option for you in order for this function to work without any additional customization is to download the source code of the whole project from here.
INFO: My best advice to every PowerShell scripter is to learn writing own PowerShell Advanced Functions and CmdLets and I have written several articles explaining this, so please read them. How To Create A Custom PowerShell CmdLet (Step By Step). Here I explain how to use PowerShell Add-on Function to be faster in writing PowerShell Functions How To Write Advanced Functions Or CmdLets With PowerShell (Fast).
Here is the source code of the whole Get-ErrorFromEventLog CmdLet:
<#
.SYNOPSIS
Get errors from Event Viewer logs for a list of servers.
.DESCRIPTION
Get errors from Event Viewer logs for a list of servers. List of servers is in txt file in 01servers folder
or list of strings with names of computers.
CmdLet has two ParameterSets one for list of computers from file and another from list of strings as computer names.
Errors will be saved in log folder PSLogs with name Error_Log.txt. Parameter errorlog controls logging of errors in log file.
Get-ErrorFromEventLog function uses Get-WinEvent PowerShell function to get errors from Event Viewer logs.
NOTE: Get-WinEvent function has best performance among all other functions that can be used for same purpose.
Result shows following columns: Environment (PROD, Acceptance, Test, Course...),
Logical Name (Application, web, integration, FTP, Scan, Terminal Server...), Server Name,
Log name, Message, Level, Level description, Logged Time, Source, Event ID, Event record ID, Server, User, IP
.PARAMETER computers
List of computers that we want to get Event Logs info from. Parameter belongs to default Parameter Set = ServerNames.
.PARAMETER filename
Name of txt file with list of servers that we want to check Event Log. .txt file should be in 01servers folder.
Parameter belongs to Parameter Set = FileName.
.PARAMETER errorlog
Switch parameter that sets to write to log or not to write to log. Error file is in PSLog folder with name Error_Log.txt.
.PARAMETER client
OK - O client
BK - B client
etc.
.PARAMETER solution
FIN - Financial solution
HR - Human resource solution
etc.
.PARAMETER days
Number of days to go in past when searching for errors from Event Viewer.
.EXAMPLE
Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7
Description
---------------------------------------
Test of default parameter with default value ( computers = 'localhost' ) in default ParameterSet = ServerName.
.EXAMPLE
Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -Verbose
Description
---------------------------------------
Test of Verbose parameter. NOTE: Notice how localhost default value of parameter computers replaces with name of server.
.EXAMPLE
'ERROR' | Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog
Description
---------------------------------------
Test of errorlog parameter. There is no server with name ERROR so this call will fail and write to Error log since errorlog switch parameter is on. Look Error_Log.txt file in PSLogs folder.
.EXAMPLE
Get-ErrorFromEventLog -computers 'APP100001' -client "OK" -solution "FIN" -days 7 -errorlog
Description
---------------------------------------
Test of computers parameter with one value. Parameter accepts array of strings.
.EXAMPLE
Get-ErrorFromEventLog -computers 'APP100001', 'APP100002' -client "OK" -solution "FIN" -days 7 -errorlog -Verbose
Description
---------------------------------------
Test of computers parameter with array of strings. Parameter accepts array of strings.
.EXAMPLE
Get-ErrorFromEventLog -hosts 'APP100001' -client "OK" -solution "FIN" -days 7 -errorlog
Description
---------------------------------------
Test of computers paramater alias hosts.
.EXAMPLE
Get-ErrorFromEventLog -computers (Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\OKFINservers.txt" )) -client "OK" -solution "FIN" -days 7 -errorlog -Verbose
Description
---------------------------------------
Test of computers parameter and values for parameter comes from .txt file that has list of servers.
.EXAMPLE
'APP100001' | Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog
Description
---------------------------------------
Test of pipeline by value of computers parameter.
.EXAMPLE
'APP100001', 'APP100002' | Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog -Verbose
Description
---------------------------------------
Test of pipeline by value with array of strings of computers parameter.
.EXAMPLE
'APP100001', 'APP100002' | Select-Object @{label="computers";expression={$_}} | Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog
Description
---------------------------------------
Test of values from pipeline by property name (computers).
.EXAMPLE
Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\OKFINservers.txt" ) | Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog -Verbose
Description
---------------------------------------
Test of pipeline by value that comes as content of .txt file with list of servers.
.EXAMPLE
Help Get-ErrorFromEventLog -Full
Description
---------------------------------------
Test of Powershell help.
.EXAMPLE
Get-ErrorFromEventLog -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 7 -Verbose
Description
---------------------------------------
This is test of ParameterSet = FileName and parameter filename. There is list of servers in .txt file.
.EXAMPLE
Get-ErrorFromEventLog -file "OKFINserverss.txt" -errorlog -client "OK" -solution "FIN" -days 7 -Verbose
Description
---------------------------------------
This is test of ParameterSet = FileName and parameter filename. This test will fail due to wrong name of the .txt file with warning message "WARNING: This file path does NOT exist:".
.INPUTS
System.String
Computers parameter pipeline both by Value and by Property Name value and has default value of localhost. (Parameter Set = ComputerNames)
Filename parameter does not pipeline and does not have default value. (Parameter Set = FileName)
.OUTPUTS
System.Management.Automation.PSCustomObject
Get-ErrorFromEventLog returns PSCustomObjects which has been converted from PowerShell function Get-WinEvent
Result shows following columns: Environment (PROD, Acceptance, Test, Course...),
Logical name (Application, web, integration, FTP, Scan, Terminal Server...), Server name
Log name, Message, Level, Level description, Logged Time, Source, Event ID, Event record ID, Server, User, IP
.NOTES
FunctionName : Get-ErrorFromEventLog
Created by : Dejan Mladenovic
Date Coded : 10/31/2018 19:06:41
More info : http://improvescripting.com/
.LINK
How To Get Windows Event Logs Details Using PowerShell
http://www.powershellish.com/blog/2015-01-19-get-winevent-max-logs
Get-WinEvent
#>
Function Get-ErrorFromEventLog {
[CmdletBinding(DefaultParametersetName="ServerNames")]
param (
[Parameter( ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
ParameterSetName="ServerNames",
HelpMessage="List of computer names separated by commas.")]
[Alias('hosts')]
[string[]]$computers = 'localhost',
[Parameter( ParameterSetName="FileName",
HelpMessage="Name of txt file with list of servers. Txt file should be in 01servers folder.")]
[string]$filename,
[Parameter( Mandatory=$false,
HelpMessage="Write to error log file or not.")]
[switch]$errorlog,
[Parameter(Mandatory=$true,
HelpMessage="Client for example OK = O client, BK = B client")]
[string]$client,
[Parameter(Mandatory=$true,
HelpMessage="Solution, for example FIN = Financial, HR = Human Resource")]
[string]$solution,
[Parameter(Mandatory=$true,
HelpMessage="How many days in the past to look for error.")]
#[ValidateRange(0,100)]
[int]$days
)
BEGIN {
if ( $PsCmdlet.ParameterSetName -eq "FileName") {
if ( Test-Path -Path "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" -PathType Leaf ) {
Write-Verbose "Read content from file: $filename"
$computers = Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" )
} else {
Write-Warning "This file path does NOT exist: $home\Documents\WindowsPowerShell\Modules\01servers\$filename"
Write-Warning "Create file $filename in folder $home\Documents\WindowsPowerShell\Modules\01servers with list of server names."
break;
}
}
}
PROCESS {
foreach ($computer in $computers ) {
if ( $computer -eq 'localhost' ) {
$computer = $env:COMPUTERNAME
Write-Verbose "Replace localhost with real name of the server."
}
$computerinfo = Get-ComputerInfo -computername $computer -client $client -solution $solution
$hostname = $computerinfo.hostname
$env = $computerinfo.environment
$logicalname = $computerinfo.logicalname
$ip = $computerinfo.ipaddress
try {
Write-Verbose "Start processing: $computer - $env - $logicalname"
Write-Verbose "Start Get-WinEvent processing..."
$events = $null
$event = $null
$obj = $null
#THIS SOLVES PROBLEM WITH EMPTY MESSAGE PROPERTY IN PS v3.0
$orgCulture = Get-Culture
[System.Threading.Thread]::CurrentThread.CurrentCulture = New-Object "System.Globalization.CultureInfo" "en-US"
#$events = Get-WinEvent -ErrorAction Stop -ComputerName $computer -FilterHashtable @{ LogName = "*"
#Use this to avoid Invalid data error due to limitation of 256 logs searching if used LogName = "*" with wildcard
#We will look only into logs that have records
$logs = Get-WinEvent -ListLog * | Where-Object {$_.RecordCount} | Select-Object -ExpandProperty LogName
$params = @{ 'ComputerName'=$computer;
'ErrorAction'='Stop';
'FilterHashtable'=@{ LogName = $logs; StartTime = ((Get-Date).AddDays(-1*[int]$days)); Level=1,2}
#'FilterHashtable'=@{ LogName = "Security", "Application", "System"; StartTime = ((Get-Date).AddDays(-1*[int]$days)); Level=1,2}
}
#'FilterHashtable'=@{ LogName = "Application", "System"; StartTime = ((Get-Date).AddDays(-1*[int]$days)); Level=1,2}
#-FilterHashtable @{ LogName = "Application"; StartTime = ((Get-Date).AddDays(-1*[int]$days)); Level=1,2}
$events = Get-WinEvent @params |
Select-Object LogName,
Level,
LevelDisplayName,
TimeCreated,
ProviderName,
MachineName,
Id,
RecordId,
UserId,
Message |
Sort-Object TimeCreated
[System.Threading.Thread]::CurrentThread.CurrentCulture = $orgCulture
Write-Verbose "Finish Get-WinEvent processing..."
foreach ( $event in $events ) {
Write-Verbose "Start processing event: $event"
$properties = @{ 'Environment'=$env;
'Logical name'=$logicalname;
'Computer name'=$computer;
'Log name'=$event.LogName;
'Message'=$event.Message;
'Level'=$event.Level;
'Level description'=$event.LevelDisplayName;
'Logged'=$event.TimeCreated;
'Source'=$event.ProviderName;
'Event ID'=$event.Id;
'Event record ID'=$event.RecordId;
'Server'=$event.MachineName;
'User'=$event.UserId;
'IP'=$ip;
'Collected'=(Get-Date -UFormat %Y.%m.%d' '%H:%M:%S)}
$obj = New-Object -TypeName PSObject -Property $properties
$obj.PSObject.TypeNames.Insert(0,'Report.ErrorFromEventLog')
Write-Output $obj
Write-Verbose "Finish processing event: $event"
}
Write-Verbose "Computer processed: $computer - $env - $logicalname"
} catch {
Write-Warning "Computer failed: $computer - $env - $logicalname Event failed: $event"
Write-Warning "Error message: $_"
if ( $errorlog ) {
$errormsg = $_.ToString()
$exception = $_.Exception
$stacktrace = $_.ScriptStackTrace
$failingline = $_.InvocationInfo.Line
$positionmsg = $_.InvocationInfo.PositionMessage
$pscommandpath = $_.InvocationInfo.PSCommandPath
$failinglinenumber = $_.InvocationInfo.ScriptLineNumber
$scriptname = $_.InvocationInfo.ScriptName
Write-Verbose "Start writing to Error log."
Write-ErrorLog -hostname $computer -env $env -logicalname $logicalname -errormsg $errormsg -exception $exception -scriptname $scriptname -failinglinenumber $failinglinenumber -failingline $failingline -pscommandpath $pscommandpath -positionmsg $pscommandpath -stacktrace $stacktrace
Write-Verbose "Finish writing to Error log."
}
}
}
}
END { }
}
#region Execution examples
#[System.Threading.Thread]::CurrentThread.CurrentCulture = "en-US";[System.Threading.Thread]::CurrentThread.CurrentCulture;
#[System.Threading.Thread]::CurrentThread.CurrentCulture = "en-US";Get-ErrorFromEventLog -computers "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 7 -Verbose
#Get-ErrorFromEventLog -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 3 -Verbose | Out-GridView
#Get-ErrorFromEventLog -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 30 -Verbose | Out-GridView
#Get-ErrorFromEventLog -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 30 -Verbose | Out-GridView
#Get-ErrorFromEventLog -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 3 -Verbose | Export-Csv -Path "$home\Documents\PSreports\kurs.csv" -NoTypeInformation -Delimiter ";"
#Get-ErrorFromEventLog -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 3 -Verbose | Export-Csv -Path "$home\Documents\PSreports\all.csv" -NoTypeInformation -Delimiter ";"
<#
#Test ParameterSet = ServerName
Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 | Out-GridView
Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog | Out-GridView
Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog -Verbose | Out-GridView
Get-ErrorFromEventLog -computers 'APP100001' -client "OK" -solution "FIN" -days 7 -errorlog | Out-GridView
Get-ErrorFromEventLog -computers 'APP100001', 'APP100002' -client "OK" -solution "FIN" -days 7 -errorlog -Verbose | Out-GridView
Get-ErrorFromEventLog -hosts 'APP100001' -client "OK" -solution "FIN" -days 7 -errorlog | Out-GridView
Get-ErrorFromEventLog -computers (Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\OKFINservers.txt" )) -client "OK" -solution "FIN" -days 7 -errorlog -Verbose | Out-GridView
#Pipeline examples
'APP100001' | Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog | Out-GridView
'APP100001', 'APP100002' | Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog -Verbose | Out-GridView
'APP100001', 'APP100002' | Select-Object @{label="computers";expression={$_}} | Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog | Out-GridView
Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\OKFINkursservers.txt" ) | Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog -Verbose | Out-GridView
'ERROR' | Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog | Out-GridView
#Test CmdLet help
Help Get-ErrorFromEventLog -Full
#SaveToExcel
Get-ErrorFromEventLog -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 30 -Verbose | Save-ToExcel -errorlog -ExcelFileName "Get-ErrorFromEventLog" -title "Get errors from servers in Financial solution for " -author "DJ PowerScript" -WorkSheetName "Errors from Event logs" -client "OK" -solution "FIN"
#SaveToExcel and send email
Get-ErrorFromEventLog -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 30 -Verbose | Save-ToExcel -sendemail -errorlog -ExcelFileName "Get-ErrorFromEventLog" -title "Get errors from servers in Financial solution for " -author "DJ PowerScript" -WorkSheetName "Errors from Event logs" -client "OK" -solution "FIN"
Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog -Verbose | Save-ToExcel -sendemail -errorlog -ExcelFileName "Get-ErrorFromEventLog" -title "Get errors from servers in Financial solution for " -author "DJ PowerScript" -WorkSheetName "Errors from Event logs" -client "OK" -solution "FIN"
Get-ErrorFromEventLog -client "OK" -solution "FIN" -days 7 -errorlog -Verbose | Save-ToExcel -errorlog -ExcelFileName "Get-ErrorFromEventLog" -title "Get errors from servers in Financial solution for " -author "DJ PowerScript" -WorkSheetName "Errors from Event logs" -client "OK" -solution "FIN"
#Benchmark
#Time = 466 sec; Total Items = 13725
Measure-BenchmarksCmdLet { Get-ErrorFromEventLog -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 30 -Verbose }
#Time = 325 sec; Total Items = 13725
Measure-BenchmarksCmdLet { Get-ErrorFromEventLog -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 30 }
#Time = sec; Total Items =
Measure-BenchmarksCmdLet { Get-ErrorFromEventLog -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 30 | Save-ToExcel -sendemail -errorlog -ExcelFileName "Get-ErrorFromEventLog" -title "Get errors from servers in Financial solution for " -author "DJ PowerScript" -WorkSheetName "Errors from Event logs" -client "OK" -solution "FIN" }
#Test ParameterSet = FileName
Get-ErrorFromEventLog -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -days 7 -Verbose | Out-GridView
Get-ErrorFromEventLog -filename "OKFINserverss.txt" -errorlog -client "OK" -solution "FIN" -days 7 -Verbose | Out-GridView
#>
#endregion