MSEndpointMgr

Win32 app State Messages Demystified

In this post we will do some digging on Win32 app state messages and look at the compliance state and enforcement state messages stored in the local registry for win32 app policies processed by the client. We will also take the state values and convert them into a readable format to help you understand if a Win32 app was processed successfully

Where are Win32 app policy results stored on the client?

Great question. When the Intune Management Extension (IME) processes the policy for Win32 apps targeted to the logged on user or device, it stores the policy evaluation results in the local registry under the key

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\IntuneManagementExtension\Win32Apps

The sub key 00000000-0000-0000-0000-000000000000 includes policy targeted to the device. Any sub key that is a GUID (highlighted in green below) includes policy targeted to the user. The GUID is the Object ID of the user in Entra ID

Object ID as seen in Entra ID

Under each user(and device) sub key are other keys for the applications targeted. The name of the key will be the appid of the Win32 app in Intune

Win32 app ID

Compliance State Messages

If the policy has been evaluated by the IME, the results of the policy evaluation is stored, in JSON format, in the ComplianceStateMessage sub key as seen below

Compliance State Messages

Enforcement State Messages

If the policy has been processed by the IME, the results of the policy enforcement is stored, in JSON format, in the EnforcementStateMessage sub key as seen below

Enforcement State Messages

Understanding State Messages

My friend @jankeskanke first brought these JSON results to my attention. Cool hey? We can use PowerShell to pull that data out to be viewed in a more friendly view. Fire up vscode!

$ComplianceState = Get-ItemProperty -Path 'HKLM:SOFTWARE\Microsoft\IntuneManagementExtension\Win32Apps\ddc3cf6e-3b3b-461c-a823-53196902d067\e316127d-a9a4-4193-8f04-b07c37d1130f_1\ComplianceStateMessage' -Name 'ComplianceStateMessage' | Select-Object -ExpandProperty ComplianceStateMessage
$ComplianceState | ConvertFrom-Json
Converting state messages from JSON into a readable format

Great, but what do those status codes mean?

You can use your favorite .NET decompiler to view the source code of the IME, cool right! I am using DotPeek by JetBrains in the example below

Compliance State Message Values

We can see that a ComplianceState of 2 means this app is NotInstalled

Doing the same with Applicability, we can see that Applicability of 0 means this app is Applicable

Applicability State Message Values

Great, but this might get slightly tedious when trying to interpret all the state message values in the JSON in the registry when troubleshooting apps on the client. Before we do some magic, let’s list out the state messages and their values for reference in the next chapter

The Microsoft source code lists the message and the corresponding value and error code. I want to put these pairs into a hash table (for the purpose of magic) so I’ll list them as you would see them in a hash table. Chat GPT was awesome converting these btw!

Applicability

$stateMessageApplicability = @{
    0    = "Applicable"
    1    = "RequirementsNotMet"
    3    = "HostPlatformNotApplicable"
    1000 = "ProcessorArchitectureNotApplicable"
    1001 = "MinimumDiskSpaceNotMet"
    1002 = "MinimumOSVersionNotMet"
    1003 = "MinimumPhysicalMemoryNotMet"
    1004 = "MinimumLogicalProcessorCountNotMet"
    1005 = "MinimumCPUSpeedNotMet"
    1006 = "FileSystemRequirementRuleNotMet"
    1007 = "RegistryRequirementRuleNotMet"
    1008 = "ScriptRequirementRuleNotMet"
    1009 = "NotTargetedAndSupersedingAppsNotApplicable"
    1010 = "AssignmentFiltersCriteriaNotMet"
    1011 = "AppUnsupportedDueToUnknownReason"
    1012 = "UserContextAppNotSupportedDuringDeviceOnlyCheckin"
    2000 = "COSUMinimumApiLevelNotMet"
    2001 = "COSUManagementMode"
    2002 = "COSUUnsupported"
    2003 = "COSUAppIncompatible"
}

ComplianceState

$stateMessageComplianceState = @{
    1   = "Installed"
    2   = "NotInstalled"
    4   = "Error"
    5   = "Unknown"
    100 = "Cleanup"
}

DesiredState

$stateMessageDesiredState = @{
    0 = "None"
    1 = "Not Present"
    2 = "Present"
    3 = "Unknown"
    4 = "Available"
}

TargetingMethod

$stateMessageTargetingMethod = @{
    0 = "EgatTargetedApplication"
    1 = "DependencyOfEgatTargetedApplication"
}

InstallContext

$stateMessageInstallContext = @{
    1 = "User"
    2 = "System"
}

TargetType

$stateMessageTargetType = @{
    0 = "None"
    1 = "User"
    2 = "Device"
    3 = "Both Device and User"
}

EnforcementState

$stateMessageEnforcementState = @{
    1000 = "Success"
    1003 = "SuccessFastNotify"
    1004 = "SuccessButDependencyFailedToInstall"
    1005 = "SuccessButDependencyWithRequirementsNotMet"
    1006 = "SuccessButDependencyPendingReboot"
    1007 = "SuccessButDependencyWithAutoInstallOff"
    1008 = "SuccessButIOSAppStoreUpdateFailedToInstall"
    1009 = "SuccessVPPAppHasUpdateAvailable"
    1010 = "SuccessButUserRejectedUpdate"
    1011 = "SuccessUninstallPendingReboot"
    1012 = "SuccessSupersededAppUninstallFailed"
    1013 = "SuccessSupersededAppUninstallPendingReboot"
    1014 = "SuccessSupersedingAppsDetected"
    1015 = "SuccessSupersededAppsDetected"
    1016 = "SuccessAppRemovedBySupersedence"
    1017 = "SuccessButDependencyBlockedByManagedInstallerPolicy"
    1018 = "SuccessUninstallingSupersededApps"
    2000 = "InProgress"
    2007 = "InProgressDependencyInstalling"
    2008 = "InProgressPendingReboot"
    2009 = "InProgressDownloadCompleted"
    2010 = "InProgressPendingUninstallOfSupersededApps"
    2011 = "InProgressUninstallPendingReboot"
    2012 = "InProgressPendingManagedInstaller"
    3000 = "RequirementsNotMet"
    4000 = "Unknown"
    5000 = "Error"
    5003 = "ErrorDownloadingContent"
    5006 = "ErrorConflictsPreventInstallation"
    5015 = "ErrorManagedInstallerAppLockerPolicyNotApplied"
    5999 = "ErrorWithImmeadiateRetry"
    6000 = "NotAttempted"
    6001 = "NotAttemptedDependencyWithFailure"
    6002 = "NotAttemptedPendingReboot"
    6003 = "NotAttemptedDependencyWithRequirementsNotMet"
    6004 = "NotAttemptedAutoInstallOff"
    6005 = "NotAttemptedDependencyWithAutoInstallOff"
    6006 = "NotAttemptedWithManagedAppNoLongerPresent"
    6007 = "NotAttemptedBecauseUserRejectedInstall"
    6008 = "NotAttemptedBecauseUserIsNotLoggedIntoAppStore"
    6009 = "NotAttemptedSupersededAppUninstallFailed"
    6010 = "NotAttemptedSupersededAppUninstallPendingReboot"
    6011 = "NotAttemptedUntargetedSupersedingAppsDetected"
    6012 = "NotAttemptedDependencyBlockedByManagedInstallerPolicy"
    6013 = "NotAttemptedUnsupportedOrIndeterminateSupersededApp"
}

PowerShell – Diving Deeper

I thought it would be cool if we can collect all the state messages, for all the Win32 apps processed by the client AND translate the state message values into “plain English”. This would make troubleshooting so much easier

Get-Win32AppResults.ps1

Head over to my GitHub Repo and grab the script

MEM/Get-Win32AppResults.ps1 at main ยท byteben/MEM (github.com)

By default, the script will iterate through all the Win32 app policy results and display the translated state codes in an array. Let’s take a look at a dummy run

Result of Get-Win32AppResults.ps1

Digging in to the last result, we can make the translation easier to understand

$stateMessages | Where-Object { $_.AppID -eq 'fe38a779-a875-4c0f-a9ff-46ded4e79753' } | Select-Object -ExpandProperty ComplianceStateMessage

Compare that to what we had previously!

state messages translated

Practical Usage for the Service Desk

Here are some common examples on how to use the script

Find Apps that are applicable, required, but not installed

$stateMessages | where-Object {$_.complianceStateMessage.Applicability -eq 'Applicable' -and $_.complianceStateMessage.ComplianceState -eq 'NotInstalled' -and $_.complianceStateMessage.DesiredState -eq 'Present'}
Win32 apps not installed

Find apps that are required but have an Enforcement Error Code

$stateMessages | where-Object {$_.complianceStateMessage.DesiredState -eq 'Present' -and $_.enforcementStateMessage.Errorcode}
Win32 app enforcement state results

Summary

In this post we covered state message briefly and discussed how difficult they are to read when troubleshooting a users device. We also used a script to iterate through the state messages and return the results in an easy to read way.

In the next version of the script, we will convert the appid’s into the respective app name in Intune and pass more switches for common scenarios. We will also look at building a workbook in Log Analytics so you can make comparisons between “data from the client” and “data in Intune”. Finally, we will iterate through the GRS schedule to understand when the failed apps are next scheduled for evaluation.

Ben Whitmore

Microsoft MVP - Enterprise Mobility, Microsoft Certified Trainer and Microsoft 365 Certified: Enterprise Administrator Expert. Community driven and passionate Customer Engineer Lead at Patch My PC with over 2 decades of experience in driving adoption and technology change within the Enterprise.

Add comment

Sponsors

Categories

MSEndpointMgr.com use cookies to ensure that we give you the best experience on our website.