Public/Entra/Application/Get-MgApplicationAssignment.ps1
|
<#
.SYNOPSIS Retrieves all Entra ID applications and their assignment types. .DESCRIPTION This function returns a list of all Entra ID applications with their assignment information, identifying whether they are assigned to all users or have specific assignments. If no assignments exist, it indicates whether the application is available to "all users". Give information about assigned users, groups, or service principals and if the group is protected/static/dynamic. .PARAMETER ApplicationId (Optional) One or more Application IDs to filter the results. If not provided, all applications will be processed. .PARAMETER OnlyAssignedToAllUsers (Optional) If specified, only applications that are assigned to "all users" (i.e., do not require assignment) will be returned. .PARAMETER ExportToExcel (Optional) If specified, exports the results to an Excel file in the user's profile directory. .EXAMPLE Get-MgApplicationAssignment Retrieves all applications and their assignment types. .EXAMPLE Get-MgApplicationAssignment -ApplicationId "xxx", "yyy" Retrieves assignment types for the specified application IDs. .EXAMPLE Get-MgApplicationAssignment -OnlyAssignedToAllUsers Retrieves only applications that are assigned to all users (no assignment required). .EXAMPLE Get-MgApplicationAssignment -ExportToExcel Gets all applications and exports them to an Excel file .LINK https://ps365.clidsys.com/docs/commands/Get-MgApplicationAssignment #> function Get-MgApplicationAssignment { param( [Parameter(Mandatory = $false)] [String[]]$ApplicationId, [Parameter(Mandatory = $false)] [switch]$OnlyAssignedToAllUsers, [Parameter(Mandatory = $false)] [switch]$ExportToExcel ) # Get all service principals (enterprise applications) if ($ApplicationId) { $servicePrincipals = @() foreach ($appId in $ApplicationId) { try { $sp = Get-MgServicePrincipal -Filter "AppId eq '$appId'" -ErrorAction Stop if ($sp) { $servicePrincipals += $sp } } catch { Write-Warning "Could not find application with ID: $appId" } } } else { $servicePrincipals = Get-MgServicePrincipal -All } # Initialize results array [System.Collections.Generic.List[PSCustomObject]]$applicationAssignmentsArray = @() Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] Starting analysis of $($servicePrincipals.Count) applications..." -ForegroundColor Cyan $counter = 0 foreach ($sp in $servicePrincipals) { $counter++ Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] [$counter/$($servicePrincipals.Count)] Analyzing application: $($sp.DisplayName)" -ForegroundColor Cyan # Get app role assignments for this service principal $appRoleAssignments = Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $sp.Id if ($appRoleAssignments.Count -gt 0) { # Process each assignment individually foreach ($assignment in $appRoleAssignments) { # Initialize assignment properties in logical order for readability $assignmentProps = [ordered]@{ # Application info (most important first) ApplicationName = $sp.DisplayName AssignmentType = '' PrincipalType = '' IsRoleAssignableGroup = $null # Principal details (User, Group, or Service Principal) UserName = $null UserPrincipalName = $null GroupName = $null GroupType = $null GroupMembershipType = $null ServicePrincipalName = $null ServicePrincipalType = $null PrincipalDisplayName = $null # Role and permission details AppRoleValue = ($sp.AppRoles | Where-Object { $_.Id -eq $assignment.AppRoleId }).Value AppRoleId = $assignment.AppRoleId AppRoleAssignmentRequired = $sp.AppRoleAssignmentRequired # Technical IDs (less important, at the end) ApplicationId = $sp.AppId ServicePrincipalId = $sp.Id UserId = $null GroupId = $null AssignedServicePrincipalId = $null PrincipalId = $null IsAssignableToRole = $null ServicePrincipalAppId = $null # Metadata (at the end) ApplicationPublisher = $sp.PublisherName CreatedDate = $assignment.CreatedDateTime } if ($assignment.PrincipalType -eq 'User') { $assignmentProps.AssignmentType = 'User Assignment' $assignmentProps.PrincipalType = 'User' try { $user = Get-MgUser -UserId $assignment.PrincipalId -ErrorAction SilentlyContinue if ($user) { Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] -> User found: $($user.DisplayName)" -ForegroundColor Green $assignmentProps.UserName = $user.DisplayName $assignmentProps.UserPrincipalName = $user.UserPrincipalName $assignmentProps.UserId = $user.Id } else { $assignmentProps.AssignmentType = 'User Assignment (Not Found)' $assignmentProps.UserName = "User ID: $($assignment.PrincipalId)" $assignmentProps.UserPrincipalName = 'Unknown' $assignmentProps.UserId = $assignment.PrincipalId } } catch { Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] -> Error retrieving user $($assignment.PrincipalId): $($_.Exception.Message)" -ForegroundColor Red $assignmentProps.AssignmentType = 'User Assignment (Error)' $assignmentProps.UserName = "User ID: $($assignment.PrincipalId)" $assignmentProps.UserPrincipalName = 'Unknown' $assignmentProps.UserId = $assignment.PrincipalId } } elseif ($assignment.PrincipalType -eq 'Group') { $assignmentProps.AssignmentType = 'Group Assignment' $assignmentProps.PrincipalType = 'Group' try { $group = Get-MgGroup -GroupId $assignment.PrincipalId -ErrorAction SilentlyContinue if ($group) { $protectedStatus = if ($null -ne $group.IsAssignableToRole) { $group.IsAssignableToRole } else { 'N/A' } Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] -> Group found: $($group.DisplayName) (Protected: $protectedStatus)" -ForegroundColor Green $assignmentProps.GroupName = $group.DisplayName $assignmentProps.GroupId = $group.Id $assignmentProps.GroupType = $group.GroupTypes -join ',' $assignmentProps.GroupMembershipType = if ($group.MembershipRule -and $group.MembershipRuleProcessingState -eq 'On') { 'Dynamic' } else { 'Static' } $assignmentProps.IsAssignableToRole = $group.IsAssignableToRole $assignmentProps.IsRoleAssignableGroup = $group.IsAssignableToRole } else { $assignmentProps.AssignmentType = 'Group Assignment (Not Found)' $assignmentProps.GroupName = "Group ID: $($assignment.PrincipalId)" $assignmentProps.GroupId = $assignment.PrincipalId $assignmentProps.GroupType = 'Unknown' $assignmentProps.GroupMembershipType = 'Unknown' $assignmentProps.IsAssignableToRole = $null $assignmentProps.IsRoleAssignableGroup = $null } } catch { Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] -> Error retrieving group $($assignment.PrincipalId): $($_.Exception.Message)" -ForegroundColor Red $assignmentProps.AssignmentType = 'Group Assignment (Error)' $assignmentProps.GroupName = "Group ID: $($assignment.PrincipalId)" $assignmentProps.GroupId = $assignment.PrincipalId $assignmentProps.GroupType = 'Unknown' $assignmentProps.GroupMembershipType = 'Unknown' $assignmentProps.IsAssignableToRole = $null $assignmentProps.IsRoleAssignableGroup = $null } } elseif ($assignment.PrincipalType -eq 'ServicePrincipal') { $assignmentProps.AssignmentType = 'Service Principal Assignment' $assignmentProps.PrincipalType = 'ServicePrincipal' try { $servicePrincipal = Get-MgServicePrincipal -ServicePrincipalId $assignment.PrincipalId -ErrorAction SilentlyContinue if ($servicePrincipal) { Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] -> Service Principal found: $($servicePrincipal.DisplayName)" -ForegroundColor Magenta $assignmentProps.ServicePrincipalName = $servicePrincipal.DisplayName $assignmentProps.ServicePrincipalAppId = $servicePrincipal.AppId $assignmentProps.ServicePrincipalType = $servicePrincipal.ServicePrincipalType $assignmentProps.AssignedServicePrincipalId = $servicePrincipal.Id } else { $assignmentProps.AssignmentType = 'Service Principal Assignment (Not Found)' $assignmentProps.ServicePrincipalName = "Service Principal ID: $($assignment.PrincipalId)" $assignmentProps.AssignedServicePrincipalId = $assignment.PrincipalId $assignmentProps.ServicePrincipalAppId = 'Unknown' $assignmentProps.ServicePrincipalType = 'Unknown' } } catch { Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] -> Error retrieving Service Principal $($assignment.PrincipalId): $($_.Exception.Message)" -ForegroundColor Red $assignmentProps.AssignmentType = 'Service Principal Assignment (Error)' $assignmentProps.ServicePrincipalName = "Service Principal ID: $($assignment.PrincipalId)" $assignmentProps.AssignedServicePrincipalId = $assignment.PrincipalId $assignmentProps.ServicePrincipalAppId = 'Unknown' $assignmentProps.ServicePrincipalType = 'Unknown' } } else { # Handle unknown/unsupported principal types $assignmentProps.AssignmentType = "$($assignment.PrincipalType) Assignment" $assignmentProps.PrincipalType = $assignment.PrincipalType $assignmentProps.PrincipalId = $assignment.PrincipalId $assignmentProps.PrincipalDisplayName = "Unknown $($assignment.PrincipalType)" Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] -> Unhandled principal type: $($assignment.PrincipalType) (ID: $($assignment.PrincipalId))" -ForegroundColor DarkYellow } # Create and add the assignment object $object = [PSCustomObject]$assignmentProps $applicationAssignmentsArray.Add($object) } } else { # No assignments found - create one entry using the same complete structure $assignmentProps = [ordered]@{ # Application info (most important first) ApplicationName = $sp.DisplayName AssignmentType = '' PrincipalType = '' IsRoleAssignableGroup = $null # Principal details (User, Group, or Service Principal) UserName = $null UserPrincipalName = $null GroupName = $null GroupType = $null GroupMembershipType = $null ServicePrincipalName = $null ServicePrincipalType = $null PrincipalDisplayName = $null # Role and permission details AppRoleValue = $null AppRoleId = $null AppRoleAssignmentRequired = $sp.AppRoleAssignmentRequired # Technical IDs (less important, at the end) ApplicationId = $sp.AppId ServicePrincipalId = $sp.Id UserId = $null GroupId = $null AssignedServicePrincipalId = $null PrincipalId = $null IsAssignableToRole = $null ServicePrincipalAppId = $null # Metadata (at the end) ApplicationPublisher = $sp.PublisherName CreatedDate = $sp.CreatedDateTime } if ($sp.AppRoleAssignmentRequired -eq $false) { $assignmentProps.AssignmentType = 'All Users (No Assignment Required)' $assignmentProps.PrincipalType = 'All Users' Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] -> Application available to all users (no assignment required)" -ForegroundColor Yellow } else { $assignmentProps.AssignmentType = 'Not Assigned' $assignmentProps.PrincipalType = 'None' Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] -> No assignments found" -ForegroundColor Gray } # Create and add the no-assignment object $object = [PSCustomObject]$assignmentProps $applicationAssignmentsArray.Add($object) } } Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] Analysis completed. Total items found: $($applicationAssignmentsArray.Count)" -ForegroundColor Cyan # Apply filtering if requested if ($OnlyAssignedToAllUsers.IsPresent) { $beforeCount = $applicationAssignmentsArray.Count $applicationAssignmentsArray = $applicationAssignmentsArray | Where-Object { $_.AssignmentType -eq 'All Users (No Assignment Required)' } Write-Host "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] Filtering applied (OnlyAssignedToAllUsers): $($applicationAssignmentsArray.Count)/$beforeCount items retained" -ForegroundColor Cyan } if ($ExportToExcel.IsPresent) { $now = Get-Date -Format 'yyyy-MM-dd_HHmmss' $excelFilePath = "$($env:userprofile)\$now-MgApplicationAssignment.xlsx" Write-Host -ForegroundColor Cyan "Exporting application assignments to Excel file: $excelFilePath" $applicationAssignmentsArray | Export-Excel -Path $excelFilePath -AutoSize -AutoFilter -WorksheetName 'EntraApplicationAssignments' Write-Host -ForegroundColor Green 'Export completed successfully!' } else { return $applicationAssignmentsArray } } |