Private/Advisors/Test-DefenderAdvisory.ps1
|
function Test-DefenderAdvisory { [CmdletBinding()] [OutputType([object[]])] param( [Parameter(Mandatory)][object]$Result, [Parameter(Mandatory)][object]$Roles ) if (-not $Result.PSObject.Properties['Defender']) { return @() } $def = $Result.Defender if ($null -eq $def) { return @() } if ($def.Engine -and $def.Engine.RealTimeProtectionEnabled -eq $false) { [pscustomobject]@{ Section='Defender'; Severity='Critical'; Rule='DefenderRtDisabled' Message='Microsoft Defender real-time protection is disabled.' Context=@{ Setting='RealTimeProtectionEnabled'; Recommended=$true } } } if (-not $Roles.HasSqlServer) { return @() } $excl = @() if ($def.Exclusions) { $excl = @($def.Exclusions.Paths) | Where-Object { $_ } } $sqlPaths = New-Object System.Collections.Generic.HashSet[string] ([StringComparer]::OrdinalIgnoreCase) foreach ($inst in @($Result.SqlServer)) { foreach ($db in @($inst.Databases)) { foreach ($f in @($db.Files)) { if ($f.Path) { [void]$sqlPaths.Add((Split-Path $f.Path -Parent)) } } } } $missing = foreach ($p in $sqlPaths) { $covered = $false foreach ($e in $excl) { if ($p -like "$e*" -or $p -ieq $e) { $covered = $true; break } } if (-not $covered) { $p } } if (@($missing).Count -gt 0) { [pscustomobject]@{ Section='Defender'; Severity='Warning'; Rule='DefenderMissingSqlExclusion' Message="SQL data/log directories not covered by Defender exclusions: $(@($missing) -join ', '). Add to ExclusionPath to avoid scan latency hits on hot files." Context=@{ MissingPaths=@($missing); ExistingExclusions=@($excl) } } } } |