functions/System/Drift/Get-FirewallStatusDrift.ps1
|
function Get-FirewallStatusDrift { <# .SYNOPSIS Detects configuration drift in Windows Firewall settings. .DESCRIPTION Checks if firewall profiles and settings match expected baselines. Supports local and remote computers, with configurable profile levels (Basis, Recommended, Strict). Returns PSCustomObject array with drift findings. .PARAMETER ComputerName Target computer name for remote firewall status check. Default: localhost (current computer). .PARAMETER Profile Firewall profile level to check against (Basis, Recommended, Strict). - Basis: All profiles enabled, minimal configuration - Recommended: All profiles enabled, standard security settings - Strict: All profiles enabled, maximum security settings Default: Basis .PARAMETER Detailed Return detailed firewall configuration information (not just drift). Includes rules count, logging settings, default actions. .PARAMETER ReportDriftOnly Only return objects with drift status = "DRIFT". Skips compliant systems. .PARAMETER Credential PSCredential for remote computer authentication (when ComputerName specified). .EXAMPLE Get-FirewallStatusDrift Checks local firewall status against Basis profile. .EXAMPLE Get-FirewallStatusDrift -ComputerName 'SERVER01' -Profile Recommended Checks SERVER01 firewall status against Recommended profile. .EXAMPLE Get-FirewallStatusDrift -Profile Strict -ReportDriftOnly Lists only strict profile violations on local computer. .NOTES DEPENDENCIES: Write-Log (Core) APPLIES TO: Windows Server 2016+ #> [CmdletBinding(SupportsShouldProcess)] param( [string]$ComputerName = 'localhost', [ValidateSet('Basis', 'Recommended', 'Strict')] [string]$Profile = 'Basis', [switch]$Detailed, [switch]$ReportDriftOnly, [pscredential]$Credential ) $findings = @() try { # Get firewall status $fwParams = @{ ErrorAction = 'SilentlyContinue' } if ($ComputerName -ne 'localhost') { $fwParams['ComputerName'] = $ComputerName if ($Credential) { $fwParams['Credential'] = $Credential } } $domainFW = (Get-NetFirewallProfile -Name Domain @fwParams).Enabled $privateFW = (Get-NetFirewallProfile -Name Private @fwParams).Enabled $publicFW = (Get-NetFirewallProfile -Name Public @fwParams).Enabled $anyDisabled = -not $domainFW -or -not $privateFW -or -not $publicFW # Define expected settings per profile $expectedSettings = @{ 'Basis' = @{ 'AllProfilesEnabled' = $true 'InboundDefault' = 'Block' 'OutboundDefault' = 'Allow' 'LogDroppedPackets' = $false 'LogSuccessfulConnections' = $false } 'Recommended' = @{ 'AllProfilesEnabled' = $true 'InboundDefault' = 'Block' 'OutboundDefault' = 'Allow' 'LogDroppedPackets' = $true 'LogSuccessfulConnections' = $false } 'Strict' = @{ 'AllProfilesEnabled' = $true 'InboundDefault' = 'Block' 'OutboundDefault' = 'Block' 'LogDroppedPackets' = $true 'LogSuccessfulConnections' = $true } } $expected = $expectedSettings[$Profile] # Check if all profiles enabled if ($anyDisabled) { if (-not $ReportDriftOnly -or $ReportDriftOnly) { $findings += [PSCustomObject]@{ Category = 'Firewall' Setting = 'Firewall Profiles' Expected = 'Domain:$true, Private:$true, Public:$true' Actual = "Domain:$domainFW, Private:$privateFW, Public:$publicFW" Status = 'DRIFT' Severity = 'HIGH' ComputerName = $ComputerName } } } # Get additional firewall settings for detailed/Recommended/Strict profiles if ($Profile -ne 'Basis' -or $Detailed) { $domainProfile = Get-NetFirewallProfile -Name Domain @fwParams $inboundDefault = $domainProfile.DefaultInboundAction $outboundDefault = $domainProfile.DefaultOutboundAction # Check inbound default action if ($inboundDefault -ne $expected['InboundDefault']) { $findings += [PSCustomObject]@{ Category = 'Firewall' Setting = 'Inbound Default Action' Expected = $expected['InboundDefault'] Actual = $inboundDefault Status = 'DRIFT' Severity = 'MEDIUM' ComputerName = $ComputerName } } # Check outbound default action if ($outboundDefault -ne $expected['OutboundDefault']) { $findings += [PSCustomObject]@{ Category = 'Firewall' Setting = 'Outbound Default Action' Expected = $expected['OutboundDefault'] Actual = $outboundDefault Status = 'DRIFT' Severity = 'MEDIUM' ComputerName = $ComputerName } } } # Get firewall rules count if ($Detailed) { $ruleParams = $fwParams.Clone() $inboundRules = @(Get-NetFirewallRule -Direction Inbound @ruleParams).Count $outboundRules = @(Get-NetFirewallRule -Direction Outbound @ruleParams).Count $findings += [PSCustomObject]@{ Category = 'Firewall' Setting = 'Inbound Rules Count' Expected = 'N/A' Actual = $inboundRules Status = 'INFO' Severity = 'INFO' ComputerName = $ComputerName } $findings += [PSCustomObject]@{ Category = 'Firewall' Setting = 'Outbound Rules Count' Expected = 'N/A' Actual = $outboundRules Status = 'INFO' Severity = 'INFO' ComputerName = $ComputerName } } # If no drift found and not Detailed, add compliance entry if ($findings.Count -eq 0 -and -not $Detailed) { if (-not $ReportDriftOnly) { $findings += [PSCustomObject]@{ Category = 'Firewall' Setting = 'Firewall Profiles' Expected = 'All Enabled' Actual = "Domain:$domainFW, Private:$privateFW, Public:$publicFW" Status = 'COMPLIANT' Severity = 'INFO' ComputerName = $ComputerName } } } # Log results if ($findings) { $driftCount = @($findings | Where-Object { $_.Status -eq 'DRIFT' }).Count Write-Log -Message "Firewall status check for $ComputerName - Profile:$Profile - Found $driftCount drift items" ` -Level Info -Caller $MyInvocation.MyCommand.Name } } catch { Write-Log -Message "Error checking firewall status on $ComputerName : $_" -Level Error -Caller $MyInvocation.MyCommand.Name throw } return $findings } |