Windows系统清理重复的防火墙规则脚本

Cleanup-FirewallDuplicates_CN.ps1

# 设置输出编码为 UTF-8,确保中文正常显示
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

# 使用 netsh 获取所有防火墙规则(比 Get-NetFirewallRule 快得多)
$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()

# 定义中英文属性名映射表(中文系统字段)
$propertyMap = @{
    "名称"          = "RuleName"
    "组"            = "Group"
    "配置文件"      = "Profiles"
    "已启用"        = "Enabled"
    "操作"          = "Action"
    "替代"          = "Override"
    "程序"          = "Program"
    "本地地址"      = "LocalIP"
    "远程地址"      = "RemoteIP"
    "协议"          = "Protocol"
    "本地端口"      = "LocalPort"
    "远程端口"      = "RemotePort"
    "授权的用户"    = "AuthorizedUsers"
    "授权的计算机"  = "AuthorizedComputers"
    "授权的本地主体" = "AuthorizedLocalPrincipals"
    "本地用户所有者" = "LocalUserOwner"
    "应用程序包"    = "AppPackage"
    "显示名称"      = "DisplayName"  # 备用名称
}

$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.Trim()
        
        # 映射为标准属性名
        $mappedName = $propertyMap[$name]
        if (-not $mappedName) {
            # 如果映射不存在,则清理原始名称
            $mappedName = $name -replace " ", ""
        }
        
        $obj.$mappedName = $value
        if($propertyNames -notcontains $mappedName) {
            $propertyNames.Add($mappedName)
        }
    }
    $obj
}) | % {
    foreach( $prop in $propertyNames ) {
        if( $_.Keys -notcontains $prop ) {
            $_.$prop = $null
        }
    }
    [PSCustomObject]$_
})

# 按中文系统属性分组
$r = $objects | Group-Object -Property RuleName, Program, Action, Profiles, RemoteIP, RemotePort, LocalIP, LocalPort, Enabled, Protocol

$r | ?{$_.Count -gt 1} | %{
    # 获取组内的第一个规则对象
    $firstRule = $_ | Select-Object -ExpandProperty group | Select-Object -First 1
    
    # 优先使用 DisplayName,其次使用 RuleName(中文系统可能使用"名称")
    if ($firstRule.PSObject.Properties.Name -contains "DisplayName") {
        $name = $firstRule.DisplayName
    } elseif ($firstRule.PSObject.Properties.Name -contains "RuleName") {
        $name = $firstRule.RuleName
    } else {
        Write-Warning "无法获取规则名称,跳过此组规则"
        return
    }
    
    Write-Host "处理重复规则组: $name" -ForegroundColor Cyan
    
    try {
        # 获取所有同名规则并跳过第一个(保留)
        $rulesToRemove = Get-NetFirewallRule -DisplayName $name | Select-Object -Skip 1
        
        if ($rulesToRemove) {
            Write-Host "  找到 $($rulesToRemove.Count) 个重复规则,正在删除..." -ForegroundColor Yellow
            $rulesToRemove | Remove-NetFirewallRule -Confirm:$false
            Write-Host "  已成功删除重复规则" -ForegroundColor Green
        } else {
            Write-Host "  没有找到需要删除的重复规则" -ForegroundColor Gray
        }
    } catch {
        Write-Error "删除规则时出错: $_"
    }
}

使用:打开Powershell,执行:

cd .\Desktop\
powershell -ExecutionPolicy Bypass -File .\Cleanup-FirewallDuplicates_CN.ps1
posted @ 2025-05-12 10:50  wanghongwei-dev  阅读(66)  评论(0)    收藏  举报