From 95c31b823b11d8c7b20a28de29c821f9a826708e Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Fri, 19 Jun 2026 22:48:01 +0800 Subject: [PATCH 1/7] Update CIPPDBCacheTypes.json --- src/data/CIPPDBCacheTypes.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/data/CIPPDBCacheTypes.json b/src/data/CIPPDBCacheTypes.json index 0d0588d2b624..f86f7d59b03d 100644 --- a/src/data/CIPPDBCacheTypes.json +++ b/src/data/CIPPDBCacheTypes.json @@ -328,5 +328,10 @@ "type": "DetectedApps", "friendlyName": "Detected Apps", "description": "All detected applications with devices where each app is installed" + }, + { + "type": "IntuneAppInstallStatus", + "friendlyName": "Intune App Install Status", + "description": "Per-application install status rollup (failed/installed/pending device counts) from the AppInstallStatusAggregate report" } ] From 2403bd4842bb14973306f76d8162f6b06ac56d38 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Fri, 19 Jun 2026 22:49:26 +0800 Subject: [PATCH 2/7] Update alerts.json --- src/data/alerts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/alerts.json b/src/data/alerts.json index e0f7ffc9b9a8..9c907c4f5e92 100644 --- a/src/data/alerts.json +++ b/src/data/alerts.json @@ -391,7 +391,7 @@ { "name": "IntunePolicyConflicts", "label": "Alert on Intune policy or app conflicts/errors", - "recommendedRunInterval": "4h", + "recommendedRunInterval": "1d", "requiresInput": true, "multipleInput": true, "inputs": [ From b08e7047fe0f40f6faeeabfd7c723b60da6f2eac Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Mon, 22 Jun 2026 14:52:21 +0800 Subject: [PATCH 3/7] Update CippUserActions.jsx --- src/components/CippComponents/CippUserActions.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/CippComponents/CippUserActions.jsx b/src/components/CippComponents/CippUserActions.jsx index 2ac784716799..deaa03a68fac 100644 --- a/src/components/CippComponents/CippUserActions.jsx +++ b/src/components/CippComponents/CippUserActions.jsx @@ -451,6 +451,7 @@ export const useCippUserActions = () => { confirmText: 'Are you sure you want to create a Temporary Access Pass for [userPrincipalName]?', multiPost: false, + allowResubmit: true, condition: () => canWriteUser, }, { From 64c492c883081f51a7f806df8e03bccf8fc696ff Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Mon, 22 Jun 2026 21:17:28 +0800 Subject: [PATCH 4/7] Custom Test Engine Changes --- src/pages/tools/custom-tests/add.jsx | 85 +++++++++++----------------- 1 file changed, 33 insertions(+), 52 deletions(-) diff --git a/src/pages/tools/custom-tests/add.jsx b/src/pages/tools/custom-tests/add.jsx index e4da31a623c5..928795ee3fca 100644 --- a/src/pages/tools/custom-tests/add.jsx +++ b/src/pages/tools/custom-tests/add.jsx @@ -814,10 +814,12 @@ All UPNs: {{join(Result[*].UserPrincipalName, ", ")}}`, - AST allowlist — approved cmdlets only. += is blocked. Data access - is automatically tenant-locked — do not pass{' '} - -TenantFilter. Type % in the editor for replacement - variables. + Runs in PowerShell ConstrainedLanguage — approved cmdlets + only. New-Object, {'[pscustomobject]@{}'} casts, and + .NET/reflection are blocked. Build rows with{' '} + {'Select-Object @{Name;Expression}'} and return a plain{' '} + {'@{}'} hashtable. Data access is tenant-locked — do not pass{' '} + -TenantFilter. Type % for replacement variables. @@ -907,20 +909,11 @@ $Licenses | ForEach-Object { # Build results - users with their resolved license names $results = $Users | Where-Object { $_.assignedLicenses.Count -gt 0 -} | ForEach-Object { - $user = $_ - $licenseNames = @($user.assignedLicenses | ForEach-Object { - $name = $SkuLookup[$_.skuId] - if ($name) { $name } else { $_.skuId } - }) - [PSCustomObject]@{ - UserPrincipalName = $user.userPrincipalName - DisplayName = $user.displayName - AccountEnabled = $user.accountEnabled - LicenseCount = $licenseNames.Count - Licenses = $licenseNames -join ', ' - } -} +} | Select-Object @{Name='UserPrincipalName'; Expression={ $_.userPrincipalName }}, + @{Name='DisplayName'; Expression={ $_.displayName }}, + @{Name='AccountEnabled'; Expression={ $_.accountEnabled }}, + @{Name='LicenseCount'; Expression={ @($_.assignedLicenses).Count }}, + @{Name='Licenses'; Expression={ (@($_.assignedLicenses | ForEach-Object { $n = $SkuLookup[$_.skuId]; if ($n) { $n } else { $_.skuId } }) -join ', ') }} # Build markdown table $header = "### Licensed Users: $($results.Count)\\n\\n| User | Display Name | Enabled | Licenses |\\n|---|---|---|---|" @@ -968,14 +961,10 @@ $Users = Get-CIPPTestData -Type 'Users' $Users | Where-Object { $_.accountEnabled -eq $false -and $_.assignedLicenses.Count -gt 0 -} | ForEach-Object { - [PSCustomObject]@{ - UserPrincipalName = $_.userPrincipalName - DisplayName = $_.displayName - LicenseCount = $_.assignedLicenses.Count - Message = 'Disabled account with active license(s)' - } -}`} +} | Select-Object @{Name='UserPrincipalName'; Expression={ $_.userPrincipalName }}, + @{Name='DisplayName'; Expression={ $_.displayName }}, + @{Name='LicenseCount'; Expression={ @($_.assignedLicenses).Count }}, + @{Name='Message'; Expression={ 'Disabled account with active license(s)' }}`} language="powershell" showLineNumbers={true} /> @@ -1008,14 +997,10 @@ $RegDetails = Get-CIPPTestData -Type 'UserRegistrationDetails' $noMfa = $RegDetails | Where-Object { $_.methodsRegistered.Count -eq 0 -and $_.userType -ne 'guest' -} | ForEach-Object { - [PSCustomObject]@{ - UserPrincipalName = $_.userPrincipalName - UserDisplayName = $_.userDisplayName - IsAdmin = $_.isAdmin - Message = 'No MFA methods registered' - } -} +} | Select-Object @{Name='UserPrincipalName'; Expression={ $_.userPrincipalName }}, + @{Name='UserDisplayName'; Expression={ $_.userDisplayName }}, + @{Name='IsAdmin'; Expression={ $_.isAdmin }}, + @{Name='Message'; Expression={ 'No MFA methods registered' }} $count = @($noMfa).Count if ($count -gt 0) { @@ -1068,18 +1053,11 @@ $cutoff = (Get-Date).AddDays(-$DaysThreshold) $Guests | Where-Object { -not $_.signInActivity.lastSignInDateTime -or [datetime]$_.signInActivity.lastSignInDateTime -lt $cutoff -} | ForEach-Object { - $lastSign = if ($_.signInActivity.lastSignInDateTime) { - $_.signInActivity.lastSignInDateTime - } else { 'Never' } - [PSCustomObject]@{ - UserPrincipalName = $_.userPrincipalName - DisplayName = $_.displayName - CreatedDateTime = $_.createdDateTime - LastSignIn = $lastSign - Message = "No sign-in within $DaysThreshold days" - } -}`} +} | Select-Object @{Name='UserPrincipalName'; Expression={ $_.userPrincipalName }}, + @{Name='DisplayName'; Expression={ $_.displayName }}, + @{Name='CreatedDateTime'; Expression={ $_.createdDateTime }}, + @{Name='LastSignIn'; Expression={ if ($_.signInActivity.lastSignInDateTime) { $_.signInActivity.lastSignInDateTime } else { 'Never' } }}, + @{Name='Message'; Expression={ "No sign-in within $DaysThreshold days" }}`} language="powershell" showLineNumbers={true} /> @@ -1111,12 +1089,8 @@ $Guests | Where-Object { $Policies = Get-CIPPTestData -Type 'ConditionalAccessPolicies' $grouped = $Policies | Group-Object -Property state -$counts = $grouped | ForEach-Object { - [PSCustomObject]@{ - State = $_.Name - Count = $_.Count - } -} +$counts = $grouped | Select-Object @{Name='State'; Expression={ $_.Name }}, + @{Name='Count'; Expression={ $_.Count }} # Build markdown summary — %tenantname% is replaced at runtime $header = "### %tenantname% — CA Policies: $(@($Policies).Count) total\n\n| State | Count |\n|---|---|" @@ -1428,6 +1402,13 @@ $md = $summaryTable + "\n\n---\n\n" + $policyTable Type % to insert replacement variables (e.g.{' '} %tenantid%, %defaultdomain%, or custom variables). + + Scripts run in ConstrainedLanguage. Build output rows with{' '} + {'Select-Object @{Name;Expression}'} (not{' '} + {'[pscustomobject]@{}'}) and return a{' '} + {'@{ CIPPStatus = ... }'} hashtable. New-Object and + .NET reflection are blocked. + {hasTenantFilterParam && ( -TenantFilter is not needed — data access functions are From aaaff43aeee37ba90bcc82b40237b53fae5f20ed Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 22 Jun 2026 10:06:57 -0400 Subject: [PATCH 5/7] fix: remove parameters from API call --- src/components/ReleaseNotesDialog.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/ReleaseNotesDialog.js b/src/components/ReleaseNotesDialog.js index 5b99535d1c36..6bc2c53cabb6 100644 --- a/src/components/ReleaseNotesDialog.js +++ b/src/components/ReleaseNotesDialog.js @@ -168,11 +168,7 @@ export const ReleaseNotesDialog = forwardRef((_props, ref) => { const releaseListQuery = ApiGetCall({ url: '/api/ListGitHubReleaseNotes', - queryKey: 'list-github-release-options', - data: { - Owner: RELEASE_OWNER, - Repository: RELEASE_REPO, - }, + queryKey: `list-github-release-options`, waiting: shouldFetchReleaseList, staleTime: 300000, }) @@ -484,7 +480,13 @@ export const ReleaseNotesDialog = forwardRef((_props, ref) => { > View release notes on GitHub - +