Skip to content

Instantly share code, notes, and snippets.

@kiwi-cam
Last active August 21, 2018 20:37
Show Gist options
  • Save kiwi-cam/1f59ca1f309c480d6c9608776f5649a8 to your computer and use it in GitHub Desktop.
Save kiwi-cam/1f59ca1f309c480d6c9608776f5649a8 to your computer and use it in GitHub Desktop.
This script uses LogParser 2.2 from Microsoft to to build a list of logon events that match some predefined searches. Supply a path to EventPath which contains the evtx files you'd like to scan. You'll want to grab Security.evtx from C:\Windows\System32\WinEvt\Logs on all servers to scan, or use this script to automate grabbing them: https://gis…
<#
.Synopsis
Crawls evtx files and gathers events based on predefined searches.
.DESCRIPTION
This script uses LogParser 2.2 from Microsoft to to build a list of logon events.
Supply a path to EventPath which contains the evtx files you'd like to scan. You'll want to grab Security.evtx from
C:\Windows\System32\WinEvt\Logs on all servers to scan.
.PARAMETER LogParserLocation
The full path to logparser.exe
Default: "C:\Program Files (x86)\Log Parser 2.2\LogParser.exe"
.PARAMETER EventPath
Required - The path to a folder containing .evtx files you'd like to parse.
.PARAMETER Start
Results can be filtered to only include events after a supplied Date/Time. This is a string which Powershell must be able
to cast to a valid date and time.
.PARAMETER Search
Type of events to find. (OldNTLM - searches for LM and NTLMv1, PTH - searches for potential Pass-The-Hash,
FailedLogon - finds failed logon attempts)
.PARAMETER Detailed
If specified, event details are returned rather than a count. Only valid for OldNTLM and FailedLogon searches
.EXAMPLE
./Get-LogonEvents.ps1 E:\LogFiles\
.EXAMPLE
./Get-LogonEvents.ps1 -EventPath E:\LogFiles\ -LogParserLocation "C:\My Applications\Log Parser 2.2\LogParser.exe"
.EXAMPLE
$Output = .\Get-LogonEvents.ps1 -EventPath E:\LogFiles -Start "1/8/2018 15:00" -Detailed
.EXAMPLE
.\Get-LogonEvents.ps1 -EventPath E:\LogFiles -Start "1/8/2018 15:00" -Search PTH
.EXAMPLE
.\Get-LogonEvents.ps1 -EventPath E:\LogFiles -Start "1/8/2018 15:00" -Search FailedLogon -Detailed
.NOTES
Version: 1.2
Author: Cameron McConnochie
Creation Date: 6 Aug 2018
Purpose/Change: Changed LogParser to output XML to improve script's parsing of the results.
Added predefined searches and renamed script to suit new functionality
Updated Returned object to DataTable to allow datatypes and sorting
Version: 1.1
Author: Cameron McConnochie
Creation Date: 2 Aug 2018
Purpose/Change: Add Date filtering to assist in diag
Added Detailed option to output indivdual events rather than the count
Added Progress bar
Version: 1.0
Author: Cameron McConnochie
Creation Date: 1 Aug 2018
Purpose/Change: Initial script development
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True,Position=1)]
[ValidateScript({
if(-Not ($_ | Test-Path -PathType Container) ){
throw "The Path argument must be a folder."
}
return $true
})]
[System.IO.FileInfo]$EventPath,
[Parameter(Mandatory=$False)]
[ValidateScript({
if(-Not ($_ | Test-Path -PathType Leaf) ){
throw "LogParser.exe not found! Please install it, or provide the LogParserLocation parameter."
}
return $true
})]
[System.IO.FileInfo]$LogParserLocation = "C:\Program Files (x86)\Log Parser 2.2\LogParser.exe",
[Parameter(Mandatory=$False)]
[ValidateScript({
if(-Not (Get-Date($_))){
throw "Start cannot be after the current date."
}
return $true
})]
[String]$Start,
[Parameter(Mandatory=$False)]
[ValidateSet("OldNTLM","PTH","FailedLogon")]
[String]$Search = "OldNTLM",
[Parameter(Mandatory=$False)]
[Switch]$Detailed
)
#Error checking
if(-not (Test-Path $LogParserLocation)){
throw "LogParser.exe not found! Please install it, or provide the LogParserLocation parameter."
}
$EVTFiles = Get-ChildItem -Path $EventPath -Filter *.evtx
if($EVTFiles.Length -lt 1){
throw "No .evtx files found in $($EventPath)! Please check the EventPath parameter."
}
IF($Detailed -and ($Search -match "PTH")){
Write-Host "Detailed parameter ignored, not supported in this search." -ForegroundColor Magenta
}
#Create a Collection for the results
$LPRecords = New-Object system.Data.DataTable
#Build the date Query
IF ($Start -ne $null -and $Start -ne ""){
$DateQuery = " AND TimeGenerated > '$(Get-Date $Start -Format 'yyyy-MM-dd HH:mm:ss')'"
}else{
$DateQuery = ""
}
$count = 0
#iterate through the files
Write-Progress -Activity "Querying events from LogFiles..." -PercentComplete 0
foreach ($file in $EVTFiles){
Write-Progress -Activity "Querying events from LogFiles..." -Status "Parsing file: $($file.FullName) ($($count+1) of $($EVTFiles.Length))..." -PercentComplete (($count/$EVTFiles.Length)*100) -CurrentOperation "Running Query..."
Write-Host "Parsing file: $($file.FullName)..." -NoNewline
#Build the Query for LogParser
If ($Search -match "OldNTLM"){
If($Detailed){
$Query = "`"SELECT TimeGenerated, EXTRACT_TOKEN(Strings, 5, '|') as Username, EXTRACT_TOKEN(Strings, 6, '|') as Domain, `
EXTRACT_TOKEN(Strings, 8, '|') as LogonType, EXTRACT_TOKEN(strings, 9, '|') AS AuthPackage, `
EXTRACT_TOKEN(Strings, 11, '|') AS Workstation, EXTRACT_TOKEN(Strings, 14, '|') AS LmPackageName, `
EXTRACT_TOKEN(Strings, 17, '|') AS ProcessName, EXTRACT_TOKEN(Strings, 18, '|') AS SourceIP, ComputerName `
FROM '$($file.FullName)' `
WHERE EventID = 4624 AND Username NOT IN ('SYSTEM'; 'ANONYMOUS LOGON'; 'LOCAL SERVICE'; 'NETWORK SERVICE') `
AND Domain NOT IN ('NT AUTHORITY') AND AuthPackage LIKE '%NtLmSsp%' AND Username NOT LIKE '%$' `
AND LmPackageName NOT LIKE '%NTLM V2%' $($DateQuery)`""
}else{
$Query = "`"SELECT COUNT(*) AS Count, EXTRACT_TOKEN(Strings, 5, '|') as Username, EXTRACT_TOKEN(Strings, 6, '|') as Domain, `
EXTRACT_TOKEN(Strings, 8, '|') as LogonType, EXTRACT_TOKEN(strings, 9, '|') AS AuthPackage, `
EXTRACT_TOKEN(Strings, 11, '|') AS Workstation, EXTRACT_TOKEN(Strings, 14, '|') AS LmPackageName, `
EXTRACT_TOKEN(Strings, 17, '|') AS ProcessName, EXTRACT_TOKEN(Strings, 18, '|') AS SourceIP, ComputerName `
FROM '$($file.FullName)' `
WHERE EventID = 4624 AND Username NOT IN ('SYSTEM'; 'ANONYMOUS LOGON'; 'LOCAL SERVICE'; 'NETWORK SERVICE') `
AND Domain NOT IN ('NT AUTHORITY') AND AuthPackage LIKE '%NtLmSsp%' AND Username NOT LIKE '%$' `
AND LmPackageName NOT LIKE '%NTLM V2%' $($DateQuery)`
GROUP BY Username, Domain, LogonType, AuthPackage, Workstation, LmPackageName, ProcessName, SourceIP, ComputerName`""
}
}elseif ($Search -match "PTH") {
$Query = "`"SELECT TimeGenerated AS Date, EXTRACT_TOKEN(Strings, 5, '|') as Username, EXTRACT_TOKEN(Strings, 6, '|') as Domain, `
EXTRACT_TOKEN(Strings, 8, '|') as LogonType, EXTRACT_TOKEN(strings, 10, '|') AS AuthPackage, `
EXTRACT_TOKEN(Strings, 11, '|') AS Workstation, EXTRACT_TOKEN(Strings, 17, '|') AS ProcessName, `
EXTRACT_TOKEN(Strings, 18, '|') AS SourceIP, ComputerName `
FROM '$($file.FullName)' `
WHERE EventID = 4624 AND Username NOT IN ('SYSTEM'; 'ANONYMOUS LOGON'; 'LOCAL SERVICE'; 'NETWORK SERVICE') `
AND Domain NOT IN ('NT AUTHORITY') AND AuthPackage LIKE '%NtLmSsp%' AND Username NOT LIKE '%$' $($DateQuery)`""
}elseIf ($Search -match "FailedLogon"){
If($Detailed){
$Query = "`"SELECT TimeGenerated AS Date, EXTRACT_TOKEN(Strings, 5, '|') as Username, EXTRACT_TOKEN(Strings, 6, '|') as Domain, `
EXTRACT_TOKEN(Strings, 10, '|') as LogonType,EXTRACT_TOKEN(strings, 11, '|') AS AuthPackage, `
EXTRACT_TOKEN(Strings, 13, '|') AS Workstation, EXTRACT_TOKEN(Strings, 19, '|') AS SourceIP, ComputerName `
FROM '$($file.FullName)' `
WHERE EventID = 4625 AND Username NOT IN ('SYSTEM'; 'ANONYMOUS LOGON'; 'LOCAL SERVICE'; 'NETWORK SERVICE') `
AND Domain NOT IN ('NT AUTHORITY') AND Username NOT LIKE '%$' $($DateQuery)`""
}else{
$Query = "`"SELECT COUNT(*) AS Count, EXTRACT_TOKEN(Strings, 5, '|') as Username, EXTRACT_TOKEN(Strings, 6, '|') as Domain, `
EXTRACT_TOKEN(Strings, 10, '|') as LogonType, EXTRACT_TOKEN(strings, 11, '|') AS AuthPackage, `
EXTRACT_TOKEN(Strings, 13, '|') AS Workstation, EXTRACT_TOKEN(Strings, 19, '|') AS SourceIP, ComputerName `
FROM '$($file.FullName)' `
WHERE EventID = 4625 AND Username NOT IN ('SYSTEM'; 'ANONYMOUS LOGON'; 'LOCAL SERVICE'; 'NETWORK SERVICE') `
AND Domain NOT IN ('NT AUTHORITY') AND Username NOT LIKE '%$' $($DateQuery) `
GROUP BY Username, Domain, LogonType, AuthPackage, Workstation, SourceIP, ComputerName`""
}
}
#Run LogParser with our Query
try {
[XML]$LPRecordSet = & "$($LogParserLocation)" -q:ON -stats:OFF -i:EVT -o:XML "$($Query)"
} catch {
Write-Warning "Could not run LogParser query on $($file.FullName)"
continue
}
Write-Progress -Activity "Querying events from LogFiles..." -Status "Parsing file: $($file.FullName) ($($count) of $($EVTFiles.Length))..." -PercentComplete (($count/$EVTFiles.Length)*95) -CurrentOperation "Gathering Events..."
if ($LPRecordSet.ROOT.ROW.Count -gt 0){
Write-Host " ($($LPRecordSet.ROOT.ROW.Count) found)" -NoNewline -ForegroundColor Magenta
}
#All Records are stored as ROW attributes under ROOT
foreach ($row in $LPRecordSet.ROOT.ROW) {
#First run, now we have some results, build the columns.
If ($LPRecords.Columns.Count -lt 1){
foreach ($Property in $row.ChildNodes){
If($Property.Name -match "Count"){
$column = New-Object System.Data.DataColumn $Property.Name,([int])
}else{
$column = New-Object System.Data.DataColumn $Property.Name,([string])
}
$LPRecords.Columns.Add($Column)
}
}
#Iterate through the Attributes of the current ROW
$Temp = $LPRecords.NewRow()
foreach ($Property in $row.ChildNodes){
$Temp[$Property.Name] = $Property.InnerText.Trim()
}
$LPRecords.Rows.Add($Temp)
}
Write-Host " done!" -ForegroundColor Green
$count++
}
Write-Host "" -ForegroundColor Green
#Check if anything was returned
If ($LPRecords.Rows.Count -lt 1) {
Write-Host "No events found" -ForegroundColor Cyan
}else{
Write-Host "$($LPRecords.Rows.Count) events found" -ForegroundColor Cyan
Write-Progress -Activity "Querying events from LogFiles..." -Status "Sorting Results..." -PercentComplete 95
$LPRecords = $LPRecords | Sort-Object -Property $LPRecords.Columns[0].ColumnName
}
Write-Progress -Activity "Querying events from LogFiles..." -Status "Complete" -PercentComplete 100
#Return the resulting output
Return $LPRecords
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment