Tuesday, March 04, 2025

Microsoft Graph, Intune, All intune apps and who/what has them installed.

All Intune apps and who/what has them installed.

This is much better, it is using the REST API so can get rate limited (HTTP 429), but insert a delay and get a coffee. This pulled out a ~150,000 line CSV.

Huge shout out to a mate of a mate, who created https://graphxray.merill.net/ as this allowed me to find the undocumented endpoints and command lines, the traditional PowerShell did not work, but the REST APIs work well.

 

Thanks Eunice, Dhruv, Clement, Monica & @merill.

## Script starts

#ApplicationProfile
$tenantId = 'xxx'
$appId = 'xxx'  # Application (client) ID
$appSecret = 'xxx' #Value

# Obtain an access token using client credentials  
$body = @{  
    grant_type    = "client_credentials"  
    scope         = "https://graph.microsoft.com/.default"  
    client_id     = $appId  
    client_secret = $appSecret  
}  
 
 
$response = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -Method Post -Body $body -ContentType "application/x-www-form-urlencoded"  
$token = $response.access_token  
 
# Retrieve applications  
$appUri = "https://graph.microsoft.com/beta/deviceAppManagement/mobileApps"  
$applications = Invoke-RestMethod -Uri $appUri -Method Get -Headers @{Authorization = "Bearer $token"}  
 
# Prepare output collection  
$output = @()  
 
# Loop through each application  
foreach ($checkApp in $applications.value) {   
    $ApplicationId = $checkApp.id  
    $ApplicationName = $checkApp.displayName  
 
    # Request URI and parameters for the report  
    $uri = "https://graph.microsoft.com/beta/deviceManagement/reports/retrieveDeviceAppInstallationStatusReport"  
    $params = @{  
        select = @("DeviceName", "UserPrincipalName", "DeviceId")  
        skip = 0  
        top = 5000  ### Max number of users/computers allocation to the app
        filter = "(ApplicationId eq '$ApplicationId')"  
        orderBy = @()  
    }  
 
    # Make the POST request  
    $response = Invoke-RestMethod -Uri $uri -Method Post -Headers @{Authorization = "Bearer $token"} -Body ($params | ConvertTo-Json) -ContentType "application/json"  
      
    # Check if Values contain data  
    if ($response.Values) {  
        foreach ($value in $response.Values) {  
            # Split the concatenated string to extract the relevant fields  
            $fields = $value -split ' '  
 
            # Assuming the format is consistent, map the fields  
            $outputObject = [PSCustomObject]@{  
                ApplicationName = $ApplicationName  
                ComputerName    = $fields[1] # Assuming this is DeviceName  
                UserUPN         = $fields[2] # Assuming this is UserPrincipalName  
                ## There are more here, I just didnt need them

            }  
            $output += $outputObject  
        }  
    } else {  
        Write-Host "No installation data found for Application ID $ApplicationId ($ApplicationName)." -ForegroundColor Yellow  
    }  
    Start-Sleep -Seconds 6 # Adjust the number of seconds as necessary, this is to stop HTTP 429 rate limiting.
}  
 
# Output to screen  
$output | Format-Table -AutoSize  
 $output.Count

# Export to CSV  
$output | Export-Csv -Path "ApplicationInstallStatusReport.csv" -NoTypeInformation  

 

No comments:

Blog Archive