Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b149112
docs: add Required API scope(s) to comment help + drop stale PolicyDi…
royklo Jul 6, 2026
95cce1e
feat: add Get-InforcerSecureScore + -User filter on audit events + Id…
royklo Jul 6, 2026
31ac0cf
fix: correct response-shape and aliasing bugs found by live-API verif…
royklo Jul 6, 2026
749539d
docs: add Bug Fixes section to 0.6.0 CHANGELOG entry
royklo Jul 6, 2026
fc1ee31
chore: strip dev/localhost servers and mutable info.version from Open…
royklo Jul 6, 2026
2f1d4f8
revert: restore openapi-snapshot.json to byte-identical live spec (lo…
royklo Jul 6, 2026
c54faff
refactor: shrink ConvertFrom-InforcerSecureString to NetworkCredentia…
royklo Jul 7, 2026
fb82070
refactor: drop Get-InforcerReportTypeStaticKeys wrapper, keep $script…
royklo Jul 7, 2026
b9ac140
refactor: move Get-InforcerPolicyDisplayInfo next to its sibling helpers
royklo Jul 7, 2026
7278502
docs: log the 3 internal ponytail-audit cuts in v0.6.0 CHANGELOG
royklo Jul 7, 2026
b20fe95
refactor: drop dead -PrimaryGroup / -SecondaryGroup from Get-Inforcer…
royklo Jul 7, 2026
50bda55
test: migrate Assert-MockCalled to Should -Invoke for Pester 6 compat
royklo Jul 7, 2026
fcb7655
test: cover new SecureScore ControlCategoryScores / HistoricScores al…
royklo Jul 7, 2026
e5c9c09
Fix cmdlet response structure and improve internals
royklo Jul 7, 2026
39f06f9
feat: expand Get-InforcerSecureScore default view + fix dead-var tests
royklo Jul 7, 2026
84ad4cb
fix: ISO 8601 dates in SecureScore ScoreHistory view (culture-safe)
royklo Jul 7, 2026
8120e42
fix: cap CurrentScorePercentage at 2 decimals in SecureScore view
royklo Jul 7, 2026
e5827fe
feat: surface top 3 recommendations in SecureScore view + dedicated C…
royklo Jul 7, 2026
50f8475
chore: remove throwaway live-securescore-check.sh (was for local veri…
royklo Jul 7, 2026
1a73ff4
test: cover SecureScore drill-in patterns from the docs examples
royklo Jul 7, 2026
911ae3d
docs: update SecureScore docs + Get-Help examples to match v0.6.0 view
royklo Jul 7, 2026
e186408
docs: bring CHANGELOG in sync with the v0.6.0 SecureScore view + dril…
royklo Jul 7, 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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,6 @@ api-feedback-evidence/
*api-feedback*.md
.planning-archive/
scripts/Test-ApiFeedbackItems.ps1

# Local API key for live-* scripts (never commit)
.inforcer-key.local
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,34 @@ All notable changes to this project will be documented in this file.

The format follows [Conventional Commits](https://www.conventionalcommits.org/). Versioning deviates from strict SemVer: every shipped change (feat / fix / perf / non-breaking refactor) bumps MINOR; only breaking changes bump MAJOR; docs/tests/chore-only commits don't bump. There is intentionally no `[Unreleased]` section — every entry is dated at ship time.

## [0.6.0] - 2026-07-06

### Features

- **New cmdlet: `Get-InforcerSecureScore`** — retrieves the current and historic Microsoft Secure Score for a tenant from `GET /beta/tenants/{tenantId}/secureScores`. Returns the current score, max score, licensed user count, enabled services, up to 90 days of daily score history, per-category scores, and actionable control profiles with remediation guidance. `-TenantId` accepts numeric ID, GUID, or tenant name (name/GUID resolution via `Resolve-InforcerTenantId`). Supports `-OutputType JsonObject`. Required scopes: `Tenants.SecureScores.Read` + `Tenants.Read` (only when `-TenantId` is a GUID or tenant name). PSTypeName `InforcerCommunity.SecureScore` with a ListControl default view showing:
- `CurrentScore` / `MaxScore` / `CurrentScorePercentage` (capped at 2 decimals for display) / `LicensedUserCount` / `EnabledServices` (joined).
- `ScoreHistory` — day count + `first → last` ISO 8601 date range + latest score. Culture-safe: dates use InvariantCulture so nl-NL / de-DE etc. all read the same as en-US.
- `ControlCategoryScores` — every category inline, e.g. `Identity: 49.13/71, Apps: 177/198, Data: 7/9, Device: 769.75/989`.
- `ControlProfilesCount` and `TopRecommendations` — the 3 highest-`scoreDifference` open controls, so "what do I fix next" is on-screen without drilling.
- `Hint` — points to `.ControlProfiles | Sort-Object ScoreDifference -Descending`, `.Scores`, and `.ControlCategoryScores[0].HistoricScores` for the full data.
- **New nested PSTypeName: `InforcerCommunity.SecureScoreControlProfile`** — every item in `.ControlProfiles` gets this type inserted, so `$s.ControlProfiles | Format-List` renders a compact view (`Title`, `ControlCategory`, `Service`, current/max score with potential gain, `RemediationImpact`, `ActionUrl`, `Id`) instead of dumping the giant HTML `remediation` blob. The full remediation HTML is still on the object as `.remediation` when needed.
- **`Get-InforcerAuditEvent -User <string>`** — new parameter that server-side filters audit events by the specified user (matches the `user` field in the `POST /beta/auditEvents/search` request body). Previously users had to fetch all events and filter client-side.
- **`Id` alias on audit event output** — `AuditEvent` objects now expose the raw `id` field as PascalCase `Id`, consistent with every other object type in the module.
- **Dynamic `-EventType` tab completion** — the completer on `Get-InforcerAuditEvent -EventType` now reads `$global:InforcerCachedEventTypes`, which `Get-InforcerSupportedEventType` refreshes with the live server-side list on any authenticated call. New event types the API adds appear in tab completion automatically after the next `Get-InforcerSupportedEventType` call — no module release required. A static fallback list (currently 80 event types) covers the pre-connect case.
- **`Get-InforcerSecureScore` nested aliasing extended** — `.ControlCategoryScores` and its inner `.historicScores` now get PascalCase aliases too (previously only top-level, `.Scores`, and `.ControlProfiles` were aliased).

### Documentation

- **`Required API scope(s):` line added to `Get-Help` output for 13 cmdlets** — `Compare-InforcerEnvironments`, `Export-InforcerTenantDocumentation`, `Get-InforcerAlignmentDetails`, `Get-InforcerAssessment`, `Get-InforcerAuditEvent`, `Get-InforcerBaseline`, `Get-InforcerGroup`, `Get-InforcerRole`, `Get-InforcerSupportedEventType`, `Get-InforcerTenant`, `Get-InforcerTenantPolicies`, `Get-InforcerUser`, `Invoke-InforcerAssessment`. Users no longer need to leave PowerShell and open `docs/API-REFERENCE.md` to learn which scope a cmdlet needs. Follows the pattern already used by the Reports cmdlets.
- **Removed stale `PolicyDiffFormatted` mention** in `docs/CMDLET-REFERENCE.md` — the property was removed from the module in an earlier version (see FINDINGS #63) but one line in the docs was missed.
- Added `Get-InforcerSecureScore` section to `docs/CMDLET-REFERENCE.md`; endpoint description, schemas (`TenantSecureScoreDetails`, `TenantSecureScoreHistoryPoint`, `TenantSecureScoreControlProfile`), and scope-mapping row added to `docs/API-REFERENCE.md`; cmdlet added to the README public-surface table.
- Expanded the `Get-InforcerSecureScore` docs and `Get-Help` examples with 10 drill-in patterns: sort recommendations by score gap, filter by control `Id`, group open work by category with total potential gain, drill into a category's daily history, `Export-Csv` for a remediation ticket, `Start-Process` on the top `ActionUrl`, etc.

### Bug Fixes

- **`Get-InforcerUser -UserId` was returning the wrong shape.** Live-API verification exposed this: without `-PreserveStructure`, `Invoke-InforcerApiRequest`'s "unwrap first array property of `.data`" convenience was unwrapping the user object's nested arrays (e.g. `groups`, `assignedLicenses`), so the cmdlet returned an array of group memberships instead of the user detail. `PSTypeName` was never applied. Fix: added `-PreserveStructure` to the API call.
- **New `Get-InforcerSecureScore` needed the same fix on first flight** — same root cause, same defense (`-PreserveStructure` added). Live-verified: cmdlet now returns a single `InforcerCommunity.SecureScore` object with 90-day history, control profiles, and category scores populated as documented.

## [0.5.0] - 2026-06-30

### Features
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ Disconnect-Inforcer
| **Get-InforcerUser** | Retrieves users from a tenant (list/search or detail by UserId). |
| **Get-InforcerGroup** | Retrieves Entra ID groups from a tenant (list/search or detail by GroupId). |
| **Get-InforcerRole** | Retrieves Entra ID directory role definitions from a tenant. |
| **Get-InforcerSecureScore** | Retrieves the current and 90-day historic Microsoft Secure Score for a tenant, including per-category scores and actionable control profiles. |
| **Export-InforcerTenantDocumentation** | Generates comprehensive tenant documentation in HTML, Markdown, or Excel format. |
| **Compare-InforcerEnvironments** | Compares two tenants' Intune configuration and generates an interactive HTML comparison report. Supports baseline-scoped comparison via `-SourceBaselineId` / `-DestinationBaselineId` with automatic baseline owner resolution. |
| **Get-InforcerAssessment** | Lists available assessments (CIS, Essential Eight, etc.). |
Expand Down
Loading