[pull] master from KelvinTegelaar:master#59
Open
pull[bot] wants to merge 416 commits into
Open
Conversation
[pull] dev from KelvinTegelaar:dev
[pull] dev from KelvinTegelaar:dev
[pull] dev from KelvinTegelaar:dev
[pull] dev from KelvinTegelaar:dev
[pull] dev from KelvinTegelaar:dev
[pull] dev from KelvinTegelaar:dev
[pull] dev from KelvinTegelaar:dev
[pull] dev from KelvinTegelaar:dev
[pull] dev from KelvinTegelaar:dev
[pull] dev from KelvinTegelaar:dev
Add severity and resolvingComment to the incident PATCH so users can reprioritise and document why an incident was resolved. Build the body as a hashtable/JSON so free-text comments with quotes are escaped, and gate assignee changes behind an explicit AssignToSelf flag so status and severity and status edits no longer clobber the existing owner.
[pull] dev from KelvinTegelaar:dev
The SetAuthMethod endpoint only toggled state and group targeting, so method-specific options (TAP lifetimes/usable-once, Authenticator feature settings, Email OTP external/exclude, QR code, FIDO2 attestation and self-service, Voice office phone, SMS sign-in) could not be managed from the portal. Forward those settings through the handler, honor them in Set-CIPPAuthenticationPolicy, treat an explicit empty Email exclude list as a clear, and add Pester coverage.
[pull] dev from KelvinTegelaar:dev
[pull] dev from KelvinTegelaar:dev
[pull] dev from KelvinTegelaar:dev
The generated openapi.json types every request body but leaves each 200
response as the generic StandardResults envelope, and carries no operationId
on any operation. That makes the spec hard to consume: OpenAPI importers that
key on operationId skip every operation, and downstream tools get no typed
output fields to map against.
This adds a deterministic post-processing stage that enriches the generated
spec without replacing the upstream generator:
- operationId injection: bare endpoint name per operation, method-prefixed
only where a single path carries multiple methods. Existing operationIds are
preserved; collisions are a hard failure.
- typed 200 responses: derived from two checked-in sources, the frontend shape
baselines (Tests/Shapes/*.json) and page simpleColumns declarations. The
{ Results, Metadata } envelope is preserved as the API actually returns it.
The enriched spec is published as the openapi.enriched.json asset on each
GitHub Release. A PR check workflow runs the test suite and strictly lints the
enriched spec against a committed ignore-baseline that pins pre-existing
upstream findings, so any new finding fails CI.
Pure function of the two repositories; same input produces byte-identical
output. Stage and runner are PowerShell with a Pester suite (50 tests).
[pull] dev from KelvinTegelaar:dev
Add ExcludeGroupIds and AssignmentDirection so exclude groups are targeted by ID and a Replace edits only one direction, preserving the other plus All Users/All Devices. Exclude-only requests no longer error or wipe assignments, and exclusion targets drop the settings block that Graph rejects.
…vanced) Get-CIPPAlertCheckExtension reads a per-tenant watermark from the AlertLastRun table to only fetch alerts newer than the previous run, but never wrote it back. So $Since always fell back to the default 24h window and the same alerts were re-sent on every scheduled run. Capture the run start, read/store an explicit LastRunTime watermark (falling back to the existing Timestamp for compatibility), and upsert it after processing so each run only sends alerts created since the last run. Fixes #6216
[pull] dev from KelvinTegelaar:dev
The detection script of a Win32 Custom Application was base64-encoded from the raw input, so %tenantid% and other Get-CIPPTextReplacement tokens were not resolved (they reached Intune as literal text), unlike the install and uninstall scripts. Run the detection script through Get-CIPPTextReplacement first, matching the install/uninstall handling. Fixes KelvinTegelaar/CIPP#6226
When AppCache.ApplicationId differs from the Key Vault-backed ApplicationID, Get-GraphToken now reloads auth and updates the AppCache marker to the KV value. This prevents repeated auth reloads on every token request when AppCache and KV are out of sync.
Expand the NudgeMFA standard to support: - Multiple authentication methods (Authenticator, Passkey) - Group-level include/exclude targeting with group name resolution - Snooze enforcement limits (max 3 snoozes) Adds Set-CIPPRegistrationCampaign helper function as a single writer for the campaign, shared by the new ExecRegistrationCampaign HTTP endpoint and the enhanced NudgeMFA standard. The standard now supports both portal-configured and template-specified group targeting, with full compliance comparison.
Expand the NudgeMFA standard to support: - Multiple authentication methods (Authenticator, Passkey) - Group-level include/exclude targeting with group name resolution - Snooze enforcement limits (max 3 snoozes) Adds Set-CIPPRegistrationCampaign helper function as a single writer for the campaign, shared by the new ExecRegistrationCampaign HTTP endpoint and the enhanced NudgeMFA standard. The standard now supports both portal-configured and template-specified group targeting, with full compliance comparison. Backwards compatible with any current configuration
Update the default assignment mode to 'append' for a less destructive default. Frontend PR: KelvinTegelaar/CIPP#6342
Resolves KelvinTegelaar/CIPP#6349, "[Feature Request]: Auto-create NinjaOne vulnerability scan group during CVE sync". Previously, `Invoke-NinjaOneTenantSync` looked up the NinjaOne CVE vulnerability scan group by name and failed the CVE sync step for the tenant if that scan group did not already exist in NinjaOne. This forced admins to manually pre-create the scan group in every tenant before CVE sync could function. - Extract the scan-group lookup into a new, independently testable helper `Resolve-NinjaOneCveScanGroup` (Private/NinjaOne). It now: - Looks up the scan group by configured name. - Auto-creates it via the NinjaOne API when not found, using the configured (or default) device-id/cve-id header names. - Returns $null and logs an Error via Write-LogMessage when lookup and creation both fail, so the outer CVE sync block can log and continue instead of throwing. - Wire `Invoke-NinjaOneTenantSync`'s CVE sync block to call the new helper instead of inline lookup-or-fail logic. - Fix an unrelated but adjacent bug: the NinjaOne API Authorization header was being built without the required "Bearer " prefix (`"Bearer $($Token.access_token)"`), which would have caused every authenticated NinjaOne API call to fail with 401 Unauthorized. - Address PR review feedback (review comment r3581392606) on `Resolve-NinjaOneCveScanGroup`: - Wrap the initial scan-group lookup GET request in its own try/catch. Previously an uncaught exception here (e.g. 401, timeout) would propagate out of the function, contradicting its documented `$null`-on-failure contract; it now logs an Error-severity message and returns $null like the create-failure path already did. - Pipe the `Where-Object` name match through `Select-Object -First 1` so the function always returns a single scan-group object as documented, even if NinjaOne has multiple scan groups sharing the same name (previously it could return an array in that case, silently breaking downstream `.id`/`.deviceIdHeader`/`.cveIdHeader` access and upload-URI construction in the caller). Tests: - Add `Tests/NinjaOne/Resolve-NinjaOneCveScanGroup.Tests.ps1`: 5 scenarios covering existing scan group found, auto-create on missing, auto-create using custom header names, auto-create using default header names, and the not-found/creation-failure path. Plus 2 new scenarios added for the review-feedback fix: the initial lookup GET failing (returns $null, logs Error, does not throw, does not attempt create), and multiple scan groups sharing the same name (returns a single object, not an array). - Add `Tests/NinjaOne/Invoke-NinjaOneTenantSync.Tests.ps1`: a comprehensive Pester suite for the full sync function (16 scenarios) covering successful sync, tenant match validation, hostname allow-list validation, CVE sync (including the new auto-create path, exception filtering, and isolated failure handling), UserDocuments/LicenseDocuments toggles, final custom-fields PATCH failure handling, and the tenant-sync concurrency guard. While writing the concurrency-guard test, discovered a genuine, pre-existing production bug: the guard parses the stored `lastStartTime` (a UTC ISO-8601 string) with `Get-Date($string)`, which returns a `Kind=Local` DateTime, then compares it directly against `(Get-Date).ToUniversalTime()` (`Kind=Utc`). .NET's DateTime comparison operators ignore `Kind` and compare raw ticks, so the "already running" check is silently wrong by the host's UTC offset on any non-UTC host. This is out of scope for #6349 and is tracked separately as KelvinTegelaar/CIPP#6351; the test documents the current (buggy) comparison behavior deterministically across host timezones rather than masking or silently working around it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Convert `AgeLimitForRetention` from `TimeSpan.TotalDays` to an integer before state comparison in `Invoke-CIPPStandardRetentionPolicyTag`. This avoids decimal day values causing false drift detection when validating retention policy tag settings.
Update Smart Lockout metadata and docs to use the correct on-premises mode value (`Enforce` instead of `Enforced`). In `Invoke-CIPPStandardSmartLockout`, add compatibility mapping for legacy templates that still store `Enforced`, converting it to `Enforce` before compliance checks and remediation calls so tenants are not incorrectly flagged as non-compliant.
Use the actual policy properties returned by the test when building the failed policy table, and hardcode the expected action as `Quarantine` so the report matches the check logic.
Update ORCA121 to inspect hosted content filter policies instead of quarantine policies and flag SpamAction or PhishSpamAction values that Zero Hour Autopurge cannot remediate. This adds clearer pass/fail output with per-setting details and documents the test intent.
Add field-level projection to Get-CIPPTestData and New-CIPPDbRequest to reduce memory usage by only materializing queried fields. Introduce Get-CippTestDataFieldManifest to manage per-type field whitelists, and replace ConvertFrom-Json with CIPP.CippJson (System.Text.Json-based) for faster parsing. Update Get-CippDbRoleMembers with missing fields (appId, EndDateTime, IsPermanent) required by role member callers. Refactor CIPPTestDataCache to use direct PSObject APIs instead of reflection for heap-size estimation.
Add the required RoleManagement permissions to SAMManifest and update PIM cache jobs to use app-only Graph calls (`-AsApp`) so role APIs stop failing with unauthorized delegated access. Role assignment and eligibility schedule caching now expands `principal` to preserve member identity fields, and role management policy caching now reads `roleManagementPolicyAssignments` (with required filter/expands) and flattens policy rules/effectiveRules alongside `roleDefinitionId` for role-to-policy lookups.
Fix multiple bugs in CIPP test functions where incorrect field names or IDs were used when querying role data and policies: - Replace `$GA.id` with `$GA.roleTemplateId` when matching PIM role assignments (CIS_1_1_2, CIS_1_1_3) - Replace `$Role.templateId` with `$Role.roleTemplateId` when filtering roles and policies (ZTNA21813, 21816, 21818, 21820) - Fix app protection policy tests to read from correct data type and distinguish between missing data vs. missing platform-specific policy (ZTNA24548, ZTNA24549) - Replace `IsPermanent` for permanent GA detection instead of `AssignmentType -eq 'Permanent'` (ZTNA21835) - Use correct field names from Get-CippDbRoleMembers: `id` instead of `principalId`, `displayName` instead of `principalDisplayName` (ZTNA21835, ZTNA21836) - Fix role management policy lookup to use `roleDefinitionId` instead of nonexistent `effectiveRules.target.targetObjects.id` (ZTNA21819, ZTNA21820) - Clean up Entra URL construction (ZTNA21836) These changes fix tests that were silently returning false negatives due to incorrect field references.
…ching (#6347) The drift report failed to detect Intune configuration deviations because Get-CIPPDrift.ps1 compared template and tenant policy names using `.displayName -eq .displayName` alone. When both sides had no `.displayName` property (common for Graph policy types that only expose `.name`), this evaluated `$null -eq $null` as true, causing every such tenant policy to be incorrectly matched against the first Intune template in the loop and suppressing real drift. The fix restores all four original name/displayName pairings (displayName<->displayName, name<->name, displayName<->name, name<->displayName), with each pairing individually null-guarded so a match only counts when both sides have a real, non-null value. This is a strict superset of the prior matching capability - it only excludes the null-eq-null case that caused the false positive - so Settings Catalog and other name-only policy types deployed from a template continue to match correctly on name<->name. Adds Tests/Reports/Get-CIPPDrift.Tests.ps1, a new Pester suite (16 tests) covering: - the original null-eq-null false-match bug - each of the four name/displayName pairing combinations - the Settings Catalog name<->name regression path - multi-template alignment loops (matching a later template when earlier ones don't match) - Conditional Access template matching - standards deviation display-name/description resolution - stale drift-entity pruning Fixes KelvinTegelaar/CIPP#6347
Add CopilotPolicySettings.ReadWrite to the permissions translator for both Delegated and Application origins, and include the corresponding scope/role IDs in SAMManifest requiredResourceAccess. This updates the SAM app permission set so Copilot policy settings can be managed in both signed-in and app-only flows.
Remove the scheduled SharePointSharingLinks cache task from Push-CIPPDBCacheData and leave it as an ad-hoc-only operation, since full sharing-link enumeration can run too long on large tenants.
…ching (#6347) (#2143) ## What Fixes drift report failing to detect Intune configuration deviations (#6347). `Get-CIPPDrift.ps1` matched an Intune template to a tenant policy using `.displayName -eq .displayName` only. Graph policy types that expose only a `.name` property (no `.displayName`) evaluated `$null -eq $null` as `true`, so every such tenant policy silently matched the first template in the loop regardless of actual content - suppressing real drift detection entirely for those policy types. ## Fix Restores all four original name/displayName pairings used before the regression was introduced, each individually null-guarded so a match only counts when both sides have a real, non-null value: - `displayName <-> displayName` - `name <-> name` - `displayName <-> name` - `name <-> displayName` This is a strict superset of the prior matching capability - the only behavior removed is the null-eq-null false match. Settings Catalog and other name-only policy types deployed from a template still match correctly via `name <-> name`. ## Tests Adds `Tests/Reports/Get-CIPPDrift.Tests.ps1`, a new Pester suite (16 tests) covering: - the original null-eq-null false-match bug - each of the four name/displayName pairing combinations - the Settings Catalog name<->name matching path - multi-template alignment loops (matching a later template when earlier ones don't match) - Conditional Access template matching - standards deviation display-name/description resolution - stale drift-entity pruning All 16 tests pass locally via `Invoke-Pester -Path Tests\Reports\Get-CIPPDrift.Tests.ps1`. Fixes KelvinTegelaar/CIPP#6347
…#2141) Resolves KelvinTegelaar/CIPP#6349, "[Feature Request]: Auto-create NinjaOne vulnerability scan group during CVE sync". ## Summary Previously, `Invoke-NinjaOneTenantSync` looked up the NinjaOne CVE vulnerability scan group by name and failed the CVE sync step for the tenant if that scan group did not already exist in NinjaOne. This forced admins to manually pre-create the scan group in every tenant before CVE sync could function. - Extract the scan-group lookup into a new, independently testable helper `Resolve-NinjaOneCveScanGroup` (`Private/NinjaOne`). It now: - Looks up the scan group by configured name. - Auto-creates it via the NinjaOne API when not found, using the configured (or default) device-id/cve-id header names. - Returns `$null` and logs an Error via `Write-LogMessage` when lookup and creation both fail, so the outer CVE sync block can log and continue instead of throwing. - Wire `Invoke-NinjaOneTenantSync`'s CVE sync block to call the new helper instead of inline lookup-or-fail logic. - Fix an unrelated but adjacent bug: the NinjaOne API Authorization header was being built without the required `Bearer ` prefix, which would have caused every authenticated NinjaOne API call to fail with 401 Unauthorized. ## Tests - `Tests/NinjaOne/Resolve-NinjaOneCveScanGroup.Tests.ps1`: 5 scenarios covering existing scan group found, auto-create on missing, auto-create using custom header names, auto-create using default header names, and the not-found/creation-failure path. - `Tests/NinjaOne/Invoke-NinjaOneTenantSync.Tests.ps1`: a comprehensive Pester suite for the full sync function (16 scenarios) covering successful sync, tenant match validation, hostname allow-list validation, CVE sync (including the new auto-create path, exception filtering, and isolated failure handling), UserDocuments/LicenseDocuments toggles, final custom-fields PATCH failure handling, and the tenant-sync concurrency guard. While writing the concurrency-guard test, discovered a genuine, pre-existing production bug: the guard parses the stored `lastStartTime` (a UTC ISO-8601 string) with `Get-Date($string)`, which returns a `Kind=Local` DateTime, then compares it directly against `(Get-Date).ToUniversalTime()` (`Kind=Utc`). .NET's DateTime comparison operators ignore `Kind` and compare raw ticks, so the "already running" check is silently wrong by the host's UTC offset on any non-UTC host. **This is out of scope for #6349** and is tracked separately as #4; the test documents the current (buggy) comparison behavior deterministically across host timezones rather than masking or silently working around it. Both suites pass 100% (5/5 and 16/16). PSScriptAnalyzer run clean on all touched/new files (only pre-existing repo-wide style warnings, no errors).
Refactor Set-CIPPUser to use a shared helper that decides whether group membership changes should use Exchange cmdlets based on `addedFields.calculatedGroupType`, with fallback to legacy `groupType` values. This fixes inconsistent add/remove behavior caused by the previous inline condition and variable-case mismatch, ensuring distribution lists and mail-enabled security groups are handled consistently.
Signed-off-by: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )