# GPOFirewall.ps1 # Windows Firewall rule and profile management via GPO. # Uses Open-NetGPO / New-NetFirewallRule -GPOSession / Save-NetGPO cmdlets. # Depends on: GPOCore.ps1 (Get-GPOSysvolPath) function Set-GPOFirewallProfiles { <# .SYNOPSIS Sets Windows Firewall profile settings (Domain/Private/Public) on a GPO via registry values. #> param( [Parameter(Mandatory)] [string]$GPOName, [Parameter(Mandatory)] [hashtable]$FirewallProfiles, [string]$Domain = (Get-ADDomain).DNSRoot ) $profileKeyMap = @{ Domain = 'HKLM\Software\Policies\Microsoft\WindowsFirewall\DomainProfile' Private = 'HKLM\Software\Policies\Microsoft\WindowsFirewall\PrivateProfile' Public = 'HKLM\Software\Policies\Microsoft\WindowsFirewall\PublicProfile' } $actionMap = @{ 'Block' = 1 'Allow' = 0 'NotConfigured' = 0 } foreach ($profileName in $FirewallProfiles.Keys) { $profile = $FirewallProfiles[$profileName] $regKey = $profileKeyMap[$profileName] if (-not $regKey) { Write-Host " [WARN] Unknown firewall profile: $profileName" -ForegroundColor Yellow continue } # Enable/Disable firewall for this profile if ($profile.ContainsKey('Enabled')) { $enableValue = if ($profile.Enabled) { 1 } else { 0 } Set-GPRegistryValue -Name $GPOName -Key $regKey -ValueName 'EnableFirewall' ` -Type DWord -Value $enableValue -Domain $Domain | Out-Null } # Default inbound action if ($profile.ContainsKey('DefaultInboundAction')) { $inValue = $actionMap[$profile.DefaultInboundAction] Set-GPRegistryValue -Name $GPOName -Key $regKey -ValueName 'DefaultInboundAction' ` -Type DWord -Value $inValue -Domain $Domain | Out-Null } # Default outbound action if ($profile.ContainsKey('DefaultOutboundAction')) { $outValue = $actionMap[$profile.DefaultOutboundAction] Set-GPRegistryValue -Name $GPOName -Key $regKey -ValueName 'DefaultOutboundAction' ` -Type DWord -Value $outValue -Domain $Domain | Out-Null } Write-Host " [SET] Firewall profile: $profileName" -ForegroundColor Green } } function Compare-GPOFirewallProfiles { <# .SYNOPSIS Compares desired firewall profile settings against current GPO state. #> param( [Parameter(Mandatory)] [string]$GPOName, [Parameter(Mandatory)] [hashtable]$FirewallProfiles, [string]$Domain = (Get-ADDomain).DNSRoot ) $profileKeyMap = @{ Domain = 'HKLM\Software\Policies\Microsoft\WindowsFirewall\DomainProfile' Private = 'HKLM\Software\Policies\Microsoft\WindowsFirewall\PrivateProfile' Public = 'HKLM\Software\Policies\Microsoft\WindowsFirewall\PublicProfile' } $actionMap = @{ 'Block' = 1 'Allow' = 0 'NotConfigured' = 0 } $diffs = @() Write-Host " Comparing firewall profiles..." -ForegroundColor Yellow foreach ($profileName in $FirewallProfiles.Keys) { $profile = $FirewallProfiles[$profileName] $regKey = $profileKeyMap[$profileName] if (-not $regKey) { continue } $settingsToCheck = @() if ($profile.ContainsKey('Enabled')) { $desired = if ($profile.Enabled) { 1 } else { 0 } $settingsToCheck += @{ ValueName = 'EnableFirewall'; Desired = $desired } } if ($profile.ContainsKey('DefaultInboundAction')) { $settingsToCheck += @{ ValueName = 'DefaultInboundAction'; Desired = $actionMap[$profile.DefaultInboundAction] } } if ($profile.ContainsKey('DefaultOutboundAction')) { $settingsToCheck += @{ ValueName = 'DefaultOutboundAction'; Desired = $actionMap[$profile.DefaultOutboundAction] } } foreach ($setting in $settingsToCheck) { $current = $null try { $regResult = Get-GPRegistryValue -Name $GPOName -Key $regKey -ValueName $setting.ValueName ` -Domain $Domain -ErrorAction Stop $current = $regResult.Value } catch { $current = $null } if ($current -ne $setting.Desired) { $currentDisplay = if ($null -eq $current) { '(not set)' } else { $current } Write-Host " [DRIFT] $profileName\$($setting.ValueName): $currentDisplay -> $($setting.Desired)" -ForegroundColor Red $diffs += [PSCustomObject]@{ Type = 'FirewallProfile' Profile = $profileName Setting = $setting.ValueName Current = $currentDisplay Desired = $setting.Desired } } else { Write-Host " [OK] $profileName\$($setting.ValueName) = $current" -ForegroundColor Green } } } if ($diffs.Count -eq 0) { Write-Host " [OK] All firewall profiles match desired state" -ForegroundColor Green } return $diffs } function Set-GPOFirewall { <# .SYNOPSIS Writes Windows Firewall rules to a GPO using Open-NetGPO session. Full overwrite semantics -- removes all existing rules, then creates declared rules. #> param( [Parameter(Mandatory)] [string]$GPOName, [Parameter(Mandatory)] [array]$FirewallRules, [string]$Domain = (Get-ADDomain).DNSRoot ) $domainFqdn = $Domain Write-Host " Applying firewall rules..." -ForegroundColor Yellow # Open a GPO session $gpoSession = Open-NetGPO -PolicyStore "$domainFqdn\$GPOName" # Remove all existing rules in this GPO try { $existing = Get-NetFirewallRule -GPOSession $gpoSession -ErrorAction SilentlyContinue if ($existing) { Remove-NetFirewallRule -GPOSession $gpoSession -All Write-Host " Removed $(@($existing).Count) existing rule(s)" -ForegroundColor Yellow } } catch { # No existing rules -- nothing to remove } # Create each declared rule foreach ($rule in $FirewallRules) { $params = @{ GPOSession = $gpoSession DisplayName = $rule.DisplayName Direction = $rule.Direction Action = $rule.Action } if ($rule.Protocol) { $params.Protocol = $rule.Protocol } if ($rule.LocalPort) { $params.LocalPort = $rule.LocalPort } if ($rule.RemotePort) { $params.RemotePort = $rule.RemotePort } if ($rule.LocalAddress) { $params.LocalAddress = $rule.LocalAddress } if ($rule.RemoteAddress) { $params.RemoteAddress = $rule.RemoteAddress } if ($rule.Program) { $params.Program = $rule.Program } if ($rule.Description) { $params.Description = $rule.Description } if ($rule.ContainsKey('Enabled')) { $params.Enabled = if ($rule.Enabled) { 'True' } else { 'False' } } if ($rule.Profile) { $params.Profile = $rule.Profile } New-NetFirewallRule @params | Out-Null Write-Host " [CREATED] $($rule.DisplayName)" -ForegroundColor Green } # Save the GPO session Save-NetGPO -GPOSession $gpoSession Write-Host " [OK] $($FirewallRules.Count) firewall rule(s) applied" -ForegroundColor Green } function Compare-GPOFirewall { <# .SYNOPSIS Compares desired firewall rules against current GPO state. Reports missing, extra, and differing rules. #> param( [Parameter(Mandatory)] [string]$GPOName, [Parameter(Mandatory)] [array]$FirewallRules, [string]$Domain = (Get-ADDomain).DNSRoot ) $domainFqdn = $Domain $diffs = @() Write-Host " Comparing firewall rules..." -ForegroundColor Yellow # Read rules via PolicyStore (Get-NetFirewallRule has no -GPOSession parameter) $policyStore = "$domainFqdn\$GPOName" $existing = @() try { $existing = @(Get-NetFirewallRule -PolicyStore $policyStore -ErrorAction SilentlyContinue) } catch { # No rules found } $existingByName = @{} foreach ($r in $existing) { $existingByName[$r.DisplayName] = $r } # Check for missing rules foreach ($rule in $FirewallRules) { if ($existingByName.ContainsKey($rule.DisplayName)) { $current = $existingByName[$rule.DisplayName] $mismatch = $false if ($rule.Direction -and $current.Direction -ne $rule.Direction) { $mismatch = $true } if ($rule.Action -and $current.Action -ne $rule.Action) { $mismatch = $true } if ($mismatch) { Write-Host " [DRIFT] Rule differs: $($rule.DisplayName)" -ForegroundColor Red $diffs += [PSCustomObject]@{ Type = 'FirewallRule' Rule = $rule.DisplayName Status = 'Differs' } } else { Write-Host " [OK] $($rule.DisplayName)" -ForegroundColor Green } } else { Write-Host " [DRIFT] Missing rule: $($rule.DisplayName)" -ForegroundColor Red $diffs += [PSCustomObject]@{ Type = 'FirewallRule' Rule = $rule.DisplayName Status = 'Missing' } } } # Check for extra rules (in GPO but not declared) $declaredNames = @{} foreach ($rule in $FirewallRules) { $declaredNames[$rule.DisplayName] = $true } foreach ($r in $existing) { if (-not $declaredNames.ContainsKey($r.DisplayName)) { Write-Host " [DRIFT] Extra rule: $($r.DisplayName)" -ForegroundColor Red $diffs += [PSCustomObject]@{ Type = 'FirewallRule' Rule = $r.DisplayName Status = 'Extra (undeclared)' } } } if ($diffs.Count -eq 0) { Write-Host " [OK] All firewall rules match desired state" -ForegroundColor Green } else { Write-Host " [DRIFT] $($diffs.Count) firewall rule difference(s) found" -ForegroundColor Red } return $diffs }