PowerShell Get-WinEvent Data Query - powershell

Trying to write a script to retrieve all the details for events being triggered for a certain issue.
The events that have been seen within the event viewer have no Event ID's etc. that would help to filter the results.
The only data I can potential use is contained within the EventData section with "Married"
Get-WinEvent #{LogName='Application';Level=2} | Where {$_.ProviderName -eq 'BizTalk Server' -and $_.Message -contains 'Marri'}
I'm not sure if the $_.Message is looking at the EventData section.. any advice?

So this isn't a fully working solution but it should give you an output of data that provides you with insight on what to use.
I can't really do it for you completely because i don't have the data to test with.
$events = Get-WinEvent -FilterHashTable #{LogName = "Application";Level=2} -MaxEvents 50 | where {$_.Message -like '*'}
foreach($event in $events){
"-"*150
$eventXML = [xml]$event.ToXml()
#if there is data in the XML
if($eventXML.Event.EventData.data -like '*Marri*'){
$event.Message
$event | gm
write-host $event
write-host $eventXML.Event.EventData.data -ForegroundColor Green
}
"-"*150
}

I don't really understand what you mean with the count /date time part.
you could display the time and provider so:
$events = Get-WinEvent -FilterHashTable #{LogName = "Application";Level=2} -MaxEvents 50 |
where {$_.Message -like '*'}
foreach($event in $events){
"-"*50
$event.TimeCreated
$event.ProviderName
$event.Message
"-"*50
}

I don't know where in eventdata "married" is, but in powershell 6 you can do something like this and use -filterhashtable on eventdata named data fields. Providername can be in the hashtable as well.
Get-WinEvent #{LogName='Application'; Level=2;
providername='biztalk server'; status='married'}
An example that works for me:
get-winevent #{ logname = 'application'; param2 = 'suppressduplicateduration' }

Related

How to replace Filter Origin in this PowerShell command with Windows Firewall's display name?

Get-WinEvent -FilterHashtable #{ LogName="Security"; Id=5152; } | ? { $_.Message -like "*Outbound*" -and -not($_.message -like "*ICMP*")} | select Message | ft -wrap
Found that in here, after running it, the results look like this:
filter origin has this ID which is Firewall's unique name but I want to see a more user friendly name so I can understand immediately which Firewall rule, based on its display name that I set, blocked this connection.
Update:
I want to do something like this. but it doesn't work like this and I need help fixing it. basically, I want to keep the same output format that the original script shows and only replace things like this {a42a62ec-83d9-4ab5-9d54-4dbd20cfab17} with their display name.
$data = (Get-WinEvent -FilterHashtable #{ LogName="Security"; Id=5152; } |
? { $_.Message -like "*Outbound*" -and -not($_.message -like "*ICMP*")}).message
$data -replace "(?<=Filter Origin:[^{]+){.+?}",{(Get-NetFirewallRule -Name $Matches[0]).DisplayName}
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comparison_operators?view=powershell-7.2#replacement-with-a-script-block
You can turn events into xml and access each field seperately. I don't have your exact event type.
$a = Get-WinEvent #{ LogName='Security' } -maxevents 1
$xml = [xml]$a.toxml()
$xml.event.eventdata.data
Name #text
---- -----
SubjectUserSid S-1-5-19
SubjectUserName LOCAL SERVICE
SubjectDomainName NT AUTHORITY
SubjectLogonId 0x3e5
PreviousTime 2023-01-03T14:40:58.3894712Z
NewTime 2023-01-03T14:40:58.3975397Z
ProcessId 0x59c
ProcessName C:\Windows\System32\svchost.exe
$xml.event.eventdata.data | ? name -eq processname | % '#text'
C:\Windows\System32\svchost.exe
Get-WinEvent #{ LogName='Security' } | % { $xml = [xml]$_.toxml()
$xml.event.eventdata.data | ? name -eq 'processname' | % '#text' }
Did a quick google search and saw this documentation on troubleshooting firewalls, and it points to Get-NetFireWallRule being able to get the display name from the ID. That said, you can use some handy RegEx of (?<=Filter Origin:[^{]+){.+?} to get the unique ID and query its friendly name:
Get-WinEvent -FilterHashtable #{ LogName="Security"; Id=5152; } |
? { $_.Message -like "*Outbound*" -and $_.Message -notlike "*ICMP*" } |
Select TimeCreated, #{
Name = 'Msg'
Expression = {
if ($_.Message -match ($pattern = '(?<=Filter Origin:[^{]+){.+?}'))
{
$_.Message -replace $pattern, (Get-NetFirewallRule -Name $Matches[0]).DisplayName
}
else
{
$_.Message
}
}
} | Ft -Wrap
Placing it inside an if statement allows it to leave the message alone if no match was found for patterns that may be the unique ID. See RegEx101 for more info on the pattern itself.

(PowerShell) How do I filter usernames with Get-EventLog

I'm working on a Powershell script to get all users who have logged in/out of a server in the past 7 days, where their name is not like "*-organization". The below works, but no matter what I try I'm not able to filter names
$logs = get-eventlog system -ComputerName $env: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
I've tried adding this line in various places and ways, but no matter what I can't get it to filter. It either fails and tells me my operator must have a property and value, or it runs fine and ignores any username filtering.
| Where-Object $_.User -notlike "*-organization"
Is it even possible to filter the login username with this method? If so, what am I doing wrong? If it's not possible, is there another way I can get what I need?
There would have to be a property named 'user' for that to work. Get-eventlog is actually obsolete now, and replaced by get-winevent. Unfortunately, you have to get into the xml to filter by usersid. I've included a time filter.
$a = get-winevent #{logname='system';
providername='Microsoft-Windows-Winlogon'} -MaxEvents 1
$e = $a.ToXml() -as 'xml'
$e.event.EventData
Data
----
{TSId, UserSid}
get-winevent #{logname='system';providername='Microsoft-Windows-Winlogon';
data='S-2-6-31-1528843147-473324174-2919417754-2001';starttime=(Get-Date).AddDays(-7);
id=7001,7002}
In powershell 7 you can refer to the eventdata named data fields directly:
get-winevent #{logname='system';providername='Microsoft-Windows-Winlogon';
usersid='S-2-6-31-1528843147-473324174-2919417754-2001'}
The get-winevent docs say you can use "userid" in the filterhashtable, but I can't get that to work.
EDIT: Actually this works. But without limiting it too much, at least for me.
get-winevent #{logname='system';userid='js2010'}
get-winevent #{providername='Microsoft-Windows-Winlogon';userid='js2010'}
You can do this with the -FilterXPath parameter like below:
$filter = "(*[System/EventID=7001] or *[System/EventID=7002]) and *[System/Provider[#Name='Microsoft-Windows-Winlogon']]"
$result = Get-WinEvent -LogName System -FilterXPath $filter | ForEach-Object {
# convert the event to XML and grab the Event node
$eventXml = ([xml]$_.ToXml()).Event
$eventData = $eventXml.EventData.Data
$userSID = ($eventData | Where-Object { $_.Name -eq 'UserSid' }).'#text'
$userName = [System.Security.Principal.SecurityIdentifier]::new($userSID).Translate([System.Security.Principal.NTAccount])
# you can add username filtering here if you like.
# remember the $userName is in formal DOMAIN\LOGONNAME
# if ($username -notlike "*-organization") {
# output the properties you need
[PSCustomObject]#{
Time = [DateTime]$eventXml.System.TimeCreated.SystemTime
Event = if ($eventXml.System.EventID -eq 7001) { 'LogOn' } else { 'LogOff' }
UserName = $userName
UserSID = $userSID
Computer = $eventXml.System.Computer
}
# }
}
# output on screen
$result
# output to CSV file
$result | Export-Csv -Path 'X:\TheOutputFile.csv' -NoTypeInformation
Note, I have commented out the username filtering in the code. It is just there to give you an idea of where to put it. Of course, you can also filter the $result afterwards:
$result | Where-Object { $_.UserName -notlike "*-organization" }
Adding to #js2010's helpful answer, and with the assumption you're using PowerShell 5.1. I usually identify the property array index and use Select-Object to create a custom property as needed.
$WinEvents =
get-winevent #{logname='system'; providername='Microsoft-Windows-Winlogon'} |
Select-Object #{Name = 'Time'; Expression = {$_.TimeCreated}},
#{Name = 'Event'; Expression = { If($_.ID -eq 7001){'Logon'} ElseIf($_.ID -eq 7002){ 'Logoff' } } },
#{Name = 'User'; Expression = { [System.Security.Principal.SecurityIdentifier]::new( $_.Properties[1].Value ).Translate([System.Security.Principal.NTAccount]) } }
In your case this should add a property called User with a value like DomainName\UserName to the objects. I also added expressions to derive the other properties you were adding to your custom objects. Select-Object emits custom objects as well so this should give the result you're looking for.
Let me know if this helps.
Update
Respectfully, the other 2 answers make the assumption that you are looking for logon/off events for a specific user. That's not how I read the question; in particular:
"get all users who have logged in/out of a server"
While PowerShell 7+ does let you directly cite UserID in the FilterHashtable, it's not very useful here because we're not seeking events for a specific user. Furthermore, it seems unhelpful for the ultimate output as by default it echoes as a SID. It would still need to be translated, not only for display but for further filtering. I'm also not positive that UserID will always be the same as Properties[1], there's certainly some variance when looking at other event IDs.
The XML work is very cool, but I don't think it's called for here.
There were some issues with my answer as well. I overlooked filtering the event IDs & dates up front. I also realized we don't need to instantiate [System.Security.Principal.SecurityIdentifier] class because the property is already typed as such. Along with some readability improvements I corrected those issues below.
# Should be the 1st line!
using NameSpace System.Security.Principal
$ResolveEventType = #{ 7001 = 'Logon'; 7002 = 'Logoff' }
$FilterHashTable =
#{
LogName = 'system'
ProviderName = 'Microsoft-Windows-Winlogon'
ID = 7001,7002
StartTime = (Get-Date).AddDays(-7)
}
[Array]$WinEvents =
Get-WinEvent -FilterHashtable $FilterHashTable |
Select-Object #{ Name = 'Time'; Expression = { $_.TimeCreated } },
#{ Name = 'Event'; Expression = { $ResolveEventType[ $_.ID ] } },
#{ Name = 'User'; Expression = { $_.Properties[1].Value.Translate( [NTAccount] ) } }
$WinEvents |
Where-Object{ $_.UserName -notlike "*-organization" } |
Format-Table -AutoSize
This tested good in PowerShell 5.1 & 7.0. I added Format-Table to display the output, but you can just change that out for an Export-Csv command as needed
Note: The last 2 pipelines can be combined, but I thought this was a
little more readable.
Let me know if this helps.

get-winevent: cannot filter specific field FailureReason %%2313

I'm poking around with get-winevent for the event 4625 because i need the failure-reason, which is in a xml field of the event.
the first thing i tried is to print out all fields hoping, the failure reason is available somewhere in the data-path of the xml, with no success.
i did not found a way to query the statuscode %%2313 to something with powershell to get the readable text.
the last thing i did is filtering the specific event and write the statusmessage myself in a custom field of my export file.
I used this code to accomplish that:
Get-WinEvent -FilterHashtable #{Path="c:\temp\test.evtx";} -ErrorAction SilentlyContinue |
Where-Object {($_.id -eq "4625" -and $_.properties[9].value -in "%% 2313")}|ForEach-Object{
$SelectorStrings = [string[]]#(
'Event/EventData/Data[#Name="TargetUserName"]',
'Event/EventData/Data[#Name="TargetDomainName"]',
'Event/EventData/Data[#Name="WorkstationName"]',
'Event/EventData/Data[#Name="IpAddress"]',
'Event/EventData/Data[#Name="IpPort"]',
'Event/EventData/Data[#Name="LogonType"]',
'Event/EventData/Data[#Name="FailureReason"]',
'Event/EventData/Data[#Name="Remark"]'
)
$PropertySelector = [System.Diagnostics.Eventing.Reader.EventLogPropertySelector]::new($SelectorStrings)
$TargetUserName,$TargetDomainName,$WorkstationName,$IpAddress,$IpPort,$LogonType,$FailureReason,$Remark = $_.GetPropertyValues($PropertySelector)
$Remark ="Unbekannter Benutzername oder ungültiges Kennwort."
#Create the PSCustomObject from the given Fieldnames
[PSCustomObject]#{
TimeCreated = $_.TimeCreated
Id = $_.Id
UserName = $TargetUserName
Domain = $TargetDomainName
WorkstationName = $WorkstationName
IPAddress = $IpAddress
Port = $IpPort
LogonType = $LogonType
Message = ($_.Message).split(".")[0]
Remark = $Remark
FailureReason =$FailureReason
}
}|Export-Csv -NoTypeInformation -Force -Encoding UTF8 -Path 'c:\temp\failurereason.csv'
but: it seams i cannot filter for %%2313 as property value. no idea why. Even with quotation marks or something, dont get any event out.

Get events from yesterday

I am trying to use PowerShell to get the results from the TaskScheduler events since yesterday. This is my code:
Get-WinEvent -LogName Microsoft-Windows-TaskScheduler/Operational -MaxEvents 5 |
Where-Object ($_.TimeCreated -gt [DateTime]::Today.AddDays(-1))
Format-List *
Notes:
The -MaxEvents 5 is to limit output while I am developing.
When I remove the Where-object the cmdlet returns a full list. This is expected since no filtering is applied. So the error must be in the way the filtering is being done.
You can use the FilterHashTable property of Get-WinEvent to filter, it will be faster than retrieving all the events and then filtering only those you want.
This retrieves all events in the last day from the System log as I don't have any logging for TaskScheduler.
$date = (Get-Date).AddDays(-1)
$events = Get-WinEvent -FilterHashTable #{ LogName = "System"; StartTime = $date;}
$events | Format-List
You can filter on pretty much any field in the event log - further info on this

Powershell search by single and multiple keyword

I have some commands below that do not give any output when looking for specific keywords in Windows Logs using PowerShell.
Get-WinEvent -FilterHashtable #{LogName="Application"} | Select-String "Information"
However, if I only run Get-WinEvent -FilterHashtable #{LogName="Application"}, there are many entries with Information keyword. Select-String -pattern "Information" also does not work.
Ideally I'd like to search for multiple keywords in the above scenario.
You need to do:
Get-WinEvent -FilterHashtable #{LogName="Application"} | ? { $_.leveldisplayname -eq 'Information' }
The Information you're looking for is a property of the object. The Get-WinEvent cmdlet returns a collection of objects, so you need to add the Where-Object or ? to filter on the LevelDisplayName object property.
To answer your new questions:
The leveldisplayname is going to be Information, Error or Warning. You can add either of these or use logic to combine them. In order to search for keywords in a message, using a regex is probably the best approach:
Get-WinEvent -FilterHashtable #{LogName="Application"} | ? message -imatch "keyword1"
To search multiple keywords, you can modify the regex using the OR | operator:
Get-WinEvent -FilterHashtable #{LogName="Application"} | ? message -imatch "keyword1|keyword2|foo|bar"
If you wanted to search for all Error messages containing "foo" or "bar" you could do;
Get-WinEvent -FilterHashtable #{LogName="Application"} | ? { ($_.message -imatch "foo|bar") -and ($_.leveldisplayname -eq 'Error') }