PowerShell module for analyzing Microsoft Graph permissions
Install-Module -Name LeastPrivilegedMSGraph -Repository PSGallery
Import-Module LeastPrivilegedMSGraph
Application.Read.All permissionAppRoleAssignment.Read.All permission# Define your Azure AD app and workspace details
$tenantId = "12345678-1234-1234-1234-123456789012"
$clientId = "87654321-4321-4321-4321-210987654321"
$clientSecret = "your-client-secret-here" | ConvertTo-SecureString -AsPlainText -Force
$workspaceId = "abcdef00-1111-2222-3333-444444444444"
$daysToAnalyze = 30
# Initialize Log Analytics API service
Initialize-LogAnalyticsApi
# Connect to both Microsoft Graph and Log Analytics
$connectSplat = @{
ClientID = $clientId
TenantID = $tenantId
ClientSecret = $clientSecret
Service = "LogAnalytics", "GraphBeta"
}
Connect-EntraService @connectSplat
# Get all apps with Graph permissions
$apps = Get-AppRoleAssignment
# Add API activity data from Log Analytics
$apps | Get-AppActivityData -WorkspaceId $workspaceId -Days $daysToAnalyze
# Add throttling statistics
$apps | Get-AppThrottlingData -WorkspaceId $workspaceId -Days $daysToAnalyze
# Perform permission analysis
$analysis = $apps | Get-PermissionAnalysis
# Generate interactive HTML report
Export-PermissionAnalysisReport -AppData $analysis -OutputPath ".\PermissionReport.html"
# Open the report in your default browser
Invoke-Item ".\PermissionReport.html"
# Or review in PowerShell
$analysis | Where-Object { $_.ExcessPermissions.Count -gt 0 } |
Select-Object PrincipalName,
@{N='Current';E={$_.CurrentPermissions.Count}},
@{N='Optimal';E={$_.OptimalPermissions.Count}},
@{N='Excess';E={$_.ExcessPermissions.Count}} |
Format-Table -AutoSize
# Complete permission analysis workflow
$tenantId = "12345678-1234-1234-1234-123456789012"
$clientId = "87654321-4321-4321-4321-210987654321"
$clientSecret = "your-secret" | ConvertTo-SecureString -AsPlainText -Force
$workspaceId = "abcdef00-1111-2222-3333-444444444444"
# Setup
Import-Module LeastPrivilegedMSGraph
Initialize-LogAnalyticsApi
$connectSplat = @{
ClientID = $clientId
TenantID = $tenantId
ClientSecret = $clientSecret
Service = "LogAnalytics", "GraphBeta"
}
Connect-EntraService @connectSplat
# Analysis pipeline
$results = Get-AppRoleAssignment |
Get-AppActivityData -WorkspaceId $workspaceId -Days 30 |
Get-AppThrottlingData -WorkspaceId $workspaceId -Days 30 |
Get-PermissionAnalysis
# Generate report
Export-PermissionAnalysisReport -AppData $results -OutputPath ".\analysis-$(Get-Date -Format 'yyyyMMdd').html"
# Display summary
"`nAnalysis Complete!"
"Applications analyzed: $($results.Count)"
"Over-privileged apps: $(($results | Where-Object { $_.ExcessPermissions.Count -gt 0 }).Count)"
"Total excess permissions: $(($results.ExcessPermissions | Measure-Object).Count)"
# Analyze only specific applications
$criticalApps = Get-AppRoleAssignment |
Where-Object { $_.PrincipalName -like "*Production*" }
$analysis = $criticalApps |
Get-AppActivityData -WorkspaceId $workspaceId -Days 90 |
Get-AppThrottlingData -WorkspaceId $workspaceId -Days 90 |
Get-PermissionAnalysis
# Find apps with high-privilege permissions they don't use
$dangerousPerms = @('Directory.ReadWrite.All', 'RoleManagement.ReadWrite.Directory')
$overPrivileged = $analysis | Where-Object {
$excessive = $_.ExcessPermissions | Where-Object { $_ -in $dangerousPerms }
$excessive.Count -gt 0
}
if ($overPrivileged) {
Write-Warning "Found $($overPrivileged.Count) apps with unused high-privilege permissions!"
$overPrivileged | Select-Object PrincipalName, @{N='UnusedHighPrivPerms';E={$_.ExcessPermissions | Where-Object { $_ -in $dangerousPerms }}}
}
# Test Log Analytics connectivity
Initialize-LogAnalyticsApi
Connect-EntraService -ClientID $clientId -TenantID $tenantId -ClientSecret $clientSecret -Service "LogAnalytics"
# Verify you can query the workspace
$testQuery = @{
query = "MicrosoftGraphActivityLogs | take 1"
}
Invoke-EntraRequest -Service 'LogAnalytics' -ApiUrl "/v1/workspaces/$workspaceId/query" -Method POST -Body $testQuery
MicrosoftGraphActivityLogs | take 10-Days parameter (applications may have infrequent activity)# Verify your app has required permissions
Get-MgServicePrincipal -Filter "appId eq '$clientId'" |
Select-Object -ExpandProperty AppRoles |
Where-Object { $_.Value -in @('Application.Read.All', 'AppRoleAssignment.Read.All') }