Compliance backend reference
Everything the Compliance UI reads or writes lives in the HealthCheck and Collector schemas on the Minion repository DB. This page maps each UI concept to its backing objects.
End-to-end data flow
flowchart LR
subgraph "Every N minutes / hours"
C1["Collectors scrape<br/>target servers"] --> C2["Collector.Logins<br/>Collector.DBProperties<br/>Collector.InstanceConfig<br/>..."]
end
subgraph "One time (per profile)"
S1["User picks metrics"] --> S2["HealthCheck.ReportMetric<br/>links profile to metrics"]
S3["User adds tuning"] --> S4["HealthCheck.MetricThreshold<br/>per-scope rules"]
end
subgraph "Each Run"
R1["User clicks Run now"] --> R2["ComplianceService<br/>calls ReportMaster"]
R2 --> R3["ReportMaster resolves<br/>cascading thresholds"]
R3 --> R4["Load HealthCheck.Work<br/>with per-row context"]
R4 --> R5["EXEC each metric SP"]
R5 --> R6["Each SP joins<br/>Collector.* + Work"]
R6 --> R7["Write to<br/>HealthCheck.MetricLog*"]
R7 --> R8["Update HealthCheck.ReportLog<br/>with Pass/Fail counts"]
end
C2 -.->|"read at run time"| R6
S2 -.->|"walked at run time"| R2
S4 -.->|"resolved at run time"| R3
R8 -.->|"shown in history grid"| U1["Compliance UI<br/>Run & History tab"]
R7 -.->|"detail queries"| U2["Query Runner<br/>MetricLog inspection"]
Key property: the compliance engine never touches remote SQL Servers directly. It reads from the pre-collected Collector.* fact tables. The collectors that fill those tables are the ones that talk to production; the engine grades what they wrote.
Tables
| Table | Compliance UI concept | Notes |
|---|---|---|
HealthCheck.Report |
Profile (left rail row) | Primary key ReportName. IsAudit drives the AUDIT/CUSTOM badge. Comment shows on Overview tab. |
HealthCheck.Metric |
Metric library (Available pane) | ~90 rows. ProcName points at the backing SP; MeasureLevel = Instance or Database. |
HealthCheck.ReportMetric |
In-profile metrics (Metrics tab left pane) | Junction: ReportName + MetricID + MetricOrder + IsActive. IsActive = 0 = "Off" button. |
HealthCheck.MetricThreshold |
Threshold rules (Thresholds grid) | Cascade key: (ReportName, MetricID, InstanceID, DBName). InstanceID = 0 means "any instance"; NULL is "unspecified" (also = any). |
HealthCheck.AuditDictionary |
Benchmark provenance card | Populated for canned audits (CIS, MVA). One row per ReportName. |
HealthCheck.AuditMetricDictionary |
(not surfaced yet) | Per-audit metric metadata: IsScored, Description. Useful for showing "CIS calls this control X". |
HealthCheck.Work |
(transient) | Per-run job packet populated by ReportMaster. Deleted at end of run. |
HealthCheck.ReportLog |
Run & History grid rows | Header rows written by each metric SP with FailCount / PassCount / ExecutionTimeInSecs per (run × metric). |
HealthCheck.ReportLogCurrent |
(view over ReportLog) | Convenience view of recent runs. |
HealthCheck.MetricLog* |
(drill-down) | One table per metric type — row-level pass/fail detail. Names line up with HealthCheck.Metric.LogTable. |
Metric library snapshot
The shipped metric SPs cluster into three families.
Instance-level Metric* SPs
Per-instance checks — evaluate once per SQL Server.
HealthCheck.MetricSysadminCountHealthCheck.MetricSpConfigureSetting(parameterized — used for many sp_configure toggles)HealthCheck.MetricSARenamedHealthCheck.MetricLoginDisabled(used forsadisabled check)HealthCheck.MetricServerAuthenticationHealthCheck.MetricHideInstanceYesHealthCheck.MetricTempdbFileCountHealthCheck.MetricTempDBOneDataFileHealthCheck.MetricLatestServicePackHealthCheck.MetricSQLLoginsSecurity(MUST_CHANGE / CHECK_POLICY / CHECK_EXPIRATION)
Database-level Metric* SPs
Per-database checks — evaluate once per DB on each in-scope instance.
HealthCheck.MetricDatabaseOwnerHealthCheck.MetricTrustworthyHealthCheck.MetricContainedAUTOCLOSEOffHealthCheck.MetricContainedNoSQLAuthHealthCheck.MetricDataLogFilesLocationsHealthCheck.MetricDBPrincipalPermHealthCheck.MetricDropOrphanedUsersHealthCheck.MetricCLRAssemblyPermission
VA* SPs (Microsoft Vulnerability Assessment mappings)
Direct rule-number mappings to the checks SSMS's Vulnerability Assessment produces. VA1020, VA1043, VA1044, VA1048, VA1051, VA1054, VA1070, VA1095–VA1099, VA1102, VA1143, VA1219, VA1221, VA1222, VA1224, VA1244–VA1248, VA1256, VA1265, VA1267, VA1281, VA1282, VA2020, VA2033, VA2108, VA2109, VA2128, VA2129.
Each VA* SP is a Microsoft-defined check translated to run against Minion's Collector.* data.
Stored procedures
| SP | UI callsite | Purpose |
|---|---|---|
HealthCheck.ReportMaster |
▶ Run now button on Run & History | The real orchestrator. Resolves cascading thresholds, populates Work, executes each metric SP in the profile, writes ReportLog and per-metric MetricLog* rows. |
HealthCheck.CloneReport |
Clone button on left rail | Copies a Report row + its ReportMetric links into a new name. Threshold rules are NOT copied. |
HealthCheck.Results |
(Reports tab consumes this) | Retrieves per-metric results for a given (ReportName, ExecutionDateTime). |
GUI.ChooseMetrics |
(legacy — older UI used this) | Returns metrics linked to a profile. New UI queries ReportMetric directly. |
GUI.HCCustomizeMetrics |
(legacy) | Returns per-metric customization data. New UI queries MetricThreshold directly. |
GUI.HCMetricOperators |
Op dropdown in the Thresholds add-row form | Returns valid comparison operators (=, <>, <, <=, >, >=, IS, LIKE, /). |
GUI.SLAList |
Service level dropdown on Scope tab | Returns the SLA values ((All), Bronze, Silver, Gold) from dbo.Servers.ServiceLevel. |
There's also HealthCheck.RunReport — this is a stale stub referencing tables (ReportElement, Element) that no longer exist. The Compliance UI intentionally does NOT call it. Use ReportMaster instead.
Per-metric log tables
Each metric writes row-level results to its own HealthCheck.MetricLog* table. The table name is stored in HealthCheck.Metric.LogTable. Examples:
| Metric | Log table |
|---|---|
MetricSysadminCount |
HealthCheck.MetricLogSysadminCount |
MetricDatabaseOwner |
HealthCheck.MetricLogDatabaseOwner |
MetricSpConfigureSetting |
HealthCheck.MetricLogSpConfigureSetting (all sp_configure metrics share this table, keyed by MetricName) |
VA1020 |
HealthCheck.MetricLogVA1020 |
Every log table has a common preamble of columns:
ReportExecutionDateTime— the run identifierInstanceID(+ oftenServerNamevia join)MetricExecutionDateTimeThresholdMeasure/ThresholdOperator/ThresholdValue(the resolved rule that graded this row)MetricFail(bit — 1 = failed, 0 = passed)CollectorExecutionDateTime(which collector snapshot the SP graded)
Metric-specific columns follow, such as SysadminName + SysadminCount on MetricLogSysadminCount.
Sample queries
Every failing row in a run
DECLARE @Run datetime = '2026-07-06 14:30:22';
SELECT ML.MetricName,
ML.LogTable,
ML.FailCount
FROM HealthCheck.ReportLog ML
WHERE ML.ReportExecutionDateTime = @Run
AND ML.FailCount > 0
ORDER BY ML.FailCount DESC;
Follow up with a SELECT ... FROM <LogTable> WHERE ReportExecutionDateTime = @Run AND MetricFail = 1 for each.
Show the resolved threshold for one row
SELECT TOP 1
L.InstanceID,
S.ServerName,
L.DBName,
L.ThresholdMeasure,
L.ThresholdOperator,
L.ThresholdValue,
L.MetricFail
FROM HealthCheck.MetricLogSysadminCount L
JOIN dbo.Servers S ON S.InstanceID = L.InstanceID
WHERE L.ReportExecutionDateTime = '2026-07-06 14:30:22'
AND S.ServerName = 'Prod-DB-01';
If ThresholdOperator = <= and ThresholdValue = 8, the Instance-level override for Prod-DB-01 is what graded this row.
Profile-level pass/fail rollup for one run
SELECT MetricName,
SUM(FailCount) AS Failed,
SUM(PassCount) AS Passed,
CASE WHEN SUM(FailCount) = 0 THEN 'OK' ELSE 'FAIL' END AS Result
FROM HealthCheck.ReportLog
WHERE ReportName = 'Acme Prod CIS'
AND ReportExecutionDateTime = '2026-07-06 14:30:22'
GROUP BY MetricName
ORDER BY Failed DESC, MetricName;
Trend a metric over the last 30 days
SELECT ReportExecutionDateTime, FailCount, PassCount
FROM HealthCheck.ReportLog
WHERE ReportName = 'Acme Prod CIS'
AND MetricName = 'Sysadmin Count'
AND ReportExecutionDateTime >= DATEADD(day, -30, GETDATE())
ORDER BY ReportExecutionDateTime DESC;
Collector dependency
Every metric SP reads from at least one Collector.* table. The collector job's cadence therefore governs how fresh your compliance results can be. Common collector tables the metric SPs read:
| Collector table | Feeds metrics |
|---|---|
Collector.Logins |
Sysadmin count, sa disabled, sa renamed, MUST_CHANGE, CHECK_POLICY |
Collector.DBProperties |
Database owner, Trustworthy, Auto Close, Auto Shrink, Read Only |
Collector.InstanceConfig |
sp_configure toggles, Server Authentication mode |
Collector.DBFileProperties |
Data/Log file locations, TempDB file count |
Collector.DBPrincipalPermissions |
GUEST access, DB principal permission checks |
Collector.ErrorLogFiles |
Error log file count metric |
If a metric returns Pass = 0 AND Fail = 0, that generally means the collector table for that metric is empty or hasn't been populated since the profile started referencing it.
Related: Compliance overview, Compliance thresholds, Compliance run & history, Reports.