1

This is the base code:

 foreach ($event in Get-WinEvent -FilterHashtable @{LogName='Security';ID=5152}) {
    $xml = [xml]$event.toxml();
    $xml.event.eventdata.data | 
    foreach { $hash = @{} } { $hash[$_.name] = $_.'#text' } { [pscustomobject]$hash } |
    Where FilterOrigin -notmatch 'stealth|unknown|Query User Default' 
  }

the output is this:

enter image description here

I want to replace FilterOrigin with Firewall Display name, direction with either inbound or outbound and protocol with correct name from here.

I just need to know how to do one or two of them, then I can do the rest myself once I know the syntax/pattern.

starting with FilterOrigin, I tried this:

foreach ($event in Get-WinEvent -FilterHashtable @{LogName='Security';ID=5152}) {
    $xml = [xml]$event.toxml();
    $xml.event.eventdata.data | 
    foreach { $hash = @{} } { $hash[$_.name] = $_.'#text' } { [pscustomobject]$hash } |
    Where FilterOrigin -notmatch 'stealth|unknown|Query User Default' | ForEach-Object {

    if ($_.filterorigin -match ($pattern = '{.+?}'))

    {
    $_.filterorigin -replace $pattern, (Get-NetFirewallRule -Name $Matches[0]).DisplayName

    }

    }
  }

But the output is only the Firewall displaynames, so it does recognize the Firewall name (which is the ID you see in the FilterOrigin) but doesn't replace it inside the object.

for Protocol, let's say I only want to replace TCP (6) and UDP (17), how should I do that?

for Direction, %%14592 is for inbound and %%14593 is for outbound

UPDATE:

foreach ($event in Get-WinEvent -FilterHashtable @{LogName='Security';ID=5152}) {
    $xml = [xml]$event.toxml();
    $xml.event.eventdata.data | 
    foreach { $hash = @{} } { $hash[$_.name] = $_.'#text' } { [pscustomobject]$hash } |
    Where FilterOrigin -notmatch 'Stealth|Unknown|Query User Default|WSH Default' | ForEach-Object {

        $pattern = '\{.+?\}'
        $_.FilterOrigin =  $_.FilterOrigin -replace $pattern, (Get-NetFirewallRule -Name $Matches[0]).DisplayName


        $protocolName = @{ 6 = 'TCP'; 17 = 'UDP' }[$_.Protocol]
        $_.Protocol =  if (-not $protocolName) { $_.Protocol } else { $protocolName }



        # Conceptually clearer PowerShell (Core) 7+ alternative:
        $_.Direction = $_.Direction -eq '%%14592' ? 'Outbound' : 'Inbound'
        # $_.Direction = ('Outbound', 'Inbound')[$_.Direction -eq '%%14592']


        $_



    }
  }

So with this script, there are few problems,

  1. the protocol isn't replaced, still the numbers are displayed
  2. FilterOrigin shows up empty
  3. there is a constant error after each result

enter image description here

in the picture, only the direction is being applied correctly. the filter that blocked the connection shown in the script has a name but it's name not showing up.

  • 2
    As an aside: while `'{.+?}'` technically works, because what's between `{` and `}` happens not to be a valid quantifier, it's best to signal the intent to use these metacharacters _literally_ explicitly, by ``\``-escaping them: ``'\{.+?\}'`` – mklement0 Jan 19 '23 at 21:41

1 Answers1

0

With the exception of ++ and -- (and compound assignments such as +=, ...) PowerShell's operator do not perform in-place updates - instead they return (output) a result.

The -replace operator is no exception, so for in-place updating you must assign the result of the operation back to the input variable:

$_.FilterOrigin = 
  $_.FilterOrigin -replace $pattern, (Get-NetFirewallRule -Name $Matches[0]).DisplayName

for Protocol, let's say I only want to replace TCP (6) and UDP (17), how should I do that?

$protocolName = @{ 6 = 'TCP'; 17 = 'UDP' }[[int] $_.Protocol]
$_.Protocol =  if (-not $protocolName) { $_.Protocol } else { $protocolName }

for Direction, %%14592 is for inbound and %%14593 is for outbound

# Conceptually clearer PowerShell (Core) 7+ alternative:
#    $_.Direction = $_.Direction -eq '%%14592' ? 'Outbound' : 'Inbound'
$_.Direction = ('Outbound', 'Inbound')[$_.Direction -eq '%%14592']
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Thank you so much, works like a charm. if I wanted to add the date when each blocked event was created, how would I do that? just to point me to the right direction. because I don't see the date being mentioned in the output but it should be called `TimeCreated` as mentioned [here](https://stackoverflow.com/a/74988532/20682592). so is it even possible to add `TimeCreated` as a new property there in the XML input? –  Jan 19 '23 at 23:15
  • 1
    @Jameschad, presumably, the following works; if it doesn't, please ask a new question. In lieu of `foreach { $hash = @{ } } { $hash[$_.name] = $_.'#text' } { [pscustomobject]$hash }`, use `foreach { $hash = @{ TimeCreated = [datetime] $xml.Event.System.TimeCreated.SystemTime } } { $hash[$_.name] = $_.'#text' } { [pscustomobject]$hash }` – mklement0 Jan 19 '23 at 23:23
  • 1
    Thank you again, just want to confirm that it does indeed work and successfully adds `TimeCreated` as a new property. –  Jan 19 '23 at 23:29