🔗 Maester Integration

Turn TCM’s server-side drift detection into Maester test results — unified M365 security reporting in one place.


What is Maester?

Maester is the community-standard tool for Microsoft 365 security testing. It ships with 400+ built-in checks covering Entra ID, Exchange, Teams, and SharePoint — things like:

Maester runs these checks on demand and produces an HTML report with pass/fail results. Security teams use it for audits, compliance reviews, and continuous validation.

What Maester doesn’t do (yet): detect when someone changes a policy that was previously compliant. Maester checks the current state, but can’t tell you “this CA policy was modified yesterday at 3 PM.”

That’s what TCM does. And EasyTCM bridges the two.


Why Combine TCM + Maester?

They solve different but complementary problems:

  Maester TCM (via EasyTCM)
What it checks “Is this setting correct?” “Has this setting changed?”
How Client-side Pester tests against Graph API Server-side baseline comparison every 6 hours
Catches Misconfigurations (wrong value) Drift (value changed from known-good)
Blind spot Doesn’t know what the value was before Doesn’t judge if the value is good

Together they cover both angles:

Real-World Example

Your tenant has a CA policy “Require MFA for Admins” — it’s enabled and Maester’s check passes.

Tuesday 2 PM: Someone adds an exclusion for breakglass@contoso.com to troubleshoot a sign-in issue. They forget to remove it.


How It Works

┌─────────────────────────────────────────────────────┐
│          TCM Service (runs every 6 hours)            │
│  Compares tenant config against your baseline        │
│  Detects property-level changes                      │
└──────────────────┬──────────────────────────────────┘
                   │ drift data
                   ▼
┌─────────────────────────────────────────────────────┐
│     Show-TCMDrift -Maester  (or Sync-TCMDrift...)  │
│                                                      │
│  1. Fetches drift from TCM API                       │
│  2. Generates per-monitor test suites:               │
│     • baseline.json  (known-good state)              │
│     • current.json   (baseline + drift applied)      │
│     • TCM-Drift.Tests.ps1  (Pester test file)        │
│  3. Runs Invoke-Maester on the drift folder          │
└──────────────────┬──────────────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────────────────┐
│              Maester HTML Report                     │
│                                                      │
│  ✅ 423 security checks passed                       │
│  ❌ 2 TCM drift tests FAILED                         │
│     → conditionalaccesspolicy: excludeUsers changed  │
│     → namedlocation: ipRanges changed                │
│  ✅ 15 TCM drift tests passed (no changes)           │
└─────────────────────────────────────────────────────┘

File Structure Generated

maester-tests/
├── tests/                        ← Maester's built-in 400+ tests
├── Drift/                        ← EasyTCM generates this
│   └── TCM-EasyTCM Recommended/
│       ├── baseline.json         ← Your approved configuration
│       ├── current.json          ← Current state (baseline + drifts)
│       └── TCM-Drift.Tests.ps1   ← Auto-generated Pester tests
└── ...

What Appears in the Maester Report

Each monitored resource becomes a test. Drifted resources fail with property-level detail:

Maester report showing 4 drifted properties across Entra, Exchange, and Teams

Clean resources show as passing tests — giving you a full inventory of what’s monitored and stable.


Setup

Prerequisites

# Install Maester if you haven't
Install-Module Maester -Scope CurrentUser -Force

# Set up your Maester tests folder
mkdir D:\maester-tests
cd D:\maester-tests
Install-MaesterTests

Tell EasyTCM Where Maester Lives

# Set once — persists across terminal sessions
[Environment]::SetEnvironmentVariable('MAESTER_TESTS_PATH', 'D:\maester-tests', 'User')
$env:MAESTER_TESTS_PATH = 'D:\maester-tests'

Run It

# One command: sync TCM drift → generate tests → run Maester
Show-TCMDrift -Maester

That’s it. The Maester HTML report opens with your drift results alongside all standard security tests.

Step-by-Step (If You Prefer Control)

# Step 1: Sync drift data to Maester format
Sync-TCMDriftToMaester

# Step 2: Run ONLY drift tests
Invoke-Maester -Path "$env:MAESTER_TESTS_PATH\Drift"

# OR run the full Maester suite (drift + 400+ security checks)
cd $env:MAESTER_TESTS_PATH
Connect-Maester
Invoke-Maester

Catching New and Deleted Resources

TCM drift detection only catches property changes on resources in the baseline. It won’t detect:

Add -CompareBaseline to catch these:

Show-TCMDrift -Maester -CompareBaseline

This takes a fresh snapshot (cached for 1 hour to save quota) and includes new/deleted resources in the Maester report as additional test results.

Baseline drift detection showing a new shadow Conditional Access policy


Key Design Decisions

Why generate .Tests.ps1 files? Maester discovers tests by scanning for *.Tests.ps1 files. By generating standard Pester tests, EasyTCM integrates without any Maester code changes. It just works.

Why Add-MtTestResultDetail? This is Maester’s own helper for enriching test output in the HTML report. Using it means drift results get the same formatting as Maester’s built-in tests — consistent UX.

Why baseline.json + current.json? This is the pattern the Maester community established for drift data. EasyTCM follows it for future compatibility if Maester adds native drift support.

Why does TCM store baselines server-side? The Maester community spent months debating where to store drift baselines (local files? git? blob storage?). TCM eliminates this entirely — Microsoft stores your baseline in the TCM service. No state management needed on your end.


← Back to Home

GitHub Actions →

Continuous Monitoring →