Skip to content

Commit d7d4bb4

Browse files
committed
v1.12.0 — Windows Defender status dashboard
New feature: Defender Status Dashboard shows protection layers, signature version/age, scan history, and recent threat detections with color-coded warnings. Security & Access menu expanded to 10 items.
1 parent 11598d5 commit d7d4bb4

8 files changed

Lines changed: 122 additions & 11 deletions

File tree

Changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## v1.12.0
4+
5+
- **New Feature:** Windows Defender Status Dashboard — shows real-time protection status for all 5 protection layers (real-time, behavior monitor, download scanning, network inspection, antispyware), signature version/age/last update date, engine version, scan history (last full and quick scan with age), and recent threat detections (last 10). Color-coded warnings for disabled protections and stale signatures (>1 day yellow, >7 days red). Accessible from Security & Access > option [7] (17-DefenderExclusions, 48-MenuDisplay, 49-MenuRunner).
6+
- Security & Access menu expanded from 9 to 10 items — Defender Status Dashboard inserted as [7], admin account options renumbered to [8]-[10] (48-MenuDisplay, 49-MenuRunner).
7+
- 63 modules, 1854 tests
8+
39
## v1.11.0
410

511
- **New Feature:** Certificate Expiry Check — scans Local Machine certificate stores (Personal, Trusted Root CA, Intermediate CA, Web Hosting, Remote Desktop) and categorizes certificates as expired, expiring soon (within 90 days), or valid. Color-coded output with per-store grouping. Accessible from Operations > option [19] (35-Utilities, 56-OperationsMenu).

Header.ps1

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,16 @@
3030
7h3 4b1d3r
3131
3232
.VERSION
33-
1.11.0
33+
1.12.0
3434
3535
.LAST UPDATED
3636
03/04/2026
3737
38+
.CHANGELOG v1.12.0
39+
DEFENDER STATUS DASHBOARD & SECURITY MENU EXPANSION:
40+
- NEW: Windows Defender Status Dashboard — shows real-time protection status (RT, behavior monitor, download scanning, network inspection, antispyware), signature version/age/update date, engine version, scan history (last full/quick scan), and recent threat detections. Color-coded warnings for disabled protections and stale signatures. Accessible from Security & Access menu option [7] (17-DefenderExclusions, 48-MenuDisplay, 49-MenuRunner)
41+
- Security & Access menu expanded from 9 to 10 items with Defender Status at [7], admin accounts renumbered to [8]-[10]
42+
3843
.CHANGELOG v1.11.0
3944
CERTIFICATE CHECK & ERROR HANDLING:
4045
- NEW: Certificate Expiry Check — scans Personal, Root CA, Intermediate CA, Web Hosting, and Remote Desktop certificate stores. Groups by expired/expiring soon (90 days)/valid with color-coded output. Shows certificate count by store. Accessible from Operations menu option [19] (35-Utilities, 56-OperationsMenu)

Modules/00-Initialization.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ if (-not $script:ModuleRoot) { $script:ModuleRoot = $PSScriptRoot }
135135
if (-not $script:ModuleRoot -and $script:ScriptPath) {
136136
$script:ModuleRoot = [System.IO.Path]::GetDirectoryName($script:ScriptPath)
137137
}
138-
$script:ScriptVersion = "1.11.0"
138+
$script:ScriptVersion = "1.12.0"
139139
$script:ScriptStartTime = Get-Date
140140

141141
# OS version detection (for feature compatibility)

Modules/17-DefenderExclusions.ps1

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,4 +367,102 @@ function Remove-DefenderExclusion {
367367
}
368368
}
369369
}
370+
371+
# Windows Defender Status Dashboard
372+
function Show-DefenderStatus {
373+
Clear-Host
374+
Write-OutputColor "" -color "Info"
375+
Write-OutputColor " ╔════════════════════════════════════════════════════════════════════════╗" -color "Info"
376+
Write-OutputColor "$((" WINDOWS DEFENDER STATUS").PadRight(72))" -color "Info"
377+
Write-OutputColor " ╚════════════════════════════════════════════════════════════════════════╝" -color "Info"
378+
Write-OutputColor "" -color "Info"
379+
380+
# Get Defender status
381+
try {
382+
$mpStatus = Get-MpComputerStatus -ErrorAction Stop
383+
} catch {
384+
Write-OutputColor " Windows Defender is not available: $_" -color "Error"
385+
return
386+
}
387+
388+
# Protection status
389+
$rtColor = if ($mpStatus.RealTimeProtectionEnabled) { "Success" } else { "Error" }
390+
$bhColor = if ($mpStatus.BehaviorMonitorEnabled) { "Success" } else { "Warning" }
391+
$ioColor = if ($mpStatus.IoavProtectionEnabled) { "Success" } else { "Warning" }
392+
$niColor = if ($mpStatus.NISEnabled) { "Success" } else { "Warning" }
393+
$amColor = if ($mpStatus.AntispywareEnabled) { "Success" } else { "Warning" }
394+
395+
Write-OutputColor " ┌────────────────────────────────────────────────────────────────────────┐" -color "Info"
396+
Write-OutputColor "$(" PROTECTION STATUS".PadRight(72))" -color "Info"
397+
Write-OutputColor " ├────────────────────────────────────────────────────────────────────────┤" -color "Info"
398+
$rtText = if ($mpStatus.RealTimeProtectionEnabled) { "Enabled" } else { "DISABLED" }
399+
$bhText = if ($mpStatus.BehaviorMonitorEnabled) { "Enabled" } else { "Disabled" }
400+
$ioText = if ($mpStatus.IoavProtectionEnabled) { "Enabled" } else { "Disabled" }
401+
$niText = if ($mpStatus.NISEnabled) { "Enabled" } else { "Disabled" }
402+
$amText = if ($mpStatus.AntispywareEnabled) { "Enabled" } else { "Disabled" }
403+
Write-OutputColor "$(" Real-time Protection: $rtText".PadRight(72))" -color $rtColor
404+
Write-OutputColor "$(" Behavior Monitor: $bhText".PadRight(72))" -color $bhColor
405+
Write-OutputColor "$(" Download Scanning: $ioText".PadRight(72))" -color $ioColor
406+
Write-OutputColor "$(" Network Inspection: $niText".PadRight(72))" -color $niColor
407+
Write-OutputColor "$(" Antispyware: $amText".PadRight(72))" -color $amColor
408+
Write-OutputColor " └────────────────────────────────────────────────────────────────────────┘" -color "Info"
409+
Write-OutputColor "" -color "Info"
410+
411+
# Signature info
412+
$sigAge = if ($null -ne $mpStatus.AntivirusSignatureAge) { $mpStatus.AntivirusSignatureAge } else { "Unknown" }
413+
$sigColor = if ($sigAge -is [int] -and $sigAge -le 1) { "Success" } elseif ($sigAge -is [int] -and $sigAge -le 7) { "Warning" } else { "Error" }
414+
$sigDate = if ($null -ne $mpStatus.AntivirusSignatureLastUpdated) { $mpStatus.AntivirusSignatureLastUpdated.ToString("MM/dd/yyyy HH:mm") } else { "Unknown" }
415+
$sigVer = if ($mpStatus.AntivirusSignatureVersion) { $mpStatus.AntivirusSignatureVersion } else { "Unknown" }
416+
417+
Write-OutputColor " ┌────────────────────────────────────────────────────────────────────────┐" -color "Info"
418+
Write-OutputColor "$(" SIGNATURE STATUS".PadRight(72))" -color "Info"
419+
Write-OutputColor " ├────────────────────────────────────────────────────────────────────────┤" -color "Info"
420+
Write-OutputColor "$(" Signature Version: $sigVer".PadRight(72))" -color "Info"
421+
Write-OutputColor "$(" Last Updated: $sigDate".PadRight(72))" -color $sigColor
422+
Write-OutputColor "$(" Signature Age: $sigAge day(s)".PadRight(72))" -color $sigColor
423+
Write-OutputColor "$(" Engine Version: $($mpStatus.AMEngineVersion)".PadRight(72))" -color "Info"
424+
Write-OutputColor " └────────────────────────────────────────────────────────────────────────┘" -color "Info"
425+
Write-OutputColor "" -color "Info"
426+
427+
# Scan history
428+
$lastFull = if ($null -ne $mpStatus.FullScanEndTime -and $mpStatus.FullScanEndTime.Year -gt 2000) { $mpStatus.FullScanEndTime.ToString("MM/dd/yyyy HH:mm") } else { "Never" }
429+
$lastQuick = if ($null -ne $mpStatus.QuickScanEndTime -and $mpStatus.QuickScanEndTime.Year -gt 2000) { $mpStatus.QuickScanEndTime.ToString("MM/dd/yyyy HH:mm") } else { "Never" }
430+
$fullAge = if ($null -ne $mpStatus.FullScanAge) { $mpStatus.FullScanAge } else { "Unknown" }
431+
$quickAge = if ($null -ne $mpStatus.QuickScanAge) { $mpStatus.QuickScanAge } else { "Unknown" }
432+
433+
Write-OutputColor " ┌────────────────────────────────────────────────────────────────────────┐" -color "Info"
434+
Write-OutputColor "$(" SCAN HISTORY".PadRight(72))" -color "Info"
435+
Write-OutputColor " ├────────────────────────────────────────────────────────────────────────┤" -color "Info"
436+
Write-OutputColor "$(" Last Full Scan: $lastFull ($fullAge day(s) ago)".PadRight(72))" -color "Info"
437+
Write-OutputColor "$(" Last Quick Scan: $lastQuick ($quickAge day(s) ago)".PadRight(72))" -color "Info"
438+
Write-OutputColor " └────────────────────────────────────────────────────────────────────────┘" -color "Info"
439+
Write-OutputColor "" -color "Info"
440+
441+
# Threat detection history
442+
try {
443+
$threats = @(Get-MpThreatDetection -ErrorAction Stop)
444+
if ($threats.Count -gt 0) {
445+
$recent = @($threats | Sort-Object InitialDetectionTime -Descending | Select-Object -First 10)
446+
Write-OutputColor " ┌────────────────────────────────────────────────────────────────────────┐" -color "Warning"
447+
Write-OutputColor "$(" RECENT THREAT DETECTIONS ($($threats.Count) total)".PadRight(72))" -color "Warning"
448+
Write-OutputColor " ├────────────────────────────────────────────────────────────────────────┤" -color "Warning"
449+
foreach ($threat in $recent) {
450+
$tName = if ($threat.ThreatName) { $threat.ThreatName } else { "Unknown" }
451+
if ($tName.Length -gt 42) { $tName = $tName.Substring(0, 39) + "..." }
452+
$tDate = if ($null -ne $threat.InitialDetectionTime) { $threat.InitialDetectionTime.ToString("MM/dd HH:mm") } else { "N/A" }
453+
$line = " $($tName.PadRight(44)) $tDate"
454+
Write-OutputColor "$($line.PadRight(72))" -color "Warning"
455+
}
456+
Write-OutputColor " └────────────────────────────────────────────────────────────────────────┘" -color "Warning"
457+
} else {
458+
Write-OutputColor " ┌────────────────────────────────────────────────────────────────────────┐" -color "Success"
459+
Write-OutputColor "$(" No threat detections found.".PadRight(72))" -color "Success"
460+
Write-OutputColor " └────────────────────────────────────────────────────────────────────────┘" -color "Success"
461+
}
462+
} catch {
463+
Write-OutputColor " Could not query threat history: $_" -color "Warning"
464+
}
465+
466+
Add-SessionChange -Category "Security" -Description "Viewed Defender status: RT=$rtText, Sig age=$sigAge days, Threats=$(@($threats).Count)"
467+
}
370468
#endregion

Modules/48-MenuDisplay.ps1

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -377,15 +377,16 @@ function Show-SecurityAccessMenu {
377377
Write-MenuItem "[4] Firewall Rule Templates"
378378
Write-MenuItem "[5] Firewall Rule Search ►"
379379
Write-MenuItem "[6] Defender Exclusions"
380+
Write-MenuItem "[7] Defender Status Dashboard"
380381
Write-OutputColor " └────────────────────────────────────────────────────────────────────────┘" -color "Info"
381382
Write-OutputColor "" -color "Info"
382383

383384
Write-OutputColor " ┌────────────────────────────────────────────────────────────────────────┐" -color "Info"
384385
Write-OutputColor "$(" ADMIN ACCOUNTS".PadRight(72))" -color "Info"
385386
Write-OutputColor " ├────────────────────────────────────────────────────────────────────────┤" -color "Info"
386-
Write-MenuItem "[7] Add Local Admin Account"
387-
Write-MenuItem "[8] Disable Built-in Admin" -Status $adminDisplay -StatusColor $adminColor
388-
Write-MenuItem "[9] Local Account Audit"
387+
Write-MenuItem "[8] Add Local Admin Account"
388+
Write-MenuItem "[9] Disable Built-in Admin" -Status $adminDisplay -StatusColor $adminColor
389+
Write-MenuItem "[10] Local Account Audit"
389390
Write-OutputColor " └────────────────────────────────────────────────────────────────────────┘" -color "Info"
390391
Write-OutputColor "" -color "Info"
391392
Write-OutputColor " [B] ◄ Back to Server Config" -color "Info"

Modules/49-MenuRunner.ps1

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,13 @@ function Start-Show-SecurityAccessMenu {
237237
"4" { Set-FirewallRuleTemplates; Write-PressEnter }
238238
"5" { Show-FirewallRuleSearch }
239239
"6" { Set-DefenderExclusions; Write-PressEnter }
240-
"7" { Add-LocalAdminAccount; Write-PressEnter }
241-
"8" { Disable-BuiltInAdminAccount; Write-PressEnter }
242-
"9" { Show-LocalAccountAudit; Write-PressEnter }
240+
"7" { Show-DefenderStatus; Write-PressEnter }
241+
"8" { Add-LocalAdminAccount; Write-PressEnter }
242+
"9" { Disable-BuiltInAdminAccount; Write-PressEnter }
243+
"10" { Show-LocalAccountAudit; Write-PressEnter }
243244
"back" { return }
244245
default {
245-
Write-OutputColor "Invalid choice. Please enter 1-9 or B." -color "Error"
246+
Write-OutputColor "Invalid choice. Please enter 1-10 or B." -color "Error"
246247
Start-Sleep -Seconds 2
247248
}
248249
}

RackStack.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
Environment-specific settings are configured via defaults.json.
1414
1515
.VERSION
16-
1.11.0
16+
1.12.0
1717
1818
.NOTES
1919
- Requires Windows Server 2012 R2 or later (or Windows 10/11 for testing)

Tests/Run-Tests.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<#
22
.SYNOPSIS
3-
Automated Test Runner for RackStack v1.11.0
3+
Automated Test Runner for RackStack v1.12.0
44
55
.DESCRIPTION
66
Comprehensive non-interactive test suite covering:

0 commit comments

Comments
 (0)