Private/Get-IntuneWin32AppPolicies.ps1
<#
.SYNOPSIS Function .DESCRIPTION #************************************************************************************************************ # Disclaimer # # This sample script is not supported under any Microsoft standard support program or service. This sample # script is provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties # including, without limitation, any implied warranties of merchantability or of fitness for a particular # purpose. The entire risk arising out of the use or performance of this sample script and documentation # remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, # production, or delivery of this script be liable for any damages whatsoever (including, without limitation, # damages for loss of business profits, business interruption, loss of business information, or other # pecuniary loss) arising out of the use of or inability to use this sample script or documentation, even # if Microsoft has been advised of the possibility of such damages. # #************************************************************************************************************ #> #region Get-IntuneWin32AppPolicies function Get-IntuneWin32AppPolicies { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] [string]$LogPath ) $statusList = [System.Collections.Generic.List[pscustomobject]]::new() # check if the script is running with administrative privileges if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { if ([string]::IsNullOrEmpty($script:MDMDiagReportPathVariable)) { # The message does only makes sense if the script is run locally without the MDMDiagReportPath parameter Write-Host "To get a more detailed Win32App report run the command with administrative permissions" -ForegroundColor Yellow } } else { [array]$win32AppStatusServiceReports = Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\IntuneManagementExtension\SideCarPolicies\StatusServiceReports" foreach ($report in $win32AppStatusServiceReports) { $identityID = $report.Name | Split-Path -Leaf -ErrorAction SilentlyContinue $assignedTo = if ($identityID -eq '00000000-0000-0000-0000-000000000000'){'💻 Device'}else{'👤 {0}' -f $identityID.ToString()} [array]$reportData = Get-ChildItem -Path $report.PSPath foreach ($dataItem in $reportData) { # adding some symbols $tmpApplicabilityCode = $dataItem.GetValue("ApplicabilityCode") if ($tmpApplicabilityCode -eq 'Applicable'){$tmpApplicabilityCode = '✅ Applicable'}else{$tmpApplicabilityCode = '❌ {0}' -f $tmpApplicabilityCode} $tmpStatus = $dataItem.GetValue("Status") if ($tmpStatus -eq 'Installed'){$tmpStatus = '✅ Installed'}else{$tmpStatus = '❌ {0}' -f $tmpStatus} $tmpObj = [pscustomobject][ordered]@{ #AssignedTo = $assignedTo Identity = $assignedTo AppId = $dataItem.GetValue("AppId") ApplicabilityCode = $tmpApplicabilityCode ApplicabilityCode2 = $dataItem.GetValue("ApplicabilityCode2") CustomError = $dataItem.GetValue("CustomError") Required = $dataItem.GetValue("Required") Status = $tmpStatus Status2 = $dataItem.GetValue("Status2") ErrorCode = $dataItem.GetValue("ErrorCode") } $statusList.Add($tmpObj) } } } if ([string]::IsNullOrEmpty($LogPath)) { # Default log path for Win32 App Management logs $LogPath = "C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\AppWorkload*.log" } $logFiles = Get-ChildItem -Path $LogPath | Sort-Object -Property LastWriteTime -Descending # Corrected regex pattern for extracting the policy JSON $pattern = '<!\[LOG\[Get policies = (?<policy>\[\{.*?\}\])\]LOG\]!>' # Get all policies with regex pattern filter $lines = $logFiles | Select-String -Pattern $pattern if ($lines) { $appPolicyList = [System.Collections.Generic.List[PSCustomObject]]::new() $boolErrorHappened = $false foreach ($line in $lines) { # Extract date and time $Matches = $null if ($line.Line -match 'time="(?<time>.*?)" date="(?<date>.*?)"') { $dateTimeString = '{0} {1}' -f ($Matches['date']), ($Matches['time']) # Parse the date and time to a DateTime object $dateTime = $null $dateTime = Get-ValidDateTime -DateTimeString $dateTimeString # If parsing fails, output a warning once. Every line might fail and we dont want 200 errors visible if ((-NOT $dateTime) -and (-not $boolErrorHappened)) { Write-Warning "Failed to parse date and time from file: $($line.Filename) and line: $($line.Line)" $boolErrorHappened = $true continue } } # Extract and convert the policy JSON $Matches = $null if ($line.Line -match $pattern) { $policyJson = $Matches['policy'] try { $policyObject = $policyJson | ConvertFrom-Json -ErrorAction Stop # add property foreach ($app in $policyObject) { # Set to default value $app | Add-Member -MemberType NoteProperty -Name 'AppState' -Value @() } $appPolicyList.Add([PSCustomObject][ordered]@{ DateTime = $dateTime PolicyCount = $policyObject.Count Policy = $policyObject }) } catch { Write-Warning "Failed to parse JSON from line: $($line.Filename). Error: $_" } } } # Output the parsed policies $appList = $appPolicyList | Sort-Object -Property DateTime -Descending | Select-Object -First 1 } # Now we have the appList with the latest policies, lets add the status information if ($statusList.count -gt 0) { foreach ($app in $appList.Policy) { [array]$appState = $statusList | Where-Object -Property 'AppID' -EQ ($app.Id) | Select-Object Identity, ApplicabilityCode, Required, Status, ErrorCode if ($appState.count -gt 0) { $app.AppState = $appState } } } return ($appList.Policy | Sort-Object -Property Name) } #endregion |