Skip to content

Instantly share code, notes, and snippets.

@TiloGit
Created May 30, 2023 19:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TiloGit/4a2768fff5fc1b53b4976252d21e89e2 to your computer and use it in GitHub Desktop.
Save TiloGit/4a2768fff5fc1b53b4976252d21e89e2 to your computer and use it in GitHub Desktop.
##based on https://github.com/12Knocksinna/Office365itpros/blob/master/ReportPermissionsApps.PS1
#
# ReportPermissionsApps.PS1
# A script using Azure Automation and a managed identity to scan for apps assigned high-priority permissions and report them
# for administrator review
##install graph PS
Install-Module Microsoft.Graph -Scope CurrentUser
#Connect-AzAccount -Identity
$AccessToken = Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com"
Connect-MgGraph -AccessToken $AccessToken.Token
#Define the desired graph endpoint
Select-MgProfile Beta
# Define Output Files - only used if executed interactively
#$OutputFile = "c:\temp\AppsAndPermissions.csv"
#$OutputFile2 = "c:\temp\AppsForReview.csv"
$OutputFile = "/home/tilo/AppsAndPermissions.csv"
$OutputFile2 = "/home/tilo/AppsForReview.csv"
# Get tenant information
$Tenant = (Get-MgOrganization)
$TenantId = $Tenant.Id
$TenantName = $Tenant.DisplayName
# Define the set of high-priority permissions we're interested in
[array]$HighPriorityPermissions = "User.Read.All", "User.ReadWrite.All", "Mail.ReadWrite", `
"Files.ReadWrite.All", "Calendars.ReadWrite", "Mail.Send", "User.Export.All", "Directory.Read.All", `
"Exchange.ManageAsApp", "Directory.ReadWrite.All", "Sites.ReadWrite.All"
# Define check period for new service principals
[datetime]$CheckforRecent = (Get-Date).AddDays(-360)
# Populate a set of hash tables with permissions used for different Office 365 management functions
$GraphApp = Get-MgServicePrincipal -Filter "AppId eq '00000003-0000-0000-c000-000000000000'"
# Populate hash table with Graph permissions
$GraphRoles = @{}
ForEach ($Role in $GraphApp.AppRoles) { $GraphRoles.Add([string]$Role.Id, [string]$Role.Value) }
# Populate hash table with Exchange Online permissions
$ExoPermissions = @{}
$ExoApp = Get-MgServicePrincipal -Filter "AppId eq '00000002-0000-0ff1-ce00-000000000000'"
ForEach ($Role in $ExoApp.AppRoles) { $ExoPermissions.Add([string]$Role.Id, [string]$Role.Value) }
$O365Permissions = @{}
$O365API = Get-MgServicePrincipal -Filter "DisplayName eq 'Office 365 Management APIs'"
ForEach ($Role in $O365API.AppRoles) { $O365Permissions.Add([string]$Role.Id, [string]$Role.Value) }
$AzureADPermissions = @{}
$AzureAD = Get-MgServicePrincipal -Filter "DisplayName eq 'Windows Azure Active Directory'"
ForEach ($Role in $AzureAD.AppRoles) { $AzureADPermissions.Add([string]$Role.Id, [string]$Role.Value) }
$TeamsPermissions = @{}
$TeamsApp = Get-MgServicePrincipal -Filter "DisplayName eq 'Skype and Teams Tenant Admin API'"
ForEach ($Role in $TeamsApp.AppRoles) { $TeamsPermissions.Add([string]$Role.Id, [string]$Role.Value) }
$RightsManagementPermissions = @{}
$RightsManagementApp = Get-MgServicePrincipal -Filter "DisplayName eq 'Microsoft Rights Management Services'"
ForEach ($Role in $RightsManagementApp.AppRoles) { $RightsManagementPermissions.Add([string]$Role.Id, [string]$Role.Value) }
# Create output tables
$Report = [System.Collections.Generic.List[Object]]::new()
$ProblemApps = [System.Collections.Generic.List[Object]]::new()
# Find all service principals belonging to registered apps
[array]$SPs = Get-MgServicePrincipal -top 999 -Filter "Tags/any(t:t eq 'WindowsAzureActiveDirectoryIntegratedApp')"
# And those for managed identities
[array]$ManagedIdentities = Get-MgServicePrincipal -top 999 -Filter "ServicePrincipalType eq 'ManagedIdentity'"
[array]$Apps = $SPs + $ManagedIdentities
# Loop through the apps and managed identities we've found to resolve the permissions assigned to each app
Write-Output ("{0} service principals for Azure AD registered apps found" -f $Apps.Count)
$i = 0
ForEach ($App in $Apps) {
$i++; $AppRecentFlag = $False
Write-Output ("Processing app {0} {1}/{2}" -f $App.DisplayName, $i, $Apps.Count)
if ($App.AdditionalProperties.createdDateTime) {
Write-Output "createdDateTime not null."
[datetime]$AppCreationDate = $App.AdditionalProperties.createdDateTime
}
else{
Write-Output "createdDateTime is null. set to 1970"
[datetime]$AppCreationDate = '1970-01-01'
}
If ($AppCreationDate -gt $CheckforRecent) {$AppRecentFlag = $True}
[array]$AppRoles = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $App.Id
If ($AppRoles) {
ForEach ($AppRole in $AppRoles) {
$Permission = $Null
Switch ($AppRole.ResourceDisplayName) {
"Microsoft Graph" {
[string]$Permission = $GraphRoles[$AppRole.AppRoleId] }
"Office 365 Exchange Online" {
[string]$Permission = $ExoPermissions[$AppRole.AppRoleId] }
"Office 365 Management APIs" {
[string]$Permission = $O365Permissions[$AppRole.AppRoleId] }
"Windows Azure Active Directory" {
[string]$Permission = $AzureADPermissions[$AppRole.AppRoleId] }
"Skype and Teams Tenant Admin API" {
[string]$Permission = $TeamsPermissions[$AppRole.AppRoleId] }
"Microsoft Rights Management Services" {
[string]$Permission = $RightsManagementPermissions[$AppRole.AppRoleId] }
}
If ($App.ServicePrincipalType -ne "ManagedIdentity") {
If ($App.AppOwnerOrganizationId -eq $TenantId) { #Resolve tenant name
$Name = $TenantName }
Else {
$LookUpId = $App.AppOwnerOrganizationId.toString()
$Uri = "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$LookUpId')"
$ExternalTenantData = Invoke-MgGraphRequest -Uri $Uri -Method Get
$Name = $ExternalTenantData.DisplayName }
$VerifiedPublisher = $Null
If ($App.AdditionalProperties["verifiedpublisher"]) { $VerifiedPublisher = $App.AdditionalProperties["verifiedpublisher"] }
}
$ReportLine = [PSCustomObject] @{
DisplayName = $App.DisplayName
ServicePrincipalId = $App.Id
Publisher = $App.PublisherName
VerifiedPublisher = $VerifiedPublisher
Homepage = $App.Homepage
OwnerOrgId = $App.AppOwnerOrganizationId
OwnerOrgName = $Name
AppRoleId = $AppRole.AppRoleId
AppRoleCreation = $AppRole.CreationTimeStamp
Id = $AppRole.Id
Resource = $AppRole.ResourceDisplayName
ResourceId = $AppRole.ResourceId
Permission = $Permission
SPType = $App.ServicePrincipalType
CreatedDate = Get-Date($AppCreationDate) -format g
RecentApp = $AppRecentFlag }
$Report.Add($ReportLine) }
} # End ForEach AppRole
} #End ForEach App
Write-Output ("{0} apps scanned and {1} permissions found" -f $Apps.Count, $Report.Count)
Write-Output ""
Write-Output "Permissions found"
Write-Output "-----------------"
Write-Output ""
$Report | Group Permission | Sort-Object Name | Format-Table Name, Count
# Uncomment the next two lines if you want to generate the output file (interactive use only)
$Report | Export-CSV -NoTypeInformation $OutputFile
Write-Output ("Full permissions report is available in {0}" -f $OutputFile)
ForEach ($Record in $Report) {
If ($Record.Permission -in $HighPriorityPermissions) {
$ProblemApps.Add($Record) }
}
# Uncomment the next two lines if you want to generate the report about problem apps
$ProblemApps | Export-CSV -NoTypeInformation $OutputFile2
Write-Output ("List of apps for review is available in {0}" -f $OutputFile2)
[array]$AppSet = $ProblemApps | Sort-Object ServicePrincipalId -Unique
$AppOutput = [System.Collections.Generic.List[Object]]::new()
ForEach ($App in $AppSet) {
$Records = $ProblemApps | Where-Object {$_.ServicePrincipalId -eq $App.ServicePrincipalId}
$AppPermissions = $Records.Permission -join ", "
$ReportLine = [PSCustomObject] @{
DisplayName = $App.DisplayName
ServicePrincipalId = $App.ServicePrincipalId
Publisher = $App.Publisher
Permissions = $AppPermissions
SPType = $App.SPType
CreatedDate = $App.CreatedDate
RecentApp = $App.RecentApp}
$AppOutput.Add($ReportLine)
}
# Add sign-in information for apps
[array]$MIAuditRecords = Get-MgAuditLogSignIn -Filter "(signInEventTypes/any(t:t eq 'managedIdentity'))" -Top 2000 -Sort "createdDateTime DESC"
[array]$AuditRecords = Get-MgAuditLogSignIn -Filter "(signInEventTypes/any(t:t eq 'servicePrincipal'))" -Top 2000 -Sort "createdDateTime DESC"
$AuditRecords = $AuditRecords + $MIAuditRecords
ForEach ($AppRecord in $AppOutput) {
$SignInFound = $AuditRecords | Where-Object {$_.ServicePrincipalId -eq $AppRecord.ServicePrincipalId} | Select-Object -First 1
If ($SignInFound) { Write-Output ("App {0} last signed in at {1}" -f $AppRecord.DisplayName, $SignInFound.CreatedDateTIme)
$AppRecord | Add-Member -NotePropertyName LastSignIn -NotePropertyValue $SignInFound.CreatedDateTime
}
}
##done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment