intune-inventory-discovered-apps.ps1
<#PSScriptInfo
.VERSION 1.0.4 .GUID 7b1c483b-b109-4d45-8abc-84760c84d9d9 .AUTHOR AndrewTaylor .DESCRIPTION Lists all discovered apps with drill-down .COMPANYNAME .COPYRIGHT GPL .TAGS intune endpoint MEM environment .LICENSEURI https://github.com/andrew-s-taylor/public/blob/main/LICENSE .PROJECTURI https://github.com/andrew-s-taylor/public .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES #> <# .SYNOPSIS Lists all discovered apps with drill-down .DESCRIPTION Lists all discovered apps with drill-down .INPUTS None .OUTPUTS Creates a log file in %Temp% .NOTES Version: 1.0.4 Author: Andrew Taylor Twitter: @AndrewTaylor_2 WWW: andrewstaylor.com Creation Date: 04/11/2022 Updated: 07/02/2023 Purpose/Change: Initial script development Change: Added Regex escape for special characters .EXAMPLE N/A #> $ErrorActionPreference = "Continue" ##Start Logging to %TEMP%\intune.log $date = get-date -format yyyyMMddTHHmmssffff Start-Transcript -Path $env:TEMP\intune-$date.log #Install MS Graph if not available Write-Host "Installing Microsoft Graph modules if required (current user scope)" #Install MS Graph if not available if (Get-Module -ListAvailable -Name Microsoft.Graph.authentication) { Write-Host "Microsoft Graph Already Installed" } else { try { Install-Module -Name Microsoft.Graph.authentication -Scope CurrentUser -Repository PSGallery -Force } catch [Exception] { $_.message exit } } # Load the Graph module Import-Module microsoft.graph.authentication Function Connect-ToGraph { <# .SYNOPSIS Authenticates to the Graph API via the Microsoft.Graph.Authentication module. .DESCRIPTION The Connect-ToGraph cmdlet is a wrapper cmdlet that helps authenticate to the Intune Graph API using the Microsoft.Graph.Authentication module. It leverages an Azure AD app ID and app secret for authentication or user-based auth. .PARAMETER Tenant Specifies the tenant (e.g. contoso.onmicrosoft.com) to which to authenticate. .PARAMETER AppId Specifies the Azure AD app ID (GUID) for the application that will be used to authenticate. .PARAMETER AppSecret Specifies the Azure AD app secret corresponding to the app ID that will be used to authenticate. .PARAMETER Scopes Specifies the user scopes for interactive authentication. .EXAMPLE Connect-ToGraph -TenantId $tenantID -AppId $app -AppSecret $secret -#> [cmdletbinding()] param ( [Parameter(Mandatory = $false)] [string]$Tenant, [Parameter(Mandatory = $false)] [string]$AppId, [Parameter(Mandatory = $false)] [string]$AppSecret, [Parameter(Mandatory = $false)] [string]$scopes ) Process { Import-Module Microsoft.Graph.Authentication $version = (get-module microsoft.graph.authentication | Select-Object -expandproperty Version).major if ($AppId -ne "") { $body = @{ grant_type = "client_credentials"; client_id = $AppId; client_secret = $AppSecret; scope = "https://graph.microsoft.com/.default"; } $response = Invoke-RestMethod -Method Post -Uri https://login.microsoftonline.com/$Tenant/oauth2/v2.0/token -Body $body $accessToken = $response.access_token $accessToken if ($version -eq 2) { write-host "Version 2 module detected" $accesstokenfinal = ConvertTo-SecureString -String $accessToken -AsPlainText -Force } else { write-host "Version 1 Module Detected" Select-MgProfile -Name Beta $accesstokenfinal = $accessToken } $graph = Connect-MgGraph -AccessToken $accesstokenfinal Write-Host "Connected to Intune tenant $TenantId using app-based authentication (Azure AD authentication not supported)" } else { if ($version -eq 2) { write-host "Version 2 module detected" } else { write-host "Version 1 Module Detected" Select-MgProfile -Name Beta } $graph = Connect-MgGraph -scopes $scopes Write-Host "Connected to Intune tenant $($graph.TenantId)" } } } ##Connect to MS Graph Connect-ToGraph -Scopes "DeviceManagementApps.ReadWrite.All, DeviceManagementConfiguration.ReadWrite.All, DeviceManagementManagedDevices.ReadWrite.All, openid, profile, email, offline_access" Function Get-ScriptVersion(){ <# .SYNOPSIS This function is used to check if the running script is the latest version .DESCRIPTION This function checks GitHub and compares the 'live' version with the one running .EXAMPLE Get-ScriptVersion Returns a warning and URL if outdated .NOTES NAME: Get-ScriptVersion #> [cmdletbinding()] param ( $liveuri ) $contentheaderraw = (Invoke-WebRequest -Uri $liveuri -Method Get) $contentheader = $contentheaderraw.Content.Split([Environment]::NewLine) $liveversion = (($contentheader | Select-String 'Version:') -replace '[^0-9.]','') | Select-Object -First 1 $currentversion = ((Get-Content -Path $PSCommandPath | Select-String -Pattern "Version: *") -replace '[^0-9.]','') | Select-Object -First 1 if ($liveversion -ne $currentversion) { write-host "Script has been updated, please download the latest version from $liveuri" -ForegroundColor Red } } Get-ScriptVersion -liveuri "https://raw.githubusercontent.com/andrew-s-taylor/public/main/Powershell%20Scripts/Intune/intune-inventory-discovered-apps.ps1" ##Grab all devices $uri = "https://graph.microsoft.com/beta/deviceManagement/manageddevices" $alldevices = (Invoke-MgGraphRequest -uri $uri -Method GET -OutputType PSObject).value ##Drop them into an array to save too many nested loops $deviceids = @() ##Populate the array foreach ($device in $alldevices) { $deviceid = $device.id $deviceids += $deviceid } ##Create an array for the apps $discoveredapps = @() ##Populate App array foreach ($deviceapp in $deviceids) { $uri = "https://graph.microsoft.com/beta/deviceManagement/manageddevices('$deviceapp')?`$expand=detectedApps" $appsfound = (Invoke-MgGraphRequest -uri $uri -Method GET -OutputType PSObject).detectedApps foreach ($app in $appsfound) { $discoveredapps += $app.DisplayName } } ##Group the apps to get a count, sort and then display in GUI with drill-down $appslist = $discoveredapps | group | select Count, Name | Sort-Object Count -Descending | Out-GridView -Title "Discovered Apps" -PassThru | ForEach-Object { ##App to search for $appname = [regex]::Escape($_.Name) $rawappname = $_.Name ##Create an array of devices with the app installed in case we want to export-csv or GUI popup with this data at a later date $deviceswithappinstalled = @() ##Loop through machines looking for the app foreach ($findtheapp in $deviceids) { $uri = "https://graph.microsoft.com/beta/deviceManagement/manageddevices('$findtheapp')?`$expand=detectedApps" $appsfound = (Invoke-MgGraphRequest -uri $uri -Method GET -OutputType PSObject).detectedApps ##App found, grab the devicename if ($appsfound -match "$appname") { $deviceuri = "https://graph.microsoft.com/beta/deviceManagement/manageddevices/$Aappsfound" $devicename = (Invoke-MgGraphRequest -uri $uri -Method GET -OutputType PSObject).devicename write-host "App $rawappname found on device $devicename ($findtheapp)" $deviceswithappinstalled += $devicename } } } Stop-Transcript |