Get-Win32AppResult.ps1
<#PSScriptInfo
.VERSION 1.0.3 .GUID 022c90a3-471c-4c22-9441-da2e8a4f8f56 .AUTHOR Will .COMPANYNAME Me .COPYRIGHT .TAGS .LICENSEURI .PROJECTURI .ICONURI .EXTERNALMODULEDEPENDENCIES Microsoft.Graph.Authentication Microsoft.Graph.Beta.Devices.CorporateManagement .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES ### Version 1.0.3 ### - Still trying to fixed the errors that appear when splitting the psparentpath ### Version 1.0.2 ### - Fixed the errors that appear when splitting the psparentpath ### Version 1.0.1 ### - Commented out the write-Host in the loop. ### Version 1.0.0 ### - Added all of script information .PRIVATEDATA #> <# .DESCRIPTION Attempts to collect win32 app results from local machine #> <# .EXAMPLE $results = .\Get-Win32Appresults.ps1 .EXAMPLE \Get-Win32Appresults.ps1 | Out-Gridview .EXAMPLE .\Get-Win32Appresults.ps1 | Export-Csv -Path .\Win32AppResults.csv -NoTypeInformation #> ################### # Functions # ################### function Get-ComplianceStateMessage { param ( [int]$StateId ) switch ($StateId) { 1 { return "Installed" } 2 { return "NotInstalled" } 4 { return "Error" } 5 { return "Unknown" } 100 { return "Cleanup" } default { return "Unknown State ID" } } } function Get-ComplianceApplicability { param ( [int]$ApplicabilityId ) switch ($ApplicabilityId) { 0 { return "Applicable" } 1 { return "RequirementsNotMet" } 3 { return "HostPlatformNotApplicable" } 1000 { return "ProcessorArchitectureNotApplicable" } 1001 { return "MinimumDiskSpaceNotMet" } 1002 { return "MinimumOSVersionNotMet" } 1003 { return "MinimumPhysicalMemoryNotMet" } 1004 { return "MinimumLogicalProcessorCountNotMet" } 1005 { return "MinimumCPUSpeedNotMet" } 1006 { return "FileSystemRequirementRuleNotMet" } 1007 { return "RegistryRequirementRuleNotMet" } 1008 { return "ScriptRequirementRuleNotMet" } 1009 { return "NotTargetedAndSupersedingAppsNotApplicable" } 1010 { return "AssignmentFiltersCriteriaNotMet" } 1011 { return "AppUnsupportedDueToUnknownReason" } 1012 { return "UserContextAppNotSupportedDuringDeviceOnlyCheckin" } 2000 { return "COSUMinimumApiLevelNotMet" } 2001 { return "COSUManagementMode" } 2002 { return "COSUUnsupported" } 2003 { return "COSUAppIncompatible" } default { return "Unknown Applicability ID" } } } function Get-ComplianceDesiredState { param ( [int]$DesiredStateId ) switch ($DesiredStateId) { 0 { return "None" } 1 { return "Not Present" } 2 { return "Present" } 3 { return "Unknown" } 4 { return "Available" } default { return "Unknown Desired State ID" } } } function Get-ComplianceTargetingMethod { param ( [int]$TargetingMethodId ) switch ($TargetingMethodId) { 0 { return "TargetedApplication" } 1 { return "DependencyOfTargetedApplication" } default { return "Unknown Targeting Method" } } } function Get-ComplianceTargetType { param ( [int]$targetId ) switch ($targetId) { 0 { "None" } 1 { "User" } 2 { "Device" } 3 { "Both Device and User" } default { "Unknown Target Type" } } } function Get-ComplianceInstallContext { param ( [int]$contextId ) switch ($contextId) { 1 { "User" } 2 { "Device" } } } function Get-EnforcementStateMessage { param ( [int]$StateId ) $stateMessageEnforcementState = @{ 0 = "Success" 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 = "ErrorWithImmediateRetry" 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" } # Looks up the reference in the hashtable above. return $stateMessageEnforcementState[$StateId] -or "Unknown State ID: $StateId" } function Get-EnforcementTargetingMethod { param ( [int]$TargetingMethodId ) switch ($TargetingMethodId) { 0 { return "TargetedApplication" } 1 { return "DependencyOfTargetedApplication" } default { return "Unknown Targeting Method" } } } ####################### # Script Starts # ####################### # Microsoft.Graph, Microsoft.Graph.Beta.Devices.CorporateManagement # Check if the required modules are installed, if not, install them $requiredModules = @("Microsoft.Graph.Authentication", "Microsoft.Graph.Beta.Devices.CorporateManagement") foreach ($module in $requiredModules) { if (-not (Get-Module -ListAvailable -Name $module)) { Write-Host "Module $module is not installed. Attempting to install..." -ForegroundColor Yellow try { Install-Module -Name $module -Force -Scope CurrentUser -AllowClobber Write-Host "Module $module installed successfully." -ForegroundColor Green } catch { Write-Host "Failed to install module $module. Please install it manually." -ForegroundColor Red } } else { Write-Host "Module $module is already installed." -ForegroundColor Green } } # Connect to Graph Connect-MgGraph -NoWelcome # Collect all intune apps # Uses Beta because it returns more apps\types of apps. # Graph API call returns more, possible update in future. Write-Host "Getting all intune applications" -ForegroundColor Yellow $intuneApps = Get-MgBetaDeviceAppManagementMobileApp -All # Get the Win32Apps registry key $Win32appKey = "HKLM:SOFTWARE\Microsoft\IntuneManagementExtension\Win32Apps" # get valid Contexts(GUIDs) in the Win32Apps key $regKeys = Get-ChildItem -Path $win32appKey -Force -ErrorAction SilentlyContinue $getValidContexts = $regKeys | Where-Object { ([System.Guid]::TryParse((Split-Path -Path $_.Name -Leaf), [System.Management.Automation.PSReference]([guid]::empty))) } | Select-Object -ExpandProperty Name # initialize $appKeyResults array to hold results of win32app policies found under each context (for both device and users) $appKeyResults = @() Foreach ($getApp in $getValidContexts) { # get apps under each context $appKeys = Get-ChildItem -Path "$win32appKey\$(Split-Path -Path $getApp -Leaf)" -Force -ErrorAction SilentlyContinue foreach ($key in $appKeys) { # Get the key properties $keyValues = Get-ItemProperty -Path REGISTRY::$key # Cheeky host update to host for debugging #Write-Host "Working on: $($keyValues.PSPath -replace 'Microsoft.PowerShell.Core\\Registry::','')" -ForegroundColor Yellow # Get the subkeys $subKeys = Get-ChildItem $keyValues.PSPath -ErrorAction SilentlyContinue # Initialise array to store subkey values $subkeyData = @() # Get the subkey values foreach ($subkey in $subKeys) { $subkeyData += Get-ItemProperty -Path REGISTRY::$subkey -ErrorAction SilentlyContinue } # Convert the JSON strings to objects (annoying) $complianceMessages = "$($subkeyData.ComplianceStateMessage)" | ConvertFrom-Json $enforcementState = "$($subkeyData.EnforcementStateMessage)" | ConvertFrom-Json # Bulding a custom object and adding the results to the $appKeyResults array, outside the loop. if($keyValues.PSParentPath) { $appKeyResults += [PSCustomObject]@{ AppRegParent = ($keyValues.PSParentPath).split("\\")[-1] AppGuid = $keyValues.PSChildName -replace '_\d+$' AppName = ($intuneApps | Where-Object id -match ($keyValues.PSChildName -replace '_\d+$')).DisplayName ComplianceApplicability = Get-ComplianceApplicability -ApplicabilityId $complianceMessages.Applicability ComplianceDesiredState = Get-ComplianceDesiredState -DesiredStateId $complianceMessages.DesiredState ComplianceState = Get-ComplianceStateMessage -StateId $complianceMessages.ComplianceState ComplianceErrorCode = if ($null -eq $complianceMessages.ErrorCode) { "Null" } else { $complianceMessages.ErrorCode } ComplianceTargetingMethod = Get-ComplianceTargetingMethod -TargetingMethodId $complianceMessages.TargetingMethod ComplianceInstallContext = Get-ComplianceInstallContext -contextId $complianceMessages.InstallContext ComplianceInstallType = Get-ComplianceTargetType -targetId $complianceMessages.TargetType EnforcementState = Get-EnforcementStateMessage -StateId $enforcementState.EnforcementState EnforcementErrorCode = Get-ComplianceTargetingMethod -TargetingMethodId $enforcementState.ErrorCode EnforcemntTargetingMethod = Get-EnforcementTargetingMethod -TargetingMethodId $enforcementState.TargetingMethod ProductVersion = if ($null -eq $complianceMessages.ProductVersion) { "Null" } else { $complianceMessages.ProductVersion } AssignmentFilters = if ($null -eq $complianceMessages.AssignmentFilterIds) { "Null" } else { $complianceMessages.AssignmentFilterIds } RegPath = $keyValues.PSPath -replace "Microsoft.PowerShell.Core\\Registry::", "" } } } } return $appKeyResults |