PowerShell find firewall rule by port

Viewed 141

What I want to do

I want to list all firewall rules involving some ports and list their display name but the only way I found for now displays only the port part and has no idea what the display name is.

First the basics

If we call Show-NetFirewallRule without argument, it lists all rules and each is formatted like that (notice DisplayName that is on "root" and LocalPort that is under Get-NetFirewallPortFilter):

Name                          : {96022E5F-666B-4E9E-8BD4-040498CEF1F5}
DisplayName                   : Google Chrome (mDNS-In)
Description                   : Inbound rule for Google Chrome to allow mDNS traffic.
DisplayGroup                  : Google Chrome
Group                         : Google Chrome
Enabled                       : True
Profile                       : Any
Platform                      : 
Direction                     : Inbound
Action                        : Allow
EdgeTraversalPolicy           : Block
LooseSourceMapping            : False
LocalOnlyMapping              : False
Owner                         : 
PrimaryStatus                 : OK
Status                        : The rule was parsed successfully from the store. (65536)
EnforcementStatus             : NotApplicable
PolicyStoreSource             : PersistentStore
PolicyStoreSourceType         : Local
RemoteDynamicKeywordAddresses :

$_ | Get-NetFirewallAddressFilter
     LocalAddress             : Any
     RemoteAddress            : Any

$_ | Get-NetFirewallServiceFilter
     Service                  : Any

$_ | Get-NetFirewallApplicationFilter
     Program                  : C:\Program Files\Google\Chrome\Application\chrome.exe
     Package                  :

$_ | Get-NetFirewallInterfaceFilter
     InterfaceAlias           : Any

$_ | Get-NetFirewallInterfaceTypeFilter
     InterfaceType            : Any

$_ | Get-NetFirewallPortFilter
     Protocol                 : UDP
     LocalPort                : 5353
     RemotePort               : Any
     IcmpType                 : Any
     DynamicTarget            : Any

$_ | Get-NetFirewallSecurityFilter
     Authentication           : NotRequired
     Encryption               : NotRequired
     OverrideBlockRules       : False
     LocalUser                : Any
     RemoteUser               : Any
     RemoteMachine            : Any

What I tried

  • The closer, I think, is
Show-NetFirewallRule  | where {$_.LocalPort -eq "5353" -or $_.LocalPort -eq "5354"}

But it returns only Get-NetFirewallPortFilter part as said above:

$_ | Get-NetFirewallPortFilter
     Protocol                 : UDP
     LocalPort                : 5353
     RemotePort               : Any
     IcmpType                 : Any
     DynamicTarget            : Any

$_ | Get-NetFirewallPortFilter
     Protocol                 : UDP
     LocalPort                : 5353
     RemotePort               : Any
     IcmpType                 : Any
     DynamicTarget            : Any

$_ | Get-NetFirewallPortFilter
     Protocol                 : UDP
     LocalPort                : 5353
     RemotePort               : Any
     IcmpType                 : Any
     DynamicTarget            : Any

On same basis I tried:

Get-NetFirewallRule | where { $_.Get-NetFirewallPortFilter.LocalPort -Eq "5353" }

that displays a parse error, and all

Get-NetFirewallRule | where { $_.NetFirewallPortFilter.LocalPort -Eq "5353" }
Get-NetFirewallRule | where { ($_ | Get-NetFirewallAddressFilter).LocalPort -Eq "5353" }
Get-NetFirewallRule | where { ($_ | Get-NetFirewallAddressFilter).$_.LocalPort -Eq "5353" }

That gives no result.

Get-NetFirewallRule  |
     Format-Table -Property Name,
     DisplayName,
     DisplayGroup,
     @{Name='Protocol';Expression={($PSItem | Get-NetFirewallPortFilter).Protocol}},
     @{Name='LocalPort';Expression={($PSItem | Get-NetFirewallPortFilter).LocalPort}},
     @{Name='RemotePort';Expression={($PSItem | Get-NetFirewallPortFilter).RemotePort}},
     @{Name='RemoteAddress';Expression={($PSItem | Get-NetFirewallAddressFilter).RemoteAddress}} | where {$PSItem.LocalPort -eq "5353"}

But it seems doing nothing, and when I call it without the | where ... it is very slow, displaying approximatively 1 line per second. Note I tried also $_.LocalPort -eq "5353" and $_ -like "5353" in where.

  • I also tried
Get-NetFirewallRule | Get-NetFirewallPortFilter | Where-Object -Property { $_.LocalPort -Eq "5353" }

But is returns nothing (and is also very slow).

Workaround

For now I use a dirty "workaround", I call Show-NetFirewallRule > NetFirewallRule.txt and search manually in file, but I would like to have a script that does this automatically for me (and that is not very slow, since some commands that seems close to the answer are very slow).

The question

Anybody knows if/how can I achieve that ? Thanks !

2 Answers

This is what works for me:

Get-NetFirewallRule |Select-Object -First 20 -PipelineVariable Rule |
  Get-NetFirewallPortFilter |Where-Object LocalPort -in 'RPCEPMap', 'Any' |
    ForEach-Object { [pscustomobject]@{ name = $Rule.DisplayName; port = $_.LocalPort } }

But there are two tricky things here to deal with:

  • The common parameter -PipelineVariable is limited (see the information in the description along with the Note and the Caution) which I assume covers the reason why you can't remove the |Select-Object -First 20 part and place the -PipelineVariable Rule directly on the Get-NetFirewallRule cmdlet (but I don't fully understand the implication myself)
  • The Get-NetFirewallPortFilter cmdlet requires a CimInstance rather than e.g. a usual (PS)Object. This presumable explains why you can't replace the |Select-Object -First 20 with |Select-Object * know that former command actually places a reference to object output by Get-NetFirewallRule. See: Select-Object -First affects prior cmdlet in the pipeline

Update

as there appears to be a bug: "after some tests, it started to return always same name, of a "random" rule not involving port(s) I am searching for"

This is probably because the CimInstances run asynchronously and the refences in the -PipelineVariable are probably being overwritten (even with NetFirewallRule -ThrottleLimit 1 -OutBuffer 1). This means that this probably can't piped correctly.

Anyways, this (doing a filter on each specific rule instance) also appears to work for me:

Get-NetFirewallRule |ForEach-Object {
    $Ports = $_ |Get-NetFirewallPortFilter |Where-Object LocalPort -in 'RPCEPMap', 'Any'
    if ($Ports) { $_ |Select-Object DisplayName, @{n='LocalPort';e={$Ports.LocalPort} } }
}

I believe you want to start with Get-NetFirewallPortFIlter, filter the results, and pass them to Get-NetFirewallRule. That should be much faster than looping on all results of Get-NetFirewallRule and testing each yourself.

Example (indented for readability, but can be a one-liner, of course):

Get-NetFirewallPortFilter |
    Where-Object { $_.LocalPort -eq 5353 } |
    Get-NetFirewallRule

Searched 717 rules and an equivalent 717 port filters in 1.2 seconds with 6 results.

If you'd like to show the port information alongside each rule, something like (this may or might not be optimal, but ...):

Get-NetFirewallPortFilter |
    Where-Object { $_.LocalPort -eq 5353 } |
    ForEach-Object {
        "----"
        "Rule"
        "----"
        $_ | Get-NetFirewallRule
        "-----------"
        "Port Filter"
        "-----------"
        $_
    }

With the above, you'll still be looping over the filtered results rather than the entire set of rules.

Related