Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@ release notes.

## [Unreleased]

Nothing yet.
### Fixed

- `Get-IntuneAgentTimeline` reported `Kind` as `Unknown` for a policy or app whose lines all sat in
a rolled log file: the rolled name (`HealthScripts-20260925-101500`) lost only its time part, so it
never matched the log table. Both parts come off now, and such a timeline reads as Remediation or
Win32App like one from the current file.
- The README's Enrollment Status Page block showed the `Log` column before it abbreviated
`IntuneManagementExtension` to `Agent`, and its diagnostic block showed the result as a table
where it has printed as a list with the size in MB since 0.28.0. Both now show what the commands
print.

## [0.31.0] - 2026-10-09

Expand Down
6 changes: 3 additions & 3 deletions Private/ConvertFrom-IslCmTraceLog.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ function ConvertFrom-IslCmTraceLog {
and Id are left empty for Get-IntuneAgentLog to fill.

The filters are the ones Get-IntuneAgentLog offers, applied to the raw record before an
object is built for it. Building the object is most of what an entry costs, so a filtered
read of a 22 MB log takes seconds where building every entry takes a minute.
object is built for it. Building the object is most of what an entry costs: on a 15 MB log
of 80,000 entries, one policy by -Id reads in 5 seconds where every entry takes 30.

.PARAMETER Path
The log file to parse.
Expand Down Expand Up @@ -91,7 +91,7 @@ function ConvertFrom-IslCmTraceLog {
$ordinalIgnoreCase = [System.StringComparison]::OrdinalIgnoreCase
$ordinal = [System.StringComparison]::Ordinal

# An agent log of 22 MB is 80,000 entries, and every statement here runs once per entry. The
# An agent log of 15 MB is 80,000 entries, and every statement here runs once per entry. The

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

15 MB is the figure the 0.28.0 changelog recorded for the same 80,000-entry log the benchmark used; the 22 MB here predated that measurement. Only the comment changes.

# attributes come out of one compiled regex in the order the agent writes them, the timestamp
# is read the way ConvertTo-IslCmTraceTime reads it without the call, and the filters run on
# the raw strings before anything is built. Lines are counted only up to an entry that is kept
Expand Down
4 changes: 3 additions & 1 deletion Public/Get-IntuneAgentTimeline.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ function Get-IntuneAgentTimeline {
Message = $_.Message
}
})
$logsSeen = @($steps | ForEach-Object { $_.Log -replace '-\d+$', '' } | Sort-Object -Unique)
# A rolled file is HealthScripts-20260925-101500: both date and time come off, or the name
# never matches the table and a policy whose lines all sit in a rolled file reads as Unknown
$logsSeen = @($steps | ForEach-Object { $_.Log -replace '-\d{8}-\d{6}$', '' } | Sort-Object -Unique)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anchored to the exact rolled shape (eight digits, dash, six digits) rather than a looser repeat of -digits, so a hypothetical log whose base name ends in a number is not shortened by accident. The agent has produced only this shape on the lab devices across all rounds.

$kind = 'Unknown'
foreach ($seen in $logsSeen) {
if ($kindByLog.ContainsKey($seen)) { $kind = $kindByLog[$seen]; break }
Expand Down
36 changes: 20 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -438,19 +438,20 @@ shared access, so the live agent is no obstacle, and a copied log folder works w

```powershell
Get-IntuneAgentLog -EventName ScriptEspPhase, EspPhase, EspAppsSelected, EspAppRegistered,
EspAppState, EspPhaseComplete, EspComplete, EspNontrackedCheckin

Time Log Event Detail
---- --- ----- ------
09-28 07:06:00.847 IntuneManagementExtension ScriptEspPhase DeviceSetup
09-28 07:06:12.299 AppWorkload EspPhase DeviceSetup
09-28 07:06:25.611 AppWorkload EspAppsSelected 2
09-28 07:06:31.011 AppWorkload EspAppRegistered DeviceSetup ISL-ESP-DEV-W32-BLOCK1
09-28 07:07:31.199 AppWorkload EspAppState InProgress Completed
09-28 07:08:20.385 AppWorkload EspPhaseComplete device
09-28 07:08:37.882 AppWorkload EspPhase AccountSetup
09-28 07:11:22.504 AppWorkload EspComplete
09-28 07:12:22.658 IntuneManagementExtension EspNontrackedCheckin True
EspAppState, EspPhaseComplete, EspComplete, EspNontrackedCheckin |
Format-Table Time, Log, Event, Detail

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The block below shows four columns, and the default view prints Message too, so the command now selects what the block shows. The column widths are what Format-Table gives these values once IntuneManagementExtension prints as Agent; the rows are the round-8 values unchanged.


Time Log Event Detail
---- --- ----- ------
09-28 07:06:00.847 Agent ScriptEspPhase DeviceSetup
09-28 07:06:12.299 AppWorkload EspPhase DeviceSetup
09-28 07:06:25.611 AppWorkload EspAppsSelected 2
09-28 07:06:31.011 AppWorkload EspAppRegistered DeviceSetup ISL-ESP-DEV-W32-BLOCK1
09-28 07:07:31.199 AppWorkload EspAppState InProgress Completed
09-28 07:08:20.385 AppWorkload EspPhaseComplete device
09-28 07:08:37.882 AppWorkload EspPhase AccountSetup
09-28 07:11:22.504 AppWorkload EspComplete
09-28 07:12:22.658 Agent EspNontrackedCheckin True
```

One Autopilot run (Validation\Findings.md, "The Enrollment Status Page") fixed where scripts sit
Expand All @@ -474,9 +475,12 @@ Started Kind Name Duration Runs Outcome

Export-IntuneAgentDiagnostic -Path C:\Temp\intune-diag.zip

Path Files Logs Registry Timeline SizeBytes
---- ----- ---- -------- -------- ---------
C:\Temp\intune-diag.zip 14 6 True True 2318402
Path : C:\Temp\intune-diag.zip
Size : 2.9 MB
Files : 29
Logs : 20
Registry : True
Timeline : True
```

`Get-IntuneAgentTimeline` groups the named log lines by the policy or app they belong to, so one
Expand Down
18 changes: 18 additions & 0 deletions Tests/Unit/Public/Get-IntuneAgentTimeline.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,24 @@ Describe 'Get-IntuneAgentTimeline' -Tag 'Unit', 'Public' {
$platform.Outcome | Should-Be 'ScriptPolicyResult Failed'
$platform.Duration.TotalSeconds | Should-Be 20
}

It 'reads the kind from a rolled log file as it does from the current one' {
# The agent rolls HealthScripts.log over to HealthScripts-<date>-<time>.log; a policy
# whose lines all sit in the rolled file is still a remediation
$rolled = Join-Path $TestDrive 'Rolled'
$hs = @{ Component = 'HealthScripts' }
Write-TestLog $rolled 'HealthScripts-20260925-101500.log' @(

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A separate folder with the rolled file alone, rather than adding a rolled file next to the fixture's current logs: with both present the current file would supply the kind and the test would pass without the fix.

New-CmTraceLine @hs -Time '08:45:14.0000000' -Message ("[HS] Runner: script $($script:Policy) " +
'will try to execute now.')
New-CmTraceLine @hs -Time '08:46:56.0000000' -Message ('[HS] new result = {"PolicyId":"' +
$script:Policy + '","Result":3}')
)
$timeline = @(Get-IntuneAgentTimeline -Path $rolled)
$timeline.Count | Should-Be 1
$timeline[0].Kind | Should-Be 'Remediation'
$timeline[0].Steps[0].Log | Should-Be 'HealthScripts-20260925-101500'
$timeline[0].Outcome | Should-Be 'RemediationReport 3'
}
}

Context 'Filters' {
Expand Down
Loading