Intune Discovered Apps – Detecting your applications and gaining back control

by | Jul 14, 2023 | Tech Blog

Patch Tuesday Webinar

Join Patch My PC's Jordan Benzing and Bryan Dam every Thursday succeeding Patch Tuesday for the Patch Tuesday Support Group Webinar.

Patch Tuesday Releases

Tech Blogs

Critical Patches

One critical aspect and goal for IT, and for the tools they use – is the ability to inventory which applications EXIST in the environment, and which of those applications are actually USED. The feature to detect EXISTANCE is often called Application Inventory or Software Inventory. The feature to track USAGE, is often called Software Metering, or Application Usage Monitoring, or Application Metering. This blog will focus on the application inventory feature (specifically the Intune “Discovered Apps” feature), and not cover anything related to Software Metering (although I may revisit this part in a future blog).

This blog post is organized into 8 parts:

  1. Discovered Apps in the Intune Portal

  2. Requirements for Intune Application Inventory

  3. Application Inventory Overview

  4. Application Inventory data stored in the Client Registry

  5. Microsoft Graph and a PowerShell scripting

  6. Using the PowerShell Script

  7. Get control back over your tenant

  8. Summary and Footnotes

1. Discovered Apps in the Intune Portal

The key feature discussed in this blog can be found at Intune portal > Apps > Monitor > Discovered apps

Intune Discovered apps

Microsoft collect an inventory for the installed appx packages, MSIs and EXEs on your Intune managed devices by way of the Intune Management Extension. A WMI class is referenced to find the installed software and this information is stored in the registry. The inventory is posted to Intune by the Intune Management Extension at regular intervals and this information can be viewed at the device level or as an aggregated report in the Intune portal.

[Quick side note. During the week of 7/7/23 – this functionality broke in Intune. Discovered Apps in Intune managed clients is now always returning blank. We at Patch My PC are still trying to track down if this was an intentional change by Microsoft and the Intune Product Team; or an accidental bug. More on this as soon as we have better information.]

2. Requirements for Intune Application Inventory

Not all devices visible in the Intune portal can return application inventory information. In order for this to be collected, and populated for a device, the device must be:

  1. A corporate-owned device, not personal (Only for a Win32 app).

  2. An Intune Enrolled Device.

  3. Co-managed devices need the client apps workload switched to Intune. The IME (Intune Management Extension) is required in order to collect the win32 app inventory.

The requirement for a device to be corporate owned is related to privacy rules around collecting information from end users on personal devices. This is part of the challenge for Intune, and why it sometimes seems less capable in application inventory than other management products.

3. Application Inventory Overview

While testing this service out, I noticed the following, crucial, details.

Slow data ingestion.

A Win32 application inventory gets synced every 24 hours per device.

Modern Microsoft Store apps are even slower. The sync happens once every seven days.

The aggregated main list populates longer than 24 hours, even for a Win32 app. Again we are averaging 7 days in my tests.

Numbers don’t match with actual install count.

Due to the potential overlap of multiple users and targeting changes, numbers are usually incorrect. Let’s hope this will improve, but it is a technical challenge for Microsoft with the many sources of application data, and the different speeds of the different data collection cycles and channels.

Export is supported.

You have 2 options to export. The raw data contains more detailed information:

Export discovered apps

4. Application Inventory data stored in the Client Registry

Inventory in the registry

In the following registry entry there is a key where you can find the time when your device last synced his app inventory.

Full path: ComputerHKEY_LOCAL_MACHINESOFTWAREMicrosoftIntuneManagementExtensionInventorySetting

Registry value: LastFullSyncTimeUtc

5. Microsoft Graph and a PowerShell scripting

You can manually discover Applications in Intune with PowerShell and Microsoft Graph.

I wrote a custom PowerShell script that can be used as a starting example for your custom detection script. The script will: –

  • Give you a sorted filtered list of discovered applications detected through Intune.

    (You can add additional apps to filter on. Adding an application to the following array will ensure it will be excluded from the output)

    $excludedAps = @(
        'Microsoft Intune Management Extension',
        'MicrosoftWindows.Client.WebExperience',
        'Microsoft Edge Update',
        'Microsoft Edge WebView2 Runtime',
        'Teams Machine-Wide Installer',
        'Microsoft Update Health Tools'                                     
    )
  • Sort the application count from low to high. Low is interesting because they are probably unmanaged applications that you need to check.

  • In the end, you can input an Application name, and it will output the devices that have that application installed.

    The result is a tabled output that shows the file version and device count per application.

6. Using the PowerShell Script

The following permissions are needed for the app registration. You can find more info on app registrations on this Microsoft Learn page.

Here are some quick steps to help you out with this:

  1. Go to portal.azure.com > App Registrations > New Registration

  2. Choose a name > choose accounts in this organizational directory only > click register

  3. API permissions > add the following permissions -> Microsoft Graph > Application permission

  4. Create a client secret.

  5. Explaining the script:

    Setup your authentication for the app registration. Replace ClientId, TenantId, Clientsecret with your values.

    #Region Authentication to Azure Application // Get token to authenticate to Azure AD
    $authparams = @{
        ClientId     = 'c9eb62ce-b748-4a6f-8ccf-21f347cd1fd96'
        TenantId     = '44647b32-d6c6-43e9-a136-dcbaa396dc973'
        ClientSecret = (ConvertTo-SecureString 'YourClientSecretHere' -AsPlainText -Force  )
    }
    
    $auth = Get-MsalToken @authParams
    
    
    #Set Access token variable for use when making API calls
    $AccessToken = $Auth.AccessToken
    #endregion

    Initialize your variables and arrays:

    #Region initialize arrays/variables
    $allAps = @()
    $alldevices = @()
    
    #Apps that need to be extra filtered out and that cannot be patched
    $excludedAps = @(
        'Microsoft Intune Management Extension',
        'MicrosoftWindows.Client.WebExperience',
        'Microsoft Edge Update',
        'Microsoft Edge WebView2 Runtime',
        'Teams Machine-Wide Installer',
        'Microsoft Update Health Tools'                                     
    )
    #endregion

    Apps that are not useful to discover are listed in the $excludedAps array. You can add some more if you want.

    #Apps that need to be extra filtered out and that cannot be patched
    $excludedAps = @(
        'Microsoft Intune Management Extension',
        'MicrosoftWindows.Client.WebExperience',
        'Microsoft Edge Update',
        'Microsoft Edge WebView2 Runtime',
        'Teams Machine-Wide Installer',
        'Microsoft Update Health Tools'                                     
    )
    #endregion

    Now let’s form the graph call:

    https://graph.microsoft.com/beta/deviceManagement/detectedApps

    While scripting this graph call, I learned a new Powershell technique called splatting. (“Splatting makes your commands shorter and easier to read. You can reuse the splatting values in different command calls and use splatting to pass parameter values from the $PSBoundParameters automatic variable to other scripts and functions.”) You can find more info about Powershell splatting on this Microsoft Learn page.

    We now get the data from the graph with

    $discoveredApps = Invoke-RestMethod @paramApps

    And get those apps that are discovered in your tenant.

    This command also taught me to use an @odata.nextLink‘. The problem you will encounter is that you can only query 50 apps per request. So ‘@odata.nextLink’ allows me to loop through the discovery of more than 50 apps at one time.

    '@odata.nextLink'#Region Form the graph call
    $URLupn = 'https://graph.microsoft.com/beta/deviceManagement/detectedApps?$filter=&$top=50' 
    
    
    $paramApps = @{
        Headers     = @{
            "Content-Type"  = "application/json"
            "Authorization" = "Bearer $($AccessToken)"
        }
        Method      = "GET"
        URI         = $URLupn
        ErrorAction = "SilentlyContinue"
    }
    #endregion#Region Get all apps with paging trough the graph call
    $discoveredApps = Invoke-RestMethod @paramApps
    $discoveredAppsNextLink = $discoveredApps.'@odata.nextLink'
    $allAps += $discoveredApps.value
    #paging 
    while ($discoveredAppsNextLink) {
        $discoveredApps = Invoke-RestMethod -Uri $discoveredAppsNextLink -Headers $paramApps.Headers -Method Get
        $discoveredAppsNextLink = $discoveredApps.'@odata.nextLink'
        $allAps += $discoveredApps.value
    }
    #endregion

Next, we count the apps we discovered and filter out the ones we want to exclude.

#Region Count apps we have discovered that are not Microsoft Store apps and not in excluded $exludedAps array
Write-Host "We discovered $(($allaps | Where-Object {$_.displayName -notlike 'Microsoft.*' -and $_.displayName -notin $excludedAps }).count) non Microsoft apps that can be managed"
#endregion

Then we will ask you to output the list and filter Microsoft Apps to clean up your list even more. I recommend filtering out those results because they are installed on every Windows device.

#Region Ask for list of all apps
Write-Host "You want a list of all apps? (y/n)"
$answer = Read-Host
if ($answer -eq "y") {
    write-host "Do you want to filter Microsoft apps? (y/n)"
    $answer = Read-Host
    if ($answer -eq "y") {
        $allApsNoMicrosoftStore = $allAps | Where-Object { $_.displayName -notlike 'Microsoft.*' -and $_.displayName -notin $excludedAps }
        $allApsNoMicrosoftStore | Sort-Object -Property deviceCount | Format-Table -AutoSize
        $listApps = $allApsNoMicrosoftStore
    }
    else {
        $allAps | Sort-Object -Property deviceCount | Format-Table -AutoSize
        $listApps = $allAps
    }
    
}
#endregion

Finally, you can type a display name of a specific app in the list and get the devices that have that application installed.

#Region Ask for an app and show the devices that have this app installed
Write-Host "Do you want to see the devices that have a specific app installed? (y/n)"
$answer = Read-Host
if ($answer -eq "y") {
    Write-Host 'Please chose an app displayName:'
    $appDisplayname = Read-Host
    $app = $listApps | Where-Object { $_.displayName -eq $appDisplayname }
    $appID = $app.id
    $URL = "https://graph.microsoft.com/beta/deviceManagement/detectedApps('$appID')/managedDevices?$filter=&$top=20"
  

    $paramApps = @{
        Headers     = @{
            "Content-Type"  = "application/json"
            "Authorization" = "Bearer $($AccessToken)"
        }
        Method      = "GET"
        URI         = $URL
        ErrorAction = "SilentlyContinue"

    }

    #Get for a specific app all the devices
    $discoverDevices = Invoke-RestMethod @paramApps
    $discoverDevicesNextlink = $discoverdevices.'@odata.nextLink'

    $allDevices += $discoverDevices.value
    #need to page trough the results
    while ($discoverDevicesNextlink) {
        $discoverDevices = Invoke-RestMethod -Uri $discoverDevicesNextlink -Headers $paramApps.Headers -Method Get
        $discoverDevicesNextlink = $discoverDevices.'@odata.nextlink'
        $allDevices += $discoverDevices.value
    }

    foreach ($device in $allDevices) {
        $devicename = $device.deviceName
        write-host "The Application $appDisplayname is found in $devicename"
    }
}
else {
    Write-Host "Ok, bye!"
}
#endregion

7. Get control back over your tenant

You got your results now. You detected probably a few apps that we should investigate, patch or block.

You can find the complete script on my Github page.

Euh..Uh, block or remove applications…How?

It’s possible to uninstall unwanted unmanaged applications with our products automatically, and our products are, of course 😉 completely amazing. But there is still a time gap for the detection to kick in, so the app that you are trying to block can still be used for a short period before it uninstalls. Remember what I said in my blog that the app could take up to 7 days to appear on the aggregated discovery application list.

I want total control!

If you want to pre-emptively block unwanted unmanaged applications, you will probably want to look into Applocker and Windows defender application control.

Applocker is older, Windows Defender application control is newer, WDAC(Windows Defender Application Control) recently also got a managed installer for Intune that is worth trying out.

8. Summary and Footnotes

Some additional peripheral information you may find interesting:

A. The IME Log

The IME (Intune Management Extension) is the agent in Intune that handles win32 app installation, and App Discovery. (Yes, Intune has an AGENT!). It has a log that can be very useful for learning and troubleshooting. You can often look into the intune management extension log for more details. The file path for the log is: %programdata%MicrosoftIntuneManagementExtensionlogsIntuneManagementExtension.log. It is key source of troubleshooting information for things related to win32 app installations; including app installation successes and failures; application detection status, and script failures.

There also recently seems to be a new file in that folder that appears to collect the win32app inventory in a separate log file. The reason for that is still unknown.

“Win32AppInventory”

B. Application Detection Rules

One key aspect of Application Inventory features across many of the Management Products is how applications are detected. This is often called “Application Detection rules”. Basically a way to look for breadcrumbs or fingerprints that an applications leaves that are indicative that the application is installed. The following multiple detection rules, methods are at your disposal:

  • File detection rule, or folder detection

  • Registry detection rule

  • Msi detection rule (MSI product code)

  • WMI detection rules

  • Custom detection rules

Intune for now is more basic with its Intune Detection Rules. It’s most versatile detection method is trough Powershell scripting. For example you can use Powershell in features like proactive remediations to script just about anything by building customer detection, and checking the exit code or stdout detection state.

Tech Blog

PowerShell Uses - Feature Image

PowerShell Uses – Things to Start Doing, Things to Stop Doing

There are some things in PowerShell that you need to start doing but also stop doing. What is PowerShell and some of the best practices?

Intune Win32 Apps Guide to Availability and Deadlines Feature Image

Intune Win32 apps: A Strategic Guide to Availability and Deadlines

Discover the ins and outs of Intune Management Extension in our latest blog post. We’re exploring its behavior with scheduled win32 app...

Windows Defender Exploit Guard breaks Google Chrome

Often, blog titles are sensationalised and designed to draw the readers attention. In September 2023, we did actually observe the behavior described...
Discovery Apps - Intune Software Inventory - Feature Image

Discovered Apps – The Intune Software Inventory

Is there an Intune Software Inventory? How does Intune detect apps installed in my tenant? Find out everything you need to know about Discovered...

Intune Scope Tags and Role-Based Access Control Explained

In today's interconnected era, it has become increasingly common for large organizations to have multiple IT departments and workers spread across...

Intune Discovered Apps – Missing Inventory Data

At the tail end of June 2023 and into the first week of July 2023, many admins started to report that application inventory data was missing in...

Intune Microsoft Store Integration App Migration Failures (0x87D1041C)

In July 2021, Microsoft announced that both Microsoft Store for Business and Education would be deprecated on March 31, 2023. While Microsoft has...
Automatic Deployment Rules and ConfigMgr

Automatic Deployment Rules (ADR) and ConfigMgr and why you should use them

What is an ADR Getting Started with ADR Creating and Defining an ADR What are Deployment Packages?In this blog we will review Automatic Deployment...

How to use PowerShell to install Windows updates & ensure long-term compliance

In this post I will walk you through how to install Windows updates and report on patch compliance using Windows PowerShell. We will be using:...

Mastering ConfigMgr Client Actions

In this blog post, we’ll take a deep dive into the various SCCM client actions, including when to use them, what they do, and which log files...

PowerShell Uses – Things to Start Doing, Things to Stop Doing

There are some things in PowerShell that you need to start doing but also stop doing. What is PowerShell and some of the best practices?

Intune Win32 apps: A Strategic Guide to Availability and Deadlines

Discover the ins and outs of Intune Management Extension in our latest blog post. We’re exploring its behavior with scheduled win32 app...

Windows Defender Exploit Guard breaks Google Chrome

Often, blog titles are sensationalised and designed to draw the readers attention. In September 2023, we did actually observe the behavior described...

Discovered Apps – The Intune Software Inventory

Is there an Intune Software Inventory? How does Intune detect apps installed in my tenant? Find out everything you need to know about Discovered...

Intune Scope Tags and Role-Based Access Control Explained

In today's interconnected era, it has become increasingly common for large organizations to have multiple IT departments and workers spread across...

Intune Discovered Apps – Missing Inventory Data

At the tail end of June 2023 and into the first week of July 2023, many admins started to report that application inventory data was missing in...

Intune Microsoft Store Integration App Migration Failures (0x87D1041C)

In July 2021, Microsoft announced that both Microsoft Store for Business and Education would be deprecated on March 31, 2023. While Microsoft has...

Automatic Deployment Rules (ADR) and ConfigMgr and why you should use them

What is an ADR Getting Started with ADR Creating and Defining an ADR What are Deployment Packages?In this blog we will review Automatic Deployment...

How to use PowerShell to install Windows updates & ensure long-term compliance

In this post I will walk you through how to install Windows updates and report on patch compliance using Windows PowerShell. We will be using:...

Mastering ConfigMgr Client Actions

In this blog post, we’ll take a deep dive into the various SCCM client actions, including when to use them, what they do, and which log files...