Skip to main content

Part 1: Microsoft 365 Data Ingestion

Set up a Microsoft 365 app so ConfigView can pull your Microsoft 365 data into the dashboard.

Step 1: Create an App or Token

This setup explains how to register and configure an application in Microsoft Entra ID (Azure AD).
  1. Retrieve your Tenant ID.
  2. Create a new App Registration in Azure AD for ConfigView.
  3. Create a Client Secret for the application and copy its value.
  4. Assign the required Read-Only permissions for Microsoft Graph APIs and Microsoft 365 data (Users, Groups).
  5. Grant admin consent for the selected permissions.

Step 2: Add the Token to ConfigView

  1. Go to your ConfigView dashboard: https://{companyname}.configview.com/admin/integrations/microsoft-365
  2. Under Credentials, enter each value and click the save icon on its row:
MSFT_CLIENT_SECRET_VALUE holds the client secret value, not the secret’s ID. Azure shows both on the same screen and only displays the value once — copy the Value column, not Secret ID.

Step 2b: A second Microsoft tenant (optional)

If you have two Microsoft tenants, the Microsoft 365 - 2 app collects the second one into parallel _2 tables (msft_users_2, msft_managed_devices_2, …). It needs its own app registration in the second tenant, and its own secrets: Graph permissions are granted per app registration, not per organisation. Every permission in the tables below has to be added and admin-consented separately on the second app registration. A tenant that works for one script family and 403s for another is almost always a permission granted on only one of the two registrations. Which tenant is “1” and which is “2” is just the order they were configured — there is nothing inherently primary about the unsuffixed one. If your production tenant is configured as the second one, the reports that matter are the _2 variants (microsoft2.* seeds and coverage.msft2_*), and the unsuffixed reports will describe the other tenant. Worth confirming which is which before acting on a Microsoft report.

Step 3: Enable the Microsoft 365 App in ConfigView

  1. Go to: https://{companyname}.configview.com/admin/integrations/microsoft-365
  2. Click Connect. ConfigView creates its tables and schedules every collector at your default run time.
  3. Click Verify now to confirm the credentials work.

Step 4: Verify

  1. Go to: https://{companyname}.configview.com/admin/status/
  2. Run the Microsoft 365 health check.
  3. All checks should pass.
If a check fails, verify that your secrets are saved correctly and the app has the required permissions.

Required Microsoft Graph Permissions

All permissions below are Application (app-only) permissions, used with the client credentials flow. After adding any permission, click Grant admin consent in the Azure portal. Only add the permissions for the scripts you intend to enable. Some endpoints additionally require an Entra ID P2 license (noted below).

Core identity & inventory

Tenant settings & policy

microsoft_get_consent_requests collects the same list the Entra portal shows under Enterprise applications → Admin consent requests — which app was requested, by whom, their written justification, the approve/deny verdict and who reviewed it. It is request history, not just what is pending: Completed and Expired requests going back years are returned alongside InProgress ones.
ConsentRequest.Read.All is the least-privileged permission for these two endpoints and is what we recommend granting. It is not the only one that works: a tenant whose app registration already holds the much broader Directory.Read.All can read both endpoints without adding anything — verified on both Thrive tenants 2026-09-18, where the collectors return data on Directory.Read.All alone. If you are choosing, prefer ConsentRequest.Read.All.
microsoft_get_admin_consent_request_policy collects the workflow’s own configuration, and is the reason an empty request list is readable. If isEnabled is 0 the admin consent workflow is switched off in that tenant and an empty msft_consent_requests is the correct answer rather than a collection failure. Check that column before investigating an empty table.
These two collectors are paced more tightly than the rest of the folder. The identityGovernance endpoints throttle on a burst window — roughly 23 requests per 10 seconds, measured — and each consent request needs its own follow-up call for the requester and verdict. A tenant with a few dozen requests takes under a minute.

Roles & PIM

Licenses & billing

Microsoft does not expose full invoice/payment billing through Graph. For invoices and usage charges, use the Microsoft 365 admin center or Partner Center APIs.

Mailboxes & calendars

microsoft_get_calendars reads the calendar list for each mailbox — one row per calendar, with its name, owner, and sharing flags. It does not read events, so no meeting subjects, bodies, or attendee lists enter your database. Calendars.ReadBasic is enough to collect it. Granting Calendars.Read as well fills in three columns that ReadBasic withholds — canEdit, canViewPrivateItems, and changeKey — which stay NULL under ReadBasic rather than defaulting to false. Note that Calendars.Read is the permission whose portal description reads “Read calendars in all mailboxes”; there is no permission literally named Calendars.ReadAll. Both are Application permissions and both grant tenant-wide mailbox access. To narrow that, scope the app registration with an application access policy so it can only reach a chosen mail-enabled security group. Mailboxes outside the policy return 403 and are skipped without failing the run.

OneDrive / SharePoint / external sharing

Audit & sign-ins

Security & identity protection

Teams & communications

Intune device policies

After granting any new permissions in Azure AD, restart the satellite (or wait for the next cron run) — tokens are cached per script invocation and will pick up the new scopes on the next run.

Device inventory: which table joins to other systems

Device.Read.All and DeviceManagementManagedDevices.Read.All return different things, and only one of them is useful for cross-system device reporting: So msft_managed_devices is the only Microsoft table that can be joined to an MDM or EDR inventory by serial. If you want reports like “Intune devices with no CrowdStrike agent” (coverage.msft_missing_crowdstrike), you need the Intune permission — Device.Read.All alone will not do it. Matching msft_devices.displayName against an EDR hostname instead is not a workable substitute; measured against a real tenant it matched under 20% of devices.

Troubleshooting an empty msft_managed_devices

An empty Intune table has two very different causes, and the collector’s own output distinguishes them:
  • Fetched 0 devices and the run succeeds — the permission is fine and the tenant genuinely has no Intune-enrolled devices. Common on tenants that use a different MDM (Jamf, Kandji, Workspace ONE) or on a sandbox tenant. Nothing to fix.
  • 403 Client Error: Forbidden on /deviceManagement/managedDevices — the app registration is missing DeviceManagementManagedDevices.Read.All, or it was added without clicking Grant admin consent. Note Device.Read.All does not cover this endpoint; an app can hold it and still 403 here.
To check a grant without waiting for a scheduled run, decode the roles claim of an app-only token — it lists exactly the application permissions that were consented:

Directory discovery

microsoft_get_directories builds an inventory of the Entra directories around your tenant — their names, default domains and identity providers — into msft_directories. It resolves each one through Microsoft Graph’s cross-tenant lookup, which answers for any directory without consent in it, so a directory appears here whether or not ConfigView collects it. It finds candidates three ways: the guest accounts in your own tenant (the directories your guests come from), the homeTenantId on cross-tenant sign-ins, and a list you supply. The list matters because no app-only credential can enumerate directories — the Azure portal’s Directories + subscriptions switcher is a view of the signed-in person’s memberships, not something an API exposes. A certificate or sandbox tenant that has never invited a guest and never had a sign-in is invisible until you name it. Set the optional secret MSFT_KNOWN_DIRECTORIES (and MSFT_KNOWN_DIRECTORIES_2 for the second tenant) to a comma-separated list of tenant IDs or domains, copied from that portal page:
The table records which source vouched for each directory in discovered_via, so a row that exists only because you seeded it is distinguishable from one your own data found. The payload is a directory’s public identity only — never its users, subscriptions or resources, which still require an app registration and role assignment inside it.

Data Tables

Once the scripts run, the corresponding Microsoft 365 tables will be created in your database. All tables include a run_at column for historical tracking.