[Update]: This article was first published on May July 25, 2018. It’s been updated and extended with more details.
Windows event logs is one of the first places an admin looks at when they analyze problems and search for their causes. But troubleshooting is not the only reason for logged events. In this article, I will show you how to use PowerShell and Get-EventLog to perform some Event Log magic. But first, a few words about the logs in general.
- What is a Windows event log
- How to view Windows event logs
- The Event Viewer
- Windows event log location
- Get-WinEvent vs Get-EventLog
- Use PowerShell to diagnose problems on multiple computers
- Checking login and logoff time with PowerShell
What is a Windows event log
Windows event log is a collection of monitoring and troubleshooting messages from your system and applications. Basically, logs tell you what’s happening with the PC, who’s done what and which system components might need fixing.
How to view Windows event log
First, there are two ways to access the events logged in Windows – through the Event Viewer and using the Get-EventLog / Get-WinEvent cmdlets. The Event Viewer is an intuitive tool which lets you find all the required info, provided you know what to look for. Searching the logs using the PowerShell has a certain advantage, though – you can check events on the local or remote computers much quicker using the console. It is an invaluable asset if you think about server health monitoring. PowerShell lets you generate automatic reports about the most important events to read while drinking your morning coffee.
To understand how to read the logs, you need to know the basic structure of an event log entry. That is:
- Each event falls under a certain category. The most used are:
- Application logs.
- Security logs.
- System logs.
- Applications and Services logs (which contains a whole lot of “sublogs” devoted to specific Apps. E.g., Windows PowerShell.
- Each entry contains:
- Specific date and time of the event.
- Level, which tells you whether the event is an Information, Warning or Error.Source – informs which Service or App generated the event.Event ID, which is the part that gives you the easiest way to learn what exactly happened after a quick Google search.
- General & Details – detailed information about what exactly happened (e.g., User A failed to log to the Computer B because C.)
The Event Viewer
The amount of logging information can be overwhelming. It means that data filtering is your priority. That’s why, before you dive into monitoring and troubleshooting, it’s a good idea to open the logs and see what they contain. The easiest way to do that is to use the Event Viewer.
To start the Event Viewer, use the Win+R key combination and execute eventvwr:
This action will open the Event Viewer:
The tree on the left lets you browse through all Event Viewer’s entries.
Windows event log location
Event logs are stored in %SystemRoot%\System32\winevt\Logs, which usually translates into C:\Windows\System32\winevt\Logs. At least, that’s their default location, which can be easily changed by going to Action > Properties in the Event Viewer. The Windows event log location is filled with a lot of *.evtx files, which store events and can be opened with the Event Viewer.
When you open such a log file, for example the locally saved System log, the event viewer will display the log in a separate branch, under Saved Logs.
You can use those files for an easy way to back up your event logs.
Get-WinEvent vs Get-EventLog
If you want to check the logs with PowerShell, you can use two different cmdlets: Get-WinEvent and Get-EventLog. In short, Get-WinEvent is a newer version of Get-EventLog. The cmdlets work in a similar manner, and Get-EventLog does the trick in most cases. According to the Microsoft documentation, the main difference is that Get-WinEvent works with “the Windows event log technology introduced in Windows Vista.” To get a clearer explanation, you can use two simple cmdlets:
Get-EventLog -list
Get-WinEvent -ListLog * | where {$_.RecordCount -gt 0}
As you can see, Get-WinEvent is a clear winner when it comes to the amount of data it can access. While it means that you can access more information, it also means that it might take more effort to filter data.
Mind that some attributes’ names are different in those two cmdlets, so you might need to do some translating if you want to use the syntax of Get-WinEvent with the Get-EventLog cmdlet. If you want to know how to filter the results, simply pipe the cmdlet to Get-Member:
Get-EventLog application -newest 1 | Get-Member
Although Get-EventLog is a “legacy cmdlet,” it still works like a charm in most diagnostic cases. It also has one clear advantage: you can use the -After and –Before attributes to filter results by date. Thanks to that, date-related queries are much quicker than piping all results and trying to sift through them.
Before you start searching through the logs for specific events, it is a good idea to get to know the structure and get the general idea of how the logging mechanism works. The Event Viewer is the right tool to get you started on that.
Use PowerShell to check event logs on multiple computers
The biggest challenge of setting up the Get-EventLog or Get-WinEvent cmdlets is to filter results. First, you have to know what to look for, next – you have to make sure that your query does not cause the PowerShell console to throw a fit. One way to run diagnostics is to use the script below:
$servers = Get-TransportService;
foreach ($server in $servers)
{Write-Host "Scanning the event log of: " -NoNewLine; Write-Host $server;
Get-EventLog system -ComputerName $server -After (Get-Date).AddHours(-12) | where {($_.EntryType -Match "Error") -or ($_.EntryType -Match "Warning")} | ft -wrap >> "C:/$server.csv";
Get-EventLog application -ComputerName $server -After (Get-Date).AddHours(-12) | where {($_.EntryType -Match "Error") -or ($_.EntryType -Match "Warning")} | ft -wrap >> "C:/$server.csv"}
The script pulls information about all Error and Warning kinds of events generated in the last 12 hours in System and Application logs for a list of servers. You can replace the Get-TransportService cmdlet with another list of machines you want to diagnose.
Checking login and logoff time with PowerShell
There are quite a few ways to check when a certain machine was turned on. If you simply need to check when was the first time a user logged in on a specific date, use the following cmdlet:
Get-EventLog system -after (get-date).AddDays(-1) | where {$_.InstanceId -eq 7001}
To learn when the computer was turned on a specific date, you can select the first logged event:
$today = get-date -Hour 0 -Minute 0;
Get-EventLog system -after $today | sort -Descending | select -First 1
Those cmdlets; however, will not work if you want to monitor the usage of a shared computer.
You could scan through the security events, looking for 4624 (logon) and 4625 (logoff) event IDs. However, the security log usually holds the greatest number of records and going through it can be extremely time-consuming. Fortunately, the system log also stores logon and logoff data and specifying the exact source of the log entry allows a relatively quick search. The script below returns a list of logon and logoff events on the target computer with their exact times and users for the last seven days.
$logs = get-eventlog system -ComputerName <name of the monitored computer> -source Microsoft-Windows-Winlogon -After (Get-Date).AddDays(-7);
$res = @(); ForEach ($log in $logs) {if($log.instanceid -eq 7001) {$type = "Logon"} Elseif ($log.instanceid -eq 7002){$type="Logoff"} Else {Continue} $res += New-Object PSObject -Property @{Time = $log.TimeWritten; "Event" = $type; User = (New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}};
$res
Result:
If you need more detailed results, you could add the Security log events IDs 4800 and 4801 for lock and unlock events. Mind that this will require you to run another Get-EventLog script to get info from the Security log. It will also significantly increase the time your PowerShell console will need to finish the task.
Further Reading:
very usefull!
Very interesting article and technics on Event Viewer data manipulation. How can I extract the times a user connected through VPN i.e SSTP VPN on a RAS Gateway server s well as the time they disconnected. I presume a lot of admins also need this solution. Preference will be the query between to dates. Thanks
Get-EventLog no longer supported in PowerShell 7. It will throw an unrecognized cmdlet error.
That’s right. You can either use Get-WinEvent instead of Get-EventLog or get back in touch with PowerShell 5.1 for a moment.
Great job, thank u so much. U made a humble supporter very happy today. I have been all over the net for this seemingly easy but yet so frsutratingly complicated task. I would bye you a beer if i could.
Great to hear that, happy supporting!
Nice article, thanks for your guide on these two cmdlets.
How can I generate an evtx file from the results?
I do this multiple times a day at work and it’s pretty tedious from the event viewer console.
Thanks!
Unfortunately, I don’t think there is any easy way to export results to an evtx file with PowerShell – those files have quite complicated structure. However, you can pipeline any of the cmdlet to push your results to a CSV file.
Hello.
Please, how to modify this script to show logins and logout of all users to all computers in the domain.
Provided you have a CSV file with all computers in your domain, with a column name in it, you can use the following script:
$computers = Import-Csv "location of a CSV file with the computer names"
ForEach ($computer in $computers){
$logs = get-eventlog system -ComputerName $computer.name -source Microsoft-Windows-Winlogon -After (Get-Date).AddDays(-7);
$res = @(); ForEach ($log in $logs) {if($log.instanceid -eq 7001) {$type = "Logon"} Elseif ($log.instanceid -eq 7002){$type="Logoff"} Else {Continue} $res += New-Object PSObject -Property @{Computer = $log.MachineName; Time = $log.TimeWritten; "Event" = $type; User = (New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}};
$res
}
What is the inputobject?
i have tried it using prowershell ise but am battling to bypass this point & your help will be highly appreciated, note that am a newby!
PS C:\Users\KABES> $logs = get-eventlog system -ComputerName LNM-JHB01 -source Microsoft-Windows-Winlogon -After (Get-Date).AddDays(-7);
$res = @(); ForEach ($log in $logs) {if($log.instanceid -eq 7001) {$type = “Logon”} Elseif ($log.instanceid -eq 7002){$type=”Logoff”} Else {Continue} $res += New-Object PSObject -Property @{Time = $log.TimeWritten; “Event” = $type; User = (New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}};
Export-Csv -Path C:\users\kabes\desktop\events.csv -Append
-NoTypeInformation
cmdlet Export-Csv at command pipeline position 1
Supply values for the following parameters:
InputObject:
You need to add a separator | instead of a semicolon somewhere before the Export-Csv cmdlet. Right now, nothing is pipelined to the Export-Csv cmdlet. Adding “$res |” right before Export-Csv should work.
How to use this to search the security log on the domain controller from a member server for the account creation ID 4720?
Hi Jonathan,
You can use the following syntax:
Get-EventLog security -ComputerName *your domain controller* | where {$_.InstanceId -eq 4720}
Adam….I tried copying and pasting in a couple of those scripts (I know NOTHING about PS) into my Windows PS ISE and got the following errors. Knowing NOTHING, I don’t even know how to troubleshoot!!
PS C:\Users\brackettd> $servers = Get-TransportService;
foreach ($server in $servers);
{Write-Host “Scanning the event log of: ” -NoNewLine; Write-Host $server;
Get-EventLog system -ComputerName $server -After (Get-Date).AddHours(-12) | where {($_.EntryType -Match “Error”) -or ($_.EntryType -Match “Warning”)} | ft -wrap >> “C:/$server.csv”;
Get-EventLog application -ComputerName $server -After (Get-Date).AddHours(-12) | where {($_.EntryType -Match “Error”) -or ($_.EntryType -Match “Warning”)} | ft -wrap >> “C:/$server.csv”}
At line:2 char:30
+ foreach ($server in $servers);
+ ~
Missing statement body in foreach loop.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingForeachStatement
PS C:\Users\brackettd> $logs = get-eventlog system -ComputerName -source Microsoft-Windows-Winlogon -After (Get-Date).AddDays(-7);
$res = @(); ForEach ($log in $logs) {if($log.instanceid -eq 7001) {$type = “Logon”} Elseif ($log.instanceid -eq 7002){$type=”Logoff”} Else {Continue} $res += New-Object PSObject -Property @{Time = $log.TimeWritten; “Event” = $type; User = (New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}};
$res
At line:1 char:43
+ $logs = get-eventlog system -ComputerName <name of the monitored comp …
+ ~
The '<' operator is reserved for future use.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : RedirectionNotSupported
In the first script, you should get rid of the semicolon directly after foreach ($server in $servers) and before the statement body (the part in the curly braces: {}). with an actual computer name. Make sure that the < and > operators are not left in the script.
In the second script, it seems you did not substitute
As a side note, it is always good to learn some PS basics before using any script in a live environment. It’s like doing a registry backup before making any changes in it. Just to be safe.
Interesting read. Thank you for the information.
I am working on some powershell scripts to extract various events from the logs. The issue that I am having is that I am not retrieving all of the information from the logs. One example is when I retrieve failed RDP connections the details that tell me the IP address of the attempt is not included in the CSV that is created. How do I get the query results to include the event data?
The details such as the IP address can be found in the Message event property. The problem with the message property is that it is a long string you need to filter. To get the IP, pipeline the right events to the Format-Table cmdlet. The example below will return Event ID, the time when the event was generated and the IP of the user trying to connect (found after “Source Network Address” in the event’s message):
... | FT EventId,TimeGenerated,@{l="User";e={$_.message.substring(($_.message.lastindexof('Source Network Address:')+24),15)}} -wrap -AutoSize
Very good article, this can help me more. I have never known this, even though I always work using a computer. Reading information like this is luck to find out more information that you have. Thank you for the information because this is very useful.
Well, it is NOT posting what I copy and paste in here, it insists on interpreting it and removing half the info.
PowerButtonTimestamp 131770063503423756
Hi Jon,
If you are looking for this particular PowerButtonTimestamp, the following script will return the event and save it to a CSV file:
Get-EventLog system | where Instanceid -eq 41 | where Message -like "*131770063503423756*" | select EventId,MachineName,TimeGenerated >> "your CSV file path"
EventID will be 41 for all returned events – PowerButtonTimestamp is exclusive to it.
Mind that each forced shutdown will have a different PowerButtonTimestamp, you might be better off going through all Events with Id equal to 41 and checking the PowerButtonTimeStamp for values which are other than 0. Basically, it depends on what you want to ultimately achieve.
‘131770063503423756’
This is the string i want to read out of the Event log and send to a Text File along with time and date and the EventID.
131770063503423756
How do I report out the contents of a named data entry in an event I searched for,
Dataname “a_specific_name”=1234567890
I am looking for help to find Chrome,Firefox browser logs of a users using Event logs. Is there a way I will be able to get those logs.
I don’t think that System logs have any mention of Chrome or Firefox activity. As far as I know, you can enable logging in those browsers; however, it is not a reliable way to monitor users’ online activity.
This is excellent. I am a PS noob.
How do i pipe the results to a CSV? I edit end of the line:
NTAccount]);} | Export-Csv -Path C:\Path\events.csv and it only retrieves the one oldest entry for the events specified.
Thanks!
One way would be to use the Export-Csv cmdlet with the -Append parameter. You could also save the results in a variable and pipeline its contents into a CSV file.
Hi, how to run this for many systems to be scanned?
I explained how to do this in the following section of the article:
Use PowerShell to diagnose problems on multiple computers
Instead of Get-TransportService, you can import a list of computers from a CSV file, or enter them manually into an array.