Merged
Conversation
…uate as falsy and report the policy as disabled even when it was enabled but misconfigured.
…ent remediation running against null state - Replace unreliable .length checks with explicit $PolicyExists/$RuleExists flags using .Count and null guards - Fix disable path treating absent policy as correctly configured, which silently skipped remediation and caused null vs false report mismatches - Include address fields in correctness checks for all paths so stale email addresses are detected as drift - Fix array comparison for email fields using -contains instead of -eq - Null out address fields in disable remediation to clean up stale values - Check and disable rule when state is disable, replacing hardcoded $true - Fix $Policy undefined variable in alert block, should be $PolicyState
drift detection also compared address fields and rule state. This caused perpetual drift reports for tenants with residual address values or an active rule, since remediation considered the state correct and never acted. - Add address field Count checks to $StateIsCorrect for 'enable' (no mail) and 'disable' cases - Add rule state check to $StateIsCorrect for both cases - Include address fields in PolicyParams so they are explicitly cleared during remediation - Remove the submission rule (rather than disable) when it should not be active, clearing SentTo in a single operation - Normalise $CurrentValue.RuleState.State to 'Disabled' when no rule exists, preventing phantom drift after rule removal
treating null and [] as different values. Address fields in $ExpectedValue were set to $null when no email is configured, but Exchange returns empty arrays for these properties, causing perpetual drift on correctly configured tenants. Changed to @() to match the actual Exchange return type.
…hile
drift detection compared all fields. This caused perpetual drift reports
for states that remediation considered correct and would never act on.
Changes:
- Expanded $StateIsCorrect checks to include address array counts (.Count -eq 0) and rule state, fully matching drift detection fields
- Use Remove-ReportSubmissionRule to clear the rule in a single API call
- Wrap Exchange address collection properties with @() in $CurrentValue to normalise the Exchange MultiValuedProperty type for consistent JSON serialisation
- Fix $ExpectedValue address fields: inline `if { @() }` returns $null (empty arrays write nothing to the pipeline); use @(if { ... }) outer wrapping instead to correctly produce an empty array
- Fix $ExpectedValue.RuleState condition to include $state -eq 'disable', preventing an incorrect State='Enabled' expectation when email is configured but the standard is set to disable
- Normalise RuleState.State to 'Disabled' and SentTo to $null in $CurrentValue when no submission rule exists
Introduce ITGlue integration: add connection helpers, API request wrapper, mapping endpoints, and full sync implementation. Files added: Connect-ITGlueAPI (builds headers/base URL), Invoke-ITGlueRequest (JSON:API helper with pagination and rate-limit handling), Get-ITGlueMapping, Get-ITGlueFieldMapping, Set-ITGlueMapping, and Invoke-ITGlueExtensionSync (creates/updates flexible assets, contacts, configurations, and org quick-notes from CIPP M365 data). Update core entrypoints and helpers to handle ITGlue: Invoke-ExecExtensionMapping, Invoke-ExecExtensionSync, Invoke-ExecExtensionTest, Invoke-ExecExtensionsConfig, Push-CippExtensionData, and Register-CIPPExtensionScheduledTasks. Set-ITGlueMapping replaces mapping table entries; Invoke-ITGlueRequest unwraps JSON:API responses and supports POST/PATCH wrapping. Overall enables scheduling, testing, mapping, and execution of ITGlue syncs from the platform.
[pull] master from KelvinTegelaar:master
Add ITGlue extension support and sync
The ITGlue API requires 'label-name' instead of 'label' in the contact-emails array. This was causing 422 errors with "can't be blank" when creating contacts. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix ITGlue contact creation - use correct label-name field
- Fix license summary bug where $_ scope issue caused incorrect SKU lookups - Replace plain text quick-notes with HTML formatting for better readability - Add license table with headers instead of plain text list - Add quick links to CIPP, M365 Admin, and Entra Admin portals - Sort licenses alphabetically by SKU part number Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Improve ITGlue quick-notes formatting
- Replace Set-Location with proper module path resolution for ConversionTable.csv - Add 100ms rate limiting between API calls to avoid hitting ITGlue limits on large tenants Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add HTML comment markers to identify CIPP managed section - Fetch existing quick-notes before updating - If CIPP section exists, replace only that section - If other content exists, append CIPP section with <hr/> separator - If no content exists, add CIPP section without separator Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix ITGlue sync reliability issues
Feature/itglue
Replace HTML comment markers with a real <div class="cipp-managed"> wrapper because ITGlue's sanitizer strips HTML comments. Update detection and replacement logic to match the new div wrapper, fall back to legacy comment markers if present, and attempt to repair orphaned CIPP content by matching the section heading and the "(CIPP Managed)" timestamp. Also refine append/replace behavior and ensure the leading <hr/> is omitted when creating a new CIPP section in empty notes.
Fix ITGlue quick-notes duplicating CIPP section on every sync
Feature/itglue
Fix ITGlue quick-notes duplicating CIPP section on every sync
Feature/itglue
ITGlue strips both HTML comments and class attributes, so marker-based approaches fail. Use greedy regex on the heading/timestamp content instead to capture all duplicates in a single replacement.
Fix ITGlue quick-notes duplicating and format domains as list
Feature/itglue
…eport Add Mailbox Forwarding Report API
Introduce a new cmdlet to manage the tenant default App Management Policy via Microsoft Graph. The script reads supplied settings (password/symmetric key addition flags and credential max lifetimes), converts day values to ISO 8601 durations, builds the desired application and service principal restrictions, compares them with the current policy, and optionally remediates via a PATCH, emits alerts, and reports results. Includes error handling and logging for Graph operations.
Add Invoke-CIPPStandardAppManagementPolicy cmdlet
Frontend may send setting values as objects like {label,value} or as plain values. Unwrap those inputs by preferring the .value property when present (using null-coalescing) for password/key lifetime fields and password restriction values, preserving existing checks for empty/"Select a value" entries and ISO duration conversion logic.
Handle {label,value} inputs for settings
Unwrap frontend autoComplete values into plain strings and convert day-based lifetime inputs into ISO 8601 duration strings. Rework how desired credential restrictions are built: replace the previous generic defs/loop with explicit construction of desiredPasswordCredentials, mirror passwordAddition state for symmetricKeyAddition, and add entries for customPasswordAddition, passwordLifetime and symmetricKeyLifetime when provided. Also rename the UI label from "Custom Password Addition" to "Custom Password".
Handle autocomplete inputs and ISO durations
Ensure stable ordering of password/key credential arrays by sorting both desired and current application/servicePrincipal restrictions by restrictionType. Use the sorted arrays when building the desired state and when constructing CurrentValue so comparisons aren't affected by Graph API ordering. Replace multiple per-property JSON comparisons with a single whole-object JSON comparison for clarity and to avoid false diffs due to ordering.
Sort credential arrays before comparing
Replace Sort-Object -Property with a script block ({ $_.restrictionType }) because the items are hashtables, not PSCustomObjects. This ensures desiredPasswordCredentials and desiredKeyCredentials are sorted correctly so their order matches Graph API responses.
Use script block in Sort-Object for hashtables
Add support for syncing M365 Conditional Access Policies into ITGlue flexible assets. This change adds CAPTypeId mapping and pulls ConditionalAccessPolicies from the extension cache, creates required flexible-asset fields, builds an HTML summary for each policy, and upserts flexible assets (create or PATCH). It also deletes orphaned assets no longer present in M365 and records logs/errors. Minor variable assignments and small sleep between requests included for rate control and stability.
Introduce full support for syncing Microsoft 365 Conditional Access Policies (CAPs) into ITGlue and refactor ITGlue sync logic for more efficient updates. Changes: - Added private helpers: Add-ITGlueFlexibleAssetFields (batch-add flexible asset fields), Format-ITGlueCAPValue (format newline lists), and Sync-ITGlueConditionalAccessPolicies (create/update/delete CAP flexible assets, HTML details, hash-based change detection, caching). - Extended Get-ITGlueFieldMapping to include ConditionalAccessPolicies mapping key. - Heavily refactored Invoke-ITGlueExtensionSync to: - Use a centralized asset cache table and hash-based detection to skip unchanged assets (users, devices, CAPs). Timestamps are excluded from hashes so only real content changes trigger updates. - Batch field additions via Add-ITGlueFlexibleAssetFields and auto-create a Conditional Access Policy flexible asset type if missing. - Support create/update/delete flows for users, devices, configurations and CAP flexible assets, with cache maintenance and improved logging/metrics (updated vs unchanged counts). - Improve HTML quick-notes replacement logic for organization overview. Why: reduce unnecessary API calls and updates, add CAP syncing capability, and simplify management of flexible asset fields and change detection.
…-API into feature/itglue
Merged
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
No description provided.