PowerShell如何对属性不统一的防火墙规则对象按所有属性分组
Windows重复防火墙规则清理实现
背景
计划清理Windows系统中的重复防火墙规则。已知存在Get-NetFirewallRule这类防火墙专用cmdlet,但传递规则获取附加信息时,例如执行Get-NetFirewallRule -DisplayName xxx | Get-NetFirewallApplicationFilter运行速度过慢,因此采用传统的netsh advfirewall firewall命令集实现需求。
现有解析代码
已经完成netsh命令输出的解析,得到规则对象数组,代码如下:
$output = netsh advfirewall firewall show rule name=all verbose | Out-String $output = [regex]::split($output.trim(), "\r?\n\s*\r?\n"); $objects = @(foreach($section in $output) { $obj = [PSCustomObject]@{} foreach($line in $($section -split '\r?\n')) { if($line -match '^\-+$') { continue } $name, $value = $line -split ':\s*', 2 $name = $name -replace " " , "" $obj | Add-Member -MemberType NoteProperty -Name $name -Value $value } $obj })
遇到的问题
- 数组中的对象属性不统一:部分通过端口+程序定义的规则包含Program、Service属性,仅通过端口定义的规则没有这两个属性
- 无法直接调用
Group-Object传入属性列表分组查找重复项,不同对象的属性集不一致会导致分组逻辑异常
补充说明:这些重复防火墙规则由之前编写的不完善脚本生成。
解决方案
核心思路是先统一所有对象的属性集,补全缺失属性后再进行分组筛选。
步骤1:收集全量属性名
遍历所有规则对象,收集所有出现过的属性名,生成统一的属性全集:
$allProperties = $objects | ForEach-Object { $_.PSObject.Properties.Name } | Select-Object -Unique
步骤2:补全所有对象的缺失属性
给每个对象补全不存在的属性,属性值统一设为空字符串,保证所有对象的属性结构完全一致:
$uniformObjects = foreach ($obj in $objects) { foreach ($prop in $allProperties) { if (-not $obj.PSObject.Properties[$prop]) { $obj | Add-Member -MemberType NoteProperty -Name $prop -Value '' -Force } } $obj }
步骤3:分组筛选重复规则
根据实际判定重复的维度选择属性列表,调用Group-Object分组,筛选出计数大于1的重复规则组:
# 示例按规则名、启用状态、规则方向、操作、协议、本地端口、关联程序维度判定重复,可按需增删属性 $duplicateGroups = $uniformObjects | Group-Object -Property RuleName, Enabled, Direction, Action, Protocol, LocalPort, Program | Where-Object Count -gt 1
步骤4:删除重复规则示例
注意:执行删除操作前建议先打印$rulesToDelete的内容确认要删除的规则是否正确,避免误删系统默认规则
遍历重复规则组,每组保留1条有效规则,删除剩余重复项:
foreach ($group in $duplicateGroups) { # 跳过每组第一条,删除其余重复规则 $rulesToDelete = $group.Group | Select-Object -Skip 1 # 先确认待删除规则可取消注释下行 # $rulesToDelete | Select-Object RuleName, Program, LocalPort, Protocol | Format-Table foreach ($rule in $rulesToDelete) { # 根据规则核心属性匹配删除,避免误删同名不同配置的规则 netsh advfirewall firewall delete rule name="$($rule.RuleName)" program="$($rule.Program)" protocol=$($rule.Protocol) localport=$($rule.LocalPort) } }
内容的提问来源于stack exchange,提问作者Just a learner
相关产品推荐
相关产品推荐

