Windows Triaging with Powershell — Part 1: Parsing Event Logs

Aditya Pratap
12 min readApr 17, 2022

This is the part 1 for Triaging a Windows system with Powershell. On a Windows machine, Event Logs play an important role in determining a timeline of various User and System activities by integrating logging information and assessing different EntryTypes comprising the logs to reveal the behavior of each activity on the machine.

There are many features available in Windows Powershell to analyze Event Logs, parse the data and create report. In this blog, we will look at some of the Powershell functions to perform these activities.

We will now look at how to parse Windows Event Logs with Powershell commands and create a HTML Report.

What is Event Logging?

As per Microsoft documentation, “Many applications record errors and events in proprietary error logs, each with their own format and user interface. Event logging provides a standard standard, centralized way for applications to record important software and hardware events. The event logging service records events from various sources and stored them in single collection called an Event Log.

Default location for Windows Event Logs

C:\Windows\System32\winevt\Logs

C:\Windows\System32\winevt\Logs

Out of these number of Event logs, major Windows Event logs are

Application Logs

  • These logs are generated by applications or programs

System Logs

  • These logs are generated by Windows system components

Security Logs

  • These logs are generated by Windows security events like login attempts or deleting objects etc.

What are different Event Types?

There are 5 types of events that are logged:

Error

  • Event indicates a significant problem such as loss of data or loss of functionality

Warning

  • Indicate a possible future problem. If an application can recover from event without loss of functionality or data, it can generally classify event as Warning event

Information

  • Describes successful operation of application, driver or service

Success Audit

  • Records an audited security access attempt that is successful

Failure Audit

  • Records an audited security access attempt that fails

How Powershell is used for parsing Log Files?

These functions are tested on Powershell version 5.1 You may check your Powershell version using command $PSVersionTable

$PSVersionTable

Before executing Powershell scripts, it’s necessary to Bypass or Unrestrict the ExecutionPolicy on Powershell by the following command

Set-ExecutionPolicy Unrestricted or Set-ExecutionPolicy Bypass

Live System Logs Parsing

On a Live Windows system, open a Powershell Windows. If possible,then open with administrative privileges. You can open the Powershell Window with admin privileges by 2 methods:

First Method

  • Press Win+R, this will open Run dialog on your screen
  • Type ‘powershell’, and press Ctrl+Shift+Enter
  • This will open the Powershell window with Admin Privileges

Second Method

  • Press Win+R, open the Run dialog on the screen
  • Type ‘powershell’ and hit Enter
  • On the powershell window, type the following command on the powershell terminal “Start-Process powershell -Verb Runas
  • This will open Powershell window again with Admin Privileges

Now, our Powershell Window is up and running with Administrative Privileges, we are good to go with parsing the Event Logs.

First task would be checking the entries in our major Event Log files. For this, on the Powershell window, type the following command

Get-EventLog -List

The output of this command will display information about the major Event Logs with some of the information as displayed in the below screenshot

Output: Get-EventLog -List

As mentioned in the screenshot, our major Event Logs are Application, HardwareEvents, InternetExplorer, KeyManagementServices, OneApp_IGCC, Security, System, WindowsPowershell.

For the following Logs, we have Entries field which shows the number of entries that are written in the particular Log. As there are no entries defined in HardwareEvents, InternetExplorer and KeyManagementService, our target would be finding the Log entries for the rest of the Log files.

Application Logs Parsing

To examine the Application Logs from Powershell, enter the following command in the Powershell window:

Get-EventLog -LogName Application | Format-Table -Wrap -AutoSize

This will display all the entries within the Application Logs on Powershell Window in Tabular format. Flags ‘Wrap’ & ‘AutoSize’ will allow to display the full content on the Powershell Windows itself.

Output: Get-EventLog -LogName Application | Format-Table -Wrap -AutoSize

Next, we can display the entries with specific EntryType. For example, if we want to display only the Application Logs with “Information” EntryType, type the following command in Powershell window

Get-EventLog -LogName Application -EntryType Information | Format-Table -Wrap -AutoSize

This command will display only the Information EntryType within the Application Logs. The below screenshot displays the output of the above command.

Output: Get-EventLog -LogName Application -EntryType Information | Format-Table -Wrap -AutoSize

Using the EventViewer, I discovered that there are only 3 EntryTypes in Application Logs i.e. “Information”,”Warning” & “Error”. To automate this process, we can use a Powershell script to perform all these actions at once.

Save the script in desired directory after copying the commands in Powershell ISE

Write-Host “[+] Collecting Application Logs” -ForegroundColor Yellow
Write-Host “[+] Collecting Application Information Logs” -ForegroundColor Red
Get-EventLog -LogName Application -EntryType Information | Format-Table -Wrap -AutoSize
Write-Host “[+] Done” -ForegroundColor Green
Write-Host “[+] Collecting Application Warning Logs” -ForegroundColor Red
Get-EventLog -LogName Application -EntryType Warning | Format-Table -Wrap -AutoSize
Write-Host “[+] Done” -ForegroundColor Green
Write-Host “[+] Collecting Application Error Logs” -ForegroundColor Red
Get-EventLog -LogName Application -EntryType Warning | Format-Table -Wrap -AutoSize
Write-Host “[+] Done” -ForegroundColor Green

Output for the above script in Powershell ISE

Security Logs Parsing

In order to parse Security logs, the command would remain the same as it was for parsing Application logs.

Note: Parsing Security Logs would require Administrative Privileges otherwise you would see access denied error

Paste the following command in Powershell window

Get-EventLog -LogName Security | Format-Table -Wrap -AutoSize

Output: Get-EventLog -LogName Security | Format-Table -Wrap -AutoSize

In Security Logs you can find two entry types, “SuccessAudit” and “FailureAudit”. Paste the following line of codes in your Powershell ISE for capturing the System Logs.

Write-Host “[+] Collecting Security Logs” -ForegroundColor Yellow
Write-Host “[+] Collecting Security AuditSuccess Logs” -ForegroundColor Red
Get-EventLog -LogName Security -EntryType SuccessAudit | Format-Table -Wrap -AutoSize
Write-Host “[+] Done” -ForegroundColor Green
Write-Host “[+] Collecting Security AuditFailure Logs” -ForegroundColor Red
Get-EventLog -LogName Security -EntryType FailureAudit | Format-Table -Wrap -AutoSize
Write-Host “[+] Done” -ForegroundColor Green

Output for the above script in Powershell ISE

System Logs Parsing

EntryType for Application and System Logs are same. System Logs comprises of three EntryTypes “Information,Warning & Error”.

Because the syntax of System Logs is the same as above two, you can paste the following line of codes in Powershell ISE to generate the System Logs based on EventType.

Write-Host “[+] Collecting System Logs” -ForegroundColor Yellow
Write-Host “[+] Collecting System Information Logs” -ForegroundColor Red
Get-EventLog -LogName System -EntryType Information | Format-Table -Wrap -AutoSize
Write-Host “[+] Done” -ForegroundColor Green
Write-Host “[+] Collecting System Warning Logs” -ForegroundColor Red
Get-EventLog -LogName System -EntryType Warning| Format-Table -Wrap -AutoSize
Write-Host “[+] Done” -ForegroundColor Green
Write-Host “[+] Collecting System Error Logs” -ForegroundColor Red
Get-EventLog -LogName System -EntryType Error | Format-Table -Wrap -AutoSize
Write-Host “[+] Done” -ForegroundColor Green

Output for the System Logs lines of code in Powershell ISE

What would be Advanced Logs Parsing with Powershell?

So far, we have discussed about parsing the major EventLogs of the Windows system. But as mentioned in the screenshot of the \winevt\Logs directory, there is a list of Logs generated by Windows system. How can we parse those Log files?

A better idea would be copying those .evtx files in your External drive and parse those .evtx files in your Lab system. However, wouldn’t copying these .evtx files tamper with the integrity of these files?

As a result, Powershell helps us once again by enabling us to create Hashes of all the .evtx files before copying them. And after copying these files, we can verify the integrity of these files.

You can create Hashes of all the files in one go by pasting the code in the Powershell ISE window, and you need to wait for a while since there are a large number of files so it will take a minute or else depends upon the system computation power.

Get-ChildItem ‘C:\Windows\System32\winevt\Logs\’ -File -Recurse -PipelineVariable File | ForEach-Object{
$stream = try {
[IO.FileStream]::new( $File.FullName, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::Read )
}
catch {
[IO.FileStream]::new( $File.FullName, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::ReadWrite )
}

if( $stream ) {
try {
Get-FileHash -InputStream $stream -Algorithm SHA1 |
Select-Object Algorithm, Hash, @{ Name = ‘Path’; Expression = { $File.Fullname } } | Format-Table -Wrap -AutoSize >> <Path_To_Hash_File.txt>
}
finally {
$stream.Close()
}
}
}

To understand the code, you may refer to the below provided link:

https://stackoverflow.com/questions/58466227/get-filehash-unable-to-read-the-file

Output of the generated Hash txt file

Once our hashes of all the .evtx files from the /winevt/Logs directory are ready, we can recursively copy each of the files from the directory to the specified path. For that, paste the following code in Powershell ISE

Write-Host “Enter Path to save Log Files: “ -ForegroundColor Yellow
Write-Host “Path Syntax: Drive:\Folder\” -ForegroundColor Cyan
$path= Read-Host

ls -Path C:\Windows\System32\winevt\Logs\ -File -Recurse | Where-Object {$_.Extension -eq “.evtx”} | ForEach-Object {
cp $_.FullName -Destination $path
}

Note: Make sure the drive is empty and specify directory in proper format where you want to save the Log files as this is going to feed 100+ .evtx files in that directory.

With use of above command, we have stored all the Log files inside our defined directory. As an investigator, we are not going to manually check all the files and examine the logs. To ease with this task, Powershell provides us with recursive function to convert each of .evtx file into a HTML file and at last, we can create an Index Page for all the log files.

But, we can view the content of any .evtx file using the following command

Get-WinEvent -Path <Name_of_evtx_file.evtx>

Now lets convert all the .evtx files to .html files. For this, paste the following lines of code in Powershell ISE.

Write-Host “[+] Converting .evtx to .html” -ForegroundColor DarkYellow
Write-Host “”

Write-Host “[+] Enter path for the copied Logs folder (For eg, C:\..\..\)”
$path= Read-Host
Write-Host “”
Write-Host “[+] Enter path to save the .html files (For eg, C:\..\..\)”
$outputpath= Read-Host
Write-Host “”

ls -Path $path -File | Where-Object {$_.Extension -eq “.evtx”} | ForEach-Object {
Write-Host “[+] Converting file: $_” -ForegroundColor Red
$name= $_.Name
$file= “$_.Name”+”_log.html”
$outputfile= $outputpath+$file
$log2html=(Get-WinEvent -Path $_.PsPath | ConvertTo-Html | Out-File -FilePath $outputfile)
}
Write-Host “[+] Done” -ForegroundColor Green

Note: Do not worry if you see any error while converting evtx to html. The error is generated for those files which do not contain any Log entry

After running this in Powershell ISE, the output directory must have the parsed HTML files of the .evtx files as displayed in the below screenshot.

Output for the above lines of code

Where’s the Report?

Powershell provides us with the capability to save our output in HTML, CSV or XML format. The major focus of this blog will be to create a HTML report with custom CSS, but we will also discuss how to create a CSV file out of the output.

Paste the following command within the Powershell window to generate a CSV file of the output.

Get-EventLog -LogName Application -EntryType Information | Select-Object EventID,MachineName,Index,EntryType,Message | Export-Csv -Path <Path.csv> -NoTypeInformation -NoClobber

This will create a CSV file for the Application logs with EntryType Information. Output of the CSV file is displayed below.

Screenshot of the generated CSV file

Similarly, we can create CSV for any type of Log when running any of the above command and piping with Export-Csv cmdlet.

Moving further, now we have to create Index page for our large number of parsed HTML files. The Index page would tell about the FileName, FileSize and Location of the file with link to open the file from the Index page itself.

Before creating the Index page, we have to rename some of the html files cause the file name consists of special character like “%4” which when added to html file as “Location Link”, it is changed to Unicode character which will create error in our Index Page. So, to remove this “%4”, run the following code in Powershell

Write-Host “Enter path for the parsed HTML Logs directory: “
$path= Read-Host
Get-ChildItem $path -Recurse | Where-Object {$_.Extension -eq ‘.html’} |
Where-Object {$_.Name -match ‘%4’} |
Rename-Item -NewName {$_.Name -replace ‘%4’,’’}

As the special character is removed from our parsed html files name, now we are good to go to create our Index page. Paste the below code in Powershell ISE to generate the Index page

$header = @”
<style>
body{
background-color: #ffffff;
}
h1 {
font-family: Verdana, Helvetica, sans-serif;
color: black;
font-size: 28px;
}
h2 {
font-family: Verdana, Helvetica, sans-serif;
color: #000099;
}
a{
font-family: Verdana, Helvetica, sans-serif;
color: #000099;
}
td{
font-family: “Verdana”, “Helvetica Neue”, Helvetica, Arial, sans-sertd;
color: rgb(17,1,1);
}
h4{
font-family: “Open Sans”, “Helvetica Neue”, Helvetica, Arial, sans-serif;
color: rgb(17, 1, 1);
font-size: small;
}
iframe{
border:none;
width:100%;
height:100%;
display:block;
}
.marginauto {
margin: 10px auto 20px;
display: block;
}
p{
font-family: Verdana, Helvetica, sans-serif;
color: black;
}
.center {
display: block;
margin-left: auto;
margin-right: auto;
width: 50%;
}
.styled-table{
border-collapse: collapse;
margin: 25px 0;
font-size: 0.9em;
font-family: Verdana, Geneva, Tahoma, sans-serif;
min-width: 400px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
}
.styled-table thead tr {
background-color: #009879;
color: #ffffff;
text-align: left;
}
.styled-table th,
.styled-table td {
padding: 12px 15px;
}
.styled-table tbody tr {
border-bottom: 1px solid #dddddd;
}

.styled-table tbody tr:nth-of-type(even) {
background-color: #f3f3f3;
}

.styled-table tbody tr:last-of-type {
border-bottom: 2px solid #009879;
}
</style>
“@

function Reporter($File,$location,$length){
$heading= “
<br>
<div>
<h2>File Name: $File</h2>
<h3>File Length: $length</h3>
<h4>File Location: $location</h4>
<a href=’$location’>Click to Open</a>
</div>
<br>

$Global:report+=($heading)
}

function Indexer(){
Get-ChildItem $path -File -Recurse -PipelineVariable File | Where-Object {$_.Extension -eq ‘.html’} | ForEach-Object{
$stream= try{
[IO.FileStream]::new($File.FullName,[IO.FileMode]::Open,[IO.FileAccess]::Read,[IO.FileShare]::Read)
}
catch{
[IO.FileStream]::new($File.FullName,[IO.FileMode]::Open,[IO.FileAccess]::Read,[IO.FileShare]::ReadWrite)
}
if($stream){
try{
$location= $File.FullName
$length= $File.Length
Reporter $File $location $length
}
finally{
$stream.Close()
}
}
}
}

function Main(){
Write-Host “Write Path for the Saved Logs HTML Files (Format: C:\..\)”
$Global:path= Read-Host
Write-Host “Write Path for Index Page: “
$indexpath= Read-Host
Indexer
$outputreport= $indexpath+”Logs_Index.html”
ConvertTo-Html -Head $header -Body $report -Title LOGS_INDEX | Out-File $outputreport
}

Main
$Global:report=Reporter @()

Output for the above code would result in creating an Index page, with Name of the HTML file, Size of the HTML file and Location of the HTML file to directly open the file from the Index page. The output should result as displayed in the below screenshot

Index Page for HTML Files

As seen in the above screenshot, the index page would contain the FileName, FileLength, FileLocation and Link to open the file.

Important thing to mention is there would be some files that won’t open as there‘s no entry inside them. The reason for including all the .evtx files within this Index Page is that for different users there will be different kinds of entries, so as investigators, we cannot ignore any single Log file.

So, if you go to Index Page and click on link for Application.evtx_log.html, this would open the Application Logs for the system.

Any viewer can modify the code as per the usability and can use this in their investigation procedures.

Note: Whenever you type the directory name, always end the directory with ‘\’, otherwise the output path may differ. For e.g, if you want to save your files in any folder within D: directory, type ‘D:\directory_name\’

Conclusion

As mentioned in the beginning, Windows Event Logs are one of the most important artifacts when investigating any Windows system. A thorough investigation should not restrict itself to just the major Events like Application, Security and System, but should also examine other Event Logs present in the system. These other Log files might contain some useful information that will assist the investigator in their analysis.

As part of the Windows Triaging with Powershell, the next step is to gather the important artifacts from Live Windows System with Powershell and to generate a report along with all the collected artifacts’ hashes.

Until then, any comments or suggestions on this would be greatly appreciated to create some new content for the readers.

--

--