Enterprise-grade, zero-dependency PowerShell auditing framework for air-gapped and hardened Windows environments.
- 21-point workstation audit - OS, activation, BitLocker, Symantec, FortiClient, SafeNet, firewall, updates, GPOs, performance, clock sync, event logs, certificates, USB devices, scheduled tasks, network config, uptime, reboot status
- SHA-256 data integrity - Every JSON report is hashed before export; dashboards verify integrity on import
- Strict configuration - No hardcoded defaults. If
HealthCheck.config.jsonis missing or invalid, execution halts with a terminating error - Template-separated dashboards - PowerShell scripts produce JSON payloads; standalone HTML templates handle all rendering in native JavaScript
- Dark mode and CSV export - Built into both dashboards
- Historical trend analysis - Multi-week comparison with color-coded change detection
AirGap-Auditor/
├── HealthCheck.config.json # Required configuration (paths, thresholds, versions)
├── 1_WorkstationHealthCheck.ps1 # Collector - runs on each workstation (Admin required)
├── 2_Generate-WeeklyReport.ps1 # Aggregator - builds JSON payload, injects into template
├── 3_Generate-HistoryDashboard.ps1 # History - change detection + trend analysis
├── WeeklyDashboard.html # Template - standalone HTML/JS for weekly report
├── HistoryDashboard.html # Template - standalone HTML/JS for history report
├── CHANGELOG.md # Version history
└── HealthCheckReports/
├── 2026-03-03/
│ ├── HOSTNAME_HHMMSS.json # Raw audit data
│ └── Dashboard.html # Generated (template + injected payload)
└── HistoryData/
└── WeeklySummary_*.json # Consolidated weekly data
[1_Collector.ps1] -> JSON + SHA-256 hash -> file
[2_WeeklyReport.ps1] -> reads JSONs -> verifies hashes -> builds payload -> injects into WeeklyDashboard.html -> Dashboard.html
[3_HistoryDashboard.ps1] -> reads all weeks -> detects changes -> builds payload -> injects into HistoryDashboard.html
- PowerShell 5.1 or later
- Administrator privileges for the collector script
HealthCheck.config.jsonmust be present and valid (see Configuration)
All thresholds, paths, and versions are defined in HealthCheck.config.json. The collector script will not run without this file.
{
"Paths": {
"ReportsFolder": ".\\HealthCheckReports"
},
"Versions": {
"SymantecRequiredVersion": "14.3"
},
"Thresholds": {
"DefThresholdDays": 5,
"DiskWarningPercent": 90,
"RAMWarningPercent": 90,
"CPUWarningPercent": 90,
"CertExpiryWarningDays": 60,
"ReportRetentionDays": 90,
"PendingRebootAlert": true,
"FirewallRequireAll": true
}
}Production environments MUST use code-signed scripts.
For production deployment, sign all .ps1 files with a valid code signing certificate:
# Sign each script with your organization's code signing certificate
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | Select-Object -First 1
Set-AuthenticodeSignature -FilePath .\1_WorkstationHealthCheck.ps1 -Certificate $cert
Set-AuthenticodeSignature -FilePath .\2_Generate-WeeklyReport.ps1 -Certificate $cert
Set-AuthenticodeSignature -FilePath .\3_Generate-HistoryDashboard.ps1 -Certificate $cert
# Enforce signed execution policy on all target machines
Set-ExecutionPolicy AllSigned -Scope LocalMachineFor localized sandbox testing only (non-production):
Set-ExecutionPolicy RemoteSigned -Scope CurrentUserNever use
-ExecutionPolicy Bypassin production. It defeats the purpose of execution policy enforcement and is a compliance violation in audited environments.
.\1_WorkstationHealthCheck.ps1.\2_Generate-WeeklyReport.ps1This reads all JSON reports from the latest date folder, verifies SHA-256 hashes, builds a JSON payload, and injects it into WeeklyDashboard.html to produce Dashboard.html.
.\3_Generate-HistoryDashboard.ps1Aggregates data across all date folders, performs change detection, and produces HistoryDashboard.html with trend analysis.
- All JSON output uses BOM-free UTF-8 to prevent encoding-based hash mismatches
- Hash verification uses raw string stripping (not object round-tripping) to guarantee byte-identical comparison
- Templates are static files that never execute PowerShell - they only read from an injected JSON payload
- No external network calls, no CDN dependencies - fully air-gap compatible


