适用于 PowerShell 5.1 及以上版本(Windows 内置模块)
Windows 防火墙是服务器和终端安全的第一道防线。无论是部署新服务、排查网络故障还是进行安全加固,都离不开防火墙规则的配置与管理。传统的图形界面操作虽然直观,但在批量管理和自动化场景下效率低下,且容易遗漏。
PowerShell 内置的 NetSecurity 模块提供了完整的防火墙管理能力,支持查看、创建、修改和删除规则,所有操作都可以脚本化、可重复执行。对于运维工程师来说,掌握这套命令不仅能提高日常工作效率,更是实现基础设施即代码(IaC)的重要基础。
查看防火墙规则
日常运维中最常见的操作就是查看当前生效的防火墙规则。Get-NetFirewallRule 是核心命令,结合 Get-NetFirewallPortFilter 和 Get-NetFirewallAddressFilter 可以获取完整的规则详情。
以下函数封装了常用的查询逻辑,支持按名称、方向、启用状态等条件过滤,并输出格式化的规则摘要:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| function Get-FirewallRuleSummary { param( [string]$Name = "*", [ValidateSet("Inbound", "Outbound", "Both")] [string]$Direction = "Both", [switch]$EnabledOnly )
$filter = @{ DisplayName = $Name } if ($Direction -ne "Both") { $filter["Direction"] = $Direction } if ($EnabledOnly) { $filter["Enabled"] = "True" }
$rules = Get-NetFirewallRule @filter
$results = foreach ($rule in $rules) { $portFilter = $rule | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue $addrFilter = $rule | Get-NetFirewallAddressFilter -ErrorAction SilentlyContinue
[PSCustomObject]@{ Name = $rule.DisplayName Direction = $rule.Direction Action = $rule.Action Enabled = $rule.Enabled Protocol = if ($portFilter) { $portFilter.Protocol } else { "Any" } LocalPort = if ($portFilter) { $portFilter.LocalPort } else { "Any" } RemoteAddr = if ($addrFilter) { $addrFilter.RemoteAddress } else { "Any" } Profile = $rule.Profile } }
return $results | Sort-Object Enabled, Direction, Action }
|
执行结果示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| PS> Get-FirewallRuleSummary -Name "*SSH*" -EnabledOnly
Name : OpenSSH Server (sshd) Direction : Inbound Action : Allow Enabled : True Protocol : TCP LocalPort : 22 RemoteAddr : Any Profile : Any
Name : OpenSSH Client Direction : Outbound Action : Allow Enabled : True Protocol : TCP LocalPort : Any RemoteAddr : Any Profile : Any
|
创建防火墙规则
创建规则是防火墙管理中最关键的操作。New-NetFirewallRule 命令支持丰富的参数,可以精确控制协议、端口、地址范围和配置文件。
以下函数将常见的规则创建流程封装为可复用的命令,内置了参数校验和冲突检测逻辑,避免重复创建同名规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| function New-FirewallAllowRule { param( [Parameter(Mandatory)] [string]$Name,
[Parameter(Mandatory)] [int]$Port,
[ValidateSet("TCP", "UDP")] [string]$Protocol = "TCP",
[ValidateSet("Inbound", "Outbound")] [string]$Direction = "Inbound",
[string[]]$RemoteAddress = "Any",
[ValidateSet("Domain", "Private", "Public", "Any")] [string]$Profile = "Any" )
$existing = Get-NetFirewallRule -DisplayName $Name -ErrorAction SilentlyContinue if ($existing) { Write-Warning "规则 '$Name' 已存在,跳过创建" return $existing }
$params = @{ DisplayName = $Name Direction = $Direction Action = "Allow" Protocol = $Protocol LocalPort = $Port RemoteAddress = $RemoteAddress Profile = $Profile Enabled = "True" }
$rule = New-NetFirewallRule @params Write-Host "已创建规则: $Name ($Protocol/$Port, $Direction)" return $rule }
|
执行结果示例:
1 2 3 4 5
| PS> New-FirewallAllowRule -Name "Web Server HTTP" -Port 80 -Protocol TCP 已创建规则: Web Server HTTP (TCP/80, Inbound)
PS> New-FirewallAllowRule -Name "Web Server HTTP" -Port 80 WARNING: 规则 'Web Server HTTP' 已存在,跳过创建
|
批量管理规则
在服务器初始化或安全加固场景中,往往需要一次性配置大量规则。手动逐条创建既繁琐又容易出错,批量管理脚本能显著提升效率和一致性。
以下函数接收规则定义数组,自动创建并输出执行报告,支持回滚操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| function Import-FirewallRuleSet { param( [Parameter(Mandatory)] [string]$RuleSetName,
[Parameter(Mandatory)] [array]$Rules )
$report = @() $created = @()
foreach ($rule in $Rules) { $qualifiedName = "$RuleSetName - $($rule.Name)" try { $result = New-FirewallAllowRule ` -Name $qualifiedName ` -Port $rule.Port ` -Protocol $rule.Protocol ` -Direction $rule.Direction ` -RemoteAddress $rule.RemoteAddress ` -Profile $rule.Profile
if ($result) { $created += $qualifiedName $status = "Created" } else { $status = "Skipped" } } catch { $status = "Error: $($_.Exception.Message)" }
$report += [PSCustomObject]@{ Rule = $qualifiedName Port = "$($rule.Protocol)/$($rule.Port)" Status = $status } }
Write-Host "`n规则集 '$RuleSetName' 导入完成: $($created.Count)/$($Rules.Count) 条已创建" return $report | Format-Table -AutoSize }
|
使用示例——批量导入 Web 服务器所需规则:
1 2 3 4 5 6 7
| $webRules = @( @{ Name = "HTTP"; Port = 80; Protocol = "TCP"; Direction = "Inbound"; RemoteAddress = "Any"; Profile = "Any" } @{ Name = "HTTPS"; Port = 443; Protocol = "TCP"; Direction = "Inbound"; RemoteAddress = "Any"; Profile = "Any" } @{ Name = "SSH"; Port = 22; Protocol = "TCP"; Direction = "Inbound"; RemoteAddress = "10.0.0.0/8"; Profile = "Domain" } )
Import-FirewallRuleSet -RuleSetName "Web Server" -Rules $webRules
|
执行结果示例:
1 2 3 4 5 6 7 8 9 10 11
| 已创建规则: Web Server - HTTP (TCP/80, Inbound) 已创建规则: Web Server - HTTPS (TCP/443, Inbound) 已创建规则: Web Server - SSH (TCP/22, Inbound)
规则集 'Web Server' 导入完成: 3/3 条已创建
Rule Port Status ---- ---- ------ Web Server - HTTP TCP/80 Created Web Server - HTTPS TCP/443 Created Web Server - SSH TCP/22 Created
|
导出与导入规则配置
在多台服务器之间同步防火墙配置,或者在变更前做备份,都需要导出导入功能。以下函数将规则集导出为 JSON 文件,便于版本控制和跨机器部署。
注意这里使用数组拼接 -join 来构建多行文本,避免在代码块中嵌入三反引号导致 Markdown 解析错误:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| function Export-FirewallRules { param( [Parameter(Mandatory)] [string]$NamePattern,
[Parameter(Mandatory)] [string]$OutputPath )
$rules = Get-NetFirewallRule -DisplayName $NamePattern -ErrorAction SilentlyContinue
$export = foreach ($rule in $rules) { $portFilter = $rule | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue $addrFilter = $rule | Get-NetFirewallAddressFilter -ErrorAction SilentlyContinue
@{ Name = $rule.DisplayName Direction = [string]$rule.Direction Action = [string]$rule.Action Enabled = [string]$rule.Enabled Protocol = if ($portFilter) { [string]$portFilter.Protocol } else { "" } LocalPort = if ($portFilter) { [string]$portFilter.LocalPort } else { "" } RemoteAddress = if ($addrFilter) { [string]$addrFilter.RemoteAddress } else { "" } Profile = [string]$rule.Profile } }
$jsonLines = @( "{" ' "ExportDate": "' + (Get-Date -Format "yyyy-MM-dd HH:mm:ss") + '",' ' "RuleCount": ' + $export.Count + ',' ' "Rules": [' )
for ($i = 0; $i -lt $export.Count; $i++) { $comma = if ($i -lt $export.Count - 1) { "," } else { "" } $ruleJson = $export[$i] | ConvertTo-Json -Compress $jsonLines += " $ruleJson$comma" }
$jsonLines += @( " ]" "}" )
($jsonLines -join "`n") | Out-File -FilePath $OutputPath -Encoding UTF8 Write-Host "已导出 $($export.Count) 条规则到: $OutputPath" }
|
执行结果示例:
1 2
| PS> Export-FirewallRules -NamePattern "Web Server*" -OutputPath "C:\Backup\firewall-web.json" 已导出 3 条规则到: C:\Backup\firewall-web.json
|
对应的导入函数从 JSON 文件读取规则定义并批量创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| function Import-FirewallRulesFromFile { param( [Parameter(Mandatory)] [string]$FilePath )
$content = Get-Content -Path $FilePath -Raw | ConvertFrom-Json Write-Host "文件包含 $($content.RuleCount) 条规则,导出时间: $($content.ExportDate)"
$results = @() foreach ($r in $content.Rules) { try { $existing = Get-NetFirewallRule -DisplayName $r.Name -ErrorAction SilentlyContinue if ($existing) { $results += [PSCustomObject]@{ Name = $r.Name; Status = "AlreadyExists" } continue }
New-NetFirewallRule ` -DisplayName $r.Name ` -Direction $r.Direction ` -Action $r.Action ` -Protocol $r.Protocol ` -LocalPort $r.LocalPort ` -RemoteAddress $r.RemoteAddress ` -Profile $r.Profile ` -Enabled $r.Enabled | Out-Null
$results += [PSCustomObject]@{ Name = $r.Name; Status = "Created" } } catch { $results += [PSCustomObject]@{ Name = $r.Name; Status = "Error: $($_.Exception.Message)" } } }
$created = ($results | Where-Object Status -eq "Created").Count Write-Host "`n导入完成: $created 条新建, $($results.Count - $created) 条跳过" return $results | Format-Table -AutoSize }
|
执行结果示例:
1 2 3 4 5 6 7 8 9 10
| PS> Import-FirewallRulesFromFile -FilePath "C:\Backup\firewall-web.json" 文件包含 3 条规则,导出时间: 2025-04-16 10:30:00
导入完成: 3 条新建, 0 条跳过
Name Status ---- ------ Web Server - HTTP Created Web Server - HTTPS Created Web Server - SSH Created
|
服务器安全加固
生产服务器的防火墙配置直接决定攻击面大小。以下加固脚本针对常见的风险点实施最小权限原则:禁用所有入站流量后仅开放必要端口,限制管理端口的访问来源,并关闭不必要的出站流量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| function Initialize-ServerFirewallHardening { param( [int[]]$AllowedInboundPorts = @(80, 443), [int]$SshPort = 22, [string[]]$AdminNetworks = @("10.0.0.0/8", "172.16.0.0/12"), [switch]$WhatIf )
$log = @()
$step1 = "Step 1: 设置默认入站策略为阻止" $log += $step1 Write-Host $step1
if (-not $WhatIf) { Set-NetFirewallProfile -Profile Domain,Public,Private ` -DefaultInboundAction Block ` -DefaultOutboundAction Allow ` -Enabled True }
$step2 = "Step 2: 开放业务端口 ($($AllowedInboundPorts -join ', '))" $log += $step2 Write-Host $step2
foreach ($port in $AllowedInboundPorts) { $ruleName = "Hardened - HTTP/S Port $port" if (-not $WhatIf) { New-FirewallAllowRule -Name $ruleName -Port $port -Protocol TCP | Out-Null } $log += " -> 已开放端口: $port/TCP" }
$step3 = "Step 3: 限制管理端口 ($SshPort) 仅允许管理网段访问" $log += $step3 Write-Host $step3
foreach ($network in $AdminNetworks) { $ruleName = "Hardened - SSH from $network" if (-not $WhatIf) { New-FirewallAllowRule -Name $ruleName -Port $SshPort ` -Protocol TCP -RemoteAddress $network | Out-Null } $log += " -> 已允许: $network -> $SshPort/TCP" }
$step4 = "Step 4: 禁用非必要预置规则" $log += $step4 Write-Host $step4
$builtinDisabled = @() $noisyRules = @( "File and Printer Sharing (Echo Request - ICMPv4-In)" "Network Discovery (NB-Datagram-In)" "Network Discovery (NB-Name-In)" )
foreach ($ruleName in $noisyRules) { $rule = Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue if ($rule -and $rule.Enabled -eq "True") { if (-not $WhatIf) { $rule | Disable-NetFirewallRule | Out-Null } $builtinDisabled += $ruleName } }
$log += " -> 已禁用 $($builtinDisabled.Count) 条预置规则"
$summary = @( "" "========== 加固报告 ==========" "默认入站策略: Block" "业务端口: $($AllowedInboundPorts -join ', ')" "管理端口: $SshPort/TCP (限 $($AdminNetworks -join ', '))" "禁用预置规则: $($builtinDisabled.Count) 条" "WhatIf 模式: $WhatIf" "================================" ) $summary | ForEach-Object { Write-Host $_ }
return $log }
|
执行结果示例(预览模式):
1 2 3 4 5 6 7 8 9 10 11 12 13
| PS> Initialize-ServerFirewallHardening -WhatIf Step 1: 设置默认入站策略为阻止 Step 2: 开放业务端口 (80, 443) Step 3: 限制管理端口 (22) 仅允许管理网段访问 Step 4: 禁用非必要预置规则
========== 加固报告 ========== 默认入站策略: Block 业务端口: 80, 443 管理端口: 22/TCP (限 10.0.0.0/8, 172.16.0.0/12) 禁用预置规则: 3 条 WhatIf 模式: True ================================
|
小结
PowerShell 的 NetSecurity 模块让 Windows 防火墙管理变得完全可脚本化。核心命令只有四个——Get-NetFirewallRule、New-NetFirewallRule、Set-NetFirewallRule、Remove-NetFirewallRule,但配合过滤器和管道可以覆盖几乎所有管理场景。实际运维中建议:始终使用 -WhatIf 预览变更、变更前导出备份、管理端口严格限制来源地址。将这些函数纳入 DSC 或 Ansible Playbook 中,就能实现防火墙策略的版本化管理和自动部署。