我需要使用PowerShell枚举Windows 10上的所有防火墙规则。我从netsh
切换到PowerShell,因为某些内置规则获得了{em>这样的名字,例如@{microsoft.windows.shellexperiencehost_10.0.17134.1_neutral_neutral_cw5n1h2txyewy?ms-resource://microsoft.windows.shellexperiencehost/resources/pkgdisplayname}
,而我无法用netsh
进行管理。切换到PowerShell显示真实名称是UID,并解决了我的问题,但是代码确实运行缓慢:
PS C:\Users\vagrant\Desktop> Measure-Command {.\ps-slow.ps1 show}
Seconds : 48
...
与Measure-Command {show-netfirewallrule}
相比:
...
Milliseconds : 644
还有netsh
:
PS C:\Users\vagrant\Desktop> Measure-Command { netsh advfirewall firewall show rule all verbose}
...
TotalSeconds : 1.0588127
通过注释掉脚本的Get-NetFirewall*Filter
部分,它可以全速运行,但是当然会丢失我想要的所有数据。想法是收集有关所有防火墙规则的详细信息,然后将其输出为JSON。
有人知道如何优化它吗?我是PowerShell的新手,所以我希望我能错过一些显而易见的事情。完整的脚本是:
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
答案 0 :(得分:0)
这种方法更快,因此,获得相同信息的方法可能会有所不同。
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
答案 1 :(得分:0)
Get-NetFirewallRule
会给您想要的东西吗?
$MyRules = Get-NetFirewallRule
foreach ($rule in $MyRules) {
[the rest of your code]
}
答案 2 :(得分:0)
好的,谢谢大家发帖。最初的问题是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}
在输出中,只能使用原始脚本由PowerShell解析。这种方法的问题是,这很慢(几分钟)。
对此线程和同事的建议是:
@FirewallAPI.dll,-25427
引用的任何资源)New-Object -ComObject HNetCfg.FwPolicy
(与netsh
具有相同的输出问题)总而言之,如果不牺牲我想要的数据,我想要的优化是不可能的。我将尝试大多数时候使用速度更快的COM API / netsh ,但在别无选择时(当无法解析的名称迫使我们使用时)切换到使用powershell API。
答案 3 :(得分:0)
我认为这不是一个很好的理解,但是get-netfirewall * filter命令可以更快地执行操作。只需将第一个管道与第二个管道进行比较即可。就像在其他命令(如get-childitem或get-wmiobject)中使用-filter选项一样。我认为甚至连在线帮助的作者都无法理解这一点。就像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