Intune reports "The application was not detected after installation completed successfully (0x87D1041C)", yet the app is right there on the device. The installer did its job; the detection rule just didn't find what it was told to look for. In this post I'll go through the usual reasons a rule misses, how to test detection the way the Intune Management Extension (IME) does, and how to confirm the fix.
Symptoms#
- The app's device install status shows a failure with
0x87D1041C, but the app is installed and works. - With a required assignment the app keeps coming back: Intune offers an app it can't detect again within about 24 hours, so you may see repeated installs or notifications.
- It hits every device (the rule is simply wrong) or only some, such as devices where the app updated itself or where a different user signed in.
Why it happens#
When the install command returns a success code, the IME evaluates the app's detection rules, and every rule must be true for the app to count as installed. If any rule fails, the install "succeeded" without proof, and Intune reports 0x87D1041C. The common reasons:
| Cause | What's going on | Fix |
|---|---|---|
| Wrong value | Typo in the product code, path or key, or the vendor changed the install location | Rebuild the rule from what's on a test device |
| 32-bit vs 64-bit | A 32-bit app writes to Program Files (x86) and WOW6432Node, but the rule looks in the 64-bit locations | Set Associated with a 32-bit app on 64-bit clients to Yes |
| Install context | A per-user app writes to HKCU or %LOCALAPPDATA% while the rule checks machine-wide locations, or the other way round | Match the rule to the Install behavior (System or User) |
| Version drift | The app updated itself, so an exact version match or MSI product version check no longer holds | Compare with "greater than or equal to", or stop the self-update |
| Script output | A custom detection script exits 0 without writing anything, or writes to the error stream | Write one line to STDOUT and suppress errors |
One more bitness trap: Microsoft notes that calling powershell.exe in a Win32 install command starts 32-bit PowerShell. If your wrapper script writes a marker under HKLM\SOFTWARE, it lands in WOW6432Node unless you call %SystemRoot%\Sysnative\WindowsPowerShell\v1.0\powershell.exe.
How to fix it#
1. See what the IME evaluated#
On an affected device, open AppWorkload.log in C:\ProgramData\Microsoft\IntuneManagementExtension\Logs; it holds the IME's Win32 app activity. Search for the app's ID (it's in the browser address bar when you open the app in the admin center) and read the [Win32App] detection lines after the install. They show which detection rule ran and what it returned.
2. Check what's really installed#
List the uninstall entries in both registry views:
$keys = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
Get-ItemProperty -Path $keys -ErrorAction SilentlyContinue |
Where-Object DisplayName -like '*Contoso*' |
Select-Object DisplayName, DisplayVersion, PSChildName, PSParentPathFor MSI-based apps, PSChildName is the product code. An entry under WOW6432Node means a 32-bit install. For per-user apps, run the same query against HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* as that user.
3. Correct the rule#
Open the app under Apps › All Apps, go to Properties and select Edit next to Detection rules:
- MSI: paste the product code exactly as the registry shows it. Turn on MSI product version check only when you control the version.
- File: put the folder in Path without quotes and the file or folder name in its own field. Use the 32-bit option for apps under
Program Files (x86). - Registry: use a full key path such as
HKLM\SOFTWARE\Vendor\App. Leave Value name empty to test the key itself; the 32-bit option switches the lookup toWOW6432Node. - Context: for System installs, detect in
HKLMand machine-wide folders; for User installs, useHKCUor%LOCALAPPDATA%. Never hard-code one person'sC:\Users\path.
4. Or use a script you control#
A custom detection script means "detected" only when it exits with 0 and writes to STDOUT. A non-zero exit, no output, or anything written to STDERR means "not detected". This example accepts version 4.2 or later, so self-updates don't break it:
$exe = Join-Path $env:ProgramFiles 'Contoso\Agent\agent.exe'
$minimum = [version]'4.2.0.0'
$file = Get-Item -Path $exe -ErrorAction SilentlyContinue
if ($file) {
$vi = $file.VersionInfo
$installed = [version]::new($vi.FileMajorPart, $vi.FileMinorPart, $vi.FileBuildPart, $vi.FilePrivatePart)
if ($installed -ge $minimum) {
Write-Output "Detected agent.exe $installed"
exit 0
}
}
exit 15. Test it the way the IME runs it#
For System installs, detection runs as SYSTEM, in a 64-bit process unless Run script as 32-bit process on 64-bit clients is set. Sysinternals PsExec gives you a matching shell from an elevated prompt:
psexec.exe -s -i C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exeIn the new window, whoami should return nt authority\system. With the script saved as C:\Temp\Detect-Agent.ps1, run powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Temp\Detect-Agent.ps1; $LASTEXITCODE and expect your output line followed by 0. Swap in the SysWOW64 path to test 32-bit behavior. For User installs, test in a normal PowerShell window as that user.
Verify the fix#
- Save the corrected rule, then trigger an IME check-in on a test device: restart the
IntuneManagementExtensionservice, or use Settings › Sync in Company Portal. - In
AppWorkload.log, the detection for that app ID now reports the app as detected. - The device's install status changes to Installed once the IME reports back.
Prevent it next time#
- Install the app on a clean test device first and build the rule from what it leaves behind.
- Decide bitness and install context before writing the rule, and set the 32-bit option and paths to match.
- For apps that patch themselves, use "greater than or equal to" or a version-independent marker, or disable auto-update and ship updates through supersedence.
- Keep detection scripts quiet: one line to STDOUT, nothing to STDERR.
- Take care when switching an existing app between User and System install behavior; the old per-user copy and the new machine-wide rule won't line up.