Helpers/SystemAudit/New-WinEventFilterXml.ps1
<#
.SYNOPSIS Create a XML filter to be used with the Get-WinEvent command. .DESCRIPTION The filter will be created by the provided parameers. Only parameter specified are included in the filter. .OUTPUTS System.String. XML filter. .EXAMPLE PS C:\> New-WinEventFilterXml -LogName 'Security' Filter for all events in the Security log. .EXAMPLE PS C:\> New-WinEventFilterXml -LogName 'Application' -Provider 'MsiInstaller' -Level 'Critical', 'Error', 'Warning' -EventId 11707, 11708, 11724, 11725, 11728, 11729 -NotBefore (Get-Date).AddDays(-7) Filter for all MSI events indicating a problem in the last 7 days. .LINK https://github.com/claudiospizzi/SecurityFever #> function New-WinEventFilterXml { [CmdletBinding()] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] param ( # Event log name. [Parameter(Mandatory = $true)] [System.String] $LogName, # Filter by provider name. [Parameter(Mandatory = $false)] [AllowEmptyCollection()] [System.String[]] $Provider, # Filter by log level. [Parameter(Mandatory = $false)] [AllowEmptyCollection()] [ValidateSet('Critical', 'Error', 'Warning', 'Information', 'Verbose')] [System.String[]] $Level, # Filter by event id. [Parameter(Mandatory = $false)] [AllowEmptyCollection()] [System.Int32[]] $EventId, # Filter the events by creation time, but not before the specified # DateTime. [Alias('From')] [Nullable[System.DateTime]] $NotBefore, # Filter the events by creation time, but not after the specified # DateTime. [Alias('To')] [Nullable[System.DateTime]] $NotAfter ) $select = @() # Filter by the provider name. The select looks like this: # Provider[@Name='MYPROVIDER' or @Name='Microsoft-Windows-ImportantService'] if ($PSBoundParameters.ContainsKey('Provider') -and $Provider.Count -gt 0) { $selectProvider = @() foreach ($providerName in $Provider) { $selectProvider += '@Name=''{0}''' -f $providerName } $select += 'Provider[{0}]' -f ($selectProvider -join ' or ') } # Filter by the log level. The command accepts the string representation of # the level, this is converted to it's numbers: # (Level=1 or Level=2) if ($PSBoundParameters.ContainsKey('Level') -and $Level.Count -gt 0) { $selectLevel = @() foreach ($levelName in $Level) { switch ($levelName) { 'Critical' { $selectLevel += 'Level=1' } 'Error' { $selectLevel += 'Level=2' } 'Warning' { $selectLevel += 'Level=3' } 'Information' { $selectLevel += 'Level=4 or Level=0' } 'Verbose' { $selectLevel += 'Level=5' } } } $select += '({0})' -f ($selectLevel -join ' or ') } # Filter by the event id numbers like this: # (EventID=12345 or EventID=999) if ($PSBoundParameters.ContainsKey('EventId') -and $EventId.Count -gt 0) { $selectEventId = @() foreach ($eventIdNumber in $EventId) { $selectEventId += 'EventID={0}' -f $eventIdNumber } $select += '({0})' -f ($selectEventId -join ' or ') } # Filter by the created time, can be specified with not before (From) until # not after (To): # TimeCreated[@SystemTime>='2021-01-01T00:00:00.000Z' and @SystemTime<='2021-12-31T23:59:59.999Z'] if (($PSBoundParameters.ContainsKey('NotBefore') -and $NotBefore.HasValue) -or ($PSBoundParameters.ContainsKey('NotAfter') -and $NotAfter.HasValue)) { $selectTimeCreated = @() if ($PSBoundParameters.ContainsKey('NotBefore') -and $NotBefore.HasValue) { $selectTimeCreated += '@SystemTime>=''{0:yyyy-MM-ddTHH:mm:ss.fffZ}''' -f $NotBefore.Value.ToUniversalTime() } if ($PSBoundParameters.ContainsKey('NotAfter') -and $NotAfter.HasValue) { $selectTimeCreated += '@SystemTime<=''{0:yyyy-MM-ddTHH:mm:ss.fffZ}''' -f $NotBefore.Value.ToUniversalTime() } $select += 'TimeCreated[{0}]' -f ($selectTimeCreated -join ' and ') } # Combine all selections into a single select where all parts must be # matched for the event to return. $select = $select -join ' and ' $filter = '<QueryList><Query Id="0" Path="{0}"><Select Path="{0}">*[System[{1}]]</Select></Query></QueryList>' -f $LogName, $select return $filter } |