Powershell and Security Event Logs

Mabrito

Supreme [H]ardness
Joined
Dec 24, 2004
Messages
7,004
I am working on a Powershell script that will go through the Windows Security Logs and parse the the user logon events, so I can keep an audit trail of who is logging into each of the servers.

I have the Powershell script working to the point where its getting each individual unique logon event and exporting it to a CSV. The fields im exporting are RecordID, ID, TaskDisplayName, MachineName, TimeCreated, Message.

The issue I am having is, by default, the export to CSV takes the whole Event Log entry "Message" field and saves it to the CSV. There is a ALOT of text in here and all I really want is the user who logged on. If you view the Event Log in XML, this field is the "TargerUserName".

Is there a way to add an additional field to the CSV export and get the TargetUserName field extracted from the "Message" field? Once you run _Get-WinEvent, the XML format is gone and can't query those attributes.

Here is the code I have so far:
Code:
$EventLogQuery =@"
<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security"> 
	 *[EventData[Data[@Name='LogonType'] and (Data ='10')]] 
	 and
	 *[EventData[Data[@Name='LogonGuid'] != '{00000000-0000-0000-0000-000000000000}']]
	 and
                 *[System[(EventID='4624')]] 
               </Select>
  </Query>
</QueryList>
"@

Get-WinEvent -FilterXml $EventLogQuery | Select RecordId, Id, TaskDisplayName, MachineName, TimeCreated, Message | export-csv "C:\EventLogs\LogonAuditLog.csv"
 
Not the best way as I'm sure you could use XPath or something on the eventXML to query just what you wanted, but I just looped through all the fields and added the one I wanted.
Using the same $EventLogQuery you already have defined -
Code:
$allEvents = Get-WinEvent -FilterXml $EventLogQuery 
ForEach ($Event in $allEvents) {            
    # Convert the event to XML            
    $eventXML = [xml]$Event.ToXml()            
    # Iterate through each one of the XML message properties            
    For ($i=0; $i -lt $eventXML.Event.EventData.Data.Count; $i++) {
	if($eventXML.Event.EventData.Data[$i].Name -eq 'TargetUserName') 
	{              
	  Add-Member -InputObject $Event -MemberType NoteProperty -Force -Name 'User' -Value $eventXML.Event.EventData.Data[$i].'#text'
	}
    }            
}  

$allEvents | Select RecordId, Id, TaskDisplayName, MachineName, TimeCreated, User | export-csv "C:\EventLogs\LogonAuditLog.csv"
 
You can call .ToXml() on the event and pull information from there (e.g. Event.System.EventRecordId, Event.System.EventId, and for username, you can use Event.EventData.Data.Where({$_.Name -eq "TargetUserName"}).'#text')
 
Not the best way as I'm sure you could use XPath or something on the eventXML to query just what you wanted, but I just looped through all the fields and added the one I wanted.
Using the same $EventLogQuery you already have defined -
Code:
$allEvents = Get-WinEvent -FilterXml $EventLogQuery 
ForEach ($Event in $allEvents) {            
    # Convert the event to XML            
    $eventXML = [xml]$Event.ToXml()            
    # Iterate through each one of the XML message properties            
    For ($i=0; $i -lt $eventXML.Event.EventData.Data.Count; $i++) {
	if($eventXML.Event.EventData.Data[$i].Name -eq 'TargetUserName') 
	{              
	  Add-Member -InputObject $Event -MemberType NoteProperty -Force -Name 'User' -Value $eventXML.Event.EventData.Data[$i].'#text'
	}
    }            
}  

$allEvents | Select RecordId, Id, TaskDisplayName, MachineName, TimeCreated, User | export-csv "C:\EventLogs\LogonAuditLog.csv"

I added this after my EventLogQuery filter statement and it works!

Confused on one part though:

What is statement "-Value $eventXML.Event.EventData.Data[$i].'#text'" saying? I get the IF statement, but how is it getting the value of 'TargetUserName' ?

Slowly learning the ropes of PowerShell...so just trying to understand this statement in its entirely!
 
I added this after my EventLogQuery filter statement and it works!

Confused on one part though:

What is statement "-Value $eventXML.Event.EventData.Data[$i].'#text'" saying? I get the IF statement, but how is it getting the value of 'TargetUserName' ?

Slowly learning the ropes of PowerShell...so just trying to understand this statement in its entirely!

If you look at Event.EventData, you will see that Data is an array of objects. Those objects each have two properties, "Name" and "#text". So that retrieves the i-th Data object and returns its text property, which has quotes around it because normally the "#" starts a comment.
 
The IF statement is checking the Name property. It's only doing the #text part when I already know I'm on the right object that has TargetUserName for the name property. Once I have that, the line inside the IF statement is putting the text for the value of that field I'm adding.

To break this down:
Code:
Add-Member -InputObject $Event -MemberType NoteProperty -Force -Name 'User' -Value $eventXML.Event.EventData.Data[$i].'#text'
Add-Member -InputObject $Event is adding a new field(member) to our #Event object
-MemberType NoteProperty is making it a text field
-Name 'User' is telling it to add the field with a name of 'User'.
-Value $eventXML.Event.EventData.Data[$i].'#text' is saying that we want the Value of this field to be whatever is $eventXML.Event.EventData.Data[$i].'#text'. We already know we're on the right field(TargetUserName) because we checked it with the IF statement.

We could do it cleaner than looping through all the fields using the .Where() that Tawnos mentioned, but I don't have a later version of powershell on this specific machine I'm on right now so I couldn't test it out, but you should be able to get rid of the inner loop if you use that one and have later versions of powershell.
 
Back
Top