[英]How can I speed up powershell to get firewall rules on windows 10?
I need to enumerate all firewall rules on windows 10 using PowerShell.我需要使用 PowerShell 枚举 Windows 10 上的所有防火墙规则。 I switched to PowerShell from netsh
because some built-in rules were getting funny names like @{microsoft.windows.shellexperiencehost_10.0.17134.1_neutral_neutral_cw5n1h2txyewy?ms-resource://microsoft.windows.shellexperiencehost/resources/pkgdisplayname}
which I was unable to manage with netsh
.我从netsh
切换到 PowerShell,因为一些内置规则的名称很有趣,例如@{microsoft.windows.shellexperiencehost_10.0.17134.1_neutral_neutral_cw5n1h2txyewy?ms-resource://microsoft.windows.shellexperiencehost/resources/pkgdisplayname}
而我无法使用使用netsh
管理。 Switching to PowerShell shows that the real name was a UID and fixed my problem but the code is really slow to run:切换到 PowerShell 显示真实名称是一个 UID 并解决了我的问题,但代码运行起来真的很慢:
PS C:\Users\vagrant\Desktop> Measure-Command {.\ps-slow.ps1 show}
Seconds : 48
...
In contrast to Measure-Command {show-netfirewallrule}
:与Measure-Command {show-netfirewallrule}
:
...
Milliseconds : 644
And netsh
:和netsh
:
PS C:\Users\vagrant\Desktop> Measure-Command { netsh advfirewall firewall show rule all verbose}
...
TotalSeconds : 1.0588127
By commenting out the Get-NetFirewall*Filter
part of the script it runs at full speed but of course is missing all the data I want.通过注释掉脚本的Get-NetFirewall*Filter
部分,它会全速运行,但当然缺少我想要的所有数据。 The idea is to collect detailed info on all firewall rules and then output the lot as JSON.这个想法是收集所有防火墙规则的详细信息,然后将批次输出为 JSON。
Does anyone have an idea how to optimize this?有谁知道如何优化它? I'm a PowerShell noob so I'm hoping I missed something obvious.我是 PowerShell 菜鸟,所以我希望我错过了一些明显的东西。 The complete script is:完整的脚本是:
Show-NetFirewallRule | `
Where-Object { $_.cimclass.toString() -eq "root/standardcimv2:MSFT_NetFirewallRule" } | `
ForEach-Object { `
$af = $_ | Get-NetFirewallAddressFilter | Select-Object -First 1; # Assumes only one filter
$appf = $_ | Get-NetFirewallApplicationFilter | Select-Object -First 1; # Assumes only one filter
$pf = $_ | Get-NetFirewallPortFilter | Select-Object -First 1; # Assumes only one filter
$if = $_ | Get-NetFirewallInterfaceTypeFilter | Select-Object -First 1; # Assumes only one filter
New-Object -Type PSCustomObject -Property @{
Name = $_.Name
DisplayName = $_.DisplayName
Description = $_.Description
Enabled = $_.Enabled.toString()
Action = $_.Action.toString()
Direction = $_.Direction.toString()
EdgeTraversalPolicy = $_.EdgeTraversalPolicy.toString()
Profile = $_.Profile.toString()
DisplayGroup = $_.DisplayGroup
# Address Filter
LocalAddress = $af.LocalAddress
RemoteAddress = $af.RemoteAddress
LocalIp = $af.LocalIp
RemoteIp = $af.RemoteIp
# Port Filter
LocalPort = $pf.LocalPort
RemotePort = $pf.RemotePort
Protocol = $pf.Protocol
IcmpType = $pf.IcmpType
# Application Filter
Program = $appf.Program
# Interface Filter
InterfaceType = $if.InterfaceType.toString()
}
} | Convertto-json
Ok thanks heaps for everyone who posted.好的,感谢所有发帖的人。 The original problem was that netsh
leaves unresolved names like:最初的问题是netsh
留下未解析的名称,例如:
@{Microsoft.Todos_1.41.12842.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Todos/Resources/app_name_ms_todo}
@{Microsoft.Todos_1.41.12842.0_x64__8wekyb3d8bbwe?ms-resource://Microsoft.Todos/Resources/app_name_ms_todo}
In its output that can only be resolved by PowerShell, using the original script.在只能由 PowerShell 解析的输出中,使用原始脚本。 The problem with this approach is that this is very slow (minutes).这种方法的问题是速度非常慢(几分钟)。
Suggestions on this thread and from colleagues were:关于这个线程和同事的建议是:
@FirewallAPI.dll,-25427
to whatever resource that references)直接读取注册表(大多数情况下有效,但数据以不同的方式未解析,并且需要缓慢的注册表扫描才能解析 - 例如@FirewallAPI.dll,-25427
到引用的任何资源)New-Object -ComObject HNetCfg.FwPolicy
(has the same output problems as netsh
)使用 COM API New-Object -ComObject HNetCfg.FwPolicy
(与netsh
有相同的输出问题)In summary, the optimization I want is impossible without sacrificing the data that I want.综上所述,如果不牺牲我想要的数据,我想要的优化是不可能的。 I'm going to attempt to use the faster COM API/netsh most of the time but switch to using the powershell API when there is no choice (when unresolved names force us to)我将在大部分时间尝试使用更快的 COM API/netsh,但在别无选择时切换到使用 powershell API(当未解析的名称迫使我们这样做时)
This approach is faster, so, maybe a different approach for you to get the same information.这种方法更快,因此,您可能会采用不同的方法来获取相同的信息。
param
(
[switch]$Local,
[switch]$GPO
)
# If no switches are set the script will default to local firewall rules
if (!($Local) -and !($Gpo))
{ $Local = $true }
$RegistryKeys = @()
if ($Local) {$RegistryKeys += 'Registry::HKLM\System\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\FirewallRules'}
if ($GPO) {$RegistryKeys += 'Registry::HKLM\Software\Policies\Microsoft\WindowsFirewall\FirewallRules'}
Foreach ($Key in $RegistryKeys)
{
if (Test-Path -Path $Key)
{
(Get-ItemProperty -Path $Key).PSObject.Members |
Where-Object {
(@('PSPath','PSParentPath','PSChildName') -notcontains $_.Name) -and
($_.MemberType -eq 'NoteProperty') -and
($_.TypeNameOfValue -eq 'System.String')} |
ForEach-Object {
# Prepare hashtable
$HashProps = @{
NameOfRule = $_.Name
RuleVersion = ($_.Value -split '\|')[0]
Action = $null
Active = $null
Dir = $null
Protocol = $null
LPort = $null
App = $null
Name = $null
Desc = $null
EmbedCtxt = $null
Profile = $null
RA4 = $null
RA6 = $null
Svc = $null
RPort = $null
ICMP6 = $null
Edge = $null
LA4 = $null
LA6 = $null
ICMP4 = $null
LPort2_10 = $null
RPort2_10 = $null
}
# Determine if this is a local or a group policy rule and display this in the hashtable
if ($Key -match 'HKLM\\System\\CurrentControlSet')
{ $HashProps.RuleType = 'Local' }
else
{ $HashProps.RuleType = 'GPO' }
# Iterate through the value of the registry key and fill PSObject with the relevant data
ForEach ($FireWallRule in ($_.Value -split '\|'))
{
switch (($FireWallRule -split '=')[0])
{
'Action' {$HashProps.Action = ($FireWallRule -split '=')[1]}
'Active' {$HashProps.Active = ($FireWallRule -split '=')[1]}
'Dir' {$HashProps.Dir = ($FireWallRule -split '=')[1]}
'Protocol' {$HashProps.Protocol = ($FireWallRule -split '=')[1]}
'LPort' {$HashProps.LPort = ($FireWallRule -split '=')[1]}
'App' {$HashProps.App = ($FireWallRule -split '=')[1]}
'Name' {$HashProps.Name = ($FireWallRule -split '=')[1]}
'Desc' {$HashProps.Desc = ($FireWallRule -split '=')[1]}
'EmbedCtxt' {$HashProps.EmbedCtxt = ($FireWallRule -split '=')[1]}
'Profile' {$HashProps.Profile = ($FireWallRule -split '=')[1]}
'RA4' {[array]$HashProps.RA4 += ($FireWallRule -split '=')[1]}
'RA6' {[array]$HashProps.RA6 += ($FireWallRule -split '=')[1]}
'Svc' {$HashProps.Svc = ($FireWallRule -split '=')[1]}
'RPort' {$HashProps.RPort = ($FireWallRule -split '=')[1]}
'ICMP6' {$HashProps.ICMP6 = ($FireWallRule -split '=')[1]}
'Edge' {$HashProps.Edge = ($FireWallRule -split '=')[1]}
'LA4' {[array]$HashProps.LA4 += ($FireWallRule -split '=')[1]}
'LA6' {[array]$HashProps.LA6 += ($FireWallRule -split '=')[1]}
'ICMP4' {$HashProps.ICMP4 = ($FireWallRule -split '=')[1]}
'LPort2_10' {$HashProps.LPort2_10 = ($FireWallRule -split '=')[1]}
'RPort2_10' {$HashProps.RPort2_10 = ($FireWallRule -split '=')[1]}
Default {}
}
}
# Create and output object using the properties defined in the hashtable
New-Object -TypeName 'PSCustomObject' -Property $HashProps
}
}
}
# Partial results
Action : Allow
LPort2_10 :
RuleType : Local
LPort : 135
Edge :
LA6 :
Dir : In
Desc : @icsvc.dll,-710
ICMP4 :
RA4 :
Name : @icsvc.dll,-709
LA4 :
App : %SystemRoot%\system32\svchost.exe
ICMP6 :
Protocol : 6
RuleVersion : v2.0
NameOfRule : vm-monitoring-dcom
RPort :
Svc : RpcSs
RA6 :
Profile :
EmbedCtxt : @icsvc.dll,-700
RPort2_10 :
Active : FALSE
Does Get-NetFirewallRule
give you what you want? Get-NetFirewallRule
满足您的需求吗?
$MyRules = Get-NetFirewallRule
foreach ($rule in $MyRules) {
[the rest of your code]
}
I don't think this is well understood, but the get-netfirewall*filter commands are meant to do things faster.我不认为这很好理解,但 get-netfirewall*filter 命令旨在更快地完成任务。 Just compare the first pipeline to the second pipeline.只需将第一个管道与第二个管道进行比较。 It's like using the -filter option in other commands like get-childitem or get-wmiobject.这就像在 get-childitem 或 get-wmiobject 等其他命令中使用 -filter 选项一样。 I don't think even the writers of the online help understand this.我认为即使是在线帮助的作者也无法理解这一点。 It's like powershell is only 80% documented.就像 powershell 只有 80% 的文档。
Get-NetFirewallRule |
Get-NetFirewallPortFilter |
Where LocalPort -eq 3389 | Get-NetFirewallRule |
Set-NetFirewallRule -RemoteAddress 192.168.1.1 -WhatIf
Get-NetFirewallPortFilter |
Where LocalPort -eq 3389 | Get-NetFirewallRule |
Set-NetFirewallRule -RemoteAddress 192.168.1.1 -WhatIf
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.