A PowerShell module that audits Microsoft Graph permission assignments and recommends least-privilege permissions based on actual app activity.
- Queries all app registrations with Microsoft Graph permissions assigned
- Translates permission GUIDs into friendly names
- Cross-references against Microsoft Graph Activity Logs to see what endpoints each app actually calls
- Anonymizes API URLs to reduce noise (millions of calls → unique URL patterns)
- Generates an HTML report showing current permissions, optimal permissions, and excess permissions per app
- Optionally includes throttling statistics per app
| Front Page | Details Modal |
|---|---|
![]() |
![]() |
Try the sample report — an anonymized example with 50 app registrations.
- Entra ID P1 or P2 license (required for Microsoft Graph Activity Logs)
- A Log Analytics workspace with the
MicrosoftGraphActivityLogsdiagnostic setting enabled - An App Registration with:
Application.Read.AllMicrosoft Graph application permissionDirectory.Read.All(only needed to include delegated permissions in the report)Log Analytics ReaderRBAC role on the Log Analytics workspace
New to this setup? Follow the step-by-step setup guide for a walkthrough covering Log Analytics, Entra diagnostics, and app registration configuration.
Install-Module LeastPrivilegedMSGraphOr from source:
git clone https://github.com/Mynster9361/Least_Privileged_MSGraph.git
cd LeastPrivilegedMSGraph
./build.ps1 -ResolveDependency -Tasks build
Import-Module ./output/LeastPrivilegedMSGraph -Force$tenantId = "your-tenant-id"
$clientId = "your-app-id"
$clientSecret = "your-secret" | ConvertTo-SecureString -AsPlainText -Force
$logAnalyticsWorkspaceId = "your-workspace-id"
$daysToQuery = 30
Import-Module LeastPrivilegedMSGraph
Initialize-LPMSLogAnalyticsApi
Connect-EntraService -ClientID $clientId -TenantID $tenantId -ClientSecret $clientSecret -Service "LogAnalytics", "GraphBeta"
Get-LPMSAppRoleAssignment |
Get-LPMSAppActivityData -WorkspaceId $logAnalyticsWorkspaceId -Days $daysToQuery |
Get-LPMSAppThrottlingData -WorkspaceId $logAnalyticsWorkspaceId -Days $daysToQuery |
Get-LPMSPermissionAnalysis |
Export-LPMSPermissionAnalysisReport -OutputPath ".\report.html"Use Select-Object -First N to limit the scope during initial testing:
Get-LPMSAppRoleAssignment | Select-Object -First 10 |
Get-LPMSAppActivityData -WorkspaceId $logAnalyticsWorkspaceId -Days $daysToQuery |
Get-LPMSAppThrottlingData -WorkspaceId $logAnalyticsWorkspaceId -Days $daysToQuery |
Get-LPMSPermissionAnalysis |
Export-LPMSPermissionAnalysisReport -OutputPath ".\report.html"Get help for any function:
Get-Help Get-LPMSAppRoleAssignment -Full- SharePoint scoped permissions — the module may suggest
Sites.Read.AllwhereSites.Selectedwould be more appropriate - Cross-permission correlations — e.g. if you query group members and need
User.ReadBasic.AllalongsideGroup.Read.All, this may not always be detected - Recommendations are a guide, not a guarantee — use your knowledge of each app to validate suggestions
See CONTRIBUTING.md for development setup, coding standards, testing requirements, and how to submit pull requests.
- GitHub Issues — bug reports and feature requests
- LinkedIn — questions and feedback

