The following code works to return the Windows Log events with ID = 100.

$Date = (Get-Date).AddDays(-30)
Get-WinEvent -FilterHashTable @{ LogName = "Microsoft-Windows-Diagnostics-Performance/Operational"; StartTime = $Date; ID = 100 } -MaxEvents 1 | Select-Object -Property TimeCreated, Id, Task, TaskDisplayName, LevelDisplayName, Message

This code returns an error for the TaskDisplayName = 'Boot Performance Monitoring'

$Date = (Get-Date).AddDays(-30)
Get-WinEvent -FilterHashTable @{ LogName = "Microsoft-Windows-Diagnostics-Performance/Operational"; StartTime = $Date; TaskDisplayName = 'Boot Performance Monitoring' } | Select-Object -Property TimeCreated, Id, Task, TaskDisplayName, LevelDisplayName, Message

Get-WinEvent : No events were found that match the specified selection criteria. At D:\tfsws\TG-Dev-ICSG2\Support\PowerShell Scripts\Get-WinEvent-TEST.ps1:6 char:1 + Get-WinEvent -FilterHashTable @{ LogName = "Microsoft-Windows-Diagnos ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ObjectNotFound: (:) [Get-WinEvent], Exception + FullyQualifiedErrorId : NoMatchingEventsFound,Microsoft.PowerShell.Commands.GetWinEventCommand

How do I make Get-WinEvent accept the TaskDisplayName filter?

2

There are 2 best solutions below

0
On BEST ANSWER

Unfortunately you can't use -FilterHashTable to filter on TaskDisplayName for 2 reasons:

In the Microsoft docs Get-WinEvent valid FilterHashTable values are:

  • LogName=<String[]>
  • ProviderName=<String[]>
  • Path=<String[]>
  • Keywords=<Long[]>
  • ID=<Int32[]>
  • Level=<Int32[]>
  • StartTime=<DateTime>
  • EndTime=<DataTime>
  • UserID=<SID>
  • Data=<String[]>

TaskDisplayName isn't one of the -FilterHashTable options.... ok. So next option is to use -FilterXPath or -FilterXML which gives us access to some more lower level filtering. For simplicity, I will use -FilterXPath. In order to find the right keys to filter on, you have to go to the details tab on the event. Here is a sample event:

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
<System>
    <Provider Name="Microsoft-Windows-Diagnostics-Performance" Guid="{CFC18EC0-96B1-4EBA-961B-622CAEE05B0A}" /> 
    <EventID>100</EventID> 
    <Version>2</Version> 
    <Level>2</Level> 
    <Task>4002</Task> 
    <Opcode>34</Opcode> 
    <Keywords>0x8000000000010000</Keywords> 
    <TimeCreated SystemTime="2018-05-23T21:09:42.047563100Z" /> 
    <EventRecordID>8</EventRecordID> 
    <Correlation ActivityID="{F774E0CC-F2D9-0006-E0FA-74F7D9F2D301}" /> 
    <Execution ProcessID="3876" ThreadID="4980" /> 
    <Channel>Microsoft-Windows-Diagnostics-Performance/Operational</Channel> 
    <Computer>D4700.adcfcu.connectfirstcu.com</Computer> 
    <Security UserID="S-1-5-19" /> 
</System>
<EventData>
    <Data Name="BootTsVersion">2</Data> 
    <Data Name="BootStartTime">2018-05-23T21:06:49.733345200Z</Data> 
    ..........
    <Data Name="UserLogonWaitDuration">9415</Data> 
</EventData>
</Event>

When you expand it out, you notice that there is no TaskDisplayName. This is because TaskDisplayName == Task Category. Ok... let's look for Task Category... Well there is no Task Category either. That's because Categories are actually stored numerically in the event, and then mapped into a proper description using an Event Category String. That is why you can't filter based on a TaskDisplayName or Task Category. Instead you will have to filter on the Task number, which you in this case is 4002. And if you use the StartDate, which is TimeCreated, you can calculate that 30 days is 2592000000 miliseconds, then your code becomes:

Get-WinEvent -LogName "Microsoft-Windows-Diagnostics-Performance/Operational" -FilterXPath "*[System[Task=4002 and TimeCreated[timediff(@SystemTime) <= 2592000000]]]" | Select-Object -Property TimeCreated, Id, Task, TaskDisplayName, LevelDisplayName, Message
0
On

As stated in the Documentation, the -FilterHashTable only allows a subset of filters:

  • LogName=
  • ProviderName=
  • Path=
  • Keywords=
  • ID=
  • Level=
  • StartTime=
  • EndTime=
  • UserID=
  • Data=
  • *=

What you can do instead, is to create a FilterXML with the -FilterXML parameter. You can create an appropriate XML with eventvwr.msc (find and example event, get the task number from the details view, configure a protocol filter, switch to the "XML" tab, and copy the content).

The result will be something like this:

$Filter = @'
<QueryList>
<Query Id="0" Path="Microsoft-Windows-Diagnostics-Performance/Operational">
    <Select Path="Microsoft-Windows-Diagnostics-Performance/Operational">*[System[(EventID=100) and (Task=4002)]]</Select>
</Query>
</QueryList>
'@
Get-WinEvent -FilterXml $Filter

TaskDisplayName however is not a valid property, you have to figure out, what Task number 'Boot Performance Monitoring' has. Note, that Task 4002 is not the one you are looking for. It's just the only number that is available in my eventlog. ;)

Alterantively, but not as performant and not recommended (general rule: filter left), you can use your sample command and add an Where-Object filter.

$FitlerHashTable =  @{ 
    LogName = "Microsoft-Windows-Diagnostics-Performance/Operational"
    StartTime = $Date
    ID = 100
}
Get-WinEvent -FilterHashTable $FitlerHashTable -MaxEvents 1 | 
Where-Object { $_.Task -eq 4002 } | 
Select-Object -Property TimeCreated, Id, Task, TaskDisplayName, LevelDisplayName, Message