PowerShell find firewall rule by port
Asked Answered
G

4

5

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 !

Gabler answered 28/7, 2022 at 6:6 Comment(0)
C
4

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.

Carcinoma answered 30/8, 2022 at 22:4 Comment(4)
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.Gabler
Even, for shorter results, I print one line per value, for instance for display name: "Display name: " + ($_ | Get-NetFirewallRule).DisplayNameGabler
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".Osburn
@Osburn 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?Carcinoma
S
2

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} } }
}
Spindle answered 28/7, 2022 at 7:56 Comment(7)
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).Gabler
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.Gabler
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.Spindle
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 1Spindle
With these there is unfortunately still the same issue...Gabler
I have update the answer with another approach.Spindle
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 ;)Gabler
O
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
Osburn answered 13/11, 2022 at 20:32 Comment(0)
S
0

I took pieces of other answers above and added some of my own logic to create this function that will provide a list of rules that match the port provided with port match and/or range match. Feel free to improve as you see fit.

function Get-FWRulesOnPort
{
    <#
        Get Firewall Rules associated to a specific Port
        Ranges parameter includes results with Port matches in Ranges

        Get-FWRulesOnPort -Port 5500
        Get-FWRulesOnPort -Port 5001 -Ranges
    #>
    param(
        [int]$Port,
        [switch]$Ranges
    )
    #Rule Match Counter
    $i = 0
    
    #Get Firewall Port Filters that match Specific Port
    # or contain a Range of Ports
    Get-NetFirewallPortFilter | 
    Where-Object { ($_.LocalPort -eq $Port) -or ($_.localport -match '-') } | 
    Sort-Object -Property DisplayName |
    
    #Loop Port Filter Objects
    ForEach-Object {

        #Clear Match Variables each iteration
        $RangeMatch = $false
        $matches = $null

        # if Ranges parameter used and LocalPort contains a Range: 123-456
        if ($Ranges -and $_.LocalPort -match '-') 
        { 
            # if LocalPort is an Array: -match returns the matched range array value
            $match = $_.LocalPort -match "(.*-.*)"
            
            # if Local Port is a string value containing a range: -match returns true
            if($_.localport.count -eq 1)
            {
                # Get matched range from regex capture $matches[0]
                $match = $matches[0]
            }

            #Split matched Range Values into Start and End values
            $Start,$End = $match -split '-'

            #If Port is in the current range: Set RangeMatch 
            if ($Port -in $Start..$End) { $RangeMatch = $true }
        }#if Range
        
        # if Range or Port Match: Show Result 
        if ($RangeMatch -or $_.LocalPort -eq $Port)
        {
            "--------------------------------------------------------------------------------------------------------------"
            "                                                  Rule $((++$i))"
            "--------------------------------------------------------------------------------------------------------------"
            $_ | Get-NetFirewallRule | Format-Table -AutoSize
            "Port Filter"
            "--------------"
            $_ | Format-Table -AutoSize
        }#if match
        
    }#foreach
}#funtion
Statocyst answered 22/6 at 1:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.