Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b972595
refactor(core): move Intune anomaly script state into Initialize-RKIn…
Oct 25, 2026
613702e
feat(core): Graph path, status and batch-body helpers, and the module…
Oct 25, 2026
d209e0c
fix(core): status code from direct StatusCode, guard repeated nextLin…
Oct 25, 2026
940f7e0
refactor(core): move Get-GroupInfo, Get-DetailedPolicyAssignments and…
Oct 25, 2026
bf16f71
refactor(core): move the Intune anomaly collector and resolvers into …
Oct 25, 2026
4c844e2
fix(core): retry transient Graph errors, honour -ThrowOnError in the …
Oct 25, 2026
7a75cb0
feat(core): collect through the core adapters, GET only, with require…
Oct 25, 2026
fc6a805
fix(core): null serials, LAPS group warnings, clearer compliance note
Oct 25, 2026
f244cc4
fix(core): fewer pages, wider stale-policy warning, collector tests
Oct 25, 2026
72ef31c
feat(core): resolvers take -Data and return Rows and Warnings; add th…
Oct 25, 2026
1a35645
test(core): pin resolver edge cases (exclusions as Info, UPN case, un…
Oct 25, 2026
beea41b
feat: Get-RKIntuneAnomaly, and Get-IntuneAnomaliesReport renders its …
Oct 25, 2026
c64a290
fix: document that -DebugMode on Get-IntuneAnomaliesReport has no eff…
Oct 25, 2026
4daa495
fix(core): BitLocker and LAPS resolvers work when a tenant has no suc…
Oct 25, 2026
505c496
ci: open a sync pull request in the Maester pack repository when modu…
Oct 25, 2026
a23ca69
ci: sync workflow fails on git errors, keeps a CHANGELOG entry and sy…
Oct 25, 2026
b52fe57
fix(core): unreadable keys or LAPS passwords give Unknown instead of …
Oct 25, 2026
8569a91
fix: retry dropped connections, quieter duplicates, accurate docs
Oct 25, 2026
b3df2fa
fix(core): general warnings on every device check, leave cached polic…
Oct 25, 2026
ee825a9
fix: app install failures come from the Intune report again; installS…
Oct 25, 2026
7ae0669
fix: no temp file left behind when the app list cannot be read; accur…
Oct 25, 2026
78b473a
refactor: Get-RKIntuneAnomaly is internal; the module exports the sam…
Oct 26, 2026
c19e19a
chore: release 1.3.0
Oct 26, 2026
bc0fa11
fix: look up the device type of every device again; permission notice…
Oct 26, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:

- name: Run Consistency.Tests.ps1
run: |
$result = Invoke-Pester ./Tests/Consistency.Tests.ps1 -PassThru -Output Detailed
$result = Invoke-Pester ./Tests -PassThru -Output Detailed
if ($result.FailedCount -gt 0) { exit 1 }
shell: pwsh

Expand Down
77 changes: 77 additions & 0 deletions .github/workflows/sync-maester-pack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Copies module/Core into royklo/maester-pack-rksolutions (intune-anomalies/helpers/core) and opens or updates
# one pull request there, with the pack's patch version raised and a CHANGELOG entry added. The pack's own CI checks it before it can be merged.
# Needs the secret PACK_SYNC_TOKEN: a fine-grained token with Contents and Pull requests write on that repository only.
name: Sync Maester pack

on:
push:
branches: [main]
paths: ['module/Core/**']
workflow_dispatch:

permissions:
contents: read

concurrency:
group: sync-maester-pack

jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
path: module
fetch-depth: 0

- uses: actions/checkout@v5
with:
repository: royklo/maester-pack-rksolutions
token: ${{ secrets.PACK_SYNC_TOKEN }}
path: pack

- name: Copy the core and raise the version
shell: pwsh
run: |
$PSNativeCommandUseErrorActionPreference = $true
# The commit that last changed Core, so a run without Core changes leaves the copied files as they are.
$commit = git -C module log -1 --format=%h -- module/Core
./pack/tools/Sync-Core.ps1 -ModuleRoot ./module -Commit $commit
if (-not (git -C pack status --porcelain)) { Write-Output 'The core is already in sync.'; return }
$utf8 = [System.Text.UTF8Encoding]::new($false)
$manifestPath = Join-Path $PWD 'pack/intune-anomalies/maester-pack.json'
$text = [System.IO.File]::ReadAllText($manifestPath)
$v = [version](($text | ConvertFrom-Json).Version)
$version = "$($v.Major).$($v.Minor).$($v.Build + 1)"
# Replace the value in the text so the rest of the manifest stays byte for byte as it was.
$new = $text -replace '("Version"\s*:\s*")[^"]+(")', "`${1}$version`${2}"
if ($new -ceq $text) { throw "Could not raise the Version in $manifestPath." }
[System.IO.File]::WriteAllText($manifestPath, $new, $utf8)
$changelogPath = Join-Path $PWD 'pack/CHANGELOG.md'
$log = [System.IO.File]::ReadAllText($changelogPath)
$nl = if ($log.Contains("`r`n")) { "`r`n" } else { "`n" }
$entry = "## intune-anomalies $version$nl$nl- Core synced from RKSolutions-Module@$commit.$nl$nl"
$log = $log -replace '(?m)\A(# Changelog[ \t]*\r?\n\r?\n)', ('${1}' + $entry.Replace('$', '$$'))
[System.IO.File]::WriteAllText($changelogPath, $log, $utf8)
"COMMIT=$commit" >> $env:GITHUB_ENV
"VERSION=$version" >> $env:GITHUB_ENV

- name: Open or update the pull request
if: env.COMMIT != ''
shell: pwsh
env:
GH_TOKEN: ${{ secrets.PACK_SYNC_TOKEN }}
run: |
$PSNativeCommandUseErrorActionPreference = $true
Set-Location pack
git config user.name 'rksolutions-sync'
git config user.email 'rksolutions-sync@users.noreply.github.com'
git checkout -B sync/rksolutions-core
git add intune-anomalies CHANGELOG.md
git commit -m "chore(intune-anomalies): sync core from RKSolutions-Module@$env:COMMIT"
git push --force origin sync/rksolutions-core
$title = "Sync core from RKSolutions-Module@$env:COMMIT ($env:VERSION)"
$body = "Copied module/Core from royklo/RKSolutions-Module@$env:COMMIT into intune-anomalies/helpers/core and raised the pack to $env:VERSION. A CHANGELOG.md entry was added automatically; edit it after the last sync and before merging."
$open = gh pr list --head sync/rksolutions-core --state open --json number --jq '.[0].number'
if ($open) { gh pr edit $open --title $title --body $body }
else { gh pr create --base main --head sync/rksolutions-core --title $title --body $body }
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,29 @@ The format follows [Conventional Commits](https://www.conventionalcommits.org/)



## Unreleased

## [1.3.0] - 2026-10-26

Release for the Intune Anomalies report.

### Changes

- **Access denied on BitLocker keys, LAPS credentials or apps shows a notice** instead of flagging every device or stopping the report. Unreadable BitLocker keys show `KeyEscrowed = Unknown`.
- **Failed required Graph reads stop the report** instead of producing a half-empty one.
- **`-DebugMode` has no effect any more.** Use `-Verbose`, which now also shows the progress messages.
- **Deprecated settings take their names from Microsoft Graph** instead of a download.

### Fixes

- **A tenant without a BitLocker or LAPS policy no longer crashes the report.**
- **The report no longer stops silently at 10,000 devices or users.**
- ***Multiple Users* no longer lists devices without an enrollment profile** on tenants without a single-user Autopilot profile.
- **One device that cannot be processed no longer stops the report**; it is listed as a notice.
- **Dropped connections, timeouts and rejected `$batch` reads are retried.**

---

## [1.2.2] - 2026-09-24

Patch release for the Intune Anomalies report.
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ RKSolutions-Module/
│ ├── RKSolutions.psd1
│ ├── RKSolutions.psm1
│ ├── README.md
│ ├── Core/ # Intune anomaly detection shared with the Maester pack
│ ├── Public/ # Exported cmdlets
│ └── Private/ # Helpers
└── Tests/
└── Consistency.Tests.ps1 # Pester tests
├── Consistency.Tests.ps1 # Pester tests
└── IntuneAnomalyCore.Tests.ps1 # Pester tests for module/Core and the Graph adapter
```

## Prerequisites
Expand Down
6 changes: 4 additions & 2 deletions Tests/Consistency.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ Describe 'BitLocker / LAPS anomaly resolver output contracts' {
DeviceManufacturer = 'TestCorp'
DeviceModel = 'TestModel'
}
$rows = Resolve-IntuneBitLockerAnomalies -Devices @($d) -Context $ctx -TenantName 'TestTenant'
$data = [PSCustomObject]@{ TenantName = 'TestTenant'; Devices = @($d); SecurityKeyContext = $ctx; Warnings = @() }
$rows = (Resolve-IntuneBitLockerAnomalies -Data $data).Rows
$rows[0]
}
$row | Should -Not -BeNullOrEmpty -Because 'an unencrypted device with no aadId must surface as an anomaly row'
Expand Down Expand Up @@ -254,7 +255,8 @@ Describe 'BitLocker / LAPS anomaly resolver output contracts' {
DeviceModel = 'TestModel'
DeviceOwnership = 'company' # matches Get-AllDeviceData's output property
}
$rows = Resolve-IntuneLapsAnomalies -Devices @($d) -Context $ctx -TenantName 'TestTenant'
$data = [PSCustomObject]@{ TenantName = 'TestTenant'; Devices = @($d); SecurityKeyContext = $ctx; Warnings = @() }
$rows = (Resolve-IntuneLapsAnomalies -Data $data).Rows
$rows[0]
}
$row | Should -Not -BeNullOrEmpty -Because 'a device covered by a LAPS policy with no credential must surface'
Expand Down
Loading
Loading