windows 防火墙重复规则清理脚本

Windows每此点击防火墙规则放行都会不加验证的生成一条新的规则,一段时间后你打开规则列表,那密密麻麻的重复规则能让强迫症现场去世。虽然说对性能的影响微乎其微,但看不得,手动清理太慢还容易出错,把需求整理了一下让AI糊了一个脚本。定期执行一下,舒爽。

用法:把下面的代码保存为随便什么名字,比如 FirewallClean.ps1,保存格式记得 UTF8 with DOM (win毛病多,没 DOM 有时候会乱码),然后管理员方式运行,根据提示操作,旧的规则会被备份到 文档/Firewall_Backups,删不删你来定,备份是硬判定,不用担心。没了!

25/12/03 更新:感谢xiaoh同学反馈,新版本已强化端口协议判定,交互也更清晰了。

主要改进:

  • 使用 Get-NetFirewallPortFilter 获取完整的协议和端口信息
  • 使用 Get-NetFirewallAddressFilter、Get-NetFirewallApplicationFilter、Get-NetFirewallServiceFilter 获取所有过滤器详情
  • 构建唯一指纹字符串,包含所有关键属性
  • 在显示结果时明确展示协议和端口信息,便于确认

(无论如何,自定义规则备份很重要)

<#
.SYNOPSIS
    一个用于查找和清理 Windows 防火墙中重复规则的交互式脚本。

.DESCRIPTION
    该脚本提供一个菜单,允许用户选择检查入站、出站或所有规则。
    它会首先识别并列出所有内容完全一致的重复规则。在用户确认后,
    脚本会自动备份当前的防火墙设置,然后清理掉这些重复的规则(每个重复组仅保留一条)。
    最后,它会重新运行检查以验证清理效果。

.NOTES
    必须以管理员身份运行此脚本。
#>

# --- 前置检查:确保以管理员权限运行 ---
$currentUserPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if (-not $currentUserPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Write-Error "错误:此脚本需要管理员权限才能修改防火墙规则。"
    Write-Host "请右键单击此脚本文件,然后选择 '以管理员身份运行'。" -ForegroundColor Yellow
    Start-Sleep -Seconds 7
    exit
}

# --- 核心函数定义 ---

function Get-DuplicateFirewallRules {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateSet('Inbound', 'Outbound', 'All')]
        [string]$Scope
    )
    
    Write-Host "正在检查重复规则,范围: $Scope..." -ForegroundColor Cyan

    $rulesToProcess = switch ($Scope) {
        'Inbound'  { Get-NetFirewallRule -Direction Inbound  -ErrorAction SilentlyContinue }
        'Outbound' { Get-NetFirewallRule -Direction Outbound -ErrorAction SilentlyContinue }
        'All'      { Get-NetFirewallRule -ErrorAction SilentlyContinue }
    }

    # 为每条规则构建完整的指纹信息
    $rulesWithFingerprint = $rulesToProcess | ForEach-Object {
        $rule = $_
        $portFilter = $rule | Get-NetFirewallPortFilter
        $addressFilter = $rule | Get-NetFirewallAddressFilter
        $applicationFilter = $rule | Get-NetFirewallApplicationFilter
        $serviceFilter = $rule | Get-NetFirewallServiceFilter
        
        [PSCustomObject]@{
            Rule = $rule
            Fingerprint = @(
                $rule.DisplayName
                $rule.Direction
                $rule.Action
                $rule.Enabled
                $rule.Profile
                $portFilter.Protocol
                $portFilter.LocalPort -join ','
                $portFilter.RemotePort -join ','
                $addressFilter.LocalAddress -join ','
                $addressFilter.RemoteAddress -join ','
                $applicationFilter.Program
                $serviceFilter.Service
            ) -join '|'
        }
    }

    # 根据指纹分组,筛选出重复组
    $duplicateGroups = $rulesWithFingerprint | Group-Object -Property Fingerprint | Where-Object { $_.Count -gt 1 }
    
    return $duplicateGroups
}

function Display-DuplicateResults {
    [CmdletBinding()]
    param (
        $DuplicateGroups
    )

    if ($DuplicateGroups) {
        Write-Host "----------------- 检查结果 -----------------" -ForegroundColor Yellow
        Write-Host "发现 $($DuplicateGroups.Count) 组重复的防火墙规则。详情如下:" -ForegroundColor Yellow
        
        $totalRedundantCount = 0
        
        $DuplicateGroups | ForEach-Object {
            $group = $_
            $redundantInGroup = $group.Count - 1
            $totalRedundantCount += $redundantInGroup
            
            $firstRule = $group.Group[0].Rule
            $portFilter = $firstRule | Get-NetFirewallPortFilter

            Write-Host " "
            Write-Host "规则组: '$($firstRule.DisplayName)' (共 $($group.Count) 条, 可清理 $redundantInGroup 条)" -ForegroundColor Green
            Write-Host "  协议: $($portFilter.Protocol) | 本地端口: $($portFilter.LocalPort) | 远程端口: $($portFilter.RemotePort)" -ForegroundColor Gray
            $group.Group.Rule | Select-Object Name, Description | Format-Table -AutoSize
        }
        
        Write-Host "========================================================" -ForegroundColor Yellow
        Write-Host "总计发现可清理的冗余规则数量: $totalRedundantCount" -ForegroundColor Yellow
        return $true
    } else {
        Write-Host "----------------- 检查结果 -----------------" -ForegroundColor Green
        Write-Host "恭喜!在指定范围内未发现任何重复的防火墙规则。" -ForegroundColor Green
        Write-Host "========================================================" -ForegroundColor Green
        return $false
    }
}

function Backup-FirewallRules {
    Write-Host " "
    Write-Host "正在执行清理前的备份操作..." -ForegroundColor Cyan
    
    try {
        $documentsPath = [Environment]::GetFolderPath('MyDocuments')
        $backupFolder = Join-Path -Path $documentsPath -ChildPath "Firewall_Backups"
        
        if (-not (Test-Path -Path $backupFolder)) {
            New-Item -ItemType Directory -Path $backupFolder | Out-Null
        }

        $backupFile = "firewall_backup_$(Get-Date -Format 'yyyy-MM-dd_HHmmss').wfw"
        $backupPath = Join-Path -Path $backupFolder -ChildPath $backupFile
        
        netsh advfirewall export $backupPath
        
        Write-Host "防火墙规则已成功备份到:" -ForegroundColor Green
        Write-Host $backupPath -ForegroundColor White
        return $true
    } catch {
        Write-Error "备份失败! 错误信息: $_"
        return $false
    }
}

function Clean-DuplicateFirewallRules {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        $DuplicateGroups
    )

    Write-Host " "
    Write-Host "开始执行清理操作..." -ForegroundColor Cyan
    $progress = 0
    $totalToDelete = ($DuplicateGroups | ForEach-Object { $_.Count - 1 } | Measure-Object -Sum).Sum

    $DuplicateGroups | ForEach-Object {
        $group = $_
        # 跳过每个组的第一条规则(保留),将其余的全部删除
        $rulesToDelete = $group.Group | Select-Object -Skip 1
        
        foreach ($item in $rulesToDelete) {
            $progress++
            Write-Progress -Activity "正在清理重复规则" -Status "正在删除 '$($item.Rule.DisplayName)'" -PercentComplete (($progress / $totalToDelete) * 100)
            
            try {
                Remove-NetFirewallRule -Name $item.Rule.Name -ErrorAction Stop
            } catch {
                Write-Warning "删除规则 '$($item.Rule.Name)' 时遇到错误: $_"
            }
        }
    }
    Write-Progress -Activity "清理完成" -Completed
    Write-Host "清理操作已完成。" -ForegroundColor Green
}

# --- 脚本主流程 ---

Clear-Host

# 1. 显示菜单并获取用户选择
$menuChoice = 0
while ($menuChoice -notin 1..4) {
    Write-Host @"

欢迎使用 Windows 防火墙重复规则清理工具
==========================================
请选择要检查的规则范围:

    1. 仅检查【入站】规则
    2. 仅检查【出站】规则
    3. 检查【入站和出站】所有规则
    
    4. 退出

==========================================
"@ -ForegroundColor White
    $input = Read-Host "请输入数字并按回车"
    if ($input -match "^\d+$") {
        $menuChoice = [int]$input
    }
}

if ($menuChoice -eq 4) {
    Write-Host "已退出。"
    exit
}

# 2. 根据选择确定范围
$scope = switch ($menuChoice) {
    1 { 'Inbound' }
    2 { 'Outbound' }
    3 { 'All' }
}

# 3. 首次执行检查
$duplicateGroups = Get-DuplicateFirewallRules -Scope $scope
$hasDuplicates = Display-DuplicateResults -DuplicateGroups $duplicateGroups

# 4. 如果有重复,询问是否清理
if ($hasDuplicates) {
    Write-Host " "
    $confirmation = Read-Host "是否要自动备份并清理这些重复规则? (请输入 Y 确认,其他任意键取消)"
    
    if ($confirmation -eq 'Y' -or $confirmation -eq 'y') {
        # 5. 执行备份
        if (Backup-FirewallRules) {
            # 6. 执行清理
            Clean-DuplicateFirewallRules -DuplicateGroups $duplicateGroups
        
            # 7. 再次执行检查以验证结果
            Write-Host " "
            Write-Host "--- 清理后验证 ---" -ForegroundColor Cyan
            $postCleanupGroups = Get-DuplicateFirewallRules -Scope $scope
            Display-DuplicateResults -DuplicateGroups $postCleanupGroups
        } else {
            Write-Host "由于备份失败,清理操作已中止。" -ForegroundColor Red
        }
    } else {
        Write-Host "操作已取消,未做任何更改。" -ForegroundColor Yellow
    }
}

# 8. 结束退出
Write-Host " "
Read-Host "所有操作已完成。按回车键退出。"
操作系统类型版本是否兼容
客户端 (Client)Windows 11✅ 是
Windows 10✅ 是
Windows 8.1 / 8✅ 是
Windows 7❌ 否
服务器 (Server)Windows Server 2022✅ 是
Windows Server 2019✅ 是
Windows Server 2016

( important!游戏机搞搞就行了,别在你的 Winserver 上搞这些,概不负责)

本文链接:

https://blog.coffox.cc/archives/32/
1 + 8 =
2 评论
    xiaohChrome 140Windows 10
    2025年09月17日 回复

    我这一个例子,爱思助手,tcp两条,udp两条,返回结果共4可清理3。这不分tcp和udp呀,清掉3条,就只有1条tcp了吧

      coffoxChrome 142Windows 10
      2025年12月03日 回复

      @xiaoh 感谢回馈 :) 检查更新一下,现在的清理逻辑有点简单,主要应对的是那些编译测试或软件更新重复添加的大量规则。