# TenantReports & TenantReports-Web A PowerShell module for generating Microsoft 365 and Azure security reports. - ![[Demo_Dashboard.jpeg]] - ![[Demo_IdentityAccess.jpeg]] - ![[Demo_Exchange.jpeg]] - ![[Demo_SecurityOperations.jpeg]] ## Why This Module? After years in the MSP space as a SysAdmin and Consultant, I noticed a growing trend: clients increasingly want periodic security and compliance reports for their Microsoft 365 tenants. What started as manual data gathering became repetitive, time-consuming work. TenantReports automates this process. Connect once, run a single command, and get a complete security posture assessment—Secure Score, Conditional Access, Intune compliance, privileged access, and more. ## Quick Start Get your first report in under a minute—no app registration required. > **Requires PowerShell 7.** Run `$PSVersionTable.PSVersion` to check. [Download PowerShell 7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell) ```powershell Install-Module TenantReports -Scope CurrentUser Import-Module TenantReports $Report = Invoke-TntReport -Interactive ``` A browser window opens for sign-in. **Make usre to authenticate with an account that has Global Administrator permissions.** The module handles permissions, authentication, and session management automatically. > **Don't worry about errors.** If a section fails due to missing permissions or disabled features, the report continues. Check `$Report.ReportMetadata.SectionStatus` to see what succeeded—most sections will work out of the box. ## What You Get - **24 report functions** covering identity, devices, email security, and cloud infrastructure - **One command** (`Invoke-TntReport`) runs everything and consolidates results - **Flexible output** — pipe to JSON, CSV, or use directly in scripts - **Graceful error handling** — missing permissions or disabled features won't break your report; affected sections return warnings while everything else continues - **Multiple auth methods** — interactive sign-in for quick runs, app registration for automation ### Interactive Mode Limitations Two sections require application-level permissions and are skipped in interactive mode: | Section | Reason | |---------|--------| | `RiskyUsers` | Requires `IdentityRiskyUser.Read.All` application permission | | `Defender` | Requires application-level Defender for Office 365 permissions | Everything else works with interactive authentication. ## Installation ### From PowerShell Gallery ```powershell Install-Module TenantReports -Scope CurrentUser ``` ### Dependencies The module requires several Microsoft Graph modules. Install them once: ```powershell # Required modules $Modules = @( 'ExchangeOnlineManagement' 'Microsoft.Graph.Applications' 'Microsoft.Graph.Authentication' 'Microsoft.Graph.Beta.Security' 'Microsoft.Graph.Beta.Users' 'Microsoft.Graph.DeviceManagement' 'Microsoft.Graph.Groups' 'Microsoft.Graph.Identity.DirectoryManagement' 'Microsoft.Graph.Identity.Governance' 'Microsoft.Graph.Identity.SignIns' 'Microsoft.Graph.Reports' 'Microsoft.Graph.Security' 'Microsoft.Graph.Users' ) $Modules | ForEach-Object { Install-Module $_ -Scope CurrentUser -Force } ``` > **Note:** The first `Import-Module TenantReports` may take 10-20 seconds as all dependencies are loaded via the module manifest. Subsequent imports in the same session are instant. ## Web Viewer The JSON output from `Invoke-TntReport` can be visualized with the **TenantReports Web Viewer**—a static web application that transforms your report into interactive dashboards. Check it out: https://report.systom.dev ### Features - Interactive charts and visualizations - Filterable data tables - Executive summary views - Export to PDF for client deliverables - Works entirely client-side—no data leaves your browser ### Generate and View ```powershell # Generate the report $Report = Invoke-TntReport -Interactive # Export to JSON $Report | ConvertTo-Json -Depth 20 | Out-File 'TenantReport.json' ``` Visit https://report.systom.dev and load the JSON file. Your security dashboard is ready. > **Blog post coming soon** — A detailed walkthrough of the Web Viewer and how to use it for client reporting. ## Automation Interactive mode is great for ad-hoc reports. For scheduled or unattended runs, set up an Azure AD App Registration. ### Quick Setup The module includes a setup script that creates and configures everything: ```powershell .\Setup\New-TenantReportsAppRegistration.ps1 -TenantId "your-tenant-id" -CreateClientSecret -AssignDirectoryRoles ``` This creates an app registration with all required permissions, grants admin consent, and outputs a client secret. > **Save the output!** The client secret is only displayed once. ### Running Automated Reports ```powershell $ReportParams = @{ TenantId = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' ClientId = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' ClientSecret = ConvertTo-SecureString 'your-secret' -AsPlainText -Force } $Report = Invoke-TntReport @ReportParams ``` ### Additional Options Include audit logs and mailbox analysis for deeper insights: ```powershell $Report = Invoke-TntReport @ReportParams ` -IncludeAuditReports ` -IncludeMailboxPermissions ` -IncludeCalendarPermissions ``` Run specific sections only: ```powershell # Include only what you need $Report = Invoke-TntReport @ReportParams -IncludeSections @('SecureScore', 'ConditionalAccess', 'Users') # Or exclude specific sections $Report = Invoke-TntReport @ReportParams -ExcludeSections @('MailboxPermissions', 'CalendarPermissions') ``` ## Available Reports | Function | Description | |----------|-------------| | `Invoke-TntReport` | Runs all reports and consolidates results | | **Tenant & Configuration** | | | `Get-TntOrganizationReport` | Tenant details and directory statistics | | `Get-TntConfigurationReport` | Tenant-wide settings and policies | | `Get-TntLicenseReport` | License allocation and usage | | `Get-TntLicenseChangeAuditReport` | License assignment and removal history | | **Identity & Access** | | | `Get-TntM365UserReport` | User accounts, sign-in activity, MFA status | | `Get-TntM365RiskyUserReport` | Risky users from Identity Protection | | `Get-TntPrivilegedRoleReport` | Privileged role assignments and break-glass accounts | | `Get-TntPIMReport` | Privileged Identity Management configuration | | `Get-TntConditionalAccessReport` | Conditional Access policy analysis | | **App Registrations & Service Principals** | | | `Get-TntServicePrincipalPermissionReport` | App registrations and permission grants | | `Get-TntAppRegistrationExpiryReport` | Credential and certificate expiration | | **Security Scores** | | | `Get-TntM365SecureScoreReport` | Microsoft 365 Secure Score with trends | | `Get-TntAzureSecureScoreReport` | Azure Security Center score | | **Devices** | | | `Get-TntIntuneDeviceComplianceReport` | Device compliance status | | `Get-TntIntuneAppleCertificateReport` | Apple DEP/APNS certificate expiration | | **Email & Exchange** | | | `Get-TntDefenderEmailThreatReport` | Email threats from Defender for Office 365 | | `Get-TntExchangeMailboxPermissionReport` | Mailbox delegation permissions | | `Get-TntExchangeCalendarPermissionReport` | Calendar folder permissions | | `Get-TntSharedMailboxComplianceReport` | Shared mailbox compliance | | `Get-TntInboxForwardingRuleReport` | External forwarding rules | | **Security & Audit** | | | `Get-TntM365AuditEvent` | Microsoft 365 and Azure AD audit events | | `Get-TntDefenderIncidentReport` | Defender incidents | Run any report individually with `-Interactive` or with app registration credentials. ## Troubleshooting ### Some report sections returned `$null` This is normal. Check what succeeded and what didn't: ```powershell $Report.ReportMetadata.SectionStatus ``` Common reasons for skipped sections: - **Exchange reports** — Requires Exchange Administrator role - **Defender reports** — Requires Defender for Office 365 to be enabled - **Azure Secure Score** — Requires Azure subscriptions linked to the tenant - **RiskyUsers** — Requires application permissions (not available in interactive mode) ### Microsoft Graph module conflicts If you see assembly loading errors like `Could not load file or assembly 'Microsoft.Graph.Authentication'`, you likely have multiple versions installed. Clean up and reinstall: ```powershell # Remove all Graph modules Get-InstalledModule Microsoft.Graph* | Uninstall-Module -AllVersions -Force # Restart PowerShell, then reinstall $Modules = @( 'Microsoft.Graph.Applications' 'Microsoft.Graph.Authentication' # ... (see Installation section for full list) ) $Modules | ForEach-Object { Install-Module $_ -Scope CurrentUser -Force } ``` ### App registration errors | Error | Solution | |-------|----------| | `AADSTS700016: Application not found` | Verify ClientId matches your app registration | | `AADSTS7000215: Invalid client secret` | Secret may be expired—create a new one in Azure Portal | | `Insufficient privileges` | Grant admin consent for all API permissions | ## Contributing Found a bug or have a feature request? Open an issue on [GitHub](https://github.com/systommy/TenantReports/issues). Pull requests are welcome. ## Author **Tom de Leeuw** - Website: [systom.dev](https://systom.dev) - GitHub: [@systommy](https://github.com/systommy) ## License MIT License — see [LICENSE](LICENSE) for details.