1

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 !

gluttony
  • 402
  • 6
  • 14

3 Answers3

1

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} } }
}
iRon
  • 20,463
  • 10
  • 53
  • 79
  • Thanks, works for me even without the `-First 20` (or `-First 2000` if I set a big number because `-First 20` will only look on first 20 rules, not all), and I changed the `$Rule.Name` to `$Rule.DiplayName` since `$Rule.Name` may not be very telling (for instance can be `{96022E5F-666B-4E9E-8BD4-040498CEF1F5}`). But it is very slow (more that one minute with 600+ rules). – gluttony Jul 28 '22 at 09:39
  • Well, in fact there is a bug, after some tests, it started to return always same name, of a "random" rule not involving port(s) I am searching for. – gluttony Jul 28 '22 at 10:07
  • 1
    I have updated my answer. With regards the performance, I guess that is mainly due to the volume and the Firewall rules behind. In case you using **Windows PowerShell**, I would certainly try the latest **PowerShell (Core)** version. – iRon Jul 28 '22 at 10:10
  • *Well, in fact there is a bug...*. Hmm, I was a little afraid of this. What happens if you set: `Get-NetFirewallRule -ThrottleLimit 1 -OutBuffer 1` – iRon Jul 28 '22 at 10:19
  • With these there is unfortunately still the same issue... – gluttony Jul 28 '22 at 10:30
  • I have update the answer with another approach. – iRon Jul 28 '22 at 10:51
  • 1
    Thanks a lot iRon, almost there, it logs too much information (all the rule object with Name, DisplayName, Description, DisplayGroup, ..., as showed in my "First the basics" section) but at least it show only the once with requested port(s), you can update your answer replacing `$_ |Select-Object *` by `$_ | Select-Object DisplayName` so that it does what I want ;) – gluttony Jul 28 '22 at 12:25
1

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.

NotTheDr01ds
  • 15,620
  • 5
  • 44
  • 70
  • WOW, very faster, thanks a lot, but since I don't need all information I changed `$_ | Get-NetFirewallRule` to `($_ | Get-NetFirewallRule).DisplayName` and `$_` above it to `$_.LocalPort`, and after I got first answer, I got the need to display program to, then added `($_ | Get-NetFirewallRule | Get-NetFirewallApplicationFilter).Program` in `ForEach-Object`. Also, for more readability, added new line with just `""` at the end of `ForEach-Object` else all appears in one block if there are several results. – gluttony Sep 01 '22 at 09:52
  • Even, for shorter results, I print one line per value, for instance for display name: `"Display name: " + ($_ | Get-NetFirewallRule).DisplayName` – gluttony Sep 01 '22 at 09:58
  • 1
    The annoying thing is localport is a string or object array of strings. It can have words like 'any', or a range that looks like "7200-17210". – js2010 Nov 13 '22 at 18:41
  • @js2010 That's a really good point. I hadn't considered that (or had use-case that ran into it yet, personally). Is there a separate question somewhere on how to handle that somewhere here? If not, there probably should be, but perhaps not on Stack Overflow -- Maybe Super User or ServerFault? – NotTheDr01ds Nov 13 '22 at 20:03
0

Trying to parse something like "1000-2000" in localport. This fails with multiple false outcomes in the same rule.

$target = 8555
get-netfirewallportfilter |
? { $_.localport -match '-' } | 
? { $_.localport | foreach { if ($_ -match '-') { $beg,$end = $_ -split '-';
  [int]$beg -le $target -and [int]$end -ge $target }}} |
select instanceid,@{n='localport';e={"$($_.localport)"}}


instanceid                             localport
----------                             ---------
NVS-FrameServer-In-TCP-NoScope         554 8554-8558
{E7D045E7-643F-4A91-94FF-63518836FA72} 5353 7200-17210 8889
{9823D038-1960-4767-9290-B36AA995FBB3} 5000 7000 7100 50000 7200-17210 8888
{123BF547-E50B-4A9D-A9E7-0FAE15D9C665} 7200-17210
IIS-WebServerRole-FTP-Passive-In-TCP   1024-65535
{25931D39-0705-4E63-A10C-E5F16BD17E0A} 7200-17210
{D6E50A26-B3A7-4683-A9FC-8485ED2B38BA} 5000 7000 7100 50000 7200-17210 8888
{B88115EB-F6B6-48D2-B194-723414C249B5} 5353 7200-17210 8889
js2010
  • 23,033
  • 6
  • 64
  • 66