A PowerShell module for Microsoft 365 tenant configuration monitoring, drift detection, and compliance reporting. Powered by the Microsoft Graph UTCM beta API.
Install-Module -Name TenantBaseline -Scope CurrentUser
- Overview
- Features
- Requirements
- Installation
- Quick Start
- Authentication
- Command Reference
- Common Workflows
- API Limits
- Project Structure
- Documentation
- Contributing
- License
TenantBaseline wraps the Microsoft Graph Unified Tenant Configuration Management (UTCM) beta API into a set of PowerShell cmdlets that make it straightforward to define baselines, detect drift, capture snapshots, and generate compliance reports for your Microsoft 365 tenant.
The module covers 249 resource types across M365 workloads including Entra ID, Exchange Online, Microsoft Intune, Microsoft Teams, and Microsoft Defender / Purview. Whether you are an IT administrator tracking Conditional Access policy changes or a compliance team auditing Intune device configurations, TenantBaseline provides the tooling to monitor and document tenant state.
If you are new to the repository, use this order:
- Install the module from PowerShell Gallery.
- Follow the setup flow in Getting Started to provision UTCM and create your first monitor.
- Read Authentication if you need delegated or unattended sign-in details.
- Read Automation if you want Azure Automation, schedules, webhooks, managed identity, or the sample runbook file.
- Connection Management - Connect to Microsoft Graph with scenario-based delegated scopes for admins and unattended authentication modes for automation runners.
- Automated Setup - Provision and configure the UTCM service principal with guided permission granting, including manual remediation steps for provider-specific permissions.
- Monitor Management - Create, update, and remove configuration monitors that track resources against a known-good baseline.
- Drift Detection - Detect configuration drift with filtering by monitor or resource type, and get aggregated summaries grouped by status and workload.
- Drift Notifications - Send webhook notifications for newly detected drift from scheduled jobs or runbooks with duplicate suppression.
- Baseline Export/Import - Export baselines to JSON for version control or migration, and import them to seed new monitors.
- Configuration Snapshots - Capture point-in-time tenant configuration snapshots, wait for completion, export data before the 7-day expiry, and compare snapshots to detect property-level changes.
- Monitor Operations - Clone monitors, export/import portable JSON backups, and track UTCM quota usage across monitors, resource-days, and snapshot jobs.
- Compliance Reporting - Generate HTML drift reports, interactive dashboards with embedded timelines, and formatted documentation for compliance review.
- Interactive Console - A menu-driven TUI (
Start-TBInteractive) with guided workflows, input validation, and resource type pickers for all module operations.
| Requirement | Details |
|---|---|
| PowerShell | 7.2 or later (Core edition) |
| Module dependency | Microsoft.Graph.Authentication v2.0.0+ |
| Tenant access | Entra ID tenant with Global Administrator or appropriate admin roles |
From the PowerShell Gallery (recommended):
Install-Module -Name TenantBaseline -Scope CurrentUserManual clone for contributors:
git clone https://github.com/ugurkocde/TenantBaseline.git
Import-Module ./tenantbaseline/src/TenantBaseline/TenantBaseline.psd1Updating to a newer version:
Update-Module -Name TenantBaselineUpdate-Module installs the new version side-by-side and does not remove older versions. To clean up previous versions after updating:
# Remove all older versions, keeping only the latest
Get-InstalledModule -Name TenantBaseline -AllVersions |
Sort-Object Version -Descending |
Select-Object -Skip 1 |
Uninstall-Module -ForceAfter installing, launch the interactive management console:
TenantBaselineOr use individual commands:
# Connect with setup permissions (first time only)
Connect-TBTenant -Scenario Setup
# Provision the UTCM service principal and grant permissions
Install-TBServicePrincipal
# Reconnect with day-to-day permissions
Connect-TBTenant -Scenario Manage
# Create a monitor to track Conditional Access policies
New-TBMonitor -DisplayName 'CA Monitor' -Resources @(
@{ resourceType = 'microsoft.entra.conditionalaccesspolicy'; displayName = 'CA Policy' }
)
# Check for configuration drift
Get-TBDrift
# Generate an HTML drift report
New-TBDriftReport -OutputPath ./drift-report.htmlTenantBaseline supports both delegated interactive sign-in and unattended automation through Connect-MgGraph.
| Scenario | Scopes | Use case |
|---|---|---|
ReadOnly |
ConfigurationMonitoring.Read.All |
View monitors, drifts, and snapshots |
Manage |
ConfigurationMonitoring.ReadWrite.All |
Create/update monitors, snapshots, and reports |
Setup |
ConfigurationMonitoring.ReadWrite.All, Application.ReadWrite.All, AppRoleAssignment.ReadWrite.All |
One-time UTCM service principal provisioning |
Unattended automation is available via managed identity, app certificate, client secret, or pre-acquired access token. For details, see docs/Authentication.md and docs/Automation.md.
| Command | Description |
|---|---|
Connect-TBTenant |
Connects to Microsoft Graph with scenario-based scopes |
Disconnect-TBTenant |
Disconnects from Microsoft Graph and clears session state |
Get-TBConnectionStatus |
Returns the current connection status, tenant, and granted scopes |
| Command | Description |
|---|---|
Install-TBServicePrincipal |
Provisions the UTCM service principal and grants workload permissions |
Test-TBServicePrincipal |
Checks whether the UTCM service principal exists in the tenant |
Grant-TBServicePrincipalPermission |
Grants permissions using a resource-aware plan with manual remediation guidance |
Get-TBPermissionPlan |
Builds a permission plan showing auto-grantable and manual-step permissions |
| Command | Description |
|---|---|
New-TBMonitor |
Creates a configuration monitor that tracks resources for drift |
Get-TBMonitor |
Gets one or all configuration monitors |
Set-TBMonitor |
Updates display name, description, status, or baseline of a monitor |
Remove-TBMonitor |
Deletes a configuration monitor |
Get-TBMonitorResult |
Gets monitoring run results and errors, optionally filtered by monitor |
Get-TBQuotaStatus |
Returns current UTCM quota usage vs limits (monitors, resource-days, snapshots) |
Export-TBMonitor |
Exports a monitor and its baseline to a portable JSON file |
Copy-TBMonitor |
Clones an existing monitor with a new display name |
| Command | Description |
|---|---|
Get-TBDrift |
Lists detected configuration drifts, filterable by drift ID or monitor |
Get-TBDriftSummary |
Aggregates drifts by resource type, monitor, and status |
Send-TBDriftNotification |
Sends webhook notifications for newly detected drift with duplicate suppression |
| Command | Description |
|---|---|
Get-TBBaseline |
Gets the baseline configuration from a monitor |
Export-TBBaseline |
Exports a monitor baseline to a local JSON file |
Import-TBBaseline |
Imports a baseline JSON file and returns resources for piping to New-TBMonitor |
| Command | Description |
|---|---|
New-TBSnapshot |
Creates a snapshot job for specified resource types |
New-TBBaselineSnapshot |
Creates a snapshot from a monitor's baseline resource types |
Get-TBSnapshot |
Gets one or all snapshot jobs |
Remove-TBSnapshot |
Deletes a snapshot job |
Wait-TBSnapshot |
Polls until a snapshot job reaches a terminal state |
Export-TBSnapshot |
Downloads snapshot content to a local JSON file before expiry |
Compare-TBSnapshot |
Compares two snapshots and returns property-level diffs |
| Command | Description |
|---|---|
New-TBDriftReport |
Generates an HTML or JSON drift report for compliance review |
New-TBDashboard |
Generates an interactive HTML dashboard with drift timelines and monitor details |
New-TBDocumentation |
Generates formatted documentation for compliance review or wiki embedding |
| Command | Description |
|---|---|
Start-TBInteractive |
Launches the menu-driven management console with guided workflows |
Connect-TBTenant -Scenario Setup
Install-TBServicePrincipal
Grant-TBServicePrincipalPermission -ResourceType @('microsoft.entra.conditionalaccesspolicy')Connect-TBTenant -Scenario Manage
Get-TBDriftSummary
New-TBDriftReport -OutputPath ./daily-drift.html# Example: run from Azure Automation, GitHub Actions, or another scheduler
Connect-TBTenant -Identity
Send-TBDriftNotification `
-WebhookUrl $env:TB_WEBHOOK_URL `
-StatePath $env:TB_NOTIFICATION_STATE_PATHTB_NOTIFICATION_STATE_PATH should point to durable storage that survives between scheduled runs.
# Export baseline from an existing monitor
Export-TBBaseline -MonitorId $sourceId -OutputPath ./baseline.json
# Import and create a new monitor from the exported baseline
$resources = Import-TBBaseline -Path ./baseline.json
New-TBMonitor -DisplayName 'Imported Monitor' -Resources $resources$snapshot = New-TBSnapshot -DisplayName 'Pre Change' -Resources @('microsoft.entra.conditionalaccesspolicy')
Wait-TBSnapshot -SnapshotId $snapshot.id
Export-TBSnapshot -SnapshotId $snapshot.id -OutputPath ./snapshot.json# Compare two snapshots to see what changed
Compare-TBSnapshot -ReferenceSnapshotId $before.Id -DifferenceSnapshotId $after.Id
# Export the comparison to a file
Compare-TBSnapshot -ReferenceSnapshotId $before.Id -DifferenceSnapshotId $after.Id -OutputPath ./diff.json# Clone a monitor with a new name
Copy-TBMonitor -MonitorId $monitor.Id -NewDisplayName 'CA Monitor (Copy)'
# Export a monitor and its baseline to a portable JSON file
Export-TBMonitor -MonitorId $monitor.Id -OutputPath ./monitor-backup.json
# Check UTCM quota usage
Get-TBQuotaStatus| Limit | Value |
|---|---|
| Monitors per tenant | 30 |
| Daily monitored resources | 800 |
| Monitoring cycle interval | 6 hours |
| Visible snapshot jobs | 12 |
| Monthly snapshot resource extractions | 20,000 |
| Snapshot retention | 7 days |
For details, see docs/API-Limits.md.
tenantbaseline/
.github/workflows/ CI (lint + Pester) and PSGallery release
build/ Build and packaging scripts
docs/ Documentation (Getting Started, Auth, API Limits, Migration)
src/TenantBaseline/ Module source
Public/ 32 exported cmdlets organized by functional area
Private/ Internal helpers (API wrapper, interactive menu system)
Data/ Resource type registry and workload metadata
en-US/ Help content
tests/
Unit/ Pester unit tests (Public + Private)
Fixtures/ Mock API response data
Integration/ Integration test stubs
| Guide | Description |
|---|---|
| Getting Started | Installation, prerequisites, and first steps |
| Authentication | Delegated and unattended authentication flows |
| Automation | Azure Automation runbooks, schedules, managed identity, hosted notification patterns, and a sample runbook file |
| API Limits | UTCM quota and throttling reference |
| Migration Guide | Upgrade notes and PowerShell 7.2+ compatibility |
- Fork the repository
- Create a feature branch (
git checkout -b feature/your-change) - Write or update tests for new functionality
- Run lint and tests locally:
The build script runs PSScriptAnalyzer and the full Pester test suite.
pwsh build/build.ps1 - Submit a pull request
This project is licensed under the MIT License. See LICENSE for details.