EventLog/ConvertFrom-EventLogRecord.ps1
function ConvertFrom-EventLogRecord { <# .SYNOPSIS Function to turn an EventLog Record in to a flat object. .DESCRIPTION Function to turn an EventLog Record in to a flat object. .INPUTS Inputs (if any) .OUTPUTS PSObject .NOTES Author: Carlos Perez, carlos_perez[at]darkoperator.com #> [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [System.Diagnostics.Eventing.Reader.EventLogRecord] $Event ) begin { function Process-EventDataElement { param( [Parameter(Mandatory)] [System.Xml.XmlNode]$Node, [Parameter(Mandatory)] [System.Collections.Specialized.OrderedDictionary]$EventInfo ) if ($Node.NodeType -eq 'Element') { #Write-Verbose "Processing element: $($Node.Name)" # Handle elements with Name attribute if ($Node.HasAttributes -and $null -ne $Node.Attributes['Name']) { $key = $Node.Attributes['Name'].Value $uniqueKey = $key $counter = 1 while ($EventInfo.Contains($uniqueKey)) { $uniqueKey = "${key}_$counter" $counter++ } #Write-Verbose "Adding named element '$uniqueKey' with value '$($Node.InnerText.Trim())'" $EventInfo[$uniqueKey] = $Node.InnerText.Trim() } # Handle elements without Name attribute elseif ($Node.InnerText -and $Node.ChildNodes.Count -eq 1 -and $Node.ChildNodes[0].NodeType -eq 'Text') { $key = $Node.Name $uniqueKey = $key $counter = 1 while ($EventInfo.Contains($uniqueKey)) { $uniqueKey = "${key}_$counter" $counter++ } #Write-Verbose "Adding element '$uniqueKey' with value '$($Node.InnerText.Trim())'" $EventInfo[$uniqueKey] = $Node.InnerText.Trim() } # Handle non-xmlns attributes for elements without Name attribute if ($Node.HasAttributes) { foreach ($attr in $Node.Attributes) { if ($attr.Name -notmatch '^xmlns' -and $attr.Name -ne 'Name') { $key = $attr.Name $uniqueKey = $key $counter = 1 while ($EventInfo.Contains($uniqueKey)) { $uniqueKey = "${key}_$counter" $counter++ } #Write-Verbose "Adding attribute '$uniqueKey' with value '$($attr.Value)'" $EventInfo[$uniqueKey] = $attr.Value } } } # Process child elements foreach ($childNode in $Node.ChildNodes) { if ($childNode.NodeType -eq 'Element') { Process-EventDataElement -Node $childNode -EventInfo $EventInfo } } } } } process { [xml]$evtxml = $Event.toxml() $EventInfo = New-Object System.Collections.Specialized.OrderedDictionary # Process System section $evtxml.Event.System.ChildNodes | ForEach-Object { if ($_.psobject.properties.name -match "#text") { $EventInfo[$_.name] = $_."#text" } } # Add standard system fields $EventInfo['TimeCreated'] = [datetime]$evtXml.Event.System.TimeCreated.SystemTime $EventInfo['TimeCreatedUTC'] = $evtXml.Event.System.TimeCreated.SystemTime $EventInfo['ProviderName'] = $evtXml.Event.System.Provider.Name $EventInfo['ProviderGuid'] = $evtXml.Event.System.Provider.Guid $EventInfo['ProcessID'] = $evtXml.Event.System.Execution.ProcessID $EventInfo['ThreadID'] = $evtXml.Event.System.Execution.ThreadID $EventInfo['SecurityID'] = $evtxml.Event.System.Security.UserID # Process EventData recursively if present if ($null -ne $evtxml.Event.EventData) { foreach ($userDataChild in $evtxml.Event.EventData.ChildNodes) { if ($userDataChild.NodeType -eq 'Element') { Process-EventDataElement -Node $userDataChild -EventInfo $EventInfo } } } # Process UserData recursively if present if ($null -ne $evtxml.Event.UserData) { #Write-Verbose "Processing UserData" #Write-Verbose "UserData children count: $($evtxml.Event.UserData.ChildNodes.Count)" foreach ($userDataChild in $evtxml.Event.UserData.ChildNodes) { if ($userDataChild.NodeType -eq 'Element') { Process-EventDataElement -Node $userDataChild -EventInfo $EventInfo } } } #Write-Verbose "Final EventInfo keys:" #$EventInfo.Keys | ForEach-Object { Write-Verbose $_ } # Create and output the object $Obj = New-Object psobject -Property $EventInfo $Obj | Select-Object * } end {} } |