Public/Get-IntuneAgentTimeline.ps1
|
function Get-IntuneAgentTimeline { <# .EXTERNALHELP IntuneScriptLab-Help.xml .SYNOPSIS One timeline per policy or app from the agent's logs: the steps it went through and how they ended. #> [CmdletBinding()] [OutputType('IntuneScriptLab.AgentTimeline')] param( [Parameter(Position = 0)] [string[]]$Path, [ValidateSet('Agent', 'AppWorkload', 'HealthScripts', 'AgentExecutor', 'All')] [string[]]$Log = @('Agent', 'AppWorkload', 'HealthScripts', 'AgentExecutor'), [string[]]$Id, [datetime]$After, [datetime]$Before ) Write-Verbose "Starting $($MyInvocation.MyCommand.Name)" $logSplat = @{ Log = $Log } if ($Path) { $logSplat.Path = $Path } if ($Id) { $logSplat.Id = $Id } if ($PSBoundParameters.ContainsKey('After')) { $logSplat.After = $After } if ($PSBoundParameters.ContainsKey('Before')) { $logSplat.Before = $Before } $entries = @(Get-IntuneAgentLog @logSplat) # App names travel in the policy list the agent logs; nothing else names a policy $names = @{} foreach ($entry in ($entries | Where-Object Event -eq 'AppPolicyFetch')) { foreach ($match in [regex]::Matches($entry.Message, '"Id":"([0-9a-fA-F-]{36})","Name":"([^"]*)"')) { $names[$match.Groups[1].Value.ToLower()] = $match.Groups[2].Value } } $launches = 'RemediationStart', 'ScriptPolicyStart', 'AppExecution' $results = 'RemediationReport', 'DetectionResult', 'ScriptPolicyResult', 'ScriptExit', 'AppReport', 'AppInstallOutcome', 'AppDetection', 'AppApplicability', 'EspAppState' $kindByLog = @{ HealthScripts = 'Remediation'; AppWorkload = 'Win32App' } $timelines = foreach ($group in ($entries | Where-Object { $_.Event -and $_.Id } | Group-Object Id)) { $steps = @($group.Group | Sort-Object Time, Log, Line | ForEach-Object { [pscustomobject]@{ PSTypeName = 'IntuneScriptLab.AgentTimelineStep' Time = $_.Time Log = $_.Log Event = $_.Event Detail = $_.Detail Message = $_.Message } }) $logsSeen = @($steps | ForEach-Object { $_.Log -replace '-\d+$', '' } | Sort-Object -Unique) $kind = 'Unknown' foreach ($seen in $logsSeen) { if ($kindByLog.ContainsKey($seen)) { $kind = $kindByLog[$seen]; break } } if ($kind -eq 'Unknown' -and ($steps | Where-Object Event -like 'Script*')) { $kind = 'PlatformScript' } $lastResult = $steps | Where-Object Event -in $results | Select-Object -Last 1 $outcome = if ($lastResult) { "$($lastResult.Event) $($lastResult.Detail)".Trim() } else { '' } $started = $steps[0].Time $ended = $steps[-1].Time $summaryParts = foreach ($step in $steps) { $label = if ($step.Detail) { "$($step.Event) $($step.Detail)" } else { $step.Event } "$($step.Time.ToString('HH:mm:ss')) $label" } $key = "$($group.Name)".ToLower() [pscustomobject]@{ PSTypeName = 'IntuneScriptLab.AgentTimeline' Id = $group.Name Name = if ($names.ContainsKey($key)) { $names[$key] } else { $group.Name } Kind = $kind Started = $started Ended = $ended Duration = $ended - $started Runs = @($steps | Where-Object Event -in $launches).Count Outcome = $outcome Steps = $steps Summary = ($summaryParts -join ' > ') } } $timelines | Sort-Object Started Write-Verbose "Completed $($MyInvocation.MyCommand.Name)" } |