powershellhashtablewindows-firewallevent-viewerpscustomobject

How to replace only specific strings in PowerShell custom object?


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.


Solution

  • 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']