scripts/Detect_Security_Drift.ps1
|
<# .SYNOPSIS Detects configuration drift in Windows security hardening settings. .DESCRIPTION Comprehensive security drift detection script that checks multiple hardening categories: - Account Policies (password length, complexity) - Network Security (SMB1, NTLMv2) - RDP Security (encryption, NLA) - Firewall Status (all profiles enabled) - Audit Policies (logon, privilege use) - Windows Updates (automatic updates) - Service Security (dangerous services disabled) Generates and exports CSV report with detailed drift findings. .PARAMETER OutputDirectory Output directory for CSV report (default: logs/). .EXAMPLE .\Detect_Security_Drift.ps1 .\Detect_Security_Drift.ps1 -OutputDirectory "C:\Reports" .NOTES AUTHOR: WinHarden Team VERSION: 1.0 REQUIRES: PowerShell 5.1+ RUN AS: SYSTEM (Highest Privileges recommended) SCHEDULE: Weekly (e.g., Monday @ 10:00 AM via Task Scheduler) DEPENDENCIES: Core Module (Write-Log), System Module (Drift functions) #> [CmdletBinding(SupportsShouldProcess)] param( [string]$OutputDirectory = "$(Split-Path $PSScriptRoot -Parent)\logs" ) $ErrorActionPreference = "Stop" # Load Core Module (Write-Log, validation helpers) $corePath = Join-Path (Split-Path $PSScriptRoot -Parent) "modules\Core.psm1" if (-not (Test-Path $corePath)) { Write-Error "Core module not found at: $corePath" -ErrorAction Stop } . $corePath Write-Output "" Write-Output "==============================================================" Write-Output " WINHARDEN CONFIGURATION DRIFT DETECTION" Write-Output "==============================================================" Write-Output "" Write-Output "Start Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" $driftFindings = @() $startTime = Get-Date try { # Load Drift Detection Functions dynamically $driftFunctionsPath = Join-Path (Split-Path $PSScriptRoot -Parent) "functions\System\Drift" if (-not (Test-Path $driftFunctionsPath)) { throw "Drift functions directory not found at: $driftFunctionsPath" } # Required drift detection functions $requiredFunctions = @( 'Get-AccountPoliciesDrift', 'Get-NetworkSecurityDrift', 'Get-RDPSecurityDrift', 'Get-FirewallStatusDrift', 'Get-AuditPoliciesDrift', 'Get-UpdateStatusDrift', 'Get-ServiceSecurityDrift', 'New-SecurityDriftReport' ) # Load all Get-*.ps1 files Get-ChildItem -Path $driftFunctionsPath -Filter "Get-*.ps1" | ForEach-Object { Write-Verbose "Loading drift detection function: $($_.BaseName)" . $_.FullName } # Load New-SecurityDriftReport helper $reportFuncPath = Join-Path $driftFunctionsPath "New-SecurityDriftReport.ps1" if (Test-Path $reportFuncPath) { . $reportFuncPath } # Validate that all required functions are loaded $missingFunctions = @() foreach ($funcName in $requiredFunctions) { if (-not (Get-Command $funcName -ErrorAction SilentlyContinue)) { $missingFunctions += $funcName } } if ($missingFunctions.Count -gt 0) { throw "Required drift detection functions not loaded: $($missingFunctions -join ', ')" } # [1] Account Policies Write-Output "" Write-Output "[1] CHECKING ACCOUNT POLICIES" Write-Output "==============================================================" $accountDrifts = Get-AccountPoliciesDrift $driftFindings += $accountDrifts if ($accountDrifts.Count -eq 0) { Write-Output "[OK] Account policies: COMPLIANT" } else { Write-Output "[ERROR] Account policy drift detected: $($accountDrifts.Count) issue(s)" $accountDrifts | Write-Output } # [2] Network Security Write-Output "" Write-Output "[2] CHECKING NETWORK SECURITY" Write-Output "==============================================================" $networkDrifts = Get-NetworkSecurityDrift $driftFindings += $networkDrifts if ($networkDrifts.Count -eq 0) { Write-Output "[OK] Network security: COMPLIANT" } else { Write-Output "[ERROR] Network security drift detected: $($networkDrifts.Count) issue(s)" $networkDrifts | Write-Output } # [3] RDP Security Write-Output "" Write-Output "[3] CHECKING RDP SECURITY" Write-Output "==============================================================" $rdpDrifts = Get-RDPSecurityDrift $driftFindings += $rdpDrifts if ($rdpDrifts.Count -eq 0) { Write-Output "[OK] RDP security: COMPLIANT" } else { Write-Output "[ERROR] RDP security drift detected: $($rdpDrifts.Count) issue(s)" $rdpDrifts | Write-Output } # [4] Firewall Status Write-Output "" Write-Output "[4] CHECKING FIREWALL STATUS" Write-Output "==============================================================" $firewallDrifts = Get-FirewallStatusDrift $driftFindings += $firewallDrifts if ($firewallDrifts.Count -eq 0) { Write-Output "[OK] Firewall status: COMPLIANT" } else { Write-Output "[ERROR] Firewall drift detected: $($firewallDrifts.Count) issue(s)" $firewallDrifts | Write-Output } # [5] Audit Policies Write-Output "" Write-Output "[5] CHECKING AUDIT POLICIES" Write-Output "==============================================================" $auditDrifts = Get-AuditPoliciesDrift $driftFindings += $auditDrifts if ($auditDrifts.Count -eq 0) { Write-Output "[OK] Audit policies: COMPLIANT" } else { Write-Output "[ERROR] Audit policy drift detected: $($auditDrifts.Count) issue(s)" $auditDrifts | Write-Output } # [6] Windows Update Write-Output "" Write-Output "[6] CHECKING WINDOWS UPDATE" Write-Output "==============================================================" $updateDrifts = Get-UpdateStatusDrift $driftFindings += $updateDrifts if ($updateDrifts.Count -eq 0) { Write-Output "[OK] Windows update: COMPLIANT" } else { Write-Output "[ERROR] Update status drift detected: $($updateDrifts.Count) issue(s)" $updateDrifts | Write-Output } # [7] Service Security Write-Output "" Write-Output "[7] CHECKING SERVICE SECURITY" Write-Output "==============================================================" $serviceDrifts = Get-ServiceSecurityDrift $driftFindings += $serviceDrifts if ($serviceDrifts.Count -eq 0) { Write-Output "[OK] Service security: COMPLIANT" } else { Write-Output "[ERROR] Service security drift detected: $($serviceDrifts.Count) issue(s)" $serviceDrifts | Write-Output } # Summary Write-Output "" Write-Output "==============================================================" Write-Output "" Write-Output "[DRIFT ANALYSIS SUMMARY]" Write-Output "==============================================================" if ($driftFindings.Count -eq 0) { Write-Output "" Write-Output "[OK] NO CONFIGURATION DRIFT DETECTED" Write-Output "All hardening settings are intact and active." } else { Write-Output "" Write-Output "[WARN] CONFIGURATION DRIFT DETECTED!" Write-Output "Found $($driftFindings.Count) settings that differ from hardening baseline." Write-Output "" Write-Output "Detailed Findings:" $driftFindings | Format-Table -AutoSize } # Generate Report Write-Output "" Write-Output "[REPORT OUTPUT]" Write-Output "==============================================================" $report = New-SecurityDriftReport -DriftFindings $driftFindings -OutputDirectory $OutputDirectory Write-Output "" Write-Output "[OK] Report saved: $($report.ReportPath)" Write-Output "Status: $($report.Status) | Drifts: $($report.DriftCount) | Severity: $($report.Severity)" # Action Items if ($driftFindings.Count -gt 0) { Write-Output "" Write-Output "[ACTION REQUIRED]" Write-Output " 1. Review detected drift findings above" Write-Output " 2. Investigate cause of changes (unauthorized or accidental)" Write-Output " 3. Re-apply hardening rules if necessary" Write-Output " 4. Document changes and approvals" } Write-Log -Message "Security drift detection completed. Status: $($report.Status) | Drifts: $($report.DriftCount)" ` -Level Info -Caller $MyInvocation.MyCommand.Name } catch { Write-Error "Script error: $_" -ErrorAction Continue Write-Log -Message "Security drift detection failed: $_" -Level Error -Caller $MyInvocation.MyCommand.Name exit 1 } Write-Output "" Write-Output "End Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" Write-Output "Duration: $(((Get-Date) - $startTime).TotalSeconds) seconds" Write-Output "==============================================================" exit 0 |