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
-
+