Src/Private/Get-AbrIntuneAppManagement.ps1
|
function Get-AbrIntuneAppManagement { <# .SYNOPSIS Documents Intune App Management configuration (MAM/MDM apps and protection policies). .DESCRIPTION Collects and reports on: - Mobile Application Management (MAM) App Protection Policies - Managed app configurations - Published app inventory (top deployed apps) - App Assignment summary .NOTES Version: 0.1.0 Author: Pai Wei Sing #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory)] [string]$TenantId ) begin { Write-PScriboMessage -Message "Collecting Intune App Management for $TenantId." Show-AbrDebugExecutionTime -Start -TitleMessage 'App Management' } process { Section -Style Heading2 'App Management' { Paragraph "The following section documents App Management (MAM/MDM) configuration for tenant $TenantId." BlankLine # Aggregated metrics for compliance checks $TotalAppProtPolicies = 0 $UnassignedAppPolicies = 0 #region App Protection Policies try { Write-Host " - Retrieving App Protection Policies..." # iOS App Protection Policies $iOSAppProtResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/v1.0/deviceAppManagement/iosManagedAppProtections?$expand=assignments" ` -ErrorAction SilentlyContinue $iOSPolicies = $iOSAppProtResp.value # Android App Protection Policies $AndroidAppProtResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/v1.0/deviceAppManagement/androidManagedAppProtections?$expand=assignments" ` -ErrorAction SilentlyContinue $AndroidPolicies = $AndroidAppProtResp.value $AllAppProtPolicies = @() if ($iOSPolicies) { $AllAppProtPolicies += $iOSPolicies | ForEach-Object { $_ | Add-Member -NotePropertyName '_platform' -NotePropertyValue 'iOS / iPadOS' -PassThru -Force } } if ($AndroidPolicies) { $AllAppProtPolicies += $AndroidPolicies | ForEach-Object { $_ | Add-Member -NotePropertyName '_platform' -NotePropertyValue 'Android' -PassThru -Force } } $null = ($TotalAppProtPolicies = @($AllAppProtPolicies).Count) if ($AllAppProtPolicies -and @($AllAppProtPolicies).Count -gt 0) { Section -Style Heading3 'App Protection Policies' { BlankLine $AppProtObj = [System.Collections.ArrayList]::new() foreach ($AppProt in ($AllAppProtPolicies | Sort-Object displayName)) { $assignResolved = Resolve-IntuneAssignments -Assignments $AppProt.assignments -CheckMemberCount:$script:CheckEmptyGroups $AssignedTo = $assignResolved.AssignmentSummary if ($assignResolved.AssignmentSummary -eq 'Not assigned') { $null = ($UnassignedAppPolicies++) } $appProtInObj = [ordered] @{ 'Policy Name' = $AppProt.displayName 'Platform' = $AppProt._platform 'Data Transfer Block' = if ($null -ne $AppProt.allowedOutboundDataTransferDestinations) { $AppProt.allowedOutboundDataTransferDestinations } else { '--' } 'PIN Required' = if ($null -ne $AppProt.pinRequired) { $AppProt.pinRequired } else { '--' } 'Managed Browser Required'= if ($null -ne $AppProt.managedBrowserToOpenLinksRequired) { $AppProt.managedBrowserToOpenLinksRequired } else { '--' } 'Assignments' = $AssignedTo 'Last Modified' = if ($AppProt.lastModifiedDateTime) { ([datetime]$AppProt.lastModifiedDateTime).ToString('yyyy-MM-dd') } else { '--' } } $AppProtObj.Add([pscustomobject](ConvertTo-HashToYN $appProtInObj)) | Out-Null } $null = (& { if ($HealthCheck.Intune.AppManagement) { $null = ($AppProtObj | Where-Object { $_.'Assignments' -eq 'Not assigned' } | Set-Style -Style Warning | Out-Null) } }) $AppProtTableParams = @{ Name = "App Protection Policies - $TenantId"; ColumnWidths = 22, 14, 16, 11, 14, 13, 10 } if ($Report.ShowTableCaptions) { $AppProtTableParams['Caption'] = "- $($AppProtTableParams.Name)" } $AppProtObj | Table @AppProtTableParams if (Get-IntuneExcelSheetEnabled -SheetKey 'AppProtection') { $script:ExcelSheets['App Protection'] = $AppProtObj } if (Get-IntuneBackupSectionEnabled -SectionKey 'AppProtectionPolicies') { $script:BackupData['AppProtectionPolicies'] = $AllAppProtPolicies } } } else { Paragraph "No App Protection Policies found in tenant $TenantId." } } catch { if (Test-AbrGraphForbidden -ErrorRecord $_) { Write-AbrPermissionError -Section 'App Protection Policies' -RequiredRole 'Intune Service Administrator or Global Administrator' } else { Write-AbrSectionError -Section 'App Protection Policies' -Message "$($_.Exception.Message)" } } #endregion #region Published Apps Summary if ($InfoLevel.AppManagement -ge 1) { try { Write-Host " - Retrieving published apps..." # /beta required -- v1.0 mobileApps returns BadRequest with $select on some tenants # @odata.type is a system property returned automatically -- do not include in $select # Removing $select entirely avoids BadRequest on tenants with strict Graph validation $AppsResp = Invoke-MgGraphRequest -Method GET ` -Uri "$($script:GraphEndpoint)/beta/deviceAppManagement/mobileApps" ` -ErrorAction SilentlyContinue $Apps = $AppsResp.value # Handle paging for large app libraries while ($AppsResp -and $AppsResp.'@odata.nextLink') { $AppsResp = Invoke-MgGraphRequest -Method GET -Uri $AppsResp.'@odata.nextLink' -ErrorAction SilentlyContinue if ($AppsResp.value) { $Apps += $AppsResp.value } } if ($Apps -and @($Apps).Count -gt 0) { Section -Style Heading3 'Published Apps' { BlankLine # Summary counts by type $AppTypes = $Apps | Group-Object { $_.'@odata.type' -replace '#microsoft.graph.', '' } | Sort-Object Count -Descending $AppSumObj = [System.Collections.ArrayList]::new() foreach ($AT in $AppTypes) { $atObj = [ordered] @{ 'App Type' = $AT.Name 'Count' = $AT.Count } $AppSumObj.Add([pscustomobject]$atObj) | Out-Null } $AppSumTableParams = @{ Name = "Published App Summary - $TenantId"; ColumnWidths = 65, 35 } if ($Report.ShowTableCaptions) { $AppSumTableParams['Caption'] = "- $($AppSumTableParams.Name)" } $AppSumObj | Table @AppSumTableParams BlankLine # Full app list (InfoLevel 2) if ($InfoLevel.AppManagement -ge 2) { $AppListObj = [System.Collections.ArrayList]::new() foreach ($App in ($Apps | Sort-Object displayName)) { $AppType = $App.'@odata.type' -replace '#microsoft.graph.', '' $appInObj = [ordered] @{ 'App Name' = $App.displayName 'Publisher' = if ($App.publisher) { $App.publisher } else { '--' } 'App Type' = $AppType 'Created' = if ($App.createdDateTime) { ([datetime]$App.createdDateTime).ToString('yyyy-MM-dd') } else { '--' } 'Last Modified'= if ($App.lastModifiedDateTime) { ([datetime]$App.lastModifiedDateTime).ToString('yyyy-MM-dd') } else { '--' } } $AppListObj.Add([pscustomobject]$appInObj) | Out-Null } $AppListTableParams = @{ Name = "App Inventory - $TenantId"; ColumnWidths = 28, 24, 22, 13, 13 } if ($Report.ShowTableCaptions) { $AppListTableParams['Caption'] = "- $($AppListTableParams.Name)" } $AppListObj | Table @AppListTableParams if (Get-IntuneExcelSheetEnabled -SheetKey 'AppInventory') { $script:ExcelSheets['App Inventory'] = $AppListObj } } } } } catch { if (Test-AbrGraphForbidden -ErrorRecord $_) { Write-AbrPermissionError -Section 'Published Apps' -RequiredRole 'Intune Service Administrator or Global Administrator' } else { Write-AbrSectionError -Section 'Published Apps' -Message "$($_.Exception.Message)" } } } #endregion #region ACSC E8 Assessment if ($script:IncludeACSCe8) { BlankLine Paragraph "ACSC Essential Eight Maturity Level Assessment -- App Management:" BlankLine try { $_v = @{ TotalAppProtectionPolicies = $TotalAppProtPolicies UnassignedAppPolicies = $UnassignedAppPolicies } $E8Checks = Build-AbrIntuneComplianceChecks -Definitions (Get-AbrIntuneE8Checks -Section 'AppManagement') -Framework E8 -CallerVariables $_v New-AbrIntuneE8AssessmentTable -Checks $E8Checks -Name 'App Management' -TenantId $TenantId if ($E8Checks) { $null = $script:E8AllChecks.AddRange([object[]](@($E8Checks | Select-Object @{N='Section';E={'AppManagement'}}, ML, Control, Status, Detail))) } } catch { Write-AbrSectionError -Section 'E8 App Management Assessment' -Message "$($_.Exception.Message)" } } #endregion #region CIS Assessment if ($script:IncludeCISBaseline) { BlankLine Paragraph "CIS Microsoft 365 Foundations Benchmark Assessment -- App Management:" BlankLine try { $_v = @{ TotalAppProtectionPolicies = $TotalAppProtPolicies UnassignedAppPolicies = $UnassignedAppPolicies } $CISChecks = Build-AbrIntuneComplianceChecks -Definitions (Get-AbrIntuneCISChecks -Section 'AppManagement') -Framework CIS -CallerVariables $_v New-AbrIntuneCISAssessmentTable -Checks $CISChecks -Name 'App Management' -TenantId $TenantId if ($CISChecks) { $null = $script:CISAllChecks.AddRange([object[]](@($CISChecks | Select-Object @{N='Section';E={'AppManagement'}}, CISControl, Level, Status, Detail))) } } catch { Write-AbrSectionError -Section 'CIS App Management Assessment' -Message "$($_.Exception.Message)" } } #endregion } } end { Show-AbrDebugExecutionTime -End -TitleMessage 'App Management' } } |