PowerShell find firewall rule by port - powershell

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.
Based on https://itluke.online/2018/11/27/how-to-display-firewall-rule-ports-with-powershell/, I tried:
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 !

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.

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} } }
}

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

Related

Speed up powershell command when using calculated properties

So I wanted to get a powershell command to list the firewall rules and ports, and I had to basically use 2 commands: Get-NetFirewallRule and Get-NetFirewallPortFilter.
So I basically came up with this:
Get-NetFirewallPortFilter | where-object {$_.LocalPort -cmatch '[0-9]+'}|select-object -Property #{n='Name';e={($_ | Get-NetFirewallRule).Name}}, #{n='Description';e={($_ | Get-NetFirewallRule).description}}, Protocol, LocalPort, RemotePort, #{n='Direction';e={($_|Get-NetFirewallRule).Direction}}
I went with Get-NetFirewallPortFilter first because I wanted to only get numerical ports (so I didn't want to get 'Any' as a result).
Problem is, the more calculated properties I have, the slower this runs. It generates like 3 lines a second, which IMO is very slow.
I timed the command to see how long it takes (did an Out-GridView to also see the output, I don't think it adds THAT much more to the time, it seems to generate just as many lines a second):
PS C:\> measure-command { Get-NetFirewallPortFilter | where-object {$_.LocalPort -cmatch '[0-9]+'}|select-object -Property #{n='Name';e={($_ | Get-NetFirewallRule).Name}}, #{n='Description';e={($_ | Get-NetFirewallRule).description}}, Protocol, LocalPort, RemotePort, #{n='Direction';e={($_|Get-NetFirewallRule).Direction}} |out-gridview }
Days : 0
Hours : 0
Minutes : 1
Seconds : 59
Milliseconds : 143
Ticks : 1191434968
TotalDays : 0.00137897565740741
TotalHours : 0.0330954157777778
TotalMinutes : 1.98572494666667
TotalSeconds : 119.1434968
TotalMilliseconds : 119143.4968
It output 358 lines in ~119 seconds.
Are there any optimizations I can run to make this run faster?
You are using Get-NetFirewallRule multiple times in your code, where you could do this only once per PortFilter:
Get-NetFirewallPortFilter | Where-Object {$_.LocalPort -match '[0-9]+'} | ForEach-Object {
$rule = $_ | Get-NetFirewallRule
$_ | Select-Object #{Name = 'Name'; Expression = {$rule.Name}},
#{Name = 'Description'; Expression = {$rule.Description}},
Protocol, LocalPort, RemotePort,
#{Name = 'Direction'; Expression = {$rule.Direction}}
} | Out-GridView
It might be just a tad faster if you take out the ForEach-Object and use a foreach() instead:
$portFilters = Get-NetFirewallPortFilter | Where-Object {$_.LocalPort -match '[0-9]+'}
$result = foreach ($filter in $portFilters) {
$rule = $filter | Get-NetFirewallRule
$filter | Select-Object #{Name = 'Name'; Expression = {$rule.Name}},
#{Name = 'Description'; Expression = {$rule.Description}},
Protocol, LocalPort, RemotePort,
#{Name = 'Direction'; Expression = {$rule.Direction}}
}
$result | Out-GridView
Filtering left is always fastest, with get-netfirewallportfilter first. This takes about 18 seconds. I had trouble using -pipelinevariable (or -pv) with get-netfirewallportfilter. Powershell commands manipulate objects vs linux commands that manipulate text.
EDIT: Piping to get-netfirewallrule behaves oddly, like all the objects would be processed in one shot. I put it inside a foreach-object. I changed name to displayname and put description last.
# not work
Get-NetFirewallPortFilter -pipelinevariable port
Get-NetFirewallPortFilter : Cannot retrieve the dynamic parameters for the cmdlet. Object reference not set to an
instance of an object.
At line:1 char:1
+ Get-NetFirewallPortFilter -pipelinevariable port
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-NetFirewallPortFilter], ParameterBindingException
+ FullyQualifiedErrorId : GetDynamicParametersException,Get-NetFirewallPortFilter
Get-NetFirewallPortFilter |
where localPort -match \d -pipelinevariable port |
% { $_ | Get-NetFirewallRule } | select displayname,
#{n='Protocol'; e={$port.protocol}},
#{n='Localport'; e={$port.localport}},
#{n='Remoteport';e={$port.remoteport}},
direction, description | ft
DisplayName Protocol Localport Remoteport Direction description
----------- -------- --------- ---------- --------- -----------
SNMP Trap Service (UDP In) UDP 162 Any Inbound Inbound rule for the SNMP Trap Service to allow SNMP traps. [UDP 162]
SNMP Trap Service (UDP In) UDP 162 Any Inbound Inbound rule for the SNMP Trap Service to allow SNMP traps. [UDP 162]
Delivery Optimization (TCP-In) TCP 7680 Any Inbound Inbound rule to allow Delivery Optimization to connect to remote endpoints

Powershell - Process List with arguments

I am trying to find a way to list processes with;
PID
Process Name
CPU Usage
Execution Path
Port Number (TCP and UDP)
Description
and export it in a csv file.
Is it possible? If not, can this list be configured to search the process name as "like process_name" ?
For example, list multiple process names (as I specify) with other arguments.
So far, I've found this one but it doesn't include the port numbers;
Get-Process | select id, processname,cpu,path,description | where {$_.path -like "*postgre*"} | Export-Csv -Path C:\temp\process.csv -Delimiter ',' -NoTypeInformation
Thanks.
Here's a new function I whipped together called Get-ProcessPlus. It supports calling with process name(s) or process id(s) or without any parameters (will return all processes).
Example of output:
ProcessName : NVIDIA Web Helper
Id : 10184
Description : NVIDIA Web Helper Service
Path : C:\Program Files (x86)\NVIDIA Corporation\NvNode\NVIDIA Web Helper.exe
CPU usage (s) : 0,59375
TCP Addresses : 127.0.0.1
TCP Ports : 13549
UDP Addresses : 127.0.0.1
UDP Ports : 10010
Either run this code in ISE or VSCode, save it and dot source it (eg. . c:\path\to\Get-ProcessPlus.ps1 or maybe add it to your profile.
Then just call it with Get-ProcessPlus. Using a parameter name is optional, just providing one or more process ids or names will work, eg. Get-ProcessPlus chrome,firefox or Get-ProcessPlus 1044,894,432.
Finally, here's the code:
function Get-ProcessPlus {
[CmdletBinding(DefaultParameterSetName = 'Default')]
param (
[Parameter(ParameterSetName='ProcessName',Position = 0)]
[string[]]
$Name,
[Parameter(ParameterSetName='PID',Position = 0)]
[int[]]
$Id
)
# Check which parameter set is in use and get our processes
switch ($PSCmdlet.ParameterSetName) {
'ProcessName' {
$AllProcesses = Get-Process -Name $Name
break
}
'PID' {
$AllProcesses = Get-Process -Id $Id
break
}
default { $AllProcesses = Get-Process }
}
foreach ($Process in $AllProcesses) {
# Retrieve TCP and UDP Connection information for the current process (if any)
$UDPConnections = Get-NetUDPEndpoint -OwningProcess $Process.Id -ErrorAction Ignore |
Select-Object LocalAddress,LocalPort
$TCPConnections = Get-NetTCPConnection -OwningProcess $Process.Id -State Listen -ErrorAction Ignore |
Select-Object LocalAddress,LocalPort
$TCPPorts = $TCPConnections.LocalPort | Where-Object { $null -ne $_} | Select-Object -Unique
$UDPPorts = $UDPConnections.LocalPort | Where-Object { $null -ne $_} | Select-Object -Unique
$TCPAddresses = $TCPConnections.LocalAddress | Select-Object -Unique
$UDPAddresses = $UDPConnections.LocalAddress | Select-Object -Unique
# Collect and output all information about the current process
[PSCustomObject] #{
'ProcessName' = $Process.ProcessName
'Id' = $Process.Id
'Description' = $Process.Description
'Path' = $Process.Path
'CPU usage (s)' = $Process.CPU
'TCP Addresses' = $TCPAddresses
'TCP Ports' = $TCPPorts
'UDP Addresses' = $UDPAddresses
'UDP Ports' = $UDPPorts
}
}
}

Select-Object Cmdlet Returns Different Formatted Results for Get-NetIPConfiguration (different type)

I was trying to get the IP config details for my physical network adapter, while excluding all virtual network adapter. My script is as below:
$NetAdaptIndex = Get-NetAdapter -Physical | Select -Property InterfaceIndex -ExpandProperty InterfaceIndex
## Get Ip address, Gateway and DNS details as per configuration
$IPAddressConfig = foreach ($II in $NetAdaptIndex) {
Write-Host $II -ForegroundColor Yellow
Get-NetIPConfiguration |
Where-Object { $_.InterfaceIndex -eq $II} |
Select-Object InterfaceAlias, InterfaceDescription, InterfaceIndex, Ipv4Address, IPv4DefaultGateway, DNSServer
}
When I call the variable, I get the following results where the IPv4Address, IPv4DefaultGateway, and DNSServer are not returned in a string format.
PS C:\WINDOWS\system32> $IPAddressConfig
InterfaceAlias : WiFi 2
InterfaceDescription : D-Link DWA-171 Wireless AC Dual Band Adapter
InterfaceIndex : 46
IPv4Address : {192.168.0.103}
IPv4DefaultGateway : {MSFT_NetRoute (InstanceID = ":8:8:8:9:55?#55;C?8;#B8:8;55;")}
DNSServer : {MSFT_DNSClientServerAddress (Name = "46", CreationClassName = "", SystemCreationClassName = "", SystemName = "23"), MSFT_DNSClientServerAddress (Name = "46", CreationClassName = "", SystemCreationClassName = "", SystemName = "2")}
InterfaceAlias : Ethernet
InterfaceDescription : Broadcom NetLink (TM) Gigabit Ethernet
InterfaceIndex : 10
IPv4Address : {169.254.149.208}
IPv4DefaultGateway :
DNSServer : {MSFT_DNSClientServerAddress (Name = "10", CreationClassName = "", SystemCreationClassName = "", SystemName = "23"), MSFT_DNSClientServerAddress (Name = "10", CreationClassName = "", SystemCreationClassName = "", SystemName = "2")}
But if I were to manually remove the Select-Object code, it returns a correctly formatted results.
Get-NetIPConfiguration |
Where-Object { $_.InterfaceIndex -eq 46}
Observe how the IPv4Address, IPv4DefaultGateway, and DNSServer has returned the correctly formatted result.
InterfaceAlias : WiFi 2
InterfaceIndex : 46
InterfaceDescription : D-Link DWA-171 Wireless AC Dual Band Adapter
NetProfile.Name : <removed>
IPv6Address : <removed>
IPv4Address : 192.168.0.103
IPv6DefaultGateway : <removed>
IPv4DefaultGateway : 192.168.0.1
DNSServer : 2001:f40:0:3::12:68
2001:4860:4860::8888
1.1.1.1
8.8.8.8
My question is why is this happening? And is there any method that I can use to convert them to the correct format? The latter format are the one that I want.
Everything in the PowerShell is an object. The objects can get quite complex with multiple nested properties.
PS > (Get-NetIPConfiguration | Select-Object DNSServer)[0]
DNSServer
---------
{MSFT_DNSClientServerAddress (Name = "11", CreationClassName = "", SystemCreationClassName = "", SystemName = "23"), MSFT_DNSClientServerAddress (Name = "11", CreationClassName = "", Syste...
PS > (Get-NetIPConfiguration | Select-Object -ExpandProperty DNSServer)[0]
InterfaceAlias Interface Address ServerAddresses
Index Family
-------------- --------- ------- ---------------
LAN 11 IPv6 {}
To make your life easier, PowerShell formats objects when they're displayed on screen. Formatting rules are stored in the xml files: Formatting File Overview. For the NetTCPIP module, the file would be C:\Windows\System32\WindowsPowerShell\v1.0\Modules\NetTCPIP\Tcpip.Format.ps1xml. Here is the DNSServer item formatting code:
<ListItem>
<Label>DNSServer</Label>
<ItemSelectionCondition>
<ScriptBlock>
($_.DNSServer.Count -ne 0) -and
(($_.NetIPv4Interface.ConnectionState -eq "Connected") -or
($_.NetIPv6Interface.ConnectionState -eq "Connected"))
</ScriptBlock>
</ItemSelectionCondition>
<ScriptBlock>
$output = "";
foreach($Server in $_.DNSServer) {
foreach($Address in $Server.ServerAddresses) {
$output += $Address + "`n";
}
};
$output.Trim("`n");
</ScriptBlock>
</ListItem>
What formatting gets applied is controlled by the PSTypeNames property which exists on every object:
PS > (Get-NetIPConfiguration)[0].PSTypeNames
NetIPConfiguration
System.Object
When you use Select-Object, it modifies that property, so the resulting object loses its formatting:
PS > (Get-NetIPConfiguration | Select-Object DNSServer)[0].PSTypeNames
Selected.NetIPConfiguration
System.Management.Automation.PSCustomObject
System.Object
Alas, simply setting it back wouldn't work (object doesn't have correct structure for this), but you can emulate it by using calculated property:
Get-NetIPConfiguration | Select-Object InterfaceAlias, InterfaceDescription, InterfaceIndex, Ipv4Address, IPv4DefaultGateway, #{ n='DNSServer' ; e={$_.DNSServer.ServerAddresses -join "`n"}}
This will squash DNSServer to string, so you wouldn't be able to reuse it properly later, though. Perhaps, just outputting ServerAddresses collection would be more convenient and it would look the same:
Get-NetIPConfiguration | Select-Object InterfaceAlias, InterfaceDescription, InterfaceIndex, Ipv4Address, IPv4DefaultGateway, #{ n='DNSServer' ; e={#($_.DNSServer.ServerAddresses)}}
I've omitted to include that I'm piping the whole output to a ConvertTo-HTML cmdlet as not to make the question goes out of scope. But since I'm converting the output to HTML, it means that there is more than 1 way to skin the cat. I do not need to force the DNSServer object to be changed back to its previous formatting.
So, instead of joining the DNSServer with a ', ', I've joined it with a <br> tag instead.
Select-Object InterfaceAlias, InterfaceDescription, InterfaceIndex, #{n='IPv4 Address';e={$_.IPv4Address.IPAddress}}, #{n='IPv4 Default Gateway';e={$_.IPv4DefaultGateway.NextHop}}, #{n='DNS Server';e={$_.DNSServer.ServerAddresses -split " " -join "<br>"}}
Since ConvertTo-HTML translated the <> symbol to < and > respectively, I've added the following code to translate < and > back to <>.
$IPAddressConfigTemp = $IPAddressConfig | ConvertTo-Html -fragment -As List -PreContent "<h2>IP Address Configuration Details</h2>"
$IPAddressConfigHTML = $IPAddressConfigTemp -replace "<", "<" -replace ">", ">" -replace "'", "'"
The partial result of the code looks somewhat like this:
<table>
<tr><td>DNS Server:</td><td>2001:f40:0:3::12:68<br>2001:4860:4860::8888<br>1.1.1.1<br>8.8.8.8</td></tr>
</table>
It's not the most elegant solution, but it at least fits into what I would like to achieve. So, since I'm using calculated property to reach the final solution, I've selected #beatcracker's reply as the correct answer. It helps that his answer answered the whys and helped me to learn further.
Using Select-Object with the -Property parameter results in a new object with a new type (Selected.NetIPConfiguration, pipe to Get-Member to see this).
Formatting in PowerShell is based on types, so the formatting is seeing the new type and not applying the formatting from the old type.
You could conceivably apply a new typename (using the PSTypeNames property), and copy the formatting instructions from the old typename (NetIPConfiguration) to the new one.
Note that the difference in formatting doesn't imply any difference in the property values, it's purely cosmetic.

Select-String showing a line that does not exist on the original output

I am trying to discover which IP and interface a Windows machine is using to communicate with another machine.
This is the command that I am executing:
Find-NetRoute -RemoteIpAddress 192.168.1.10 | Select-String -Pattern "IPAddress"
And this is the response:
MSFT_NetIPAddress (Name = ";C?8;#B8:8;::55?55;55;", CreationClassName = "", SystemCreationClassName = "", SystemName = "")
I do not understand this output because the output of Find-NetRoute without the Select-String is this:
IPAddress : 192.168.0.100
InterfaceIndex : 4
InterfaceAlias : Wi-Fi
AddressFamily : IPv4
Type : Unicast
PrefixLength : 24
PrefixOrigin : Dhcp
SuffixOrigin : Dhcp
AddressState : Preferred
ValidLifetime : 01:10:34
PreferredLifetime : 01:10:34
SkipAsSource : False
PolicyStore : ActiveStore
Caption :
Description :
ElementName :
InstanceID : :8:8:8:9:55>55;C<8;#B8:8<?>55;
AdminDistance :
DestinationAddress :
IsStatic :
RouteMetric : 0
TypeOfRoute : 3
AddressFamily : IPv4
CompartmentId : 1
DestinationPrefix : 0.0.0.0/0
InterfaceAlias : Wi-Fi
InterfaceIndex : 4
InterfaceMetric : 50
NextHop : 192.168.0.254
PreferredLifetime : 02:00:00
Protocol : NetMgmt
Publish : No
State : Alive
Store : ActiveStore
ValidLifetime : 02:00:00
PSComputerName :
ifIndex : 4
Is Select-String really supposed to work similar to "grep" on Windows Powershell?
Aside from | findstr /i, here's another probably not that convenient workaround. You could shorten -stream to -s.
Find-NetRoute -RemoteIpAddress 192.168.1.10 | Out-String -Stream | Select-String ipaddress
IPAddress : 192.168.0.100
You can search property names with select-object:
Find-NetRoute -RemoteIpAddress 192.168.1.10 | select *address*
I wish I could search the property values like this, but unfortunately it doesn't work:
Find-NetRoute -RemoteIpAddress 192.168.1.10 | where * -match 192
I suppose this works, but it outputs all the properties anyway. At least it only outputs matching objects.
Find-NetRoute -RemoteIpAddress 192.168.1.10 | where { $_ -match '192' }
[pscustomobject]#{name='joe';address='here'},
[pscustomobject]#{name='james';address='there'} | where { $_ -match 'th' }
name address
---- -------
james there
EDIT:
I came up with a "search-object" script that only returns the properties (and methods) that match, by name or value:
# search-object.ps1
param ($pattern)
begin {
$hash = #{}
}
process {
$obj = $_
$obj | Get-Member | foreach name |
foreach {
$name = $_
$value = $obj.$name
if ($name -match $pattern -or $value -match $pattern) {
$hash += #{$name = $value}
}
}
[pscustomobject]$hash
}
For example:
get-process cmd | search-object cmd
Modules : {System.Diagnostics.ProcessModule (cmd.exe), System.Diagnostics.ProcessModule
(ntdll.dll), System.Diagnostics.ProcessModule (KERNEL32.DLL),
System.Diagnostics.ProcessModule (KERNELBASE.dll),
System.Diagnostics.ProcessModule (msvcrt.dll)}
Path : C:\Windows\System32\cmd.exe
MainModule : System.Diagnostics.ProcessModule (cmd.exe)
ProcessName : cmd
Name : cmd
MainWindowTitle : cmd
Find-NetRoute -RemoteIpAddress 192.168.1.10 | search-object ipaddress
IPAddress
---------
192.168.0.100
When "Grepping" in PS I tend to lean on findstr.
Try this:
find-netroute -remoteipaddress 10.0.0.1 | findstr "IPAddress"
For me (thats my gateway IP) it returns:
IPAddress : 10.0.0.136
And just an FYI, yes, your syntax gave me the same data from InstanceID.
Here's what I think is happening. As #Lee_Dailey states, Select-String works with [String] instances. Find-NetRoute outputs [CimInstance] instances...
PS> Find-NetRoute -RemoteIpAddress 192.168.1.10 | ForEach-Object { $_.PSObject.TypeNames[0] }
Microsoft.Management.Infrastructure.CimInstance#ROOT/StandardCimv2/MSFT_NetIPAddress
Microsoft.Management.Infrastructure.CimInstance#ROOT/StandardCimv2/MSFT_NetRoute
...so some transformation to [String] needs to take place so the text can be searched. If you run this...
PS> Find-NetRoute -RemoteIpAddress 192.168.1.10 | ForEach-Object { [String] $_ }
MSFT_NetIPAddress (Name = ";C?8;#B8:8;::55?55;55;", CreationClassName = "", SystemCreationClassName = "", SystemName = "")
MSFT_NetRoute (InstanceID = ":8:8:8:9:55>55;C<8;#B8:8<?>55")
...you get the [String] representation of a MSFT_NetIPAddress and MSFT_NetRoute [CimInstance] instances. If you tack the original Select-String command onto that...
PS> Find-NetRoute -RemoteIpAddress 10.10.10.10 | ForEach-Object { [String] $_ } | Select-String -Pattern IPAddress
MSFT_NetIPAddress (Name = ";C?8;#B8:8;::55?55;55;", CreationClassName = "", SystemCreationClassName = "", SystemName = "")
...you get the original output, which is missing the MSFT_NetRoute line. The CIM class name MSFT_NetIPAddress is matched by the pattern IPAddress, which is why that line is present in the output.
My first thought was that it is not casting input objects to [String] but calling ToString() on them, and that is what the documentation suggests...
Inputs
System.Management.Automation.PSObject
You can pipe any object that has a ToString method to Select-String.
...but if I do that I get different text for the MSFT_NetIPAddress instance...
PS> Find-NetRoute -RemoteIpAddress 192.168.1.10 | ForEach-Object { $_.ToString() }
192.168.0.100
MSFT_NetRoute (InstanceID = ":8:8:8:9:55>55;C<8;#B8:8<?>55")
If you look through that documentation there are some mentions of its similarity to or getting it to work like grep and findstr. The issue here, though, is the input text it was searching was not what you thought it would be; the text you saw in your console from a bare Find-NetRoute command was not the same text that would get passed to Select-String via the pipeline.
By the way, if your intention was to just filter the output down to that first IPAddress property that is displayed by Find-NetRoute -RemoteIpAddress 192.168.1.10 then instead of searching the full text for IPAddress you could just "search" for matching property (sub)names with Select-Object...
PS> Find-NetRoute -RemoteIpAddress 192.168.1.10 | Select-Object -Property '*IPAddress*'
IPAddress
---------
192.168.0.100

Why doesn't Get-NetFirewallRule show all information of the firewall rule?

I'm trying to find if a firewall rule already existing, with the same name, same configuration, like: localport.
So I use Get-NetFirewallRule to list all rules, but the rules returned do not contain the information of port, also some other information are missing. where can I find all the config of a rule. Below is the attributess returned:
Name
DisplayName
Description
DisplayGroup
Group
Enabled
Profile
Platform
Direction
Action
EdgeTraversalPolicy
LooseSourceMapping
LocalOnlyMapping
Owner
PrimaryStatus
Status
EnforcementStatus
PolicyStoreSource
PolicyStoreSourceType
What I don't think is understood by many, including me recently, is that the Get-NetFirewall*Filter commands provide a speedy shortcut to searching the firewall rules, like the -filter option does in other commands. If I were to do this, it would take a very long time:
Get-NetFirewallRule | Get-NetFirewallPortFilter |
Where LocalPort -eq 3389
While this is almost instant:
Get-NetFirewallPortFilter | Where LocalPort -eq 3389
And Get-NetFirewallPortFilter actually returns the name of the firewall rule in the InstanceID property, which isn't shown by default. That's why you can pipe Get-NetFirewallPortFilter back into Get-NetFirewallRule.
Get-NetFirewallPortFilter | Where LocalPort -eq 3389 |
Get-NetFirewallRule
Here's a function that gives netsh-like verbose output, with the ports, addresses, and applications:
function mynetsh {
param($displayname)
$rule = get-netfirewallrule -displayname $displayname
$address = $rule | Get-NetFirewallAddressFilter
$port = $rule | Get-NetFirewallPortFilter
$application = $rule | Get-NetFirewallApplicationFilter
[pscustomobject]#{
DisplayName = $rule.DisplayName
Description = $rule.Description
Enabled = $rule.Enabled
Direction = $rule.Direction
Profile = $rule.Profile
DisplayGroup = $rule.DisplayGroup
LocalAddress = $address.LocalAddress
RemoteAddress = $address.RemoteAddress
Protocol = $port.Protocol
LocalPort = $port.LocalPort
RemotePort = $port.RemotePort
EdgeTraversalPolicy = $rule.EdgeTraversalPolicy
Program = $application.Program
Action = $rule.Action
}
}
mynetsh 'Remote Desktop - User Mode (TCP-In)'
DisplayName : Remote Desktop - User Mode (TCP-In)
Description : Inbound rule for the Remote Desktop service to allow RDP traffic. [TCP 3389]
Enabled : False
Direction : Inbound
Profile : Any
DisplayGroup : Remote Desktop
LocalAddress : Any
RemoteAddress : Any
Protocol : TCP
LocalPort : 3389
RemotePort : Any
EdgeTraversalPolicy : Block
Program : %SystemRoot%\system32\svchost.exe
Action : Allow
In order to find the port numbers that are already in the firewall rules, you can use a different cmdlet Get-NetFirewallPortFilter.
(Info)
Use Get-NetFirewallRule to filter which subset of rules you want to look at and pipe it to the above cmdlet. eg.:
Get-NetFirewallRule -DisplayName "SQL Broker Service" | Get-NetFirewallPortFilter
Sounds like the property you are after is localport.
Use the below command to list all.
Get-NetFirewallRule| Where { $_.Enabled -eq $True } |
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}},
Enabled,
Profile,
Direction,
Action
The output is shown below
Use the Select-Object Cmdlet to Display all Properties
This will Display only the First one so you dont get flooded with text, feel free to delete the "-First 1" as needed
Get-NetFirewallRule | select -First 1 -Property *
However investigating that it does not seem like there is Information about the port, looking further into it - you would probably need to use Get-NetFirewallPortFilter and match them up by instanceid. If you need help with that I'll need a little more Information on what you are trying to accomplish.
If you use only the firewall cmdlets to get a list of object that include ports, programs etc., it's not an easy task, and it's very slow! Why not try the old school way, the netsh advfirewall firewall command suite. Below is my trying to get a list of objects that include all rule information.
$output = (netsh advfirewall firewall show rule name=all verbose | Out-String).Trim() -split '\r?\n\s*\r?\n'
$propertyNames = [System.Collections.Generic.List[string]]::new()
$objects = #( $(foreach($section in $output ) {
$obj = #{}
foreach( $line in ($section -split '\r?\n') ) {
if( $line -match '^\-+$' ) { continue }
$name, $value = $line -split ':\s*', 2
$name = $name -replace " ", ""
$obj.$name = $value
if($propertyNames -notcontains $name) {
$propertyNames.Add( $name )
}
}
$obj
}) | % {
foreach( $prop in $propertyNames ) {
if( $_.Keys -notcontains $prop ) {
$_.$prop = $null
}
}
[PSCustomObject]$_
})