Who is this for? IT administrators, security teams, and change advisory board (CAB) reviewers who need to independently verify the permissions granted to ContraForce enterprise applications before or after onboarding.
Overview
ContraForce provides two audit scripts that enumerate the permissions granted to ContraForce enterprise applications in your Microsoft Entra ID tenant. Both scripts produce an identical JSON output that you can compare against the Enterprise Applications Reference to verify that only the documented permissions are in place. Choose the script that fits your environment:| PowerShell | Python | |
|---|---|---|
| Best for | Microsoft-native environments | Cross-platform / CLI-first teams |
| Runtime | PowerShell 7.0+ (pwsh) | Python 3.10+ |
| Auth method | Microsoft Graph PowerShell SDK | Azure CLI (az login) |
| Dependencies | Microsoft.Graph modules (Microsoft-published) | azure-identity (Microsoft-published) + httpx |
| Government cloud | -Cloud AzureUSGovernment | -c AzureUSGovernment |
What the Scripts Access
Both scripts make read-only queries to the Microsoft Graph REST API. The specific endpoint depends on your cloud environment:| Environment | Graph API Base | Identity Platform |
|---|---|---|
| Commercial / GCC | https://graph.microsoft.com/v1.0 | https://login.microsoftonline.com |
| GCC High / DoD | https://graph.microsoft.us/v1.0 | https://login.microsoftonline.us |
| Graph API Endpoint | Purpose |
|---|---|
GET /me | Resolve the authenticated operator’s identity (UPN and object ID) |
GET /organization | Resolve the tenant ID |
GET /servicePrincipals | Look up ContraForce and Microsoft resource API service principals by name or app ID |
GET /servicePrincipals/{id}/oauth2PermissionGrants | Read delegated permission grants for each application |
GET /servicePrincipals/{id}/appRoleAssignments | Read application permission assignments for each application |
Data in the Output File
The output JSON contains:- Application names and app IDs for each ContraForce enterprise application
- Permission names and descriptions resolved to human-readable values
- The resource API each permission targets (Microsoft Graph, WindowsDefenderATP, etc.)
- Metadata: timestamp, tenant ID, cloud environment, authenticated operator, and tool version
Applications Audited
In commercial (AzureCloud) environments, both scripts use built-in app IDs that match the Quick Reference table:| Application | App ID |
|---|---|
| ContraForce API | 24d97bc0-8f2b-45d5-8e0b-7fe286732ef2 |
| ContraForce Portal | 8b7cb435-9526-47ee-b79a-34433f0daad2 |
| ContraForce for MDE | 6efccc6a-f0d3-49e5-92d0-17d4afa9ba52 |
| ContraForce Gamebooks for MDE | ad7b0e79-3c37-4408-bf8f-eb89522cc920 |
| ContraForce Gamebooks for Identity | 36b0d51c-4c0f-4810-9cc4-bfbd40c7dd4a |
| ContraForce Gamebooks for Email | 44dbf6fe-45e3-48a3-bac3-f8d4cf1dba6d |
| ContraForce Sentinel Hunting | 6bf1c74d-7ade-4671-a507-166936f89a1f |
| ContraForce User Management | 460b65b7-3a5e-4a2c-98d0-e48fd35374a9 |
Prerequisites
- PowerShell
- Python
Runtime: PowerShell 7.0+ (Required Graph scopes: For environments without a browser, use device code flow:
pwsh, not Windows PowerShell 5.1)Microsoft Graph modules:Application.Read.All and Directory.Read.AllAuthenticate before running:Minimum Permissions
The account running the script needs read access to service principals and their permission grants. The minimum Microsoft Entra ID role is Directory Reader, or you can grant the following Microsoft Graph API permissions directly:| Graph Permission | Type | Purpose |
|---|---|---|
Application.Read.All | Delegated | Read service principal properties and app roles |
Directory.Read.All | Delegated | Read delegated permission grants and role assignments |
Running the Scripts
- PowerShell
- Python
-Cloud parameter value must match the cloud you authenticated to with Connect-MgGraph -Environment. The script validates this and exits with an error if there is a mismatch. Government environments require -AppsFile because app IDs differ from commercial.Government Cloud Environments (GCC High / DoD)
Both scripts support Microsoft Azure Government cloud environments used by public sector organizations subject to CMMC, FedRAMP, or ITAR requirements. Both scripts use the same-Cloud / -c parameter values, which match the az cloud set --name values:
| Cloud | Value | PowerShell | Python |
|---|---|---|---|
| Commercial (default) | AzureCloud | -Cloud AzureCloud | -c AzureCloud |
| Government (GCC High / DoD) | AzureUSGovernment | -Cloud AzureUSGovernment | -c AzureUSGovernment |
- Use the correct Graph endpoint —
graph.microsoft.usinstead ofgraph.microsoft.com - Redact the operator’s UPN — Records the Entra object ID (an opaque GUID) instead of the User Principal Name in the
generatedBymetadata field - Restrict output file permissions — Limits file access to the current user only (PowerShell: Windows ACL; Python: POSIX
chmod 600)
-RedactUPN switch (PowerShell) or --redact-upn flag (Python).
Audit Scripts
Understanding the Output
Both scripts produce a JSON file with the same structure. Here’s an abbreviated example:Output Schema
Key Fields
| Field | Description |
|---|---|
status | OK if the application was found and audited. NOT_FOUND if the application is not consented in the tenant. |
type | Delegated (on-behalf-of user) or Application (app-only, no user context). See Permission Types Explained. |
internal | true for permissions between ContraForce applications (e.g., Portal delegating to API). These are internal platform scopes and do not grant access to your tenant data. Only present on delegated permissions. |
environment | The cloud environment the audit was run against (AzureCloud or AzureUSGovernment). Matches the az cloud set --name value. |
generatedBy | The authenticated operator. In government environments, this is an Entra object ID (GUID) rather than a UPN. |
toolVersion | Include this when sharing audit results with ContraForce support for traceability. |
Internal Scope Resolution
You may notice the output includes delegated permissions where theapi field shows a ContraForce application name (e.g., "ContraForce Portal") and "internal": true. These are cross-application delegations where one ContraForce app delegates to another via custom OAuth2 scopes.
To resolve these internal scopes to human-readable names instead of raw GUIDs, the scripts query for all service principals whose display name starts with ContraForce — not just the eight applications listed in the audit table. This broader query:
- Does not grant additional access — it reads public service principal metadata that any authenticated directory reader can see
- Is clearly tagged — all permissions from internal apps are marked
"internal": truein the output - Improves readability — without this, internal scopes would appear as opaque GUIDs that are difficult to review
Comparing Against Documentation
To verify your tenant’s permissions match the documented permissions:- Run the audit script to produce
enterprise-apps-audit.json - Open the Enterprise Applications Reference
- For each application in the JSON output, compare its
delegatedPermissionsandapplicationPermissionsagainst the corresponding tables in the reference - Permissions marked
"internal": trueare ContraForce-to-ContraForce delegations and are not listed in the reference tables
Comparing Across Audit Runs
To track permission changes over time, save each audit output with a date-stamped filename:diff, VS Code’s built-in compare, or Compare-Object in PowerShell) will surface only actual permission changes — not ordering noise.
Store audit outputs alongside your change management records. The metadata.generatedAt and metadata.toolVersion fields provide traceability for each snapshot.
Output File Access Control
The audit output reveals your tenant’s permission surface for ContraForce applications. While it does not contain secrets or tokens, it should be treated as internal documentation. Government cloud environments: Both scripts automatically restrict the output file so only the current user can read or write it:- PowerShell (Windows): Removes inherited ACL entries and grants
FullControlonly to the current user viaSet-Acl - Python (POSIX): Sets file mode to
600(chmod u=rw,go=) viaos.chmod
- Windows
- Linux / macOS
Using This Output as Audit Evidence
The audit output is designed to serve as evidence in change advisory board (CAB) reviews, compliance audits, and periodic access reviews. For CAB / Change Management:- Run the audit before and after onboarding a new ContraForce module
- Include both snapshots in your change record to show exactly which permissions were added
- The
toolVersionfield ensures reviewers know which version of the script produced the output
- Schedule monthly or quarterly audit runs and archive the output alongside your review documentation
- Use date-stamped filenames (e.g.,
audit-2026-Q1.json) for easy retrieval - Compare successive outputs using
diffto identify any permission drift
- If you suspect unauthorized permission changes, run an immediate audit and compare against your most recent baseline
- The
generatedAttimestamp provides a verifiable point-in-time snapshot
Troubleshooting
| Issue | Cause | Resolution |
|---|---|---|
NOT_FOUND for some applications | Application not consented in tenant | Expected if you haven’t deployed all modules. See Applications by Module. |
| PowerShell: “No active Microsoft Graph session” | Connect-MgGraph not run | Run Connect-MgGraph -Scopes "Application.Read.All","Directory.Read.All" first. For government cloud, add -Environment USGov (GCC High) or -Environment USGovDoD (DoD). |
| PowerShell: “Environment mismatch” | -Cloud value does not match the Connect-MgGraph -Environment session | Disconnect with Disconnect-MgGraph and reconnect with the correct -Environment flag matching your -Cloud value. |
| ”Government cloud environments require -AppsFile / —apps-file” | No apps file provided for government cloud | App IDs differ by cloud environment. Contact [email protected] for your environment’s app IDs and provide them via -AppsFile (PowerShell) or --apps-file (Python). |
| Python: “Azure CLI is not authenticated” | az login not run or session expired | Run az login to authenticate. For government cloud, run az cloud set --name AzureUSGovernment first. |
| Python: “Missing required packages” | azure-identity or httpx not installed | Run pip install azure-identity httpx |
| Python: “Python 3.10+ is required” | Running on an older Python version | Install Python 3.10 or newer |
| Script takes a long time | Microsoft Graph API throttling | Normal in large tenants. The scripts handle 429 Retry-After responses automatically. |
| Permissions don’t match documentation | Permissions changed since last documentation update | Contact [email protected] with the audit JSON and toolVersion |
Related Resources
Enterprise Applications Reference
Complete reference for all ContraForce enterprise applications and their permissions
Azure Resources Deployed
All Azure resources provisioned during ContraForce onboarding
Roles & Permissions
ContraForce platform roles and what each can do
Platform Onboarding
Step-by-step guide to onboarding your parent workspace
Questions about the audit scripts or enterprise application permissions? Contact us at [email protected].