From 29685d69b00fcc1cb774ae60600cd7607d2520b1 Mon Sep 17 00:00:00 2001 From: Bobby <31723128+kris6673@users.noreply.github.com> Date: Mon, 4 May 2026 22:54:54 +0200 Subject: [PATCH 01/38] feat(api): add license capability presets Centralize common Test-CIPPStandardLicense capability sets behind presets and migrate exact-match call sites to use them. --- .github/agents/CIPP-Alert-Agent.md | 13 +- .github/agents/CIPP-Standards-Agent.md | 1 + .github/instructions/alerts.instructions.md | 7 +- .github/instructions/cippdb.instructions.md | 4 +- .../instructions/standards.instructions.md | 8 +- .../Push-CIPPDBCacheData.ps1 | 14 +- .../Standards/Push-CIPPStandardsList.ps1 | 4 +- .../Get-CIPPAlertIntunePolicyConflicts.ps1 | 19 +-- ...Get-CIPPAlertQuarantineReleaseRequests.ps1 | 8 +- .../Functions/Test-CIPPStandardLicense.ps1 | 39 ++++- Modules/CIPPCore/Public/Get-CIPPDrift.ps1 | 4 +- .../CIPPCore/Public/Test-CIPPAccessTenant.ps1 | 2 +- ...t-CIPPDBCacheConditionalAccessPolicies.ps1 | 2 +- .../Set-CIPPDBCacheDlpCompliancePolicies.ps1 | 2 +- .../DBCache/Set-CIPPDBCacheIntunePolicies.ps1 | 2 +- .../DBCache/Set-CIPPDBCachePIMSettings.ps1 | 2 +- .../Set-CIPPDBCacheSensitivityLabels.ps1 | 2 +- .../Public/DBCache/Set-CIPPDBCacheUsers.ps1 | 2 +- .../Standards/Invoke-CIPPStandardAddDKIM.ps1 | 2 +- .../Invoke-CIPPStandardAntiPhishPolicy.ps1 | 2 +- .../Invoke-CIPPStandardAntiSpamSafeList.ps1 | 2 +- ...e-CIPPStandardAssignmentFilterTemplate.ps1 | 2 +- .../Invoke-CIPPStandardAtpPolicyForO365.ps1 | 2 +- .../Standards/Invoke-CIPPStandardAuditLog.ps1 | 2 +- .../Invoke-CIPPStandardAutoArchive.ps1 | 2 +- .../Invoke-CIPPStandardAutoArchiveMailbox.ps1 | 2 +- .../Invoke-CIPPStandardAutoExpandArchive.ps1 | 2 +- .../Invoke-CIPPStandardAutopilotProfile.ps1 | 2 +- ...Invoke-CIPPStandardAutopilotStatusPage.ps1 | 2 +- .../Standards/Invoke-CIPPStandardBookings.ps1 | 2 +- .../Standards/Invoke-CIPPStandardBranding.ps1 | 2 +- .../Invoke-CIPPStandardCloudMessageRecall.ps1 | 2 +- ...IPPStandardColleagueImpersonationAlert.ps1 | 2 +- ...-CIPPStandardConditionalAccessTemplate.ps1 | 6 +- ...e-CIPPStandardCustomBannedPasswordList.ps1 | 2 +- ...IPPStandardDefaultPlatformRestrictions.ps1 | 2 +- .../Invoke-CIPPStandardDefaultSharingLink.ps1 | 2 +- .../Invoke-CIPPStandardDelegateSentItems.ps1 | 2 +- ...voke-CIPPStandardDeletedUserRentention.ps1 | 2 +- ...CIPPStandardDeployCheckChromeExtension.ps1 | 2 +- ...oke-CIPPStandardDeployContactTemplates.ps1 | 2 +- .../Invoke-CIPPStandardDeployMailContact.ps1 | 2 +- ...PStandardDisableAddShortcutsToOneDrive.ps1 | 2 +- ...ndardDisableAdditionalStorageProviders.ps1 | 2 +- ...nvoke-CIPPStandardDisableBasicAuthSMTP.ps1 | 2 +- .../Invoke-CIPPStandardDisableEWS.ps1 | 2 +- ...tandardDisableExchangeOnlinePowerShell.ps1 | 2 +- ...StandardDisableExternalCalendarSharing.ps1 | 2 +- .../Invoke-CIPPStandardDisableGuests.ps1 | 2 +- ...voke-CIPPStandardDisableM365GroupUsers.ps1 | 2 +- ...nvoke-CIPPStandardDisableOutlookAddins.ps1 | 2 +- .../Invoke-CIPPStandardDisableReshare.ps1 | 2 +- ...oke-CIPPStandardDisableResourceMailbox.ps1 | 2 +- ...IPPStandardDisableSharePointLegacyAuth.ps1 | 2 +- .../Invoke-CIPPStandardDisableTNEF.ps1 | 2 +- ...voke-CIPPStandardDisableUserSiteCreate.ps1 | 2 +- ...e-CIPPStandardEXODisableAutoForwarding.ps1 | 2 +- ...voke-CIPPStandardEXOOutboundSpamLimits.ps1 | 2 +- ...PStandardEnableExchangeCloudManagement.ps1 | 2 +- ...nvoke-CIPPStandardEnableLitigationHold.ps1 | 2 +- .../Invoke-CIPPStandardEnableMailTips.ps1 | 2 +- ...voke-CIPPStandardEnableMailboxAuditing.ps1 | 2 +- ...voke-CIPPStandardEnableOnlineArchiving.ps1 | 2 +- ...ntWindowsHelloForBusinessConfiguration.ps1 | 2 +- ...-CIPPStandardExchangeConnectorTemplate.ps1 | 2 +- .../Invoke-CIPPStandardExcludedfileExt.ps1 | 2 +- .../Invoke-CIPPStandardFocusedInbox.ps1 | 2 +- ...PStandardGlobalQuarantineNotifications.ps1 | 2 +- ...e-CIPPStandardGlobalQuarantineSettings.ps1 | 2 +- .../Invoke-CIPPStandardGroupTemplate.ps1 | 4 +- ...e-CIPPStandardIntuneComplianceSettings.ps1 | 2 +- ...ke-CIPPStandardIntuneWindowsDiagnostic.ps1 | 2 +- ...tandardMDMEnrollmentDuringRegistration.ps1 | 2 +- .../Standards/Invoke-CIPPStandardMDMScope.ps1 | 2 +- ...oke-CIPPStandardMailboxRecipientLimits.ps1 | 2 +- ...Invoke-CIPPStandardMalwareFilterPolicy.ps1 | 2 +- .../Invoke-CIPPStandardMessageExpiration.ps1 | 2 +- .../Invoke-CIPPStandardOMEBranding.ps1 | 2 +- ...-CIPPStandardOWAAttachmentRestrictions.ps1 | 2 +- .../Invoke-CIPPStandardOutBoundSpamAlert.ps1 | 2 +- .../Invoke-CIPPStandardPhishProtection.ps1 | 2 +- ...-CIPPStandardPhishSimSpoofIntelligence.ps1 | 2 +- ...Invoke-CIPPStandardPhishingSimulations.ps1 | 2 +- .../Invoke-CIPPStandardProfilePhotos.ps1 | 2 +- ...oke-CIPPStandardQuarantineRequestAlert.ps1 | 2 +- .../Invoke-CIPPStandardQuarantineTemplate.ps1 | 2 +- ...ndardRestrictThirdPartyStorageServices.ps1 | 2 +- .../Invoke-CIPPStandardRetentionPolicyTag.ps1 | 2 +- ...e-CIPPStandardReusableSettingsTemplate.ps1 | 5 +- .../Invoke-CIPPStandardRotateDKIM.ps1 | 2 +- .../Invoke-CIPPStandardSPAzureB2B.ps1 | 2 +- .../Invoke-CIPPStandardSPDirectSharing.ps1 | 2 +- ...oke-CIPPStandardSPDisableCustomScripts.ps1 | 2 +- ...e-CIPPStandardSPDisableLegacyWorkflows.ps1 | 2 +- ...nvoke-CIPPStandardSPDisableStoreAccess.ps1 | 2 +- ...ke-CIPPStandardSPDisallowInfectedFiles.ps1 | 2 +- .../Invoke-CIPPStandardSPEmailAttestation.ps1 | 2 +- ...e-CIPPStandardSPExternalUserExpiration.ps1 | 2 +- .../Invoke-CIPPStandardSPFileRequests.ps1 | 2 +- .../Invoke-CIPPStandardSPSyncButtonState.ps1 | 2 +- ...nvoke-CIPPStandardSafeAttachmentPolicy.ps1 | 2 +- .../Invoke-CIPPStandardSafeLinksPolicy.ps1 | 2 +- ...ke-CIPPStandardSafeLinksTemplatePolicy.ps1 | 2 +- .../Invoke-CIPPStandardSafeSendersDisable.ps1 | 2 +- .../Invoke-CIPPStandardSendFromAlias.ps1 | 2 +- ...oke-CIPPStandardSendReceiveLimitTenant.ps1 | 2 +- .../Invoke-CIPPStandardShortenMeetings.ps1 | 2 +- .../Invoke-CIPPStandardSpamFilterPolicy.ps1 | 2 +- .../Invoke-CIPPStandardSpoofWarn.ps1 | 2 +- .../Invoke-CIPPStandardStaleEntraDevices.ps1 | 2 +- ...Invoke-CIPPStandardTeamsChatProtection.ps1 | 2 +- ...voke-CIPPStandardTeamsEmailIntegration.ps1 | 2 +- .../Invoke-CIPPStandardTeamsEnrollUser.ps1 | 2 +- ...-CIPPStandardTeamsExternalAccessPolicy.ps1 | 2 +- ...IPPStandardTeamsExternalChatWithAnyone.ps1 | 2 +- ...e-CIPPStandardTeamsExternalFileSharing.ps1 | 2 +- ...PPStandardTeamsFederationConfiguration.ps1 | 2 +- ...e-CIPPStandardTeamsGlobalMeetingPolicy.ps1 | 2 +- .../Invoke-CIPPStandardTeamsGuestAccess.ps1 | 2 +- ...tandardTeamsMeetingRecordingExpiration.ps1 | 2 +- ...e-CIPPStandardTeamsMeetingVerification.ps1 | 2 +- ...oke-CIPPStandardTeamsMeetingsByDefault.ps1 | 2 +- ...nvoke-CIPPStandardTeamsMessagingPolicy.ps1 | 2 +- ...PPStandardTenantAllowBlockListTemplate.ps1 | 2 +- ...voke-CIPPStandardTenantDefaultTimezone.ps1 | 2 +- ...voke-CIPPStandardTransportRuleTemplate.ps1 | 2 +- ...ke-CIPPStandardTwoClickEmailProtection.ps1 | 2 +- .../Invoke-CIPPStandardUserSubmissions.ps1 | 2 +- ...nvoke-CIPPStandardWindowsBackupRestore.ps1 | 2 +- .../Invoke-CIPPStandardcalDefault.ps1 | 2 +- .../Invoke-CIPPStandarddisableMacSync.ps1 | 2 +- ...voke-CIPPStandardintuneBrandingProfile.ps1 | 2 +- .../Invoke-CIPPStandardintuneDeviceReg.ps1 | 2 +- ...CIPPStandardintuneDeviceRetirementDays.ps1 | 2 +- .../Invoke-CIPPStandardsharingCapability.ps1 | 2 +- ...e-CIPPStandardsharingDomainRestriction.ps1 | 2 +- .../Invoke-CIPPStandardunmanagedSync.ps1 | 2 +- Tools/Update-StandardsComments.ps1 | 153 ++++++++++++++++-- 138 files changed, 337 insertions(+), 198 deletions(-) diff --git a/.github/agents/CIPP-Alert-Agent.md b/.github/agents/CIPP-Alert-Agent.md index b698cfef4eb5..b2aa3e90c887 100644 --- a/.github/agents/CIPP-Alert-Agent.md +++ b/.github/agents/CIPP-Alert-Agent.md @@ -102,16 +102,13 @@ When adding or modifying alerts: When an alert depends on a tenant having certain SKUs or capabilities, you **must**: -- Use `Test-CIPPStandardLicense` +- Use `Test-CIPPStandardLicense` +- Prefer `-Preset` for common capability sets: `Exchange`, `SharePoint`, `Intune`, `Entra`, `EntraP2`, `Teams`, `Compliance` +- Use `-RequiredCapabilities` only when no preset matches, or combine it with `-Preset` for extra edge-case capabilities - Do **not** manually inspect SKUs, raw license IDs, or raw capability lists. Example pattern (adapt to the specific feature): ```powershell -$TestResult = Test-CIPPStandardLicense -StandardName 'AutopilotProfile' -TenantFilter $Tenant -RequiredCapabilities @( - 'INTUNE_A', - 'MDM_Services', - 'EMS', - 'SCCM', - 'MICROSOFTINTUNEPLAN1' -) +$TestResult = Test-CIPPStandardLicense -StandardName 'AutopilotProfile' -TenantFilter $Tenant -Preset Intune +``` diff --git a/.github/agents/CIPP-Standards-Agent.md b/.github/agents/CIPP-Standards-Agent.md index ed5529cefe5c..506a3ee4edb8 100644 --- a/.github/agents/CIPP-Standards-Agent.md +++ b/.github/agents/CIPP-Standards-Agent.md @@ -82,6 +82,7 @@ When adding or modifying standards: - Similar logging and error handling - Reuse helper functions instead of inlining raw Graph calls or custom HTTP code. - Keep behaviour predictable. +- If a standard needs license gating, use `Test-CIPPStandardLicense` with `-Preset` for common capability sets (`Exchange`, `SharePoint`, `Intune`, `Entra`, `EntraP2`, `Teams`, `Compliance`). Use `-RequiredCapabilities` only when no preset matches, or combine it with `-Preset` for extra edge-case capabilities. ### 2. Return the code for the frontend. diff --git a/.github/instructions/alerts.instructions.md b/.github/instructions/alerts.instructions.md index c5633d083528..a05c31e3721e 100644 --- a/.github/instructions/alerts.instructions.md +++ b/.github/instructions/alerts.instructions.md @@ -97,14 +97,11 @@ if ($InputValue -is [string] -and $InputValue.Trim().StartsWith('{')) { If the alert depends on a specific M365 capability (Intune, Exchange, Defender, etc.), gate it early with `Test-CIPPStandardLicense`. Never inspect raw SKU IDs manually. ```powershell -$Licensed = Test-CIPPStandardLicense -StandardName '' -TenantFilter $TenantFilter -RequiredCapabilities @( - 'INTUNE_A', - 'MDM_Services' -) +$Licensed = Test-CIPPStandardLicense -StandardName '' -TenantFilter $TenantFilter -Preset Intune if (-not $Licensed) { return } ``` -Reference existing alerts in the same domain for common capability strings. The `Test-CIPPStandardLicense` function source documents the capability matching logic. +Use presets for common service families: `Exchange`, `SharePoint`, `Intune`, `Entra`, `EntraP2`, `Teams`, and `Compliance`. Use `-RequiredCapabilities` only when no preset matches, or combine it with `-Preset` when an alert needs a preset plus extra edge-case capabilities. ## Querying data diff --git a/.github/instructions/cippdb.instructions.md b/.github/instructions/cippdb.instructions.md index 19d31e78dcdd..fab2c73c1dad 100644 --- a/.github/instructions/cippdb.instructions.md +++ b/.github/instructions/cippdb.instructions.md @@ -141,7 +141,7 @@ function Set-CIPPDBCacheMyNewType { try { # 1. Optional license check - $Licensed = Test-CIPPStandardLicense -StandardName 'MyFeature' -TenantFilter $TenantFilter -RequiredCapabilities @('REQUIRED_SKU') + $Licensed = Test-CIPPStandardLicense -StandardName 'MyFeature' -TenantFilter $TenantFilter -Preset Intune if (-not $Licensed) { return } # 2. Fetch data from API @@ -160,7 +160,7 @@ function Set-CIPPDBCacheMyNewType { - **Always use `-AddCount`** unless you handle count rows manually - **Pipeline streaming** for large datasets: pipe directly from `New-GraphGetRequest` into `Add-CIPPDbItem` -- **License gating**: use `Test-CIPPStandardLicense` when the API requires specific SKUs +- **License gating**: use `Test-CIPPStandardLicense -Preset ` for common capability sets (`Exchange`, `SharePoint`, `Intune`, `Entra`, `EntraP2`, `Teams`, `Compliance`); use `-RequiredCapabilities` only for non-preset capabilities or additional edge-case capabilities - **Conditional `$select`**: expand Graph `$select` fields based on license capabilities - **Error handling**: catch, log with `Write-LogMessage`, do not rethrow (allows other types in the collection to continue) - **No explicit return** of data — these functions write to the table as a side effect diff --git a/.github/instructions/standards.instructions.md b/.github/instructions/standards.instructions.md index 5897a3bded4d..87c7df972c06 100644 --- a/.github/instructions/standards.instructions.md +++ b/.github/instructions/standards.instructions.md @@ -67,7 +67,7 @@ function Invoke-CIPPStandard { # 1. License gate (if the data source requires a specific SKU) $TestResult = Test-CIPPStandardLicense -StandardName '' -TenantFilter $Tenant ` - -RequiredCapabilities @('CAPABILITY_1', 'CAPABILITY_2') + -Preset Exchange if ($TestResult -eq $false) { return $true } # 2. Get current state @@ -235,13 +235,13 @@ Gate early using `Test-CIPPStandardLicense`. Never inspect raw SKU IDs. ```powershell $TestResult = Test-CIPPStandardLicense -StandardName '' -TenantFilter $Tenant ` - -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE') + -Preset Exchange if ($TestResult -eq $false) { return $true } ``` The function checks tenant capabilities, logs if missing, and automatically sets the `Set-CIPPStandardsCompareField` with `LicenseAvailable = $false`. -Reference existing standards in the same domain for common capability strings. The `Test-CIPPStandardLicense` function source documents the capability matching logic. +Use presets for common service families: `Exchange`, `SharePoint`, `Intune`, `Entra`, `EntraP2`, `Teams`, and `Compliance`. Use `-RequiredCapabilities` only when no preset matches, or combine it with `-Preset` when a standard needs a preset plus extra edge-case capabilities. ## API call patterns @@ -337,7 +337,7 @@ The comment-based help `.NOTES` block drives the frontend UI. Each field maps to | `RECOMMENDEDBY` | `recommendedBy` | `"CIS"`, `"CIPP"`, etc. | | `MULTIPLE` | `multiple` | `True` for template-based standards (can have multiple instances) | | `DISABLEDFEATURES` | `disabledFeatures` | JSON object disabling specific action modes | -| `REQUIREDCAPABILITIES` | *(discovery only)* | One capability string per line; parsed for standards metadata/JSON generation. The explicit `Test-CIPPStandardLicense` call in the function body still performs the actual runtime license check. | +| `REQUIREDCAPABILITIES` | *(discovery only)* | One capability string per line; generated from `Test-CIPPStandardLicense -Preset` and/or `-RequiredCapabilities` for standards metadata/JSON generation. The explicit `Test-CIPPStandardLicense` call in the function body still performs the actual runtime license check. | | `UPDATECOMMENTBLOCK` | *(tooling only)* | Always include with the literal value `Run the Tools\Update-StandardsComments.ps1 script to update this comment block`. Signals the comment-update tooling to regenerate this block. | ### Valid CAT values diff --git a/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-CIPPDBCacheData.ps1 b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-CIPPDBCacheData.ps1 index b52647862dc3..f4f236eca9a8 100644 --- a/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-CIPPDBCacheData.ps1 +++ b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-CIPPDBCacheData.ps1 @@ -27,7 +27,7 @@ function Push-CIPPDBCacheData { # Check tenant capabilities for license-specific features $IntuneCapable = $false try { - $IntuneCapable = Test-CIPPStandardLicense -StandardName 'IntuneLicenseCheck' -TenantFilter $TenantFilter -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') -SkipLog + $IntuneCapable = Test-CIPPStandardLicense -StandardName 'IntuneLicenseCheck' -TenantFilter $TenantFilter -Preset Intune -SkipLog } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Intune license check failed: $($_.Exception.Message)" -sev Warning -LogData $ErrorMessage @@ -35,7 +35,7 @@ function Push-CIPPDBCacheData { $ConditionalAccessCapable = $false try { - $ConditionalAccessCapable = Test-CIPPStandardLicense -StandardName 'ConditionalAccessLicenseCheck' -TenantFilter $TenantFilter -RequiredCapabilities @('AAD_PREMIUM', 'AAD_PREMIUM_P2') -SkipLog + $ConditionalAccessCapable = Test-CIPPStandardLicense -StandardName 'ConditionalAccessLicenseCheck' -TenantFilter $TenantFilter -Preset Entra -SkipLog } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Conditional Access license check failed: $($_.Exception.Message)" -sev Warning -LogData $ErrorMessage @@ -43,7 +43,7 @@ function Push-CIPPDBCacheData { $AzureADPremiumP2Capable = $false try { - $AzureADPremiumP2Capable = Test-CIPPStandardLicense -StandardName 'AzureADPremiumP2LicenseCheck' -TenantFilter $TenantFilter -RequiredCapabilities @('AAD_PREMIUM_P2') -SkipLog + $AzureADPremiumP2Capable = Test-CIPPStandardLicense -StandardName 'AzureADPremiumP2LicenseCheck' -TenantFilter $TenantFilter -Preset EntraP2 -SkipLog } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Azure AD Premium P2 license check failed: $($_.Exception.Message)" -sev Warning -LogData $ErrorMessage @@ -51,7 +51,7 @@ function Push-CIPPDBCacheData { $ExchangeCapable = $false try { - $ExchangeCapable = Test-CIPPStandardLicense -StandardName 'ExchangeLicenseCheck' -TenantFilter $TenantFilter -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') -SkipLog + $ExchangeCapable = Test-CIPPStandardLicense -StandardName 'ExchangeLicenseCheck' -TenantFilter $TenantFilter -Preset Exchange -SkipLog } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Exchange license check failed: $($_.Exception.Message)" -sev Warning -LogData $ErrorMessage @@ -59,7 +59,7 @@ function Push-CIPPDBCacheData { $ComplianceCapable = $false try { - $ComplianceCapable = Test-CIPPStandardLicense -StandardName 'ComplianceLicenseCheck' -TenantFilter $TenantFilter -RequiredCapabilities @('RMS_S_PREMIUM', 'RMS_S_PREMIUM2', 'MIP_S_CLP1', 'MIP_S_CLP2') -SkipLog + $ComplianceCapable = Test-CIPPStandardLicense -StandardName 'ComplianceLicenseCheck' -TenantFilter $TenantFilter -Preset Compliance -SkipLog } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Compliance license check failed: $($_.Exception.Message)" -sev Warning -LogData $ErrorMessage @@ -67,7 +67,7 @@ function Push-CIPPDBCacheData { $SharePointCapable = $false try { - $SharePointCapable = Test-CIPPStandardLicense -StandardName 'SharePointLicenseCheck' -TenantFilter $TenantFilter -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') -SkipLog + $SharePointCapable = Test-CIPPStandardLicense -StandardName 'SharePointLicenseCheck' -TenantFilter $TenantFilter -Preset SharePoint -SkipLog } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "SharePoint license check failed: $($_.Exception.Message)" -sev Warning -LogData $ErrorMessage @@ -75,7 +75,7 @@ function Push-CIPPDBCacheData { $TeamsCapable = $false try { - $TeamsCapable = Test-CIPPStandardLicense -StandardName 'TeamsLicenseCheck' -TenantFilter $TenantFilter -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') -SkipLog + $TeamsCapable = Test-CIPPStandardLicense -StandardName 'TeamsLicenseCheck' -TenantFilter $TenantFilter -Preset Teams -SkipLog } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Teams license check failed: $($_.Exception.Message)" -sev Warning -LogData $ErrorMessage diff --git a/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandardsList.ps1 b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandardsList.ps1 index c07b70ba5489..491bab19fae5 100644 --- a/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandardsList.ps1 +++ b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandardsList.ps1 @@ -38,7 +38,7 @@ function Push-CIPPStandardsList { if ($IntuneTemplateFound) { # Perform license check - $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneTemplate_general' -TenantFilter $TenantFilter -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneTemplate_general' -TenantFilter $TenantFilter -Preset Intune if (-not $TestResult) { # Remove IntuneTemplate standards and set compare fields @@ -253,7 +253,7 @@ function Push-CIPPStandardsList { $CAStandardFound = ($ComputedStandards.Keys.Where({ $_ -like '*ConditionalAccessTemplate*' }, 'First').Count -gt 0) if ($CAStandardFound) { - $TestResult = Test-CIPPStandardLicense -StandardName 'ConditionalAccessTemplate_general' -TenantFilter $TenantFilter -RequiredCapabilities @('AAD_PREMIUM', 'AAD_PREMIUM_P2') + $TestResult = Test-CIPPStandardLicense -StandardName 'ConditionalAccessTemplate_general' -TenantFilter $TenantFilter -Preset Entra if (-not $TestResult) { $CAKeys = @($ComputedStandards.Keys | Where-Object { $_ -like '*ConditionalAccessTemplate*' }) $BulkFields = [System.Collections.Generic.List[object]]::new() diff --git a/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertIntunePolicyConflicts.ps1 b/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertIntunePolicyConflicts.ps1 index d9b2239b1bcb..31469e4d25b9 100644 --- a/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertIntunePolicyConflicts.ps1 +++ b/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertIntunePolicyConflicts.ps1 @@ -56,14 +56,7 @@ function Get-CIPPAlertIntunePolicyConflicts { return } - $HasLicense = Test-CIPPStandardLicense -StandardName 'IntunePolicyStatus' -TenantFilter $TenantFilter -RequiredCapabilities @( - 'INTUNE_A', - 'MDM_Services', - 'EMS', - 'SCCM', - 'MICROSOFTINTUNEPLAN1' - ) - + $HasLicense = Test-CIPPStandardLicense -StandardName 'IntunePolicyStatus' -TenantFilter $TenantFilter -Preset Intune if (-not $HasLicense) { return } @@ -132,11 +125,11 @@ function Get-CIPPAlertIntunePolicyConflicts { $AppCount = ($Issues | Where-Object { $_.Type -eq 'Application' }).Count $AlertData = @([PSCustomObject]@{ - Message = "Found $PolicyCount policy issues and $AppCount application issues in Intune." - Tenant = $TenantFilter - PolicyIssues = $PolicyCount - AppIssues = $AppCount - Issues = $Issues + Message = "Found $PolicyCount policy issues and $AppCount application issues in Intune." + Tenant = $TenantFilter + PolicyIssues = $PolicyCount + AppIssues = $AppCount + Issues = $Issues }) } else { $AlertData = $Issues diff --git a/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertQuarantineReleaseRequests.ps1 b/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertQuarantineReleaseRequests.ps1 index 34e45a3cb853..cc6795457cf1 100644 --- a/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertQuarantineReleaseRequests.ps1 +++ b/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertQuarantineReleaseRequests.ps1 @@ -16,13 +16,7 @@ if ($Rerun) { return } - $HasLicense = Test-CIPPStandardLicense -StandardName 'QuarantineReleaseRequests' -TenantFilter $TenantFilter -RequiredCapabilities @( - 'EXCHANGE_S_STANDARD', - 'EXCHANGE_S_ENTERPRISE', - 'EXCHANGE_S_STANDARD_GOV', - 'EXCHANGE_S_ENTERPRISE_GOV', - 'EXCHANGE_LITE' - ) + $HasLicense = Test-CIPPStandardLicense -StandardName 'QuarantineReleaseRequests' -TenantFilter $TenantFilter -Preset Exchange if (-not $HasLicense) { return diff --git a/Modules/CIPPCore/Public/Functions/Test-CIPPStandardLicense.ps1 b/Modules/CIPPCore/Public/Functions/Test-CIPPStandardLicense.ps1 index 851822afe56c..f6e745ddd3e9 100644 --- a/Modules/CIPPCore/Public/Functions/Test-CIPPStandardLicense.ps1 +++ b/Modules/CIPPCore/Public/Functions/Test-CIPPStandardLicense.ps1 @@ -10,13 +10,17 @@ function Test-CIPPStandardLicense { .PARAMETER TenantFilter The tenant to check licensing for .PARAMETER RequiredCapabilities - Array of required capabilities for the standard + Array of required capabilities for the standard. Can be combined with Preset for edge cases. + .PARAMETER Preset + One or more predefined capability sets to check for the standard .FUNCTIONALITY Internal .EXAMPLE Test-CIPPStandardLicense -StandardName "ConditionalAccessTemplate" -TenantFilter "contoso.onmicrosoft.com" -RequiredCapabilities @('AADPremiumService') .EXAMPLE Test-CIPPStandardLicense -StandardName "SafeLinksPolicy" -TenantFilter "contoso.onmicrosoft.com" -RequiredCapabilities @('DEFENDER_FOR_OFFICE_365_PLAN_1', 'DEFENDER_FOR_OFFICE_365_PLAN_2') + .EXAMPLE + Test-CIPPStandardLicense -StandardName "TeamsGuestAccess" -TenantFilter "contoso.onmicrosoft.com" -Preset Teams #> [CmdletBinding()] param( @@ -26,13 +30,44 @@ function Test-CIPPStandardLicense { [Parameter(Mandatory = $true)] [string]$TenantFilter, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [string[]]$RequiredCapabilities, + [Parameter(Mandatory = $false)] + [ValidateSet('Exchange', 'SharePoint', 'Intune', 'Entra', 'EntraP2', 'Teams', 'Compliance')] + [string[]]$Preset, + [Parameter(Mandatory = $false)] [switch]$SkipLog ) + $Presets = @{ + Exchange = @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', + 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', + 'EXCHANGE_LITE') + SharePoint = @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', + 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', + 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + Intune = @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + Entra = @('AAD_PREMIUM', 'AAD_PREMIUM_P2') + EntraP2 = @('AAD_PREMIUM_P2') + Teams = @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + Compliance = @('RMS_S_PREMIUM', 'RMS_S_PREMIUM2', 'MIP_S_CLP1', 'MIP_S_CLP2') + } + + if ((!$Preset -or $Preset.Count -eq 0) -and (!$RequiredCapabilities -or $RequiredCapabilities.Count -eq 0)) { + throw 'Test-CIPPStandardLicense requires either -Preset or -RequiredCapabilities.' + } + + if ($Preset) { + $RequiredCapabilities = @( + $RequiredCapabilities + foreach ($CapabilityPreset in $Preset) { + $Presets[$CapabilityPreset] + } + ) | Where-Object { $_ } | Select-Object -Unique + } + try { $TenantCapabilities = Get-CIPPTenantCapabilities -TenantFilter $TenantFilter diff --git a/Modules/CIPPCore/Public/Get-CIPPDrift.ps1 b/Modules/CIPPCore/Public/Get-CIPPDrift.ps1 index 0c9f4fb305bd..8c185c51602d 100644 --- a/Modules/CIPPCore/Public/Get-CIPPDrift.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPDrift.ps1 @@ -29,8 +29,8 @@ function Get-CIPPDrift { [switch]$AllTenants ) - $IntuneCapable = Test-CIPPStandardLicense -StandardName 'IntuneTemplate_general' -TenantFilter $TenantFilter -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') - $ConditionalAccessCapable = Test-CIPPStandardLicense -StandardName 'ConditionalAccessTemplate_general' -TenantFilter $TenantFilter -RequiredCapabilities @('AAD_PREMIUM', 'AAD_PREMIUM_P2') + $IntuneCapable = Test-CIPPStandardLicense -StandardName 'IntuneTemplate_general' -TenantFilter $TenantFilter -Preset Intune + $ConditionalAccessCapable = Test-CIPPStandardLicense -StandardName 'ConditionalAccessTemplate_general' -TenantFilter $TenantFilter -Preset Entra $IntuneTable = Get-CippTable -tablename 'templates' # Always load templates for display name resolution, even if tenant doesn't have licenses diff --git a/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 b/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 index c3eda8370f7f..66c987c0d00f 100644 --- a/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 @@ -116,7 +116,7 @@ function Test-CIPPAccessTenant { $ExchangeLicenseCapable = $true $ExchangeSkippedByLicense = $false try { - $ExchangeLicenseCapable = Test-CIPPStandardLicense -StandardName 'ExchangeAccessCheck' -TenantFilter $Tenant.customerId -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') -SkipLog + $ExchangeLicenseCapable = Test-CIPPStandardLicense -StandardName 'ExchangeAccessCheck' -TenantFilter $Tenant.customerId -Preset Exchange -SkipLog } catch { $ErrorMessage = Get-CippException -Exception $_ Write-LogMessage -headers $Headers -API $APINAME -tenant $tenant.defaultDomainName -message "Exchange license capability check failed. Continuing with Exchange access validation. Error: $($ErrorMessage.NormalizedError)" -Sev 'Warning' -LogData $ErrorMessage diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 index bb516877c6c8..d5bd3ec19cde 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 @@ -17,7 +17,7 @@ function Set-CIPPDBCacheConditionalAccessPolicies { ) try { - $TestResult = Test-CIPPStandardLicense -StandardName 'ConditionalAccessCache' -TenantFilter $TenantFilter -RequiredCapabilities @('AAD_PREMIUM', 'AAD_PREMIUM_P2') -SkipLog + $TestResult = Test-CIPPStandardLicense -StandardName 'ConditionalAccessCache' -TenantFilter $TenantFilter -Preset Entra -SkipLog if ($TestResult -eq $false) { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Tenant does not have Azure AD Premium license, skipping CA' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDlpCompliancePolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDlpCompliancePolicies.ps1 index 52df23f538dd..776b868f163d 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDlpCompliancePolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDlpCompliancePolicies.ps1 @@ -17,7 +17,7 @@ function Set-CIPPDBCacheDlpCompliancePolicies { ) try { - $LicenseCheck = Test-CIPPStandardLicense -StandardName 'DlpCompliancePoliciesCache' -TenantFilter $TenantFilter -RequiredCapabilities @('RMS_S_PREMIUM', 'RMS_S_PREMIUM2', 'MIP_S_CLP1', 'MIP_S_CLP2') -SkipLog + $LicenseCheck = Test-CIPPStandardLicense -StandardName 'DlpCompliancePoliciesCache' -TenantFilter $TenantFilter -Preset Compliance -SkipLog if ($LicenseCheck -eq $false) { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Tenant does not have a Purview/AIP license, skipping DLP compliance policies' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntunePolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntunePolicies.ps1 index f770d4c37cea..427965a7b3a0 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntunePolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntunePolicies.ps1 @@ -17,7 +17,7 @@ function Set-CIPPDBCacheIntunePolicies { ) try { - $TestResult = Test-CIPPStandardLicense -StandardName 'IntunePoliciesCache' -TenantFilter $TenantFilter -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') -SkipLog + $TestResult = Test-CIPPStandardLicense -StandardName 'IntunePoliciesCache' -TenantFilter $TenantFilter -Preset Intune -SkipLog if ($TestResult -eq $false) { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Tenant does not have Intune license, skipping' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCachePIMSettings.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCachePIMSettings.ps1 index 768525f69e94..d5da952cec5c 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCachePIMSettings.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCachePIMSettings.ps1 @@ -17,7 +17,7 @@ function Set-CIPPDBCachePIMSettings { ) try { - $TestResult = Test-CIPPStandardLicense -StandardName 'PIMSettingsCache' -TenantFilter $TenantFilter -RequiredCapabilities @('AAD_PREMIUM_P2') -SkipLog + $TestResult = Test-CIPPStandardLicense -StandardName 'PIMSettingsCache' -TenantFilter $TenantFilter -Preset EntraP2 -SkipLog if ($TestResult -eq $false) { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Tenant does not have Azure AD Premium P2 license, skipping PIM' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSensitivityLabels.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSensitivityLabels.ps1 index deafb9b25f9c..b9d89242742a 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSensitivityLabels.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSensitivityLabels.ps1 @@ -17,7 +17,7 @@ function Set-CIPPDBCacheSensitivityLabels { ) try { - $LicenseCheck = Test-CIPPStandardLicense -StandardName 'SensitivityLabelsCache' -TenantFilter $TenantFilter -RequiredCapabilities @('RMS_S_PREMIUM', 'RMS_S_PREMIUM2', 'MIP_S_CLP1', 'MIP_S_CLP2') -SkipLog + $LicenseCheck = Test-CIPPStandardLicense -StandardName 'SensitivityLabelsCache' -TenantFilter $TenantFilter -Preset Compliance -SkipLog if ($LicenseCheck -eq $false) { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Tenant does not have a Purview/AIP license, skipping sensitivity labels' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheUsers.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheUsers.ps1 index e987260ab09b..e78271e0650f 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheUsers.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheUsers.ps1 @@ -19,7 +19,7 @@ function Set-CIPPDBCacheUsers { try { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching users' -sev Debug - $SignInLogsCapable = Test-CIPPStandardLicense -StandardName 'UserSignInLogsCapable' -TenantFilter $TenantFilter -RequiredCapabilities @('AAD_PREMIUM', 'AAD_PREMIUM_P2') -SkipLog + $SignInLogsCapable = Test-CIPPStandardLicense -StandardName 'UserSignInLogsCapable' -TenantFilter $TenantFilter -Preset Entra -SkipLog # Base properties needed by tests, standards, reports, UI, and integrations (Hudu, NinjaOne) $BaseSelect = @( diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 index 4597ea7d6068..e45c433b2244 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 @@ -42,7 +42,7 @@ function Invoke-CIPPStandardAddDKIM { param($Tenant, $Settings) #$Rerun -Type Standard -Tenant $Tenant -API 'AddDKIM' -Settings $Settings - $TestResult = Test-CIPPStandardLicense -StandardName 'AddDKIM' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'AddDKIM' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 index b35a16b21431..9c9ef1ace003 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAntiPhishPolicy.ps1 @@ -81,7 +81,7 @@ function Invoke-CIPPStandardAntiPhishPolicy { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'AntiPhishPolicy' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'AntiPhishPolicy' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAntiSpamSafeList.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAntiSpamSafeList.ps1 index 1a68a1be5acf..18de5c1bb8a1 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAntiSpamSafeList.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAntiSpamSafeList.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardAntiSpamSafeList { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'AntiSpamSafeList' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'AntiSpamSafeList' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAssignmentFilterTemplate.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAssignmentFilterTemplate.ps1 index 10cccd9d1527..79dbf1204143 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAssignmentFilterTemplate.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAssignmentFilterTemplate.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardAssignmentFilterTemplate { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'AssignmentFilterTemplate' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'AssignmentFilterTemplate' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 index 26e28f6443b3..1f7db14eb657 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 @@ -40,7 +40,7 @@ function Invoke-CIPPStandardAtpPolicyForO365 { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'AtpPolicyForO365' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'AtpPolicyForO365' -TenantFilter $Tenant -Preset SharePoint ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'AtpPolicyForO365' if ($TestResult -eq $false) { diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 index df4fb6e2f223..c5193f0307e0 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 @@ -43,7 +43,7 @@ function Invoke-CIPPStandardAuditLog { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'AuditLog' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'AuditLog' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoArchive.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoArchive.ps1 index 33174b679ab8..500f6fc16cfd 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoArchive.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoArchive.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardAutoArchive { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'AutoArchive' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') + $TestResult = Test-CIPPStandardLicense -StandardName 'AutoArchive' -TenantFilter $Tenant -Preset Exchange if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoArchiveMailbox.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoArchiveMailbox.ps1 index 639d1eb35a32..f5b249cce7fd 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoArchiveMailbox.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoArchiveMailbox.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardAutoArchiveMailbox { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'AutoArchiveMailbox' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') + $TestResult = Test-CIPPStandardLicense -StandardName 'AutoArchiveMailbox' -TenantFilter $Tenant -Preset Exchange if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 index 8ba91b371d16..d8eed08d8e9a 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoExpandArchive.ps1 @@ -36,7 +36,7 @@ function Invoke-CIPPStandardAutoExpandArchive { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'AutoExpandArchive' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'AutoExpandArchive' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutopilotProfile.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutopilotProfile.ps1 index 9834a03673f0..9becbd6c0533 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutopilotProfile.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutopilotProfile.ps1 @@ -46,7 +46,7 @@ function Invoke-CIPPStandardAutopilotProfile { https://docs.cipp.app/user-documentation/tenant/standards/list-standards #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'AutopilotProfile' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'AutopilotProfile' -TenantFilter $Tenant -Preset Intune # Get the current configuration diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutopilotStatusPage.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutopilotStatusPage.ps1 index 780b1457cfab..5f0011303a48 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutopilotStatusPage.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutopilotStatusPage.ps1 @@ -44,7 +44,7 @@ function Invoke-CIPPStandardAutopilotStatusPage { https://docs.cipp.app/user-documentation/tenant/standards/list-standards #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'AutopilotStatusPage' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'AutopilotStatusPage' -TenantFilter $Tenant -Preset Intune # Get current Autopilot enrollment status page configuration diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardBookings.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardBookings.ps1 index 80e95a84c45f..39026d801a93 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardBookings.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardBookings.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardBookings { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'Bookings' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'Bookings' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardBranding.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardBranding.ps1 index 0a28c4747562..6a3c80fa9bf3 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardBranding.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardBranding.ps1 @@ -41,7 +41,7 @@ function Invoke-CIPPStandardBranding { param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'Branding' -TenantFilter $Tenant -RequiredCapabilities @('AAD_PREMIUM', 'AAD_PREMIUM_P2', 'OFFICE_BUSINESS') + $TestResult = Test-CIPPStandardLicense -StandardName 'Branding' -TenantFilter $Tenant -Preset Entra -RequiredCapabilities @('OFFICE_BUSINESS') if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 index 360fb92d8666..7d4153591afc 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardCloudMessageRecall.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardCloudMessageRecall { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'CloudMessageRecall' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'CloudMessageRecall' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardColleagueImpersonationAlert.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardColleagueImpersonationAlert.ps1 index 8656f31602b4..8971ff8afd1e 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardColleagueImpersonationAlert.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardColleagueImpersonationAlert.ps1 @@ -45,7 +45,7 @@ function Invoke-CIPPStandardColleagueImpersonationAlert { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'ColleagueImpersonationAlert' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') + $TestResult = Test-CIPPStandardLicense -StandardName 'ColleagueImpersonationAlert' -TenantFilter $Tenant -Preset Exchange if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 index fe65856b730b..5a34cfde7368 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 @@ -47,7 +47,7 @@ function Invoke-CIPPStandardConditionalAccessTemplate { } - $TestResult = Test-CIPPStandardLicense -StandardName 'ConditionalAccessTemplate_general' -TenantFilter $Tenant -RequiredCapabilities @('AAD_PREMIUM', 'AAD_PREMIUM_P2') + $TestResult = Test-CIPPStandardLicense -StandardName 'ConditionalAccessTemplate_general' -TenantFilter $Tenant -Preset Entra if ($TestResult -eq $false) { Set-CIPPStandardsCompareField -FieldName "standards.ConditionalAccessTemplate.$($Settings.TemplateList.value)" -FieldValue 'This tenant does not have the required license for this standard.' -Tenant $Tenant return $true @@ -71,7 +71,7 @@ function Invoke-CIPPStandardConditionalAccessTemplate { $JSONObj = (Get-CippAzDataTableEntity @Table -Filter $Filter).JSON $Policy = $JSONObj | ConvertFrom-Json if ($Policy.conditions.userRiskLevels.count -gt 0 -or $Policy.conditions.signInRiskLevels.count -gt 0) { - $TestP2 = Test-CIPPStandardLicense -StandardName 'ConditionalAccessTemplate_p2' -TenantFilter $Tenant -RequiredCapabilities @('AAD_PREMIUM_P2') -SkipLog + $TestP2 = Test-CIPPStandardLicense -StandardName 'ConditionalAccessTemplate_p2' -TenantFilter $Tenant -Preset EntraP2 -SkipLog if (!$TestP2) { Write-Information "Skipping policy $($Policy.displayName) as it requires AAD Premium P2 license." Set-CIPPStandardsCompareField -FieldName "standards.ConditionalAccessTemplate.$($Settings.TemplateList.value)" -FieldValue "Policy $($Policy.displayName) requires AAD Premium P2 license." -Tenant $Tenant @@ -112,7 +112,7 @@ function Invoke-CIPPStandardConditionalAccessTemplate { $CheckExististing = $AllCAPolicies | Where-Object -Property displayName -EQ $Settings.TemplateList.label if (!$CheckExististing) { if ($Policy.conditions.userRiskLevels.Count -gt 0 -or $Policy.conditions.signInRiskLevels.Count -gt 0) { - $TestP2 = Test-CIPPStandardLicense -StandardName 'ConditionalAccessTemplate_p2' -TenantFilter $Tenant -RequiredCapabilities @('AAD_PREMIUM_P2') -SkipLog + $TestP2 = Test-CIPPStandardLicense -StandardName 'ConditionalAccessTemplate_p2' -TenantFilter $Tenant -Preset EntraP2 -SkipLog if (!$TestP2) { Set-CIPPStandardsCompareField -FieldName "standards.ConditionalAccessTemplate.$($Settings.TemplateList.value)" -FieldValue "Policy $($Settings.TemplateList.label) requires AAD Premium P2 license." -Tenant $Tenant } else { diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardCustomBannedPasswordList.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardCustomBannedPasswordList.ps1 index 1f1f5041c4c6..dc4c11afd0bb 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardCustomBannedPasswordList.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardCustomBannedPasswordList.ps1 @@ -43,7 +43,7 @@ function Invoke-CIPPStandardCustomBannedPasswordList { param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'CustomBannedPasswordList' -TenantFilter $Tenant -RequiredCapabilities @('AAD_PREMIUM', 'AAD_PREMIUM_P2') + $TestResult = Test-CIPPStandardLicense -StandardName 'CustomBannedPasswordList' -TenantFilter $Tenant -Preset Entra if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDefaultPlatformRestrictions.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDefaultPlatformRestrictions.ps1 index ee5ff2d213f5..37db79585cd2 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDefaultPlatformRestrictions.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDefaultPlatformRestrictions.ps1 @@ -47,7 +47,7 @@ function Invoke-CIPPStandardDefaultPlatformRestrictions { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DefaultPlatformRestrictions' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'DefaultPlatformRestrictions' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDefaultSharingLink.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDefaultSharingLink.ps1 index e866fed9b306..e7d3b7be7e7c 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDefaultSharingLink.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDefaultSharingLink.ps1 @@ -46,7 +46,7 @@ function Invoke-CIPPStandardDefaultSharingLink { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DefaultSharingLink' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'DefaultSharingLink' -TenantFilter $Tenant -Preset SharePoint # Determine the desired sharing link type (default to Internal if not specified) diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 index fb2bb660567b..8597dfef3c1d 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDelegateSentItems.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardDelegateSentItems { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DelegateSentItems' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'DelegateSentItems' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 index 19e1728bf25e..f895933d6f64 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeletedUserRentention.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardDeletedUserRentention { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DeletedUserRentention' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'DeletedUserRentention' -TenantFilter $Tenant -Preset SharePoint ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'DeletedUserRetention' if ($TestResult -eq $false) { diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployCheckChromeExtension.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployCheckChromeExtension.ps1 index 8c67aaa53158..ba17adb24c50 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployCheckChromeExtension.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployCheckChromeExtension.ps1 @@ -63,7 +63,7 @@ function Invoke-CIPPStandardDeployCheckChromeExtension { param($Tenant, $Settings) # Check for required Intune license - $TestResult = Test-CIPPStandardLicense -StandardName 'DeployCheckChromeExtension' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'DeployCheckChromeExtension' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { Set-CIPPStandardsCompareField -FieldName 'standards.DeployCheckChromeExtension' -FieldValue 'This tenant does not have the required license for this standard.' -Tenant $Tenant diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployContactTemplates.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployContactTemplates.ps1 index aad3a0183aed..c8e121eee1b9 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployContactTemplates.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployContactTemplates.ps1 @@ -40,7 +40,7 @@ function Invoke-CIPPStandardDeployContactTemplates { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DeployContactTemplates' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'DeployContactTemplates' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployMailContact.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployMailContact.ps1 index 3a66cb07f26f..a5e4d2467983 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployMailContact.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployMailContact.ps1 @@ -41,7 +41,7 @@ function Invoke-CIPPStandardDeployMailContact { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DeployMailContact' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'DeployMailContact' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 index d0d2f576c3d7..e314ca52b592 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableAddShortcutsToOneDrive.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardDisableAddShortcutsToOneDrive { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableAddShortcutsToOneDrive' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableAddShortcutsToOneDrive' -TenantFilter $Tenant -Preset SharePoint ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'DisableAddShortcutsToOneDrive' if ($TestResult -eq $false) { diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 index 2e9d5fe1a8a5..af833e5127f1 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableAdditionalStorageProviders.ps1 @@ -40,7 +40,7 @@ function Invoke-CIPPStandardDisableAdditionalStorageProviders { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableAdditionalStorageProviders' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableAdditionalStorageProviders' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 index dafcd82880e2..2606292ebd66 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableBasicAuthSMTP.ps1 @@ -42,7 +42,7 @@ function Invoke-CIPPStandardDisableBasicAuthSMTP { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableBasicAuthSMTP' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableBasicAuthSMTP' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableEWS.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableEWS.ps1 index 871aacadaef7..b462e0720915 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableEWS.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableEWS.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardDisableEWS { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableEWS' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableEWS' -TenantFilter $Tenant -Preset Exchange if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExchangeOnlinePowerShell.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExchangeOnlinePowerShell.ps1 index 568f367e6e58..a39f506886a0 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExchangeOnlinePowerShell.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExchangeOnlinePowerShell.ps1 @@ -40,7 +40,7 @@ function Invoke-CIPPStandardDisableExchangeOnlinePowerShell { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableExchangeOnlinePowerShell' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableExchangeOnlinePowerShell' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 index 9d645e3c8be2..8707a5e75a4e 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 @@ -41,7 +41,7 @@ function Invoke-CIPPStandardDisableExternalCalendarSharing { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableExternalCalendarSharing' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableExternalCalendarSharing' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 index 60531cf79033..84acf28a82b2 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableGuests.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardDisableGuests { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableGuests' -TenantFilter $Tenant -RequiredCapabilities @('AAD_PREMIUM', 'AAD_PREMIUM_P2') + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableGuests' -TenantFilter $Tenant -Preset Entra if ($TestResult -eq $false) { #writing to each item that the license is not present. diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 index c798736dfe5a..9263217655f4 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableM365GroupUsers.ps1 @@ -40,7 +40,7 @@ function Invoke-CIPPStandardDisableM365GroupUsers { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableM365GroupUsers' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableM365GroupUsers' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 index 746171c6cd91..b4e7e95d034f 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableOutlookAddins.ps1 @@ -42,7 +42,7 @@ function Invoke-CIPPStandardDisableOutlookAddins { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableOutlookAddins' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableOutlookAddins' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 index b1cfdda20880..6c1bf35618d4 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1 @@ -45,7 +45,7 @@ function Invoke-CIPPStandardDisableReshare { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableReshare' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableReshare' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableResourceMailbox.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableResourceMailbox.ps1 index d270cdce3675..46730ecd32b1 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableResourceMailbox.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableResourceMailbox.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardDisableResourceMailbox { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableResourceMailbox' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableResourceMailbox' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 index 33e453583b34..9703daa08f4e 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1 @@ -47,7 +47,7 @@ function Invoke-CIPPStandardDisableSharePointLegacyAuth { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableSharePointLegacyAuth' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableSharePointLegacyAuth' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 index 91b761a7ab3b..c81ae466d2a7 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableTNEF.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardDisableTNEF { #> param ($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableTNEF' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableTNEF' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 index 94748b7df36a..b5bfa5ff04e1 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableUserSiteCreate.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardDisableUserSiteCreate { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'DisableUserSiteCreate' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'DisableUserSiteCreate' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 index 61aae3eaddd8..f2b134cbfb77 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 @@ -43,7 +43,7 @@ function Invoke-CIPPStandardEXODisableAutoForwarding { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'EXODisableAutoForwarding' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'EXODisableAutoForwarding' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEXOOutboundSpamLimits.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEXOOutboundSpamLimits.ps1 index 786acd96dc6a..5a949daed90e 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEXOOutboundSpamLimits.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEXOOutboundSpamLimits.ps1 @@ -43,7 +43,7 @@ function Invoke-CIPPStandardEXOOutboundSpamLimits { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'EXOOutboundSpamLimits' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'EXOOutboundSpamLimits' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableExchangeCloudManagement.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableExchangeCloudManagement.ps1 index 848b545789eb..a1dae1e109ca 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableExchangeCloudManagement.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableExchangeCloudManagement.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardEnableExchangeCloudManagement { param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'EnableExchangeCloudManagement' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV') + $TestResult = Test-CIPPStandardLicense -StandardName 'EnableExchangeCloudManagement' -TenantFilter $Tenant -Preset Exchange if ($TestResult -eq $false) { Write-Host "We're exiting as the correct license is not present for this standard." diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableLitigationHold.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableLitigationHold.ps1 index 8818a8e0bd1f..2f8c0e326634 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableLitigationHold.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableLitigationHold.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardEnableLitigationHold { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'EnableLitigationHold' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'EnableLitigationHold' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 index d61e0d6b9058..4b67c83fc4e1 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableMailTips.ps1 @@ -41,7 +41,7 @@ function Invoke-CIPPStandardEnableMailTips { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'EnableMailTips' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'EnableMailTips' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 index 70249dcc7b97..62262a2b9d7f 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableMailboxAuditing.ps1 @@ -46,7 +46,7 @@ function Invoke-CIPPStandardEnableMailboxAuditing { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'EnableMailboxAuditing' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'EnableMailboxAuditing' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 index a13f0fd22075..9d75cd84746e 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableOnlineArchiving.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardEnableOnlineArchiving { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'EnableOnlineArchiving' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'EnableOnlineArchiving' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnrollmentWindowsHelloForBusinessConfiguration.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnrollmentWindowsHelloForBusinessConfiguration.ps1 index 6d89b3031904..2339a92bc47e 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnrollmentWindowsHelloForBusinessConfiguration.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnrollmentWindowsHelloForBusinessConfiguration.ps1 @@ -48,7 +48,7 @@ function Invoke-CIPPStandardEnrollmentWindowsHelloForBusinessConfiguration { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'EnrollmentWindowsHelloForBusinessConfiguration' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'EnrollmentWindowsHelloForBusinessConfiguration' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardExchangeConnectorTemplate.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardExchangeConnectorTemplate.ps1 index 4461ad335873..5f3faba79e67 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardExchangeConnectorTemplate.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardExchangeConnectorTemplate.ps1 @@ -34,7 +34,7 @@ function Invoke-CIPPStandardExchangeConnectorTemplate { https://docs.cipp.app/user-documentation/tenant/standards/list-standards #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'ExConnector' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'ExConnector' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 index d6b6202cb318..ba6cfbaf908a 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardExcludedfileExt.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardExcludedfileExt { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'ExcludedfileExt' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'ExcludedfileExt' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 index 1bc5314fe35e..6eede7fc53ee 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardFocusedInbox { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'FocusedInbox' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'FocusedInbox' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 index b5864df1fc8a..2ce49074209f 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardGlobalQuarantineNotifications.ps1 @@ -34,7 +34,7 @@ function Invoke-CIPPStandardGlobalQuarantineNotifications { https://docs.cipp.app/user-documentation/tenant/standards/list-standards #> param ($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'GlobalQuarantineNotifications' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'GlobalQuarantineNotifications' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardGlobalQuarantineSettings.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardGlobalQuarantineSettings.ps1 index 2235e1493340..bfc88c729612 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardGlobalQuarantineSettings.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardGlobalQuarantineSettings.ps1 @@ -40,7 +40,7 @@ function Invoke-CIPPStandardGlobalQuarantineSettings { https://docs.cipp.app/user-documentation/tenant/standards/list-standards #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'QuarantineTemplate' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'QuarantineTemplate' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 index ee2f5bbcf78e..f89137e5a324 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardGroupTemplate.ps1 @@ -67,7 +67,7 @@ function Invoke-CIPPStandardGroupTemplate { # Check if Exchange license is required for distribution groups if ($groupobj.groupType -in @('distribution', 'dynamicdistribution')) { - $TestResult = Test-CIPPStandardLicense -StandardName 'GroupTemplate' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_LITE') -SkipLog + $TestResult = Test-CIPPStandardLicense -StandardName 'GroupTemplate' -TenantFilter $Tenant -Preset Exchange -SkipLog if (!$TestResult) { Write-LogMessage -API 'Standards' -tenant $tenant -message "Cannot create group $($groupobj.displayname) as the tenant is not licensed for Exchange." -Sev 'Error' continue @@ -132,7 +132,7 @@ function Invoke-CIPPStandardGroupTemplate { } else { # Handle Exchange Online groups (Distribution, DynamicDistribution) - $TestResult = Test-CIPPStandardLicense -StandardName 'GroupTemplate' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_LITE') -SkipLog + $TestResult = Test-CIPPStandardLicense -StandardName 'GroupTemplate' -TenantFilter $Tenant -Preset Exchange -SkipLog if (!$TestResult) { Write-LogMessage -API 'Standards' -tenant $tenant -message "Cannot update group $($groupobj.displayName) as the tenant is not licensed for Exchange." -Sev 'Error' continue diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 index 32874304857a..a32803fbf620 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardIntuneComplianceSettings { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneComplianceSettings' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneComplianceSettings' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardIntuneWindowsDiagnostic.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardIntuneWindowsDiagnostic.ps1 index a8085874bb02..cc259250d075 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardIntuneWindowsDiagnostic.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardIntuneWindowsDiagnostic.ps1 @@ -39,7 +39,7 @@ Function Invoke-CIPPStandardIntuneWindowsDiagnostic { [CmdletBinding()] param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneWindowsDiagnostic' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneWindowsDiagnostic' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMDMEnrollmentDuringRegistration.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMDMEnrollmentDuringRegistration.ps1 index 363d24b158c5..5d2c43e167c1 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMDMEnrollmentDuringRegistration.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMDMEnrollmentDuringRegistration.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardMDMEnrollmentDuringRegistration { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'MDMEnrollmentDuringRegistration' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'MDMEnrollmentDuringRegistration' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMDMScope.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMDMScope.ps1 index c1ca2137b68a..d26434af0c5c 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMDMScope.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMDMScope.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardMDMScope { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'MDMScope' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'MDMScope' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMailboxRecipientLimits.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMailboxRecipientLimits.ps1 index 22807d8cc1a9..4ab2a5b0809d 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMailboxRecipientLimits.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMailboxRecipientLimits.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardMailboxRecipientLimits { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'MailboxRecipientLimits' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'MailboxRecipientLimits' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 index 978103c47d88..ce7762e09640 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMalwareFilterPolicy.ps1 @@ -58,7 +58,7 @@ function Invoke-CIPPStandardMalwareFilterPolicy { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'MalwareFilterPolicy' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'MalwareFilterPolicy' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMessageExpiration.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMessageExpiration.ps1 index 034dce5c97db..e5d6b42375ec 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMessageExpiration.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardMessageExpiration.ps1 @@ -34,7 +34,7 @@ function Invoke-CIPPStandardMessageExpiration { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'MessageExpiration' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'MessageExpiration' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOMEBranding.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOMEBranding.ps1 index 00d7a642232e..a295685e5129 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOMEBranding.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOMEBranding.ps1 @@ -41,7 +41,7 @@ function Invoke-CIPPStandardOMEBranding { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'OMEBranding' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') + $TestResult = Test-CIPPStandardLicense -StandardName 'OMEBranding' -TenantFilter $Tenant -Preset Exchange if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOWAAttachmentRestrictions.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOWAAttachmentRestrictions.ps1 index d7e712a525e4..06a6d08aeda2 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOWAAttachmentRestrictions.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOWAAttachmentRestrictions.ps1 @@ -42,7 +42,7 @@ function Invoke-CIPPStandardOWAAttachmentRestrictions { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'OWAAttachmentRestrictions' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'OWAAttachmentRestrictions' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 index 5727b25ddb3b..c920d59712d8 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardOutBoundSpamAlert { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'OutBoundSpamAlert' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'OutBoundSpamAlert' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 index b908df1e30e2..b8cb3c15afbf 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardPhishProtection { param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'PhishProtection' -TenantFilter $Tenant -RequiredCapabilities @('AAD_PREMIUM', 'AAD_PREMIUM_P2', 'OFFICE_BUSINESS') + $TestResult = Test-CIPPStandardLicense -StandardName 'PhishProtection' -TenantFilter $Tenant -Preset Entra -RequiredCapabilities @('OFFICE_BUSINESS') if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishSimSpoofIntelligence.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishSimSpoofIntelligence.ps1 index 6665b4749cf6..cd36ab3cb82b 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishSimSpoofIntelligence.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishSimSpoofIntelligence.ps1 @@ -36,7 +36,7 @@ function Invoke-CIPPStandardPhishSimSpoofIntelligence { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'PhishSimSpoofIntelligence' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'PhishSimSpoofIntelligence' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishingSimulations.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishingSimulations.ps1 index dd1721a81709..ba0fe12509ac 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishingSimulations.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishingSimulations.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardPhishingSimulations { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'PhishingSimulations' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'PhishingSimulations' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 index 6ce4e87cab35..d001a96e0d41 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardProfilePhotos.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardProfilePhotos { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'ProfilePhotos' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'ProfilePhotos' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardQuarantineRequestAlert.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardQuarantineRequestAlert.ps1 index 3f3eb3e06a59..dc0144141d44 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardQuarantineRequestAlert.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardQuarantineRequestAlert.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardQuarantineRequestAlert { #> param ($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'QuarantineRequestAlert' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'QuarantineRequestAlert' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 index 95cae003f66b..63ecc8f0e119 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardQuarantineTemplate.ps1 @@ -48,7 +48,7 @@ function Invoke-CIPPStandardQuarantineTemplate { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'QuarantineTemplate' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'QuarantineTemplate' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardRestrictThirdPartyStorageServices.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardRestrictThirdPartyStorageServices.ps1 index eacdaf30c731..8bd8a6e6bc55 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardRestrictThirdPartyStorageServices.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardRestrictThirdPartyStorageServices.ps1 @@ -40,7 +40,7 @@ function Invoke-CIPPStandardRestrictThirdPartyStorageServices { #> param ($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'ThirdPartyStorageServicesRestricted' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'ThirdPartyStorageServicesRestricted' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardRetentionPolicyTag.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardRetentionPolicyTag.ps1 index 348e62d9fec5..00b89883ab27 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardRetentionPolicyTag.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardRetentionPolicyTag.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardRetentionPolicyTag { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'RetentionPolicyTag' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'RetentionPolicyTag' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardReusableSettingsTemplate.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardReusableSettingsTemplate.ps1 index f9a0c9965bec..2e74d71dafcc 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardReusableSettingsTemplate.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardReusableSettingsTemplate.ps1 @@ -25,7 +25,7 @@ function Invoke-CIPPStandardReusableSettingsTemplate { ADDEDCOMPONENT {"type":"autoComplete","multiple":true,"creatable":false,"required":true,"name":"TemplateList","label":"Select Reusable Settings Template","api":{"queryKey":"ListIntuneReusableSettingTemplates","url":"/api/ListIntuneReusableSettingTemplates","labelField":"displayName","valueField":"GUID","showRefresh":true,"templateView":{"title":"Reusable Settings","property":"RawJSON","type":"intune"}}} POWERSHELLEQUIVALENT - + RECOMMENDEDBY UPDATECOMMENTBLOCK Run the Tools\Update-StandardsComments.ps1 script to update this comment block @@ -62,8 +62,7 @@ function Invoke-CIPPStandardReusableSettingsTemplate { return $InputObject } - $RequiredCapabilities = @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') - $TestResult = Test-CIPPStandardLicense -StandardName 'ReusableSettingsTemplate_general' -TenantFilter $Tenant -RequiredCapabilities $RequiredCapabilities + $TestResult = Test-CIPPStandardLicense -StandardName 'ReusableSettingsTemplate_general' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { $settings.TemplateList | ForEach-Object { $MissingLicenseMessage = "This tenant is missing one or more required licenses for this standard: $($RequiredCapabilities -join ', ')." diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 index 9d6e16d9c2cf..9b999224c4d9 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardRotateDKIM.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardRotateDKIM { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'RotateDKIM' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'RotateDKIM' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 index 24917859e8c4..30e25407bf09 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPAzureB2B.ps1 @@ -40,7 +40,7 @@ function Invoke-CIPPStandardSPAzureB2B { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SPAzureB2B' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'SPAzureB2B' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 index db4c72109298..f4abb8224b3d 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDirectSharing.ps1 @@ -40,7 +40,7 @@ function Invoke-CIPPStandardSPDirectSharing { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SPDirectSharing' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'SPDirectSharing' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisableCustomScripts.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisableCustomScripts.ps1 index d9344d5f2ff3..3b798632add4 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisableCustomScripts.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisableCustomScripts.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardSPDisableCustomScripts { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SPDisableCustomScripts' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'SPDisableCustomScripts' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 index 6bfff643ffcb..fc050627c395 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisableLegacyWorkflows.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardSPDisableLegacyWorkflows { https://docs.cipp.app/user-documentation/tenant/standards/list-standards #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SPDisableLegacyWorkflows' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'SPDisableLegacyWorkflows' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisableStoreAccess.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisableStoreAccess.ps1 index 24064a809d62..faa1079cdb03 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisableStoreAccess.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisableStoreAccess.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardSPDisableStoreAccess { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SPDisableStoreAccess' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'SPDisableStoreAccess' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 index 03db2dc19e47..c3e5d617ebe9 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPDisallowInfectedFiles.ps1 @@ -44,7 +44,7 @@ function Invoke-CIPPStandardSPDisallowInfectedFiles { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SPDisallowInfectedFiles' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV','ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'SPDisallowInfectedFiles' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 index bc99fc1f5c89..a62aadd15d2b 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPEmailAttestation.ps1 @@ -45,7 +45,7 @@ function Invoke-CIPPStandardSPEmailAttestation { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SPEmailAttestation' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'SPEmailAttestation' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 index edaff7e2817f..980eb79b1b61 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPExternalUserExpiration.ps1 @@ -45,7 +45,7 @@ function Invoke-CIPPStandardSPExternalUserExpiration { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SPExternalUserExpiration' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'SPExternalUserExpiration' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPFileRequests.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPFileRequests.ps1 index 099d196ac80e..784625e25add 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPFileRequests.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPFileRequests.ps1 @@ -41,7 +41,7 @@ function Invoke-CIPPStandardSPFileRequests { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SPFileRequests' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'SPFileRequests' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'The tenant is not licenced for this standard SPFileRequests' -sev Error diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 index e6e70dd58b4c..8f730b08f3f2 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSPSyncButtonState.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardSPSyncButtonState { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SPSyncButtonState' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'SPSyncButtonState' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 index f4e8a73738f4..17d986547ebb 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 @@ -47,7 +47,7 @@ function Invoke-CIPPStandardSafeAttachmentPolicy { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SafeAttachmentPolicy' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'SafeAttachmentPolicy' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 index 04527ce524d6..02b15bcad276 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 @@ -61,7 +61,7 @@ function Invoke-CIPPStandardSafeLinksPolicy { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SafeLinksPolicy' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'SafeLinksPolicy' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksTemplatePolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksTemplatePolicy.ps1 index 8d7f74b28706..b1a4bbfd7cf4 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksTemplatePolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksTemplatePolicy.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardSafeLinksTemplatePolicy { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SafeLinksTemplatePolicy' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'SafeLinksTemplatePolicy' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 index 4a75aa37768c..7252c9623ac2 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardSafeSendersDisable { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SafeSendersDisable' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'SafeSendersDisable' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSendFromAlias.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSendFromAlias.ps1 index 1e993982fdad..5f45f242ef9b 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSendFromAlias.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSendFromAlias.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardSendFromAlias { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SendFromAlias' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'SendFromAlias' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 index ea594cdef299..f8345408d603 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSendReceiveLimitTenant.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardSendReceiveLimitTenant { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SendReceiveLimitTenant' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'SendReceiveLimitTenant' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 index fdf996a9e9e8..96ec95382810 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardShortenMeetings.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardShortenMeetings { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'ShortenMeetings' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'ShortenMeetings' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 index eab8864f1eb6..27b7c6e49ea4 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 @@ -75,7 +75,7 @@ function Invoke-CIPPStandardSpamFilterPolicy { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SpamFilterPolicy' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'SpamFilterPolicy' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 index 6fa95268d1cc..71c60d44244d 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 @@ -44,7 +44,7 @@ function Invoke-CIPPStandardSpoofWarn { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'SpoofWarn' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'SpoofWarn' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardStaleEntraDevices.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardStaleEntraDevices.ps1 index 43beaef30d6a..74cdcd52abfc 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardStaleEntraDevices.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardStaleEntraDevices.ps1 @@ -42,7 +42,7 @@ function Invoke-CIPPStandardStaleEntraDevices { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'StaleEntraDevices' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'StaleEntraDevices' -TenantFilter $Tenant -Preset Intune # Get all Entra devices diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsChatProtection.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsChatProtection.ps1 index e79e3f25d112..603b8662b4c2 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsChatProtection.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsChatProtection.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardTeamsChatProtection { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsChatProtection' -TenantFilter $Tenant -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsChatProtection' -TenantFilter $Tenant -Preset Teams if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsEmailIntegration.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsEmailIntegration.ps1 index 640b39c5c4b9..61b0216c06ce 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsEmailIntegration.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsEmailIntegration.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardTeamsEmailIntegration { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsEmailIntegration' -TenantFilter $Tenant -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsEmailIntegration' -TenantFilter $Tenant -Preset Teams if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsEnrollUser.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsEnrollUser.ps1 index 2240f7cd2514..37a845e72388 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsEnrollUser.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsEnrollUser.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardTeamsEnrollUser { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsEnrollUser' -TenantFilter $Tenant -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsEnrollUser' -TenantFilter $Tenant -Preset Teams # Get EnrollUserOverride value using null-coalescing operator diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 index e2892d93f170..f4ed299c9094 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsExternalAccessPolicy.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardTeamsExternalAccessPolicy { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsExternalAccessPolicy' -TenantFilter $Tenant -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsExternalAccessPolicy' -TenantFilter $Tenant -Preset Teams if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsExternalChatWithAnyone.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsExternalChatWithAnyone.ps1 index db221c618f9f..89322c6142f3 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsExternalChatWithAnyone.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsExternalChatWithAnyone.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardTeamsExternalChatWithAnyone { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsExternalChatWithAnyone' -TenantFilter $Tenant -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsExternalChatWithAnyone' -TenantFilter $Tenant -Preset Teams if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 index 7ea4bf6e7ae5..fb4aed237cd6 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsExternalFileSharing.ps1 @@ -43,7 +43,7 @@ function Invoke-CIPPStandardTeamsExternalFileSharing { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsExternalFileSharing' -TenantFilter $Tenant -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsExternalFileSharing' -TenantFilter $Tenant -Preset Teams if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 index ab245b7fd939..f5714c8be50d 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsFederationConfiguration.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardTeamsFederationConfiguration { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsFederationConfiguration' -TenantFilter $Tenant -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsFederationConfiguration' -TenantFilter $Tenant -Preset Teams if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsGlobalMeetingPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsGlobalMeetingPolicy.ps1 index 646ea312797a..01e6ac4b6513 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsGlobalMeetingPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsGlobalMeetingPolicy.ps1 @@ -50,7 +50,7 @@ function Invoke-CIPPStandardTeamsGlobalMeetingPolicy { https://docs.cipp.app/user-documentation/tenant/standards/list-standards #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsGlobalMeetingPolicy' -TenantFilter $Tenant -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsGlobalMeetingPolicy' -TenantFilter $Tenant -Preset Teams if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsGuestAccess.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsGuestAccess.ps1 index 5530de4b9382..e15bc2c1c0f8 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsGuestAccess.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsGuestAccess.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardTeamsGuestAccess { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsGuestAccess' -TenantFilter $Tenant -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsGuestAccess' -TenantFilter $Tenant -Preset Teams if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMeetingRecordingExpiration.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMeetingRecordingExpiration.ps1 index e84885986aee..c977b0f648b9 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMeetingRecordingExpiration.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMeetingRecordingExpiration.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardTeamsMeetingRecordingExpiration { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsMeetingRecordingExpiration' -TenantFilter $Tenant -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsMeetingRecordingExpiration' -TenantFilter $Tenant -Preset Teams # Input validation diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMeetingVerification.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMeetingVerification.ps1 index c7baffc456f2..c07c3413ebbb 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMeetingVerification.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMeetingVerification.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardTeamsMeetingVerification { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsMeetingVerification' -TenantFilter $Tenant -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsMeetingVerification' -TenantFilter $Tenant -Preset Teams if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 index 48b8009428b1..19f1c089defd 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMeetingsByDefault.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardTeamsMeetingsByDefault { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsMeetingsByDefault' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsMeetingsByDefault' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMessagingPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMessagingPolicy.ps1 index 0137a96fda7d..8e2a0cbfa0e1 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMessagingPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsMessagingPolicy.ps1 @@ -45,7 +45,7 @@ function Invoke-CIPPStandardTeamsMessagingPolicy { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsMessagingPolicy' -TenantFilter $Tenant -RequiredCapabilities @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsMessagingPolicy' -TenantFilter $Tenant -Preset Teams if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTenantAllowBlockListTemplate.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTenantAllowBlockListTemplate.ps1 index 38ab5cedcbbc..238f2f71353a 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTenantAllowBlockListTemplate.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTenantAllowBlockListTemplate.ps1 @@ -35,7 +35,7 @@ function Invoke-CIPPStandardTenantAllowBlockListTemplate { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TenantAllowBlockListTemplate' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') + $TestResult = Test-CIPPStandardLicense -StandardName 'TenantAllowBlockListTemplate' -TenantFilter $Tenant -Preset Exchange if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 index 12aa7af173b6..71e5a2a8c6b5 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTenantDefaultTimezone.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardTenantDefaultTimezone { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TenantDefaultTimezone' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'TenantDefaultTimezone' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 index 21b57514d49c..4f82cc7a3690 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTransportRuleTemplate.ps1 @@ -35,7 +35,7 @@ function Invoke-CIPPStandardTransportRuleTemplate { https://docs.cipp.app/user-documentation/tenant/standards/list-standards #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TransportRuleTemplate' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'TransportRuleTemplate' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTwoClickEmailProtection.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTwoClickEmailProtection.ps1 index eab1d38a1ef4..65cf25ce9ae0 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTwoClickEmailProtection.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTwoClickEmailProtection.ps1 @@ -37,7 +37,7 @@ function Invoke-CIPPStandardTwoClickEmailProtection { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TwoClickEmailProtection' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'TwoClickEmailProtection' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 index cbf1546f3280..4e50340dd22a 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardUserSubmissions { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'UserSubmissions' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'UserSubmissions' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardWindowsBackupRestore.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardWindowsBackupRestore.ps1 index afeff9e56375..eff979d61a0f 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardWindowsBackupRestore.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardWindowsBackupRestore.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardWindowsBackupRestore { [CmdletBinding()] param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'WindowsBackupRestore' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'WindowsBackupRestore' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 index 455a4468c8e1..c0890e120c6c 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardcalDefault.ps1 @@ -40,7 +40,7 @@ function Invoke-CIPPStandardcalDefault { param($Tenant, $Settings, $QueueItem) ##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'calDefault' - $TestResult = Test-CIPPStandardLicense -StandardName 'calDefault' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') #No Foundation because that does not allow powershell access + $TestResult = Test-CIPPStandardLicense -StandardName 'calDefault' -TenantFilter $Tenant -Preset Exchange #No Foundation because that does not allow powershell access if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 index 09b60695d93d..b9d949bc470c 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandarddisableMacSync.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandarddisableMacSync { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'disableMacSync' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'disableMacSync' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 index 1ebe6cfd68f1..8a40218f5931 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardintuneBrandingProfile.ps1 @@ -46,7 +46,7 @@ function Invoke-CIPPStandardintuneBrandingProfile { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'intuneBrandingProfile' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'intuneBrandingProfile' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardintuneDeviceReg.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardintuneDeviceReg.ps1 index 60bcafbcabdb..e35a76013961 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardintuneDeviceReg.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardintuneDeviceReg.ps1 @@ -40,7 +40,7 @@ function Invoke-CIPPStandardintuneDeviceReg { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'intuneDeviceReg' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'intuneDeviceReg' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 index 3628c3396dc0..14e6f9b37c34 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardintuneDeviceRetirementDays.ps1 @@ -38,7 +38,7 @@ function Invoke-CIPPStandardintuneDeviceRetirementDays { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'intuneDeviceRetirementDays' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'intuneDeviceRetirementDays' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 index 6cb9f00abcfb..d1ef515b2026 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardsharingCapability.ps1 @@ -46,7 +46,7 @@ function Invoke-CIPPStandardsharingCapability { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'sharingCapability' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'sharingCapability' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 index a69778d30a12..934f6943d9bc 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardsharingDomainRestriction.ps1 @@ -45,7 +45,7 @@ function Invoke-CIPPStandardsharingDomainRestriction { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'sharingDomainRestriction' -TenantFilter $Tenant -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'sharingDomainRestriction' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardunmanagedSync.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardunmanagedSync.ps1 index 9e1a7433d62f..b089148a4e46 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardunmanagedSync.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardunmanagedSync.ps1 @@ -42,7 +42,7 @@ function Invoke-CIPPStandardunmanagedSync { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'unmanagedSync' -TenantFilter $Tenant -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + $TestResult = Test-CIPPStandardLicense -StandardName 'unmanagedSync' -TenantFilter $Tenant -Preset Intune if ($TestResult -eq $false) { return $true diff --git a/Tools/Update-StandardsComments.ps1 b/Tools/Update-StandardsComments.ps1 index 4c45f54624d9..25b182bca27e 100644 --- a/Tools/Update-StandardsComments.ps1 +++ b/Tools/Update-StandardsComments.ps1 @@ -47,9 +47,137 @@ function EscapeMarkdown([object]$InputObject) { return $Temp.Replace('\', '\\').Replace('*', '\*').Replace('_', '\_').Replace("``", "\``").Replace('$', '\$').Replace('|', '\|').Replace('<', '\<').Replace('>', '\>').Replace([System.Environment]::NewLine, '
') } +function Get-StringValuesFromAst { + param( + [Parameter(Mandatory = $true)] + [System.Management.Automation.Language.Ast]$ArgumentAst + ) + + try { + $Value = $ArgumentAst.SafeGetValue() + if ($Value -is [array]) { + return @($Value | ForEach-Object { $_.ToString() }) + } + + if ($Value -is [string]) { + return @($Value) + } + } catch {} + + if ($ArgumentAst -is [System.Management.Automation.Language.StringConstantExpressionAst]) { + return @($ArgumentAst.Value) + } + + if ($ArgumentAst -is [System.Management.Automation.Language.ExpandableStringExpressionAst]) { + return @($ArgumentAst.Value) + } + + if ($ArgumentAst -is [System.Management.Automation.Language.ArrayLiteralAst]) { + return @($ArgumentAst.Elements | ForEach-Object { Get-StringValuesFromAst -ArgumentAst $_ }) + } + + if ($ArgumentAst -is [System.Management.Automation.Language.PipelineAst]) { + return @($ArgumentAst.PipelineElements | ForEach-Object { Get-StringValuesFromAst -ArgumentAst $_ }) + } + + if ($ArgumentAst -is [System.Management.Automation.Language.CommandExpressionAst]) { + return @(Get-StringValuesFromAst -ArgumentAst $ArgumentAst.Expression) + } + + return @() +} + +function Get-CIPPCapabilityPresets { + param( + [Parameter(Mandatory = $true)] + [string]$Path + ) + + $Tokens = $null + $ParseErrors = $null + $Ast = [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref]$Tokens, [ref]$ParseErrors) + $LicenseFunction = $Ast.Find({ + param($Node) + $Node -is [System.Management.Automation.Language.FunctionDefinitionAst] -and $Node.Name -eq 'Test-CIPPStandardLicense' + }, $true) + + $PresetAssignment = $LicenseFunction.Body.Find({ + param($Node) + $Node -is [System.Management.Automation.Language.AssignmentStatementAst] -and + $Node.Left -is [System.Management.Automation.Language.VariableExpressionAst] -and + $Node.Left.VariablePath.UserPath -eq 'Presets' -and + $Node.Right -is [System.Management.Automation.Language.HashtableAst] + }, $true) + + $Presets = @{} + foreach ($Pair in $PresetAssignment.Right.KeyValuePairs) { + $PresetName = (Get-StringValuesFromAst -ArgumentAst $Pair.Item1)[0] + $Presets[$PresetName] = @(Get-StringValuesFromAst -ArgumentAst $Pair.Item2) + } + + return $Presets +} + +function Get-LicenseCheckCapabilities { + param( + [Parameter(Mandatory = $true)] + [string]$Content, + + [Parameter(Mandatory = $true)] + [hashtable]$CapabilityPresets + ) + + $Tokens = $null + $ParseErrors = $null + $Ast = [System.Management.Automation.Language.Parser]::ParseInput($Content, [ref]$Tokens, [ref]$ParseErrors) + $LicenseCheck = $Ast.Find({ + param($Node) + $Node -is [System.Management.Automation.Language.CommandAst] -and $Node.GetCommandName() -eq 'Test-CIPPStandardLicense' + }, $true) + + if (!$LicenseCheck) { + return @() + } + + $Capabilities = [System.Collections.Generic.List[string]]::new() + for ($Index = 0; $Index -lt $LicenseCheck.CommandElements.Count; $Index++) { + $Element = $LicenseCheck.CommandElements[$Index] + if ($Element -isnot [System.Management.Automation.Language.CommandParameterAst]) { + continue + } + + $Argument = if (($Index + 1) -lt $LicenseCheck.CommandElements.Count -and $LicenseCheck.CommandElements[$Index + 1] -isnot [System.Management.Automation.Language.CommandParameterAst]) { + $LicenseCheck.CommandElements[$Index + 1] + } + + if (!$Argument) { + continue + } + + switch ($Element.ParameterName) { + 'Preset' { + foreach ($PresetName in (Get-StringValuesFromAst -ArgumentAst $Argument)) { + foreach ($Capability in $CapabilityPresets[$PresetName]) { + $Capabilities.Add($Capability) + } + } + } + 'RequiredCapabilities' { + foreach ($Capability in (Get-StringValuesFromAst -ArgumentAst $Argument)) { + $Capabilities.Add($Capability) + } + } + } + } + + return @($Capabilities | Where-Object { $_ } | Select-Object -Unique) +} # Find the paths to the standards.json file based on the current script path -$StandardsJSONPath = Split-Path (Split-Path $PSScriptRoot) +$CIPPApiRoot = Split-Path $PSScriptRoot +$CapabilityPresets = Get-CIPPCapabilityPresets -Path (Join-Path $CIPPApiRoot 'Modules\CIPPCore\Public\Functions\Test-CIPPStandardLicense.ps1') + +$StandardsJSONPath = Split-Path $CIPPApiRoot $StandardsJSONPath = Resolve-Path "$StandardsJSONPath\*\src\data\standards.json" $StandardsInfo = Get-Content -Path $StandardsJSONPath | ConvertFrom-Json -Depth 10 @@ -57,7 +185,7 @@ foreach ($Standard in $StandardsInfo) { # Calculate the standards file name and path $StandardFileName = $Standard.name -replace 'standards.', 'Invoke-CIPPStandard' - $StandardsFilePath = Resolve-Path "$(Split-Path $PSScriptRoot)\Modules\CIPPStandards\Public\Standards\$StandardFileName.ps1" + $StandardsFilePath = Resolve-Path "$CIPPApiRoot\Modules\CIPPStandards\Public\Standards\$StandardFileName.ps1" if (-not (Test-Path $StandardsFilePath)) { Write-Host "No file found for standard $($Standard.name)" -ForegroundColor Yellow continue @@ -120,20 +248,15 @@ foreach ($Standard in $StandardsInfo) { } - # Extract RequiredCapabilities from Test-CIPPStandardLicense in the function body - # Match the first occurrence of -RequiredCapabilities @(...) in the file - $CapabilitiesRegex = 'Test-CIPPStandardLicense\s[^}]*-RequiredCapabilities\s+@\(([^)]+)\)' - if ($Content -match $CapabilitiesRegex) { - $RawCapabilities = $Matches[1] - $Capabilities = @($RawCapabilities -split ',' | ForEach-Object { $_.Trim().Trim("'").Trim('"') } | Where-Object { $_ }) - if ($Capabilities.Count -gt 0) { - $NewComment.Add(" REQUIREDCAPABILITIES`n") - foreach ($Cap in $Capabilities) { - $NewComment.Add(" `"$Cap`"`n") - } - # Update the standard object for JSON output - $Standard | Add-Member -NotePropertyName 'requiredCapabilities' -NotePropertyValue $Capabilities -Force + $Capabilities = Get-LicenseCheckCapabilities -Content $Content -CapabilityPresets $CapabilityPresets + if ($Capabilities.Count -gt 0) { + $NewComment.Add(" REQUIREDCAPABILITIES`n") + foreach ($Cap in $Capabilities) { + $NewComment.Add(" `"$Cap`"`n") } + + # Update the standard object for JSON output + $Standard | Add-Member -NotePropertyName 'requiredCapabilities' -NotePropertyValue $Capabilities -Force } else { # No license check — remove stale property if present if ($Standard.PSObject.Properties['requiredCapabilities']) { From 2152641640709ecfe211f3c38752edad0d3f5f13 Mon Sep 17 00:00:00 2001 From: Bobby <31723128+kris6673@users.noreply.github.com> Date: Mon, 11 May 2026 22:01:50 +0200 Subject: [PATCH 02/38] fix: add the presets to the rest of the standards --- ...CIPPDBCacheIntuneAppProtectionPolicies.ps1 | 2 +- .../Set-CIPPDBCacheIntuneApplications.ps1 | 2 +- ...Set-CIPPDBCacheIntuneAssignmentFilters.ps1 | 2 +- ...et-CIPPDBCacheIntuneCompliancePolicies.ps1 | 2 +- .../Set-CIPPDBCacheIntuneReusableSettings.ps1 | 2 +- .../DBCache/Set-CIPPDBCacheIntuneScripts.ps1 | 2 +- .../Invoke-CIPPStandardAutoAddProxy.ps1 | 30 +++++++++---------- ...oke-CIPPStandardEmptyFilterIPAllowList.ps1 | 2 +- ...nvoke-CIPPStandardEnforcePrivateGroups.ps1 | 3 +- .../Invoke-CIPPStandardExternalMFATrusted.ps1 | 2 +- .../Standards/Invoke-CIPPStandardTeamsZAP.ps1 | 2 +- 11 files changed, 25 insertions(+), 26 deletions(-) diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAppProtectionPolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAppProtectionPolicies.ps1 index 97696ddf8b52..d3dd14ad33fa 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAppProtectionPolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAppProtectionPolicies.ps1 @@ -7,7 +7,7 @@ function Set-CIPPDBCacheIntuneAppProtectionPolicies { ) try { - $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneAppProtectionPoliciesCache' -TenantFilter $TenantFilter -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') -SkipLog + $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneAppProtectionPoliciesCache' -TenantFilter $TenantFilter -Preset Intune -SkipLog if ($TestResult -eq $false) { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Tenant does not have Intune license, skipping app protection policies cache' -sev Debug return diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneApplications.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneApplications.ps1 index 35b802197442..811f2af821d3 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneApplications.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneApplications.ps1 @@ -7,7 +7,7 @@ function Set-CIPPDBCacheIntuneApplications { ) try { - $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneApplicationsCache' -TenantFilter $TenantFilter -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') -SkipLog + $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneApplicationsCache' -TenantFilter $TenantFilter -Preset Intune -SkipLog if ($TestResult -eq $false) { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Tenant does not have Intune license, skipping applications cache' -sev Debug return diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAssignmentFilters.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAssignmentFilters.ps1 index 6edfc3d9704e..882021cfb4ea 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAssignmentFilters.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAssignmentFilters.ps1 @@ -7,7 +7,7 @@ function Set-CIPPDBCacheIntuneAssignmentFilters { ) try { - $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneAssignmentFiltersCache' -TenantFilter $TenantFilter -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') -SkipLog + $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneAssignmentFiltersCache' -TenantFilter $TenantFilter -Preset Intune -SkipLog if ($TestResult -eq $false) { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Tenant does not have Intune license, skipping assignment filters cache' -sev Debug return diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneCompliancePolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneCompliancePolicies.ps1 index 6f0a7770b308..80256d0ce92c 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneCompliancePolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneCompliancePolicies.ps1 @@ -7,7 +7,7 @@ function Set-CIPPDBCacheIntuneCompliancePolicies { ) try { - $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneCompliancePoliciesCache' -TenantFilter $TenantFilter -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') -SkipLog + $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneCompliancePoliciesCache' -TenantFilter $TenantFilter -Preset Intune -SkipLog if ($TestResult -eq $false) { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Tenant does not have Intune license, skipping compliance policies cache' -sev Debug return diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneReusableSettings.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneReusableSettings.ps1 index e27fe5770dc4..77a964147403 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneReusableSettings.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneReusableSettings.ps1 @@ -7,7 +7,7 @@ function Set-CIPPDBCacheIntuneReusableSettings { ) try { - $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneReusableSettingsCache' -TenantFilter $TenantFilter -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') -SkipLog + $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneReusableSettingsCache' -TenantFilter $TenantFilter -Preset Intune -SkipLog if ($TestResult -eq $false) { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Tenant does not have Intune license, skipping reusable settings cache' -sev Debug return diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneScripts.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneScripts.ps1 index 47a074116886..8fb780b7d4ff 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneScripts.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneScripts.ps1 @@ -7,7 +7,7 @@ function Set-CIPPDBCacheIntuneScripts { ) try { - $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneScriptsCache' -TenantFilter $TenantFilter -RequiredCapabilities @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') -SkipLog + $TestResult = Test-CIPPStandardLicense -StandardName 'IntuneScriptsCache' -TenantFilter $TenantFilter -Preset Intune -SkipLog if ($TestResult -eq $false) { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Tenant does not have Intune license, skipping scripts cache' -sev Debug return diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoAddProxy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoAddProxy.ps1 index efb8efdee4a3..6acdb097014f 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoAddProxy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoAddProxy.ps1 @@ -36,7 +36,7 @@ function Invoke-CIPPStandardAutoAddProxy { $QueueItem ) - $TestResult = Test-CIPPStandardLicense -StandardName 'AutoArchive' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') + $TestResult = Test-CIPPStandardLicense -StandardName 'AutoArchive' -TenantFilter $Tenant -Preset Exchange if ($TestResult -eq $false) { return $true } @@ -66,13 +66,13 @@ function Invoke-CIPPStandardAutoAddProxy { $MissingProxies = 0 foreach ($Domain in $Domains) { $ProcessMailboxes = @($AllMailboxes | Where-Object { - $AllAddresses = @($_.primarySmtpAddress) - if (-not [string]::IsNullOrWhiteSpace($_.AdditionalEmailAddresses)) { - $AllAddresses += @($_.AdditionalEmailAddresses -split ',\s*') - } - $HasDomain = $AllAddresses | Where-Object { $_ -like "*@$Domain" } - -not $HasDomain - }) + $AllAddresses = @($_.primarySmtpAddress) + if (-not [string]::IsNullOrWhiteSpace($_.AdditionalEmailAddresses)) { + $AllAddresses += @($_.AdditionalEmailAddresses -split ',\s*') + } + $HasDomain = $AllAddresses | Where-Object { $_ -like "*@$Domain" } + -not $HasDomain + }) $MissingProxies += $ProcessMailboxes.Count } @@ -104,13 +104,13 @@ function Invoke-CIPPStandardAutoAddProxy { } else { foreach ($Domain in $Domains) { $ProcessMailboxes = @($AllMailboxes | Where-Object { - $AllAddresses = @($_.primarySmtpAddress) - if (-not [string]::IsNullOrWhiteSpace($_.AdditionalEmailAddresses)) { - $AllAddresses += @($_.AdditionalEmailAddresses -split ',\s*') - } - $HasDomain = $AllAddresses | Where-Object { $_ -like "*@$Domain" } - -not $HasDomain - }) + $AllAddresses = @($_.primarySmtpAddress) + if (-not [string]::IsNullOrWhiteSpace($_.AdditionalEmailAddresses)) { + $AllAddresses += @($_.AdditionalEmailAddresses -split ',\s*') + } + $HasDomain = $AllAddresses | Where-Object { $_ -like "*@$Domain" } + -not $HasDomain + }) $bulkRequest = foreach ($Mailbox in $ProcessMailboxes) { if ([string]::IsNullOrWhiteSpace($Mailbox.UPN)) { continue } diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEmptyFilterIPAllowList.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEmptyFilterIPAllowList.ps1 index 834a84e735ec..f8bb29881803 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEmptyFilterIPAllowList.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEmptyFilterIPAllowList.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardEmptyFilterIPAllowList { param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'EmptyFilterIPAllowList' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') + $TestResult = Test-CIPPStandardLicense -StandardName 'EmptyFilterIPAllowList' -TenantFilter $Tenant -Preset Exchange if ($TestResult -eq $false) { return $true } try { diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnforcePrivateGroups.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnforcePrivateGroups.ps1 index 6318cb73f1c1..18a682fbe48b 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnforcePrivateGroups.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnforcePrivateGroups.ps1 @@ -42,8 +42,7 @@ function Invoke-CIPPStandardEnforcePrivateGroups { param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'EnforcePrivateGroups' -TenantFilter $Tenant ` - -RequiredCapabilities @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') + $TestResult = Test-CIPPStandardLicense -StandardName 'EnforcePrivateGroups' -TenantFilter $Tenant -Preset SharePoint if ($TestResult -eq $false) { return $true } # Parse exclusion keywords from settings diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 index 1ab15ee45e88..d87b9e22c26f 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardExternalMFATrusted.ps1 @@ -36,7 +36,7 @@ function Invoke-CIPPStandardExternalMFATrusted { #> param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'ExternalMFATrusted' -TenantFilter $Tenant -RequiredCapabilities @('AAD_PREMIUM', 'AAD_PREMIUM_P2') + $TestResult = Test-CIPPStandardLicense -StandardName 'ExternalMFATrusted' -TenantFilter $Tenant -Preset Entra if ($TestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsZAP.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsZAP.ps1 index 3b8b0ea9b22d..7b3c19c146d2 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsZAP.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTeamsZAP.ps1 @@ -39,7 +39,7 @@ function Invoke-CIPPStandardTeamsZAP { param($Tenant, $Settings) - $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsZAP' -TenantFilter $Tenant -RequiredCapabilities @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') + $TestResult = Test-CIPPStandardLicense -StandardName 'TeamsZAP' -TenantFilter $Tenant -Preset Exchange if ($TestResult -eq $false) { return $true } try { From bc4abb53441d530ef84896da8f2a8414b744840c Mon Sep 17 00:00:00 2001 From: Bobby <31723128+kris6673@users.noreply.github.com> Date: Mon, 11 May 2026 22:23:28 +0200 Subject: [PATCH 03/38] feat: add DefenderForOffice365 preset to license tests --- .../Functions/Test-CIPPStandardLicense.ps1 | 20 +++++++++++-------- ...Set-CIPPDBCacheExoPresetSecurityPolicy.ps1 | 2 +- .../Invoke-CIPPStandardAtpPolicyForO365.ps1 | 2 +- ...nvoke-CIPPStandardSafeAttachmentPolicy.ps1 | 6 +++--- .../Invoke-CIPPStandardSafeLinksPolicy.ps1 | 2 +- ...ke-CIPPStandardSafeLinksTemplatePolicy.ps1 | 2 +- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Modules/CIPPCore/Public/Functions/Test-CIPPStandardLicense.ps1 b/Modules/CIPPCore/Public/Functions/Test-CIPPStandardLicense.ps1 index f6e745ddd3e9..4a998a6e6a9f 100644 --- a/Modules/CIPPCore/Public/Functions/Test-CIPPStandardLicense.ps1 +++ b/Modules/CIPPCore/Public/Functions/Test-CIPPStandardLicense.ps1 @@ -34,7 +34,7 @@ function Test-CIPPStandardLicense { [string[]]$RequiredCapabilities, [Parameter(Mandatory = $false)] - [ValidateSet('Exchange', 'SharePoint', 'Intune', 'Entra', 'EntraP2', 'Teams', 'Compliance')] + [ValidateSet('Exchange', 'SharePoint', 'Intune', 'Entra', 'EntraP2', 'Teams', 'Compliance', 'DefenderForOffice365')] [string[]]$Preset, [Parameter(Mandatory = $false)] @@ -42,17 +42,21 @@ function Test-CIPPStandardLicense { ) $Presets = @{ - Exchange = @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', + Exchange = @('EXCHANGE_S_STANDARD', 'EXCHANGE_S_ENTERPRISE', 'EXCHANGE_S_STANDARD_GOV', 'EXCHANGE_S_ENTERPRISE_GOV', 'EXCHANGE_LITE') - SharePoint = @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', + SharePoint = @('SHAREPOINTWAC', 'SHAREPOINTSTANDARD', 'SHAREPOINTENTERPRISE', 'SHAREPOINTENTERPRISE_EDU', 'SHAREPOINTENTERPRISE_GOV', 'ONEDRIVE_BASIC', 'ONEDRIVE_ENTERPRISE') - Intune = @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') - Entra = @('AAD_PREMIUM', 'AAD_PREMIUM_P2') - EntraP2 = @('AAD_PREMIUM_P2') - Teams = @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') - Compliance = @('RMS_S_PREMIUM', 'RMS_S_PREMIUM2', 'MIP_S_CLP1', 'MIP_S_CLP2') + Intune = @('INTUNE_A', 'MDM_Services', 'EMS', 'SCCM', 'MICROSOFTINTUNEPLAN1') + Entra = @('AAD_PREMIUM', 'AAD_PREMIUM_P2') + EntraP2 = @('AAD_PREMIUM_P2') + Teams = @('MCOSTANDARD', 'MCOEV', 'MCOIMP', 'TEAMS1', 'Teams_Room_Standard') + Compliance = @('RMS_S_PREMIUM', 'RMS_S_PREMIUM2', 'MIP_S_CLP1', 'MIP_S_CLP2') + DefenderForOffice365 = @( + 'ATP_ENTERPRISE', 'ATP_ENTERPRISE_GOV', + 'THREAT_INTELLIGENCE', 'THREAT_INTELLIGENCE_GOV' + ) } if ((!$Preset -or $Preset.Count -eq 0) -and (!$RequiredCapabilities -or $RequiredCapabilities.Count -eq 0)) { diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoPresetSecurityPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoPresetSecurityPolicy.ps1 index 5476d515bbe9..0810cf69ade7 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoPresetSecurityPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoPresetSecurityPolicy.ps1 @@ -19,7 +19,7 @@ function Set-CIPPDBCacheExoPresetSecurityPolicy { try { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching Exchange Preset Security Policies' -sev Debug - $MDOTestResult = Test-CIPPStandardLicense -StandardName 'ExoPresetSecurityPolicy' -TenantFilter $TenantFilter -RequiredCapabilities @('ATP_ENTERPRISE', 'ATP_ENTERPRISE_GOV', 'THREAT_INTELLIGENCE') -SkipLog + $MDOTestResult = Test-CIPPStandardLicense -StandardName 'ExoPresetSecurityPolicy' -TenantFilter $TenantFilter -Preset DefenderForOffice365 -SkipLog if ($MDOTestResult -eq $false) { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Skipping Preset Security Policy cache: tenant lacks Microsoft Defender for Office 365' -sev Debug return diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 index a7aa4b0982d4..e89461cf1430 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 @@ -47,7 +47,7 @@ function Invoke-CIPPStandardAtpPolicyForO365 { return $true } #we're done. - $MDOTestResult = Test-CIPPStandardLicense -StandardName 'AtpPolicyForO365' -TenantFilter $Tenant -RequiredCapabilities @('ATP_ENTERPRISE', 'ATP_ENTERPRISE_GOV', 'THREAT_INTELLIGENCE') + $MDOTestResult = Test-CIPPStandardLicense -StandardName 'AtpPolicyForO365' -TenantFilter $Tenant -Preset DefenderForOffice365 if ($MDOTestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 index 89939e00d904..61b515a26761 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 @@ -53,7 +53,7 @@ function Invoke-CIPPStandardSafeAttachmentPolicy { return $true } #we're done. - $MDOTestResult = Test-CIPPStandardLicense -StandardName 'SafeAttachmentPolicy' -TenantFilter $Tenant -RequiredCapabilities @('ATP_ENTERPRISE', 'ATP_ENTERPRISE_GOV', 'THREAT_INTELLIGENCE') + $MDOTestResult = Test-CIPPStandardLicense -StandardName 'SafeAttachmentPolicy' -TenantFilter $Tenant -Preset DefenderForOffice365 if ($MDOTestResult -eq $false) { return $true @@ -113,8 +113,8 @@ function Invoke-CIPPStandardSafeAttachmentPolicy { $AcceptedDomains = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-AcceptedDomain' $RuleState = $AllSafeAttachmentRule | - Where-Object -Property Name -EQ $RuleName | - Select-Object Name, SafeAttachmentPolicy, Priority, RecipientDomainIs + Where-Object -Property Name -EQ $RuleName | + Select-Object Name, SafeAttachmentPolicy, Priority, RecipientDomainIs $RuleStateIsCorrect = ($RuleState.Name -eq $RuleName) -and ($RuleState.SafeAttachmentPolicy -eq $PolicyName) -and diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 index 59012f028253..3e10dc15f1d8 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 @@ -67,7 +67,7 @@ function Invoke-CIPPStandardSafeLinksPolicy { return $true } #we're done. - $MDOTestResult = Test-CIPPStandardLicense -StandardName 'SafeLinksPolicy' -TenantFilter $Tenant -RequiredCapabilities @('ATP_ENTERPRISE', 'ATP_ENTERPRISE_GOV', 'THREAT_INTELLIGENCE') + $MDOTestResult = Test-CIPPStandardLicense -StandardName 'SafeLinksPolicy' -TenantFilter $Tenant -Preset DefenderForOffice365 if ($MDOTestResult -eq $false) { return $true diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksTemplatePolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksTemplatePolicy.ps1 index 2f671e1b4db0..475de0053c67 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksTemplatePolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksTemplatePolicy.ps1 @@ -45,7 +45,7 @@ function Invoke-CIPPStandardSafeLinksTemplatePolicy { Write-LogMessage -API 'Standards' -tenant $Tenant -message "Processing SafeLinks template with settings: $($Settings | ConvertTo-Json -Compress)" -sev Debug - $MDOTestResult = Test-CIPPStandardLicense -StandardName 'SafeLinksTemplatePolicy' -TenantFilter $Tenant -RequiredCapabilities @('ATP_ENTERPRISE', 'ATP_ENTERPRISE_GOV', 'THREAT_INTELLIGENCE') + $MDOTestResult = Test-CIPPStandardLicense -StandardName 'SafeLinksTemplatePolicy' -TenantFilter $Tenant -Preset DefenderForOffice365 if ($MDOTestResult -eq $false) { return } #tenant lacks Microsoft Defender for Office 365 — Test-CIPPStandardLicense logs and sets LicenseAvailable=false. From f5702f41f1fa33ab7cfa8be9989c913d88d7d880 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 11 May 2026 23:57:27 -0400 Subject: [PATCH 04/38] feat: Enhance Invoke-ListIntuneTemplates to include usage tracking for standards templates --- .../MEM/Invoke-ListIntuneTemplates.ps1 | 109 +++++++++++++----- 1 file changed, 83 insertions(+), 26 deletions(-) diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntuneTemplates.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntuneTemplates.ps1 index 2b0da1d4a696..3120a5d863c4 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntuneTemplates.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntuneTemplates.ps1 @@ -48,37 +48,94 @@ function Invoke-ListIntuneTemplates { } } | Sort-Object -Property displayName + + # Build a lookup of which standards templates reference each Intune template (by GUID or package) + $UsageByGuid = @{} + $UsageByPackage = @{} + $StdTemplates = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'StandardsTemplateV2'" + foreach ($StdRaw in $StdTemplates) { + try { + $StdData = $StdRaw.JSON | ConvertFrom-Json -Depth 100 -ErrorAction SilentlyContinue + if (-not $StdData -or -not $StdData.standards) { continue } + $IsDrift = $StdData.type -eq 'drift' + $StdInfo = [pscustomobject]@{ + templateName = $StdData.templateName + templateId = $StdRaw.RowKey + isDrift = $IsDrift + cippLink = "/tenant/standards/templates/template?id=$($StdRaw.RowKey)$(if ($IsDrift) { '&type=drift' })" + } + $IntuneEntries = $StdData.standards.IntuneTemplate + if (-not $IntuneEntries) { continue } + $Items = if ($IntuneEntries -is [System.Collections.IEnumerable] -and $IntuneEntries -isnot [string]) { $IntuneEntries } else { @($IntuneEntries) } + foreach ($Item in $Items) { + if ($Item.TemplateList.value) { + $Guid = $Item.TemplateList.value + if (-not $UsageByGuid.ContainsKey($Guid)) { $UsageByGuid[$Guid] = [System.Collections.Generic.List[object]]::new() } + $UsageByGuid[$Guid].Add($StdInfo) + } + if ($Item.'TemplateList-Tags'.value) { + $Pkg = $Item.'TemplateList-Tags'.value + if (-not $UsageByPackage.ContainsKey($Pkg)) { $UsageByPackage[$Pkg] = [System.Collections.Generic.List[object]]::new() } + $UsageByPackage[$Pkg].Add($StdInfo) + } + } + } catch {} + } + + # Attach usage list to each Intune template + foreach ($Tpl in $Templates) { + $Usage = [System.Collections.Generic.List[object]]::new() + if ($Tpl.GUID -and $UsageByGuid.ContainsKey($Tpl.GUID)) { + foreach ($U in $UsageByGuid[$Tpl.GUID]) { + $Entry = $U | Select-Object * + $Entry | Add-Member -NotePropertyName 'matchType' -NotePropertyValue 'direct' -Force + $Usage.Add($Entry) + } + } + if ($Tpl.package -and $UsageByPackage.ContainsKey($Tpl.package)) { + foreach ($U in $UsageByPackage[$Tpl.package]) { + # Avoid duplicates when the same template matches both GUID and package + if (-not ($Usage | Where-Object { $_.templateId -eq $U.templateId })) { + $Entry = $U | Select-Object * + $Entry | Add-Member -NotePropertyName 'matchType' -NotePropertyValue 'package' -Force + $Entry | Add-Member -NotePropertyName 'package' -NotePropertyValue $Tpl.package -Force + $Usage.Add($Entry) + } + } + } + $Tpl | Add-Member -NotePropertyName 'usedInTemplates' -NotePropertyValue @($Usage) -Force + } } else { if ($Request.query.mode -eq 'Tag') { #when the mode is tag, show all the potential tags, return the object with: label: tag, value: tag, count: number of templates with that tag, unique only $Templates = @($RawTemplates | Where-Object { $_.Package } | Group-Object -Property Package | ForEach-Object { - $package = $_.Name - $packageTemplates = @($_.Group) - $templateCount = $packageTemplates.Count - [pscustomobject]@{ - label = "$($package) ($templateCount Templates)" - value = $package - type = 'tag' - templateCount = $templateCount - templates = @($packageTemplates | ForEach-Object { - try { - $JSONData = $_.JSON | ConvertFrom-Json -Depth 100 -ErrorAction SilentlyContinue - $data = $JSONData.RAWJson | ConvertFrom-Json -Depth 100 -ErrorAction SilentlyContinue - $data | Add-Member -NotePropertyName 'displayName' -NotePropertyValue $JSONData.Displayname -Force - $data | Add-Member -NotePropertyName 'description' -NotePropertyValue $JSONData.Description -Force - $data | Add-Member -NotePropertyName 'Type' -NotePropertyValue $JSONData.Type -Force - $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.RowKey -Force - $data | Add-Member -NotePropertyName 'package' -NotePropertyValue $_.Package -Force - $data | Add-Member -NotePropertyName 'source' -NotePropertyValue $_.Source -Force - $data | Add-Member -NotePropertyName 'isSynced' -NotePropertyValue (![string]::IsNullOrEmpty($_.SHA)) -Force - $data | Add-Member -NotePropertyName 'reusableSettings' -NotePropertyValue $JSONData.ReusableSettings -Force - $data - } catch { + $package = $_.Name + $packageTemplates = @($_.Group) + $templateCount = $packageTemplates.Count + [pscustomobject]@{ + label = "$($package) ($templateCount Templates)" + value = $package + type = 'tag' + templateCount = $templateCount + templates = @($packageTemplates | ForEach-Object { + try { + $JSONData = $_.JSON | ConvertFrom-Json -Depth 100 -ErrorAction SilentlyContinue + $data = $JSONData.RAWJson | ConvertFrom-Json -Depth 100 -ErrorAction SilentlyContinue + $data | Add-Member -NotePropertyName 'displayName' -NotePropertyValue $JSONData.Displayname -Force + $data | Add-Member -NotePropertyName 'description' -NotePropertyValue $JSONData.Description -Force + $data | Add-Member -NotePropertyName 'Type' -NotePropertyValue $JSONData.Type -Force + $data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.RowKey -Force + $data | Add-Member -NotePropertyName 'package' -NotePropertyValue $_.Package -Force + $data | Add-Member -NotePropertyName 'source' -NotePropertyValue $_.Source -Force + $data | Add-Member -NotePropertyName 'isSynced' -NotePropertyValue (![string]::IsNullOrEmpty($_.SHA)) -Force + $data | Add-Member -NotePropertyName 'reusableSettings' -NotePropertyValue $JSONData.ReusableSettings -Force + $data + } catch { - } - }) - } - } | Sort-Object -Property label) + } + }) + } + } | Sort-Object -Property label) } else { $Templates = $RawTemplates.JSON | ForEach-Object { try { ConvertFrom-Json -InputObject $_ -Depth 100 -ErrorAction SilentlyContinue } catch {} } From ecbc9a50ac0584e0d0ce59259214ebe6d9cf525a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Mon, 11 May 2026 23:58:56 -0400 Subject: [PATCH 05/38] fix: Add error handling for missing standard functions in Push-CIPPStandard --- .../Activity Triggers/Standards/Push-CIPPStandard.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 index e7df2cc7f723..1e52ae35375a 100644 --- a/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 +++ b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 @@ -40,6 +40,12 @@ function Push-CIPPStandard { $StandardInfo.ConditionalAccessTemplateId = $Item.Settings.TemplateList.value } + if (-not (Get-Command -Name $FunctionName -Module CIPPStandards -ErrorAction SilentlyContinue)) { + Write-LogMessage -tenant $Tenant -message "The standard $Standard was not found. This may have been deprecated or replaced with a new standard." -sev 'Warning' -API 'Standards' + Write-Warning "Function $FunctionName not found" + return + } + # Initialize AsyncLocal storage for thread-safe per-invocation context # Uses $global: so Write-LogMessage (CIPPCore module) can read it across module boundaries if (-not $global:CippStandardInfoStorage) { From 57b7de1f31bcffa3ebc3ba1f05d5d47fa1b6bffe Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 12 May 2026 00:07:30 -0400 Subject: [PATCH 06/38] fix: Rename 'usedInTemplates' property to 'usage' for clarity in Invoke-ListIntuneTemplates --- .../HTTP Functions/Endpoint/MEM/Invoke-ListIntuneTemplates.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntuneTemplates.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntuneTemplates.ps1 index 3120a5d863c4..4944d2f2f7cb 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntuneTemplates.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-ListIntuneTemplates.ps1 @@ -103,7 +103,7 @@ function Invoke-ListIntuneTemplates { } } } - $Tpl | Add-Member -NotePropertyName 'usedInTemplates' -NotePropertyValue @($Usage) -Force + $Tpl | Add-Member -NotePropertyName 'usage' -NotePropertyValue @($Usage) -Force } } else { if ($Request.query.mode -eq 'Tag') { From 7fd7d097882ad258695905e15c19addd288d493c Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 12 May 2026 14:28:11 +0200 Subject: [PATCH 07/38] fixes sharepoint response stuff --- .../DBCache/Set-CIPPDBCacheSharePointSiteUsage.ps1 | 14 +++++++++++--- .../Teams-Sharepoint/Invoke-ListSites.ps1 | 14 +++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSharePointSiteUsage.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSharePointSiteUsage.ps1 index 90ab81351b7a..5722f962b7a0 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSharePointSiteUsage.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSharePointSiteUsage.ps1 @@ -37,9 +37,17 @@ function Set-CIPPDBCacheSharePointSiteUsage { $Result = New-GraphBulkRequest -tenantid $TenantFilter -Requests @($BulkRequests) -asapp $true $Sites = @(($Result | Where-Object { $_.id -eq 'listAllSites' }).body.value) - $UsageBase64 = ($Result | Where-Object { $_.id -eq 'usage' }).body - $UsageJson = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($UsageBase64)) - $UsageRows = @(($UsageJson | ConvertFrom-Json).value) + $UsageResponse = $Result | Where-Object { $_.id -eq 'usage' } + if ($UsageResponse.status -and $UsageResponse.status -ne 200) { + throw ($UsageResponse.body.error.message ?? "Usage report request failed with status $($UsageResponse.status)") + } + $UsageBody = $UsageResponse.body + if ($UsageBody -is [string]) { + $UsageJson = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($UsageBody)) + $UsageRows = @(($UsageJson | ConvertFrom-Json).value) + } else { + $UsageRows = @($UsageBody.value) + } # Ensure a stable row key for usage rows. foreach ($UsageRow in $UsageRows) { diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 index d8aae26f5998..0335d3357557 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ListSites.ps1 @@ -78,9 +78,17 @@ function Invoke-ListSites { $Result = New-GraphBulkRequest -tenantid $TenantFilter -Requests @($BulkRequests) -asapp $true $Sites = ($Result | Where-Object { $_.id -eq 'listAllSites' }).body.value - $UsageBase64 = ($Result | Where-Object { $_.id -eq 'usage' }).body - $UsageJson = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($UsageBase64)) - $Usage = ($UsageJson | ConvertFrom-Json).value + $UsageResponse = $Result | Where-Object { $_.id -eq 'usage' } + if ($UsageResponse.status -and $UsageResponse.status -ne 200) { + throw ($UsageResponse.body.error.message ?? "Usage report request failed with status $($UsageResponse.status)") + } + $UsageBody = $UsageResponse.body + if ($UsageBody -is [string]) { + $UsageJson = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($UsageBody)) + $Usage = ($UsageJson | ConvertFrom-Json).value + } else { + $Usage = @($UsageBody.value) + } $GraphRequest = foreach ($Site in $Sites) { $SiteUsage = $Usage | Where-Object { $_.siteId -eq $Site.sharepointIds.siteId } From 23c8994da9a523a6fbce594181f0c74e5fb1a69e Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 12 May 2026 14:33:28 +0200 Subject: [PATCH 08/38] fixes defaultr_hidden vs hidden #5990 --- .../Standards/Invoke-CIPPStandardDeployCheckChromeExtension.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployCheckChromeExtension.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployCheckChromeExtension.ps1 index 413c5b6f9594..84f5099dd7b7 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployCheckChromeExtension.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployCheckChromeExtension.ps1 @@ -137,7 +137,7 @@ function Invoke-CIPPStandardDeployCheckChromeExtension { ExtSettingsKey = "HKLM:\SOFTWARE\Policies\Microsoft\Edge\ExtensionSettings\`$edgeExtensionId" ToolbarProp = 'toolbar_state' ToolbarPinned = 'force_shown' - ToolbarUnpinned = 'hidden' + ToolbarUnpinned = 'default_hidden' } ) From ad0d096c727ec2b881f0ea8a4e5ff33a8950f0a8 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 12 May 2026 16:03:49 +0200 Subject: [PATCH 09/38] OneDrive Sharing disable --- .../Public/Invoke-CIPPOffboardingJob.ps1 | 11 ++++ .../Public/Set-CIPPOneDriveSharing.ps1 | 65 +++++++++++++++++++ .../Users/Invoke-ExecBECRemediate.ps1 | 15 +++++ .../Invoke-ExecSetOneDriveSharing.ps1 | 37 +++++++++++ 4 files changed, 128 insertions(+) create mode 100644 Modules/CIPPCore/Public/Set-CIPPOneDriveSharing.ps1 create mode 100644 Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetOneDriveSharing.ps1 diff --git a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 index 10f00534abae..2724877e0557 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPOffboardingJob.ps1 @@ -165,6 +165,17 @@ function Invoke-CIPPOffboardingJob { Headers = $Headers } } + @{ + Condition = { $Options.DisableOneDriveSharing -eq $true } + Cmdlet = 'Set-CIPPOneDriveSharing' + Parameters = @{ + TenantFilter = $TenantFilter + UserId = $Username + SharingCapability = 'Disabled' + APIName = $APIName + Headers = $Headers + } + } @{ Condition = { $Options.AccessNoAutomap.Count -gt 0 } Cmdlet = 'Set-CIPPMailboxAccess' diff --git a/Modules/CIPPCore/Public/Set-CIPPOneDriveSharing.ps1 b/Modules/CIPPCore/Public/Set-CIPPOneDriveSharing.ps1 new file mode 100644 index 000000000000..8b0c8d4ed439 --- /dev/null +++ b/Modules/CIPPCore/Public/Set-CIPPOneDriveSharing.ps1 @@ -0,0 +1,65 @@ +function Set-CIPPOneDriveSharing { + [CmdletBinding()] + param ( + $UserId, + $TenantFilter, + [ValidateSet('Disabled', 'ExternalUserSharingOnly', 'ExternalUserAndGuestSharing', 'ExistingExternalUserSharingOnly')] + [string]$SharingCapability = 'Disabled', + $APIName = 'Set OneDrive Sharing', + $Headers, + $URL + ) + + $SharingCapabilityMap = @{ + 'Disabled' = 0 + 'ExternalUserSharingOnly' = 1 + 'ExternalUserAndGuestSharing' = 2 + 'ExistingExternalUserSharingOnly' = 3 + } + $EnumValue = $SharingCapabilityMap[$SharingCapability] + + try { + if (!$URL) { + #Grab url, get root level, strip /documents + $URL = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/users/$($UserId)/drive" -asapp $true -tenantid $TenantFilter).webUrl -replace '/documents', '' + } + + $SharePointInfo = Get-SharePointAdminLink -Public $false -tenantFilter $TenantFilter + + $XML = @" + + + + $EnumValue + + + + + + + $URL + false + + + + + +"@ + $Request = New-GraphPostRequest -scope "$($SharePointInfo.AdminUrl)/.default" -tenantid $TenantFilter -Uri "$($SharePointInfo.AdminUrl)/_vti_bin/client.svc/ProcessQuery" -Type POST -Body $XML -ContentType 'text/xml' + + if (!$Request.ErrorInfo.ErrorMessage) { + $Message = "Successfully set OneDrive sharing to '$SharingCapability' for $UserId ($URL)" + Write-LogMessage -headers $Headers -API $APIName -message $Message -Sev Info -tenant $TenantFilter + return $Message + } else { + $Message = "Failed to set OneDrive sharing for $UserId : $($Request.ErrorInfo.ErrorMessage)" + Write-LogMessage -headers $Headers -API $APIName -message $Message -Sev Error -tenant $TenantFilter + return $Message + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Message = "Failed to set OneDrive sharing for $UserId. Error: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Message -Sev Error -tenant $TenantFilter -LogData $ErrorMessage + throw $Message + } +} diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecBECRemediate.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecBECRemediate.ps1 index 29bf889d3773..f9516ce5ab29 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecBECRemediate.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ExecBECRemediate.ps1 @@ -180,6 +180,21 @@ function Invoke-ExecBECRemediate { }) } + # Step 6: Disable OneDrive Sharing + $Step = 'Disable OneDrive Sharing' + try { + $OneDriveResult = Set-CIPPOneDriveSharing -UserId $Username -TenantFilter $TenantFilter -SharingCapability 'Disabled' -APIName $APIName -Headers $Headers + $AllResults.Add([pscustomobject]@{ + resultText = $OneDriveResult + state = if ($OneDriveResult -like '*Successfully*') { 'success' } else { 'error' } + }) + } catch { + $AllResults.Add([pscustomobject]@{ + resultText = "Failed to disable OneDrive sharing: $($_.Exception.Message)" + state = 'error' + }) + } + $StatusCode = [HttpStatusCode]::OK Write-LogMessage -API 'BECRemediate' -tenant $TenantFilter -message "Executed Remediation for $Username" -sev 'Info' -LogData @($AllResults) diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetOneDriveSharing.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetOneDriveSharing.ps1 new file mode 100644 index 000000000000..3bffa6f834d0 --- /dev/null +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Teams-Sharepoint/Invoke-ExecSetOneDriveSharing.ps1 @@ -0,0 +1,37 @@ +function Invoke-ExecSetOneDriveSharing { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Teams.SharePoint.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $TenantFilter = $Request.Body.tenantFilter + $UserPrincipalName = $Request.Body.UPN + $SharingCapability = $Request.Body.SharingCapability.value ?? $Request.Body.SharingCapability + + try { + $Result = Set-CIPPOneDriveSharing ` + -UserId $UserPrincipalName ` + -TenantFilter $TenantFilter ` + -SharingCapability $SharingCapability ` + -APIName $APIName ` + -Headers $Request.Headers + + $Body = @{ Results = $Result } + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -tenant $TenantFilter -message "Failed to set OneDrive sharing: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + $Body = @{ Results = "Failed to set OneDrive sharing: $($ErrorMessage.NormalizedError)" } + $StatusCode = [HttpStatusCode]::InternalServerError + } + + return [HttpResponseContext]@{ + StatusCode = $StatusCode + Body = $Body + } +} From 2869564fb904deced3eb5c076f19519db12c3769 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 12 May 2026 16:32:19 +0200 Subject: [PATCH 10/38] Add AlertUserReportPhising --- Config/SAMManifest.json | 4 ++ .../Get-CIPPAlertUserReportedPhishing.ps1 | 47 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertUserReportedPhishing.ps1 diff --git a/Config/SAMManifest.json b/Config/SAMManifest.json index 87e3978f2483..ab325ce85ae1 100644 --- a/Config/SAMManifest.json +++ b/Config/SAMManifest.json @@ -571,6 +571,10 @@ { "id": "a94a502d-0281-4d15-8cd2-682ac9362c4c", "type": "Role" + }, + { + "id": "d72bdbf4-a59b-405c-8b04-5995895819ac", + "type": "Role" } ] }, diff --git a/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertUserReportedPhishing.ps1 b/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertUserReportedPhishing.ps1 new file mode 100644 index 000000000000..60138097fc7b --- /dev/null +++ b/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertUserReportedPhishing.ps1 @@ -0,0 +1,47 @@ +function Get-CIPPAlertUserReportedPhishing { + <# + .FUNCTIONALITY + Entrypoint + #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $false)] + [Alias('input')] + $InputValue, + $TenantFilter + ) + + try { + [int]$HoursBack = if ($InputValue.HoursBack) { [int]$InputValue.HoursBack } else { 24 } + $Since = (Get-Date).AddHours(-$HoursBack).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + + $Submissions = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/security/threatSubmission/emailThreats?`$filter=createdDateTime ge $Since" -tenantid $TenantFilter -AsApp $true + + $AlertData = foreach ($Submission in $Submissions) { + # Only include user-reported submissions + if ($Submission.source -ne 'user') { continue } + + [PSCustomObject]@{ + ReportedBy = $Submission.createdBy.user.displayName + ReporterEmail = $Submission.createdBy.user.email + Sender = $Submission.sender + Subject = $Submission.emailSubject + Category = $Submission.category + ReceivedDateTime = $Submission.receivedDateTime + ReportedAt = $Submission.createdDateTime + Status = $Submission.status + ResultCategory = $Submission.result.category + ResultDetail = $Submission.result.detail + InternetMsgId = $Submission.internetMessageId + SubmissionId = $Submission.id + Tenant = $TenantFilter + } + } + if ($AlertData) { + Write-AlertTrace -cmdletName $MyInvocation.MyCommand -tenantFilter $TenantFilter -data $AlertData + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-AlertMessage -message "User-reported phishing alert failed for $($TenantFilter): $($ErrorMessage.NormalizedError)" -tenant $TenantFilter -LogData $ErrorMessage + } +} From ddb498fe81df0262aa834db9617ed08dad38aeed Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 12 May 2026 11:32:15 -0400 Subject: [PATCH 11/38] chore: bump version to 10.4.5 --- host.json | 2 +- version_latest.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/host.json b/host.json index 473ab1bfce11..5635adf20ae2 100644 --- a/host.json +++ b/host.json @@ -16,7 +16,7 @@ "distributedTracingEnabled": false, "version": "None" }, - "defaultVersion": "10.4.4", + "defaultVersion": "10.4.5", "versionMatchStrategy": "Strict", "versionFailureStrategy": "Fail" } diff --git a/version_latest.txt b/version_latest.txt index 622a6f75b792..aa725fbb1929 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -10.4.4 +10.4.5 From 35437558e4699479e303f4245fe14d3e258cdba2 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Tue, 12 May 2026 23:39:36 +0800 Subject: [PATCH 12/38] Update Viva standard --- .../Public/Standards/Invoke-CIPPStandardDisableViva.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 index 542d8edc54cb..6cf276f3ce92 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableViva.ps1 @@ -46,7 +46,7 @@ function Invoke-CIPPStandardDisableViva { } else { try { # TODO This does not work without Global Admin permissions for some reason. Throws an "EXCEPTION: Tenant admin role is required" error. -Bobby - New-GraphPOSTRequest -Uri "https://graph.microsoft.com/beta/organization/$Tenant/settings/peopleInsights" -tenantid $Tenant -Type PATCH -Body '{"isEnabledInOrganization": false}' -ContentType 'application/json' + New-GraphPOSTRequest -Uri "https://graph.microsoft.com/beta/organization/$Tenant/settings/peopleInsights" -tenantid $Tenant -Type PATCH -Body '{"isEnabledInOrganization": false}' -ContentType 'application/json' -AsApp $true Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Disabled Viva insights' -sev Info } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message From 781930205c67fc17a5ca887755361987a407012a Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 12 May 2026 12:20:47 -0400 Subject: [PATCH 13/38] fix name --- .../Activity Triggers/Push-OrchestratorBatchItems.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-OrchestratorBatchItems.ps1 b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-OrchestratorBatchItems.ps1 index 9e8fe4561a1d..df59afa91619 100644 --- a/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-OrchestratorBatchItems.ps1 +++ b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-OrchestratorBatchItems.ps1 @@ -11,8 +11,8 @@ function Push-OrchestratorBatchItems { $Entities = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq '$($Item.Parameters.BatchId)'" $BatchItems = [system.Collections.Generic.List[object]]::new() $Entities | ForEach-Object { - $Item = $_.BatchItem | ConvertFrom-Json - $BatchItems.Add($Item) + $BatchItem = $_.BatchItem | ConvertFrom-Json + $BatchItems.Add($BatchItem) } Write-Information "Retrieved $($BatchItems.Count) batch items for BatchId: $($Item.Parameters.BatchId)" } else { From 785e71c530a39b46f56cea7c598f7d609d8a8518 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Tue, 12 May 2026 18:26:46 +0200 Subject: [PATCH 14/38] fix user select --- .../Public/Set-CIPPDefaultAPDeploymentProfile.ps1 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPDefaultAPDeploymentProfile.ps1 b/Modules/CIPPCore/Public/Set-CIPPDefaultAPDeploymentProfile.ps1 index 7fa56473ec0b..770b24be8003 100644 --- a/Modules/CIPPCore/Public/Set-CIPPDefaultAPDeploymentProfile.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPDefaultAPDeploymentProfile.ps1 @@ -24,9 +24,7 @@ function Set-CIPPDefaultAPDeploymentProfile { # 'user-select' -> empty string (lets user choose during OOBE) # 'os-default' or $null -> $null (uses operating system default) # Specific tag (e.g. 'en-US') -> passed through as-is - if ($Language -eq 'user-select') { - $Language = '' - } elseif ($Language -eq 'os-default' -or $null -eq $Language) { + if ($Language -eq 'os-default') { $Language = $null } @@ -48,15 +46,19 @@ function Set-CIPPDefaultAPDeploymentProfile { 'displayName' = "$($DisplayName)" 'description' = "$($Description)" 'deviceNameTemplate' = "$($DeviceNameTemplate)" - 'locale' = $Language + 'locale' = "$($Language)" 'preprovisioningAllowed' = $([bool]($AllowWhiteGlove)) 'deviceType' = 'windowsPc' 'hardwareHashExtractionEnabled' = $([bool]($CollectHash)) 'roleScopeTagIds' = @() 'outOfBoxExperienceSetting' = $OutOfBoxSetting } + if ($Language -eq 'user-select') { + #Add language query to body only if user-select, as Graph API treats empty string differently than null + $ObjBody.locale = '' + $ObjBody | Add-Member -MemberType NoteProperty -Name 'language' -Value '' -Force + } $Body = ConvertTo-Json -InputObject $ObjBody -Depth 10 - Write-Information $Body $Profiles = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/windowsAutopilotDeploymentProfiles' -tenantid $TenantFilter | Where-Object -Property displayName -EQ $DisplayName From 2dbc480336773976fb1140194c4c5de348afe170 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Wed, 13 May 2026 04:19:45 +0800 Subject: [PATCH 15/38] auth configs --- Config/FeatureFlags.json | 19 + .../Public/Authentication/Get-CippApiAuth.ps1 | 45 +- .../Authentication/Initialize-CIPPAuth.ps1 | 100 +++- .../Public/Authentication/New-CIPPSSOApp.ps1 | 156 +++++ .../Remove-CIPPMigrationAppSetting.ps1 | 63 +++ .../Authentication/Set-CIPPSSOEasyAuth.ps1 | 182 ++++++ .../Public/Authentication/Set-CippApiAuth.ps1 | 175 ++++-- .../Public/Authentication/Test-CIPPAccess.ps1 | 39 +- .../Update-CIPPSSORedirectUri.ps1 | 126 +++++ .../Update-AppManagementPolicy.ps1 | 6 +- .../CIPP/Core/Invoke-ListFeatureFlags.ps1 | 13 +- .../CIPP/Settings/Invoke-ExecCIPPUsers.ps1 | 114 ++++ .../Invoke-ExecContainerManagement.ps1 | 173 ++++++ .../CIPP/Settings/Invoke-ListCIPPUsers.ps1 | 80 +++ .../CIPP/Setup/Invoke-ExecSSOSetup.ps1 | 531 ++++++++++++++++++ 15 files changed, 1748 insertions(+), 74 deletions(-) create mode 100644 Modules/CIPPCore/Public/Authentication/New-CIPPSSOApp.ps1 create mode 100644 Modules/CIPPCore/Public/Authentication/Remove-CIPPMigrationAppSetting.ps1 create mode 100644 Modules/CIPPCore/Public/Authentication/Set-CIPPSSOEasyAuth.ps1 create mode 100644 Modules/CIPPCore/Public/Authentication/Update-CIPPSSORedirectUri.ps1 create mode 100644 Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCIPPUsers.ps1 create mode 100644 Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecContainerManagement.ps1 create mode 100644 Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCIPPUsers.ps1 create mode 100644 Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSSOSetup.ps1 diff --git a/Config/FeatureFlags.json b/Config/FeatureFlags.json index 61a49d453458..858f8bc58bcf 100644 --- a/Config/FeatureFlags.json +++ b/Config/FeatureFlags.json @@ -20,5 +20,24 @@ "/tenant/standards/bpa-report/builder", "/tenant/standards/bpa-report/view" ] + }, + { + "Id": "SuperAdminNG", + "Name": "Super Admin", + "Description": "Additional super admin pages for CIPP instances (CIPP Users, SSO, Container management).", + "Enabled": false, + "AllowUserToggle": false, + "Timers": [], + "Endpoints": [ + "ExecCIPPUsers", + "ListCIPPUsers", + "ExecSSOSetup", + "ExecContainerManagement" + ], + "Pages": [ + "/cipp/advanced/super-admin/cipp-users", + "/cipp/advanced/super-admin/sso", + "/cipp/advanced/super-admin/container" + ] } ] diff --git a/Modules/CIPPCore/Public/Authentication/Get-CippApiAuth.ps1 b/Modules/CIPPCore/Public/Authentication/Get-CippApiAuth.ps1 index 1c5880fd8be1..6d822746d6cf 100644 --- a/Modules/CIPPCore/Public/Authentication/Get-CippApiAuth.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Get-CippApiAuth.ps1 @@ -4,27 +4,48 @@ function Get-CippApiAuth { [string]$FunctionAppName ) - $SubscriptionId = Get-CIPPAzFunctionAppSubId + $AuthSettings = $null - try { - # Get auth settings via REST - $uri = "https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$RGName/providers/Microsoft.Web/sites/$($FunctionAppName)/config/authsettingsV2/list?api-version=2020-06-01" - $response = New-CIPPAzRestRequest -Uri $uri -Method POST -ErrorAction Stop - $AuthSettings = $response.properties - } catch { - Write-Warning "Failed to get auth settings via REST: $($_.Exception.Message)" + # When the auth config is available as an env var, use it directly (no ARM call needed) + if ($env:CIPPNG -and $env:WEBSITE_AUTH_V2_CONFIG_JSON) { + $AuthSettings = $env:WEBSITE_AUTH_V2_CONFIG_JSON | ConvertFrom-Json -ErrorAction SilentlyContinue + } + + # Fall back to reading via ARM REST + if (-not $AuthSettings) { + $SubscriptionId = Get-CIPPAzFunctionAppSubId + try { + $uri = "https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$RGName/providers/Microsoft.Web/sites/$($FunctionAppName)/config/authsettingsV2/list?api-version=2020-06-01" + $response = New-CIPPAzRestRequest -Uri $uri -Method POST -ErrorAction Stop + $AuthSettings = $response.properties + } catch { + Write-Warning "Failed to get auth settings via REST: $($_.Exception.Message)" + } } - if (!$AuthSettings -and $env:WEBSITE_AUTH_V2_CONFIG_JSON) { + # Fallback to env var if ARM failed + if (-not $AuthSettings -and $env:WEBSITE_AUTH_V2_CONFIG_JSON) { $AuthSettings = $env:WEBSITE_AUTH_V2_CONFIG_JSON | ConvertFrom-Json -ErrorAction SilentlyContinue } if ($AuthSettings) { + $AAD = $AuthSettings.identityProviders.azureActiveDirectory + $Issuer = $AAD.registration.openIdIssuer ?? '' + $AllowedApps = @($AAD.validation.defaultAuthorizationPolicy.allowedApplications) + + # When SSO EasyAuth is in use, filter out its clientId — the frontend only tracks API clients + if ($env:CIPPNG) { + $SSOClientId = $AAD.registration.clientId + if ($SSOClientId) { + $AllowedApps = @($AllowedApps | Where-Object { $_ -ne $SSOClientId }) + } + } + [PSCustomObject]@{ ApiUrl = "https://$($env:WEBSITE_HOSTNAME)" - TenantID = $AuthSettings.identityProviders.azureActiveDirectory.registration.openIdIssuer -replace 'https://sts.windows.net/', '' -replace '/v2.0', '' - ClientIDs = $AuthSettings.identityProviders.azureActiveDirectory.validation.defaultAuthorizationPolicy.allowedApplications - Enabled = $AuthSettings.identityProviders.azureActiveDirectory.enabled + TenantID = $Issuer -replace 'https://sts.windows.net/', '' -replace 'https://login.microsoftonline.com/', '' -replace '/v2.0', '' + ClientIDs = $AllowedApps + Enabled = $AAD.enabled } } else { throw 'No auth settings found' diff --git a/Modules/CIPPCore/Public/Authentication/Initialize-CIPPAuth.ps1 b/Modules/CIPPCore/Public/Authentication/Initialize-CIPPAuth.ps1 index bf0b55902563..f5f48e325add 100644 --- a/Modules/CIPPCore/Public/Authentication/Initialize-CIPPAuth.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Initialize-CIPPAuth.ps1 @@ -4,8 +4,10 @@ function Initialize-CIPPAuth { Bootstraps authentication state for CIPP. .DESCRIPTION - Loads SAM credentials from Key Vault (or DevSecrets table) - and auto-patches redirect URIs on the SAM app registration. + Loads SAM credentials from Key Vault (or DevSecrets table), + auto-patches redirect URIs on the SAM and SSO app registrations, + and configures EasyAuth if SSO credentials are provisioned but + EasyAuth is not yet enabled. #> [CmdletBinding()] param() @@ -41,7 +43,99 @@ function Initialize-CIPPAuth { try { Update-CIPPSAMRedirectUri } catch { - Write-Information "[Auth-Init] Redirect URI patch failed (non-fatal): $_" + Write-Information "[Auth-Init] SAM redirect URI patch failed (non-fatal): $_" + } + + try { + Update-CIPPSSORedirectUri + } catch { + Write-Information "[Auth-Init] SSO redirect URI patch failed (non-fatal): $_" + } + } + + # 4. If EasyAuth is not configured, check for SSO credentials and set it up + $EasyAuthEnabled = [Craft.Services.AppLifecycleBridge]::IsEasyAuthConfigured() + if (-not $EasyAuthEnabled -and $AuthState.HasSAMCredentials) { + # If the central migration app ID is set, configure EasyAuth with implicit auth + # (no client secret). This lets the user log in via the shared app while the + # ForcedSsoMigrationDialog guides them through creating their own CIPP-SSO app. + # Once they complete migration, step 5 detects the clientId change and cleans up. + if ($env:CIPP_SSO_MIGRATION_APPID) { + Write-Information "[Auth-Init] CIPP_SSO_MIGRATION_APPID is set ($($env:CIPP_SSO_MIGRATION_APPID)) — configuring implicit auth EasyAuth" + try { + $Configured = Set-CIPPSSOEasyAuth -AppId $env:CIPP_SSO_MIGRATION_APPID -MultiTenant $false -TenantId $env:TenantID -UseKvReferences -ImplicitAuth + if ($Configured) { + Write-Information '[Auth-Init] Implicit auth EasyAuth configured — requesting restart' + [Craft.Services.AppLifecycleBridge]::RequestRestart('Implicit auth EasyAuth configured with central migration app during warmup') + } + } catch { + Write-Information "[Auth-Init] Implicit auth EasyAuth setup failed (non-fatal): $_" + } + return $AuthState + } + + Write-Information '[Auth-Init] EasyAuth not configured — checking for SSO credentials...' + try { + $SSOAppId = $null + $SSOMultiTenant = $false + + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true' -or $env:NonLocalHostAzurite -eq 'true') { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'SSO'" -ErrorAction SilentlyContinue + $SSOAppId = $Secret.SSOAppId + $SSOMultiTenant = $Secret.SSOMultiTenant -eq 'True' + } elseif ($KVName) { + try { $SSOAppId = Get-CippKeyVaultSecret -VaultName $KVName -Name 'SSOAppId' -AsPlainText -ErrorAction Stop } catch { } + try { + $mtVal = Get-CippKeyVaultSecret -VaultName $KVName -Name 'SSOMultiTenant' -AsPlainText -ErrorAction Stop + $SSOMultiTenant = $mtVal -eq 'True' + } catch { } + } + + if ($SSOAppId) { + Write-Information "[Auth-Init] Found SSO AppId ($SSOAppId) — configuring EasyAuth via ARM" + $Configured = Set-CIPPSSOEasyAuth -AppId $SSOAppId -MultiTenant $SSOMultiTenant -TenantId $env:TenantID -UseKvReferences + if ($Configured) { + Write-Information '[Auth-Init] EasyAuth configured — requesting container restart' + [Craft.Services.AppLifecycleBridge]::RequestRestart('EasyAuth configured from SSO credentials during warmup') + } + } else { + Write-Information '[Auth-Init] No SSO credentials found — enabling setup wizard' + [Craft.Services.AppLifecycleBridge]::RequestSetupMode('No SSO credentials found — setup wizard needed for initial EasyAuth configuration') + } + } catch { + Write-Information "[Auth-Init] SSO EasyAuth setup failed (non-fatal): $_" + } + } + + # 5. Post-migration cleanup: if CIPP_SSO_MIGRATION_APPID is still set but EasyAuth + # is now configured, check whether the EasyAuth clientId still matches the migration + # app. If it differs, the customer's own CIPP-SSO app is active and we can remove + # the migration trigger env var. + if ($EasyAuthEnabled -and $env:CIPP_SSO_MIGRATION_APPID) { + Write-Information '[Auth-Init] EasyAuth is active but CIPP_SSO_MIGRATION_APPID still set — checking if migration is complete...' + try { + $AuthConfigJson = $env:WEBSITE_AUTH_V2_CONFIG_JSON + if ($AuthConfigJson) { + $AuthConfig = $AuthConfigJson | ConvertFrom-Json -ErrorAction Stop + $ConfiguredAppId = $AuthConfig.identityProviders.azureActiveDirectory.registration.clientId + + if ($ConfiguredAppId -eq $env:CIPP_SSO_MIGRATION_APPID) { + # EasyAuth is still using the central migration app — migration not done yet + Write-Information '[Auth-Init] EasyAuth clientId matches migration app — migration still pending' + } elseif ($ConfiguredAppId) { + # EasyAuth clientId differs from the migration app — customer's own app is active + Write-Information "[Auth-Init] EasyAuth clientId ($ConfiguredAppId) differs from migration app — migration complete, cleaning up" + $Removed = Remove-CIPPMigrationAppSetting -SettingName 'CIPP_SSO_MIGRATION_APPID' + if ($Removed) { + [Craft.Services.AppLifecycleBridge]::RequestRestart('SSO migration env var cleaned up during warmup') + } + } else { + Write-Information '[Auth-Init] No clientId found in EasyAuth config — skipping cleanup' + } + } + } catch { + Write-Information "[Auth-Init] Migration cleanup check failed (non-fatal): $_" } } diff --git a/Modules/CIPPCore/Public/Authentication/New-CIPPSSOApp.ps1 b/Modules/CIPPCore/Public/Authentication/New-CIPPSSOApp.ps1 new file mode 100644 index 000000000000..d8291eacd06b --- /dev/null +++ b/Modules/CIPPCore/Public/Authentication/New-CIPPSSOApp.ps1 @@ -0,0 +1,156 @@ +function New-CIPPSSOApp { + <# + .SYNOPSIS + Creates or updates the CIPP-SSO app registration for EasyAuth SSO migration. + .DESCRIPTION + Creates a new or updates an existing Entra ID app registration for CIPP-SSO with + openid, profile, and email delegated permissions. If ExistingAppId is provided, + looks up that specific app by clientId. If the app no longer exists in the tenant, + creates a new one. Generates a client secret and returns the details needed to + configure EasyAuth. + #> + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string]$RedirectUri, + + [Parameter(Mandatory = $false)] + [bool]$MultiTenant = $false, + + [Parameter(Mandatory = $false)] + [string]$ExistingAppId + ) + + $AppDisplayName = 'CIPP-SSO' + $CallbackUri = $RedirectUri.TrimEnd('/') + '/.auth/login/aad/callback' + $SignInAudience = if ($MultiTenant) { 'AzureADMultipleOrgs' } else { 'AzureADMyOrg' } + + # Microsoft Graph resource ID and delegated permission GUIDs + $GraphResourceId = '00000003-0000-0000-c000-000000000000' + $Permissions = @( + @{ id = '37f7f235-527c-4136-accd-4a02d197296e'; type = 'Scope' } # openid + @{ id = '14dad69e-099b-42c9-810b-d002981feec1'; type = 'Scope' } # profile + @{ id = '64a6cdd6-aab1-4aaf-94b8-3cc8405e90d0'; type = 'Scope' } # email + ) + + # Look up existing app by stored AppId (not by name — supports multiple CIPP instances) + $ExistingApp = $null + if ($ExistingAppId) { + try { + $ExistingApp = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/applications(appId='$ExistingAppId')?`$select=id,appId,displayName,web" -NoAuthCheck $true -AsApp $true + Write-Information "[SSO-App] Found existing app by AppId: $ExistingAppId" + } catch { + Write-Information "[SSO-App] Stored AppId $ExistingAppId not found in tenant — will create new app" + } + } + + $AppObjectId = $null + $AppClientId = $null + $State = $null + + if ($ExistingApp) { + # Reuse existing app — patch redirect URIs and audience + $AppObjectId = $ExistingApp.id + $AppClientId = $ExistingApp.appId + $State = 'updated' + Write-Information "[SSO-App] Updating existing app: $AppClientId" + + $PatchBody = @{ + web = @{ + redirectUris = @($CallbackUri) + implicitGrantSettings = @{ enableIdTokenIssuance = $true } + } + signInAudience = $SignInAudience + requiredResourceAccess = @( + @{ + resourceAppId = $GraphResourceId + resourceAccess = $Permissions + } + ) + } | ConvertTo-Json -Depth 10 -Compress + + New-GraphPOSTRequest -uri "https://graph.microsoft.com/v1.0/applications/$AppObjectId" -body $PatchBody -type PATCH -NoAuthCheck $true -AsApp $true + } else { + # Create new app registration + $State = 'created' + Write-Information "[SSO-App] Creating new app registration: $AppDisplayName" + + $CreateBody = @{ + displayName = $AppDisplayName + signInAudience = $SignInAudience + web = @{ + redirectUris = @($CallbackUri) + implicitGrantSettings = @{ enableIdTokenIssuance = $true } + } + requiredResourceAccess = @( + @{ + resourceAppId = $GraphResourceId + resourceAccess = $Permissions + } + ) + } | ConvertTo-Json -Depth 10 -Compress + + $NewApp = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/v1.0/applications' -body $CreateBody -type POST -NoAuthCheck $true -AsApp $true + $AppObjectId = $NewApp.id + $AppClientId = $NewApp.appId + Write-Information "[SSO-App] Created app: $AppClientId (objectId: $AppObjectId)" + + # Create service principal (idempotent — catch conflict) + $Attempt = 0 + $SpnCreated = $false + while ($Attempt -lt 3 -and -not $SpnCreated) { + try { + Start-Sleep -Seconds 2 + $SpnBody = @{ appId = $AppClientId } | ConvertTo-Json -Compress + New-GraphPOSTRequest -uri 'https://graph.microsoft.com/v1.0/servicePrincipals' -body $SpnBody -type POST -NoAuthCheck $true -AsApp $true | Out-Null + $SpnCreated = $true + Write-Information "[SSO-App] Service principal created for $AppClientId" + } catch { + $Attempt++ + Write-Information "[SSO-App] SPN creation attempt $Attempt failed (may already exist): $($_.Exception.Message)" + } + } + } + + # Handle app management policy exemption (same pattern as SAM setup) + try { + $PolicyStatus = Update-AppManagementPolicy -ApplicationId $AppClientId + Write-Information "[SSO-App] Policy exemption: $($PolicyStatus.PolicyAction)" + } catch { + Write-Warning "[SSO-App] App management policy update failed (secret creation may still work): $($_.Exception.Message)" + } + + # Create client secret with retry + $SecretText = $null + $SecretAttempt = 0 + $MaxSecretRetries = 5 + while ($SecretAttempt -lt $MaxSecretRetries -and -not $SecretText) { + try { + $PasswordBody = '{"passwordCredential":{"displayName":"CIPP-SSO-Secret"}}' + $PasswordResult = New-GraphPOSTRequest -uri "https://graph.microsoft.com/v1.0/applications/$AppObjectId/addPassword" -body $PasswordBody -type POST -NoAuthCheck $true -AsApp $true + $SecretText = $PasswordResult.secretText + Write-Information "[SSO-App] Client secret created" + } catch { + $SecretAttempt++ + Write-Warning "[SSO-App] Secret creation attempt $SecretAttempt/$MaxSecretRetries failed: $($_.Exception.Message)" + if ($SecretAttempt -lt $MaxSecretRetries) { + $Delay = @(2, 5, 10, 15, 30)[$SecretAttempt - 1] + Start-Sleep -Seconds $Delay + } + } + } + + if (-not $SecretText) { + throw "Failed to create client secret for $AppDisplayName after $MaxSecretRetries attempts" + } + + return [PSCustomObject]@{ + AppId = $AppClientId + ObjectId = $AppObjectId + ClientSecret = $SecretText + TenantId = $env:TenantID + DisplayName = $AppDisplayName + State = $State + MultiTenant = $MultiTenant + } +} diff --git a/Modules/CIPPCore/Public/Authentication/Remove-CIPPMigrationAppSetting.ps1 b/Modules/CIPPCore/Public/Authentication/Remove-CIPPMigrationAppSetting.ps1 new file mode 100644 index 000000000000..118012870caf --- /dev/null +++ b/Modules/CIPPCore/Public/Authentication/Remove-CIPPMigrationAppSetting.ps1 @@ -0,0 +1,63 @@ +function Remove-CIPPMigrationAppSetting { + <# + .SYNOPSIS + Removes an app setting from the current App Service via ARM. + .DESCRIPTION + Reads the current app settings from ARM, removes the specified key, + and writes the updated settings back. Uses the managed identity for + authentication. Silently returns $false when not running in App Service. + .FUNCTIONALITY + Internal + #> + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string]$SettingName + ) + + $SiteName = $env:WEBSITE_SITE_NAME + $ResourceGroup = $env:WEBSITE_RESOURCE_GROUP + $SubscriptionId = if ($env:WEBSITE_OWNER_NAME) { ($env:WEBSITE_OWNER_NAME -split '\+')[0] } else { $null } + + if (-not $SiteName -or -not $ResourceGroup -or -not $SubscriptionId) { + Write-Information "[Migration] Not running in App Service — cannot remove app setting '$SettingName'" + return $false + } + + if (-not $env:IDENTITY_ENDPOINT -or -not $env:IDENTITY_HEADER) { + Write-Information "[Migration] No managed identity available — cannot remove app setting '$SettingName'" + return $false + } + + # Get managed identity token for ARM + $TokenUri = "$($env:IDENTITY_ENDPOINT)?resource=https://management.azure.com/&api-version=2019-08-01" + $TokenResponse = Invoke-RestMethod -Uri $TokenUri -Headers @{ 'X-IDENTITY-HEADER' = $env:IDENTITY_HEADER } -Method Get + $ArmToken = $TokenResponse.access_token + + $BaseUri = "https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroup/providers/Microsoft.Web/sites/$SiteName" + $ArmHeaders = @{ + Authorization = "Bearer $ArmToken" + 'Content-Type' = 'application/json' + } + + # Read current app settings + $CurrentSettings = Invoke-RestMethod -Uri "$BaseUri/config/appsettings/list?api-version=2024-11-01" -Method Post -Headers @{ Authorization = "Bearer $ArmToken" } + $MergedSettings = @{} + if ($CurrentSettings.properties) { + $CurrentSettings.properties.PSObject.Properties | ForEach-Object { $MergedSettings[$_.Name] = $_.Value } + } + + if (-not $MergedSettings.ContainsKey($SettingName)) { + Write-Information "[Migration] App setting '$SettingName' not found — nothing to remove" + return $true + } + + $MergedSettings.Remove($SettingName) + + $SettingsBody = @{ properties = $MergedSettings } | ConvertTo-Json -Depth 5 + Invoke-RestMethod -Uri "$BaseUri/config/appsettings?api-version=2024-11-01" -Method Put -Headers $ArmHeaders -Body $SettingsBody + + Write-Information "[Migration] Removed app setting '$SettingName'" + Write-LogMessage -API 'SSO-Migration' -message "Removed app setting '$SettingName' after successful SSO migration" -sev Info + return $true +} diff --git a/Modules/CIPPCore/Public/Authentication/Set-CIPPSSOEasyAuth.ps1 b/Modules/CIPPCore/Public/Authentication/Set-CIPPSSOEasyAuth.ps1 new file mode 100644 index 000000000000..5ca8abadae37 --- /dev/null +++ b/Modules/CIPPCore/Public/Authentication/Set-CIPPSSOEasyAuth.ps1 @@ -0,0 +1,182 @@ +function Set-CIPPSSOEasyAuth { + <# + .SYNOPSIS + Configures or updates EasyAuth (authsettingsV2) on the current App Service. + .DESCRIPTION + Handles both initial EasyAuth setup and ongoing updates. For initial setup, + creates the full authsettingsV2 config with KV references for the client secret. + For updates, reads the existing config and patches the issuer URL. + Also manages the AUTH_SECRET app setting (using KV references) and + WEBSITE_AUTH_AAD_ALLOWED_TENANTS. + Only works inside an Azure App Service with a managed identity. + .FUNCTIONALITY + Internal + #> + [CmdletBinding()] + param( + [Parameter(Mandatory)] + [string]$AppId, + + [Parameter(Mandatory)] + [bool]$MultiTenant, + + [Parameter(Mandatory)] + [string]$TenantId, + + [Parameter()] + [switch]$UseKvReferences, + + [Parameter()] + [switch]$ImplicitAuth + ) + + $SiteName = $env:WEBSITE_SITE_NAME + $ResourceGroup = $env:WEBSITE_RESOURCE_GROUP + $SubscriptionId = if ($env:WEBSITE_OWNER_NAME) { ($env:WEBSITE_OWNER_NAME -split '\+')[0] } else { $null } + + if (-not $SiteName -or -not $ResourceGroup -or -not $SubscriptionId) { + Write-Information '[SSO-EasyAuth] Not running in App Service — skipping EasyAuth config' + return $false + } + + if (-not $env:IDENTITY_ENDPOINT -or -not $env:IDENTITY_HEADER) { + Write-Information '[SSO-EasyAuth] No managed identity available — skipping EasyAuth config' + return $false + } + + # Get managed identity token for ARM + $TokenUri = "$($env:IDENTITY_ENDPOINT)?resource=https://management.azure.com/&api-version=2019-08-01" + $TokenResponse = Invoke-RestMethod -Uri $TokenUri -Headers @{ 'X-IDENTITY-HEADER' = $env:IDENTITY_HEADER } -Method Get + $ArmToken = $TokenResponse.access_token + + $BaseUri = "https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroup/providers/Microsoft.Web/sites/$SiteName" + $ArmHeaders = @{ + Authorization = "Bearer $ArmToken" + 'Content-Type' = 'application/json' + } + + $IssuerUrl = if ($MultiTenant) { + 'https://login.microsoftonline.com/common/v2.0' + } else { + "https://login.microsoftonline.com/$TenantId/v2.0" + } + + # Read current app settings and merge AUTH_SECRET + $CurrentSettings = Invoke-RestMethod -Uri "$BaseUri/config/appsettings/list?api-version=2024-11-01" -Method Post -Headers @{ Authorization = "Bearer $ArmToken" } + $MergedSettings = @{} + if ($CurrentSettings.properties) { + $CurrentSettings.properties.PSObject.Properties | ForEach-Object { $MergedSettings[$_.Name] = $_.Value } + } + + # Set AUTH_SECRET as a KV reference when requested (initial setup) + # Skip for implicit auth (no client secret needed — e.g. central migration app) + if ($UseKvReferences -and -not $ImplicitAuth) { + $KV = $env:WEBSITE_DEPLOYMENT_ID + $VaultName = if ($KV) { ($KV -split '-')[0] } else { $null } + if ($VaultName) { + $MergedSettings['AUTH_SECRET'] = "@Microsoft.KeyVault(VaultName=$VaultName;SecretName=SSOAppSecret)" + } + } + + # Always remove WEBSITE_AUTH_AAD_ALLOWED_TENANTS — we rely on the issuer URL + # for tenant restriction ("Use default restrictions based on issuer" in the portal). + # Multi-tenant uses common/v2.0 issuer, single-tenant uses {tenantId}/v2.0. + $MergedSettings.Remove('WEBSITE_AUTH_AAD_ALLOWED_TENANTS') + + $SettingsBody = @{ properties = $MergedSettings } | ConvertTo-Json -Depth 5 + Invoke-RestMethod -Uri "$BaseUri/config/appsettings?api-version=2024-11-01" -Method Put -Headers $ArmHeaders -Body $SettingsBody + + # Determine if we can read-modify-write (update) or need a full overwrite (initial setup) + if (-not $UseKvReferences -and $env:WEBSITE_AUTH_V2_CONFIG_JSON) { + # Read-modify-write: only patch the issuer URL, preserving existing allowedAudiences, + # allowedApplications, excludedPaths, tokenStore, etc. + $Current = $env:WEBSITE_AUTH_V2_CONFIG_JSON | ConvertFrom-Json -AsHashtable -Depth 20 + $ArmPayload = @{ properties = $Current } + + # Safely navigate to AAD registration + if (-not $Current.ContainsKey('identityProviders') -or $null -eq $Current.identityProviders) { $Current.identityProviders = @{} } + if (-not $Current.identityProviders.ContainsKey('azureActiveDirectory') -or $null -eq $Current.identityProviders.azureActiveDirectory) { $Current.identityProviders.azureActiveDirectory = @{} } + $AAD = $Current.identityProviders.azureActiveDirectory + + if (-not $AAD.ContainsKey('registration') -or $null -eq $AAD.registration) { $AAD.registration = @{} } + $AAD.registration.openIdIssuer = $IssuerUrl + + # Ensure the SSO app's own clientId is always in allowedAudiences and allowedApplications + if (-not $AAD.ContainsKey('validation') -or $null -eq $AAD.validation) { $AAD.validation = @{} } + + $ExistingAudiences = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase) + if ($AAD.validation.allowedAudiences) { + foreach ($a in $AAD.validation.allowedAudiences) { [void]$ExistingAudiences.Add($a) } + } + [void]$ExistingAudiences.Add("api://$AppId") + $AAD.validation.allowedAudiences = @($ExistingAudiences) + + if (-not $AAD.validation.ContainsKey('defaultAuthorizationPolicy') -or $null -eq $AAD.validation.defaultAuthorizationPolicy) { + $AAD.validation.defaultAuthorizationPolicy = @{} + } + $ExistingApps = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase) + if ($AAD.validation.defaultAuthorizationPolicy.allowedApplications) { + foreach ($a in $AAD.validation.defaultAuthorizationPolicy.allowedApplications) { [void]$ExistingApps.Add($a) } + } + [void]$ExistingApps.Add($AppId) + $AAD.validation.defaultAuthorizationPolicy.allowedApplications = @($ExistingApps) + + if (-not $AAD.validation.defaultAuthorizationPolicy.ContainsKey('allowedPrincipals')) { + $AAD.validation.defaultAuthorizationPolicy.allowedPrincipals = @{} + } + + $AuthConfig = $ArmPayload | ConvertTo-Json -Depth 20 + Write-Information "[SSO-EasyAuth] Read-modify-write: patching issuer to $IssuerUrl (preserving $(($ExistingAudiences).Count) audiences, $(($ExistingApps).Count) allowed apps)" + } else { + # Full overwrite: initial setup — build the entire authsettingsV2 from scratch + $AuthConfig = @{ + properties = @{ + platform = @{ enabled = $true } + globalValidation = @{ + unauthenticatedClientAction = 'RedirectToLoginPage' + redirectToProvider = 'azureactivedirectory' + excludedPaths = @( + '/api/Public*' + '/api/setup/health' + ) + } + identityProviders = @{ + azureActiveDirectory = @{ + enabled = $true + registration = $(if ($ImplicitAuth) { + @{ + clientId = $AppId + openIdIssuer = $IssuerUrl + } + } else { + @{ + clientId = $AppId + clientSecretSettingName = 'AUTH_SECRET' + openIdIssuer = $IssuerUrl + } + }) + validation = @{ + allowedAudiences = @("api://$AppId") + defaultAuthorizationPolicy = @{ + allowedPrincipals = @{} + allowedApplications = @($AppId) + } + } + } + } + login = @{ + tokenStore = @{ + enabled = $true + tokenRefreshExtensionHours = 72 + } + } + } + } | ConvertTo-Json -Depth 20 + } + + Invoke-RestMethod -Uri "$BaseUri/config/authsettingsV2?api-version=2020-06-01" -Method Put -Headers $ArmHeaders -Body $AuthConfig + + Write-Information "[SSO-EasyAuth] Configured EasyAuth: appId=$AppId, issuer=$IssuerUrl, multiTenant=$MultiTenant" + Write-LogMessage -API 'SSO-EasyAuth' -message "EasyAuth configured: appId=$AppId, issuer=$IssuerUrl" -sev Info + return $true +} diff --git a/Modules/CIPPCore/Public/Authentication/Set-CippApiAuth.ps1 b/Modules/CIPPCore/Public/Authentication/Set-CippApiAuth.ps1 index 91e40acb6290..1e1dc84a1fb6 100644 --- a/Modules/CIPPCore/Public/Authentication/Set-CippApiAuth.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Set-CippApiAuth.ps1 @@ -7,67 +7,144 @@ function Set-CippApiAuth { [string[]]$ClientIds ) - # Resolve subscription ID via helper (managed identity environment assumed for ARM). - $SubscriptionId = Get-CIPPAzFunctionAppSubId + if ($env:CIPPNG) { + # Read-modify-write — only patch allowedApplications + allowedAudiences, + # preserving the SSO EasyAuth config (clientSecretSettingName, excludedPaths, tokenStore, etc.) - # Get auth settings via ARM REST (managed identity) - $getUri = "https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$RGName/providers/Microsoft.Web/sites/$($FunctionAppName)/config/authsettingsV2/list?api-version=2020-06-01" - $resp = New-CIPPAzRestRequest -Uri $getUri -Method 'GET' - $AuthSettings = $resp | Select-Object -ExpandProperty Content -ErrorAction SilentlyContinue - if ($AuthSettings -is [string]) { $AuthSettings = $AuthSettings | ConvertFrom-Json } - else { $AuthSettings = $resp } + # Resolve env vars directly (same pattern as Set-CIPPSSOEasyAuth which works) + $SiteName = $env:WEBSITE_SITE_NAME + $ResourceGroup = $env:WEBSITE_RESOURCE_GROUP + $SubscriptionId = if ($env:WEBSITE_OWNER_NAME) { ($env:WEBSITE_OWNER_NAME -split '\+')[0] } else { $null } - Write-Information "AuthSettings: $($AuthSettings | ConvertTo-Json -Depth 10)" + Write-Information "[ApiAuth] SiteName=$SiteName, ResourceGroup=$ResourceGroup, SubscriptionId=$SubscriptionId" + Write-Information "[ApiAuth] ClientIds to set: $($ClientIds -join ', ')" - # Set allowed audiences - $AllowedAudiences = foreach ($ClientId in $ClientIds) { - "api://$ClientId" - } + if (-not $SiteName -or -not $ResourceGroup -or -not $SubscriptionId) { + throw "[ApiAuth] Missing App Service env vars: WEBSITE_SITE_NAME=$SiteName, WEBSITE_RESOURCE_GROUP=$ResourceGroup, SubscriptionId=$SubscriptionId" + } - if (!$AllowedAudiences) { $AllowedAudiences = @() } - if (!$ClientIds) { $ClientIds = @() } + $BaseUri = "https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroup/providers/Microsoft.Web/sites/$SiteName" + Write-Information "[ApiAuth] BaseUri=$BaseUri" - # Set auth settings + # Read current authsettingsV2 from platform-injected env var (reliable, no ARM call needed) + # Then convert to deep hashtable for safe mutation + if (-not $env:WEBSITE_AUTH_V2_CONFIG_JSON) { + throw '[ApiAuth] WEBSITE_AUTH_V2_CONFIG_JSON env var not set — EasyAuth may not be configured yet.' + } - if (($ClientIds | Measure-Object).Count -gt 0) { - $AuthSettings.properties.identityProviders.azureActiveDirectory = @{ - enabled = $true - registration = @{ - clientId = $ClientIds[0] ?? $ClientIds - openIdIssuer = "https://sts.windows.net/$TenantID/v2.0" - } - validation = @{ - allowedAudiences = @($AllowedAudiences) - defaultAuthorizationPolicy = @{ - allowedApplications = @($ClientIds) - } - } + $Current = $env:WEBSITE_AUTH_V2_CONFIG_JSON | ConvertFrom-Json -AsHashtable -Depth 20 + # Wrap in properties envelope for the ARM PUT (env var has the raw config, ARM expects {properties: ...}) + $ArmPayload = @{ properties = $Current } + + Write-Information "[ApiAuth] Read config from env var OK. Keys=$($Current.Keys -join ', ')" + + # The env var has the raw config (identityProviders at top level, no properties wrapper) + # Safely navigate/create the full path — any level may be null + if (-not $Current.ContainsKey('identityProviders') -or $null -eq $Current.identityProviders) { $Current.identityProviders = @{} } + if (-not $Current.identityProviders.ContainsKey('azureActiveDirectory') -or $null -eq $Current.identityProviders.azureActiveDirectory) { $Current.identityProviders.azureActiveDirectory = @{} } + + $AAD = $Current.identityProviders.azureActiveDirectory + Write-Information "[ApiAuth] AAD keys: $($AAD.Keys -join ', ')" + + # The SSO app's clientId is the registration clientId — always keep it in the lists + $SSOClientId = $AAD.registration.clientId + Write-Information "[ApiAuth] SSO clientId from registration: $SSOClientId" + + # Merge: SSO app + all enabled API clients + $AllAppIds = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase) + if ($SSOClientId) { [void]$AllAppIds.Add($SSOClientId) } + foreach ($id in $ClientIds) { + if (-not [string]::IsNullOrEmpty($id)) { [void]$AllAppIds.Add($id) } + } + + # Build allowed audiences: api://{id} for each + $AllAudiences = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase) + foreach ($id in $AllAppIds) { + [void]$AllAudiences.Add("api://$id") + } + + Write-Information "[ApiAuth] Merged allowedApplications: $($AllAppIds -join ', ')" + Write-Information "[ApiAuth] Merged allowedAudiences: $($AllAudiences -join ', ')" + + # Ensure every level of the validation path exists + if (-not $AAD.ContainsKey('validation') -or $null -eq $AAD.validation) { + $AAD.validation = @{} + } + $AAD.validation.allowedAudiences = @($AllAudiences) + + if (-not $AAD.validation.ContainsKey('defaultAuthorizationPolicy') -or $null -eq $AAD.validation.defaultAuthorizationPolicy) { + $AAD.validation.defaultAuthorizationPolicy = @{} + } + $AAD.validation.defaultAuthorizationPolicy.allowedApplications = @($AllAppIds) + + # Ensure allowedPrincipals exists (for "use default restrictions based on issuer") + if (-not $AAD.validation.defaultAuthorizationPolicy.ContainsKey('allowedPrincipals')) { + $AAD.validation.defaultAuthorizationPolicy.allowedPrincipals = @{} + } + + $PutBody = $ArmPayload | ConvertTo-Json -Depth 20 + Write-Information "[ApiAuth] PUT body: $PutBody" + + if ($PSCmdlet.ShouldProcess('Update authsettingsV2 (read-modify-write)')) { + $PutUri = "$BaseUri/config/authsettingsV2?api-version=2020-06-01" + $PutResult = New-CIPPAzRestRequest -Uri $PutUri -Method PUT -Body $PutBody -ContentType 'application/json' -ErrorAction Stop + Write-Information "[ApiAuth] PUT result: $($PutResult | ConvertTo-Json -Depth 10 -Compress)" + Write-Information "[ApiAuth] Updated EasyAuth successfully" } } else { - $AuthSettings.properties.identityProviders.azureActiveDirectory = @{ - enabled = $false - registration = @{} - validation = @{} + # Full overwrite path (no SSO EasyAuth config to preserve) + $SubscriptionId = Get-CIPPAzFunctionAppSubId + $BaseUri = "https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$RGName/providers/Microsoft.Web/sites/$FunctionAppName" + + $getUri = "$BaseUri/config/authsettingsV2/list?api-version=2020-06-01" + $AuthSettings = New-CIPPAzRestRequest -Uri $getUri -Method POST + + Write-Information "AuthSettings: $($AuthSettings | ConvertTo-Json -Depth 10)" + + $AllowedAudiences = foreach ($ClientId in $ClientIds) { "api://$ClientId" } + if (!$AllowedAudiences) { $AllowedAudiences = @() } + if (!$ClientIds) { $ClientIds = @() } + + if (($ClientIds | Measure-Object).Count -gt 0) { + $AuthSettings.properties.identityProviders.azureActiveDirectory = @{ + enabled = $true + registration = @{ + clientId = $ClientIds[0] ?? $ClientIds + openIdIssuer = "https://sts.windows.net/$TenantID/v2.0" + } + validation = @{ + allowedAudiences = @($AllowedAudiences) + defaultAuthorizationPolicy = @{ + allowedApplications = @($ClientIds) + } + } + } + } else { + $AuthSettings.properties.identityProviders.azureActiveDirectory = @{ + enabled = $false + registration = @{} + validation = @{} + } } - } - $AuthSettings.properties.globalValidation = @{ - unauthenticatedClientAction = 'Return401' - } - $AuthSettings.properties.login = @{ - tokenStore = @{ - enabled = $true - tokenRefreshExtensionHours = 72 + $AuthSettings.properties.globalValidation = @{ + unauthenticatedClientAction = 'Return401' + } + $AuthSettings.properties.login = @{ + tokenStore = @{ + enabled = $true + tokenRefreshExtensionHours = 72 + } } - } - if ($PSCmdlet.ShouldProcess('Update auth settings')) { - # Update auth settings via ARM REST - $putUri = "https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$RGName/providers/Microsoft.Web/sites/$($FunctionAppName)/config/authsettingsV2?api-version=2020-06-01" - $null = New-CIPPAzRestRequest -Uri $putUri -Method 'PUT' -Body $AuthSettings -ContentType 'application/json' - } + if ($PSCmdlet.ShouldProcess('Update auth settings')) { + $putUri = "$BaseUri/config/authsettingsV2?api-version=2020-06-01" + $Body = $AuthSettings | ConvertTo-Json -Depth 20 + $null = New-CIPPAzRestRequest -Uri $putUri -Method PUT -Body $Body -ContentType 'application/json' + } - if ($PSCmdlet.ShouldProcess('Update allowed tenants')) { - $null = Update-CIPPAzFunctionAppSetting -Name $FunctionAppName -ResourceGroupName $RGName -AppSetting @{ 'WEBSITE_AUTH_AAD_ALLOWED_TENANTS' = $TenantId } + if ($PSCmdlet.ShouldProcess('Update allowed tenants')) { + $null = Update-CIPPAzFunctionAppSetting -Name $FunctionAppName -ResourceGroupName $RGName -AppSetting @{ 'WEBSITE_AUTH_AAD_ALLOWED_TENANTS' = $TenantId } + } } } diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 index 2ad765e41bdf..9622bf5f0c9e 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1 @@ -202,13 +202,42 @@ function Test-CIPPAccess { $Permissions = Get-CippAllowedPermissions -UserRoles $User.userRoles $swPermsMe.Stop() $AccessTimings['GetPermissions(me)'] = $swPermsMe.Elapsed.TotalMilliseconds + + # Include SSO migration status for admins with AppSettings permissions + $MeResponse = @{ + 'clientPrincipal' = $User + 'permissions' = $Permissions + } + + # Forced SSO migration: non-dismissible prompt when migration env var is set + if ($env:CIPP_SSO_MIGRATION_APPID -and $Permissions -contains 'CIPP.AppSettings.ReadWrite') { + $MeResponse['forceSsoMigration'] = @{ + appId = $env:CIPP_SSO_MIGRATION_APPID + status = 'pending' + } + } + + if ($Permissions -contains 'CIPP.AppSettings.ReadWrite' -and $env:CIPPNG -ne 'true' -and $env:CIPP_SSO_MIGRATION_PROMPT -eq 'true') { + try { + $SSOTable = Get-CIPPTable -tablename 'SSOMigration' + $SSOMigration = Get-CIPPAzDataTableEntity @SSOTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'MigrationConfig'" -ErrorAction SilentlyContinue + if ($SSOMigration) { + $MeResponse['ssoMigration'] = @{ + status = $SSOMigration.Status + appId = $SSOMigration.AppId + multiTenant = [bool]($SSOMigration.MultiTenant -eq 'true' -or $SSOMigration.MultiTenant -eq 'True') + } + } else { + $MeResponse['ssoMigration'] = @{ status = 'none' } + } + } catch { + $MeResponse['ssoMigration'] = @{ status = 'none' } + } + } + return ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK - Body = ( - @{ - 'clientPrincipal' = $User - 'permissions' = $Permissions - } | ConvertTo-Json -Depth 5) + Body = ($MeResponse | ConvertTo-Json -Depth 5) }) } diff --git a/Modules/CIPPCore/Public/Authentication/Update-CIPPSSORedirectUri.ps1 b/Modules/CIPPCore/Public/Authentication/Update-CIPPSSORedirectUri.ps1 new file mode 100644 index 000000000000..03d113d2a214 --- /dev/null +++ b/Modules/CIPPCore/Public/Authentication/Update-CIPPSSORedirectUri.ps1 @@ -0,0 +1,126 @@ +function Update-CIPPSSORedirectUri { + <# + .SYNOPSIS + Ensures the CIPP-SSO app registration includes redirect URIs for all bound hostnames + and that signInAudience matches the stored multi-tenant flag. + + .DESCRIPTION + Reads the stored SSO AppId and MultiTenant flag from Key Vault (or DevSecrets table + in dev mode), then: + 1. Queries ARM for all hostnames bound to the App Service (custom domains + default). + 2. Ensures the SSO app's web.redirectUris includes a callback URI for each hostname. + 3. Verifies and patches signInAudience on the app reg if it doesn't match the stored + multi-tenant flag (AzureADMyOrg for single-tenant, AzureADMultipleOrgs for multi). + #> + [CmdletBinding()] + param() + + $CurrentHost = $env:WEBSITE_HOSTNAME + if (-not $CurrentHost) { + Write-Information '[SSO-Redirect] WEBSITE_HOSTNAME not set, skipping redirect URI update' + return + } + + # Resolve the stored SSO AppId and MultiTenant flag + $SSOAppId = $null + $SSOMultiTenant = $false + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true' -or $env:NonLocalHostAzurite -eq 'true') { + try { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'SSO'" -ErrorAction SilentlyContinue + $SSOAppId = $Secret.SSOAppId + $SSOMultiTenant = $Secret.SSOMultiTenant -eq 'True' + } catch { } + } else { + $KV = $env:WEBSITE_DEPLOYMENT_ID + $VaultName = if ($KV) { ($KV -split '-')[0] } else { $null } + if ($VaultName) { + try { + $SSOAppId = Get-CippKeyVaultSecret -VaultName $VaultName -Name 'SSOAppId' -AsPlainText -ErrorAction Stop + } catch { } + try { + $mtVal = Get-CippKeyVaultSecret -VaultName $VaultName -Name 'SSOMultiTenant' -AsPlainText -ErrorAction Stop + $SSOMultiTenant = $mtVal -eq 'True' + } catch { } + } + } + + if (-not $SSOAppId) { + Write-Information '[SSO-Redirect] No SSO AppId found, skipping redirect URI update' + return + } + + # Discover all bound hostnames via ARM (custom domains + default) + $AllHostnames = @($CurrentHost) + try { + $SiteName = $env:WEBSITE_SITE_NAME + $ResourceGroup = $env:WEBSITE_RESOURCE_GROUP + $SubscriptionId = if ($env:WEBSITE_OWNER_NAME) { ($env:WEBSITE_OWNER_NAME -split '\+')[0] } else { $null } + + if ($SiteName -and $ResourceGroup -and $SubscriptionId -and $env:IDENTITY_ENDPOINT -and $env:IDENTITY_HEADER) { + $TokenUri = "$($env:IDENTITY_ENDPOINT)?resource=https://management.azure.com/&api-version=2019-08-01" + $TokenResponse = Invoke-RestMethod -Uri $TokenUri -Headers @{ 'X-IDENTITY-HEADER' = $env:IDENTITY_HEADER } -Method Get + $ArmToken = $TokenResponse.access_token + + $SiteUri = "https://management.azure.com/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroup/providers/Microsoft.Web/sites/$SiteName`?api-version=2024-11-01" + $SiteResponse = Invoke-RestMethod -Uri $SiteUri -Headers @{ Authorization = "Bearer $ArmToken" } -Method Get + + if ($SiteResponse.properties.hostNames) { + $AllHostnames = @($SiteResponse.properties.hostNames) + Write-Information "[SSO-Redirect] Discovered hostnames from ARM: $($AllHostnames -join ', ')" + } + } + } catch { + Write-Information "[SSO-Redirect] ARM hostname discovery failed (using WEBSITE_HOSTNAME only): $($_.Exception.Message)" + } + + # Build required redirect URIs from all hostnames + $RequiredUris = foreach ($Hostname in $AllHostnames) { + "https://$Hostname/.auth/login/aad/callback" + } + + try { + $AppResponse = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/applications(appId='$SSOAppId')?`$select=id,web,signInAudience" -NoAuthCheck $true -AsApp $true + $ExistingUris = @($AppResponse.web.redirectUris) + + # Determine which URIs are missing + $MissingUris = $RequiredUris | Where-Object { $_ -notin $ExistingUris } + + # Determine the expected signInAudience + $ExpectedAudience = if ($SSOMultiTenant) { 'AzureADMultipleOrgs' } else { 'AzureADMyOrg' } + $AudienceMismatch = $AppResponse.signInAudience -ne $ExpectedAudience + + if ($MissingUris.Count -eq 0 -and -not $AudienceMismatch) { + Write-Information '[SSO-Redirect] All redirect URIs present and signInAudience correct' + return + } + + # Build patch body + $PatchBody = @{} + + if ($MissingUris.Count -gt 0) { + $UpdatedUris = [System.Collections.Generic.List[string]]::new() + $ExistingUris | ForEach-Object { $UpdatedUris.Add($_) } + $MissingUris | ForEach-Object { $UpdatedUris.Add($_) } + $PatchBody.web = @{ redirectUris = $UpdatedUris } + } + + if ($AudienceMismatch) { + $PatchBody.signInAudience = $ExpectedAudience + Write-Information "[SSO-Redirect] Correcting signInAudience: $($AppResponse.signInAudience) -> $ExpectedAudience" + } + + $Body = $PatchBody | ConvertTo-Json -Depth 5 + New-GraphPOSTRequest -uri "https://graph.microsoft.com/v1.0/applications/$($AppResponse.id)" -body $Body -type PATCH -NoAuthCheck $true -AsApp $true + + if ($MissingUris.Count -gt 0) { + Write-Information "[SSO-Redirect] Added redirect URIs: $($MissingUris -join ', ')" + Write-LogMessage -API 'SSO-Redirect' -message "Added redirect URIs: $($MissingUris -join ', ')" -sev Info + } + if ($AudienceMismatch) { + Write-LogMessage -API 'SSO-Redirect' -message "Updated signInAudience to $ExpectedAudience (multiTenant=$SSOMultiTenant)" -sev Info + } + } catch { + Write-LogMessage -API 'SSO-Redirect' -message "Failed to update SSO app registration: $_" -LogData (Get-CippException -Exception $_) -sev Warning + } +} diff --git a/Modules/CIPPCore/Public/GraphHelper/Update-AppManagementPolicy.ps1 b/Modules/CIPPCore/Public/GraphHelper/Update-AppManagementPolicy.ps1 index 5a44d65fddd5..d585e0122089 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Update-AppManagementPolicy.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Update-AppManagementPolicy.ps1 @@ -174,7 +174,7 @@ function Update-AppManagementPolicy { $PolicyAction = "Updated existing policy $CIPPAppPolicyId to allow credentials" } elseif ($ExistingExemptionPolicy) { # Exemption policy exists but not assigned to app - update and assign it - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/policies/appManagementPolicies/$($ExistingExemptionPolicy.id)" -type PATCH -body ($PolicyBody | ConvertTo-Json -Depth 10) -asapp $true -NoAuthCheck $true -headers $headers + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/policies/appManagementPolicies/$($ExistingExemptionPolicy.id)" -type PATCH -body ($PolicyBody | ConvertTo-Json -Depth 10) -asapp $true -NoAuthCheck $true -tenantid $TenantFilter -headers $headers if ($CIPPApp.id) { # Assign existing policy to CIPP-SAM application @@ -190,14 +190,14 @@ function Update-AppManagementPolicy { } } else { # Create new policy and assign to CIPP-SAM app - $CreatedPolicy = New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/policies/appManagementPolicies' -type POST -body ($PolicyBody | ConvertTo-Json -Depth 10) -asapp $true -NoAuthCheck $true -headers $headers + $CreatedPolicy = New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/policies/appManagementPolicies' -type POST -body ($PolicyBody | ConvertTo-Json -Depth 10) -asapp $true -NoAuthCheck $true -tenantid $TenantFilter -headers $headers if ($CIPPApp.id) { # Assign policy to CIPP-SAM application using beta endpoint $AssignBody = @{ '@odata.id' = "https://graph.microsoft.com/beta/policies/appManagementPolicies/$($CreatedPolicy.id)" } - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/applications/$($CIPPApp.id)/appManagementPolicies/`$ref" -type POST -body ($AssignBody | ConvertTo-Json) -asapp $true -NoAuthCheck $true -headers $headers + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/applications/$($CIPPApp.id)/appManagementPolicies/`$ref" -type POST -body ($AssignBody | ConvertTo-Json) -asapp $true -NoAuthCheck $true -tenantid $TenantFilter -headers $headers $PolicyAction = "Created new policy $($CreatedPolicy.id) and assigned to CIPP-SAM" $CIPPAppPolicyId = $CreatedPolicy.id $CIPPAppTargeted = $true diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListFeatureFlags.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListFeatureFlags.ps1 index 3b236cafbb4d..70304808efa0 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListFeatureFlags.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListFeatureFlags.ps1 @@ -11,10 +11,19 @@ function Invoke-ListFeatureFlags { try { Write-LogMessage -API 'ListFeatureFlags' -message 'Accessed feature flags list' -sev 'Debug' - $FeatureFlags = Get-CIPPFeatureFlag + $FeatureFlags = @(Get-CIPPFeatureFlag) + + # Environment-driven overrides: enable flags that depend on the runtime platform + if ($env:CIPPNG -eq 'true') { + foreach ($Flag in $FeatureFlags) { + if ($Flag.Id -eq 'SuperAdminNG') { + $Flag.Enabled = $true + } + } + } $StatusCode = [HttpStatusCode]::OK - $Body = @($FeatureFlags) + $Body = $FeatureFlags } catch { Write-LogMessage -API 'ListFeatureFlags' -message "Failed to retrieve feature flags: $($_.Exception.Message)" -sev 'Error' $StatusCode = [HttpStatusCode]::InternalServerError diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCIPPUsers.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCIPPUsers.ps1 new file mode 100644 index 000000000000..1220df4bad43 --- /dev/null +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCIPPUsers.ps1 @@ -0,0 +1,114 @@ +function Invoke-ExecCIPPUsers { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.SuperAdmin.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + $Action = $Request.Query.Action ?? $Request.Body.Action + $Table = Get-CippTable -tablename 'allowedUsers' + + switch ($Action) { + 'AddUpdate' { + try { + $UPN = $Request.Body.UPN + if ([string]::IsNullOrWhiteSpace($UPN)) { + throw 'UPN (email) is required' + } + $UPN = $UPN.Trim() + + $Roles = @($Request.Body.Roles) + if ($Roles.Count -eq 0) { + throw 'At least one role must be assigned' + } + + # Validate roles exist (built-in + custom) + $CippRolesJson = Join-Path -Path $env:CIPPRootPath -ChildPath 'Config\cipp-roles.json' + $BuiltInRoles = if (Test-Path $CippRolesJson) { + ([System.IO.File]::ReadAllText($CippRolesJson) | ConvertFrom-Json).PSObject.Properties.Name + } else { + @('readonly', 'editor', 'admin', 'superadmin') + } + + $CustomRolesTable = Get-CippTable -tablename 'CustomRoles' + $CustomRoles = @((Get-CIPPAzDataTableEntity @CustomRolesTable).RowKey) + $AllValidRoles = @($BuiltInRoles) + @($CustomRoles) + @('anonymous', 'authenticated') + + foreach ($Role in $Roles) { + if ($Role -notin $AllValidRoles) { + throw "Invalid role: $Role. Valid roles: $($AllValidRoles -join ', ')" + } + } + + $Entity = @{ + PartitionKey = 'User' + RowKey = $UPN + Roles = [string](@($Roles) | ConvertTo-Json -Compress -AsArray) + } + Add-CIPPAzDataTableEntity @Table -Entity $Entity -Force | Out-Null + + # Invalidate the in-memory user cache so changes apply immediately + try { [Craft.Services.AuthBridge]::InvalidateUsers() } catch {} + + $Result = "Successfully added/updated user $UPN with roles: $($Roles -join ', ')" + Write-LogMessage -API $APIName -headers $Headers -message $Result -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -headers $Headers -message "Failed to add/update user: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = "Failed: $($ErrorMessage.NormalizedError)" } + } + } + } + 'Delete' { + try { + $UPN = $Request.Body.UPN + if ([string]::IsNullOrWhiteSpace($UPN)) { + throw 'UPN (email) is required' + } + $UPN = $UPN.Trim() + + # Self-lockout protection: prevent removing yourself + $CurrentUser = $Request.Headers.'x-ms-client-principal-name' + if ($CurrentUser -and $UPN -ieq $CurrentUser) { + throw 'Cannot remove your own user account. This would lock you out.' + } + + $ExistingEntity = Get-CIPPAzDataTableEntity @Table -Filter "RowKey eq '$UPN'" + if (-not $ExistingEntity) { + throw "User $UPN not found in the allowed users table" + } + + Remove-AzDataTableEntity -Force @Table -Entity $ExistingEntity + try { [Craft.Services.AuthBridge]::InvalidateUsers() } catch {} + + $Result = "Successfully removed user $UPN" + Write-LogMessage -API $APIName -headers $Headers -message $Result -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -headers $Headers -message "Failed to delete user: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = "Failed: $($ErrorMessage.NormalizedError)" } + } + } + } + default { + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = "Unknown action: $Action. Valid actions: AddUpdate, Delete" } + } + } + } + + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ Results = $Result } + } +} diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecContainerManagement.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecContainerManagement.ps1 new file mode 100644 index 000000000000..da9948164016 --- /dev/null +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecContainerManagement.ps1 @@ -0,0 +1,173 @@ +function Invoke-ExecContainerManagement { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.SuperAdmin.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + $Action = $Request.Query.Action ?? $Request.Body.Action + + $ValidChannels = @('latest', 'dev', 'nightly') + + switch ($Action) { + 'Status' { + try { + $CurrentVersion = $env:APP_VERSION ?? 'unknown' + $CommitSha = $env:COMMIT_SHA ?? 'unknown' + $ImageTag = $env:IMAGE_TAG ?? 'unknown' + + # The channel is the image tag baked into the container at build time + $CurrentChannel = $ImageTag + + # Try to read the full container image reference from ARM + $CurrentImage = 'unknown' + $Subscription = Get-CIPPAzFunctionAppSubId + $RGName = $env:WEBSITE_RESOURCE_GROUP + if (-not $RGName) { + $Owner = $env:WEBSITE_OWNER_NAME + if ($Owner -match '^(?[^+]+)\+(?[^-]+(?:-[^-]+)*?)(?:-[^-]+webspace(?:-Linux)?)?$') { + $RGName = $Matches.RGName + } + } + $SiteName = $env:WEBSITE_SITE_NAME + if ($Subscription -and $RGName -and $SiteName) { + try { + $apiVersion = '2024-11-01' + $uri = "https://management.azure.com/subscriptions/$Subscription/resourceGroups/$RGName/providers/Microsoft.Web/sites/$SiteName/config/web?api-version=$apiVersion" + $webConfig = New-CIPPAzRestRequest -Uri $uri -Method GET + $linuxFxVersion = $webConfig.properties.linuxFxVersion + if ($linuxFxVersion) { + $CurrentImage = $linuxFxVersion -replace '^DOCKER\|', '' + # The ARM config tag may differ from the running container's baked-in tag + # if the channel was changed but the container hasn't restarted yet + if ($CurrentImage -match ':([^:]+)$') { + $ConfiguredChannel = $Matches[1] + } + } + } catch { + Write-Information "Could not read container config from ARM: $_" + } + } + + $Body = @{ + Results = @{ + CurrentVersion = $CurrentVersion + CommitSha = $CommitSha + ImageTag = $ImageTag + CurrentChannel = $CurrentChannel + ConfiguredChannel = $ConfiguredChannel ?? $CurrentChannel + CurrentImage = $CurrentImage + SiteName = $SiteName + ValidChannels = $ValidChannels + } + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -headers $Headers -message "Failed to get container status: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::InternalServerError + Body = @{ Results = "Failed: $($ErrorMessage.NormalizedError)" } + } + } + } + 'UpdateChannel' { + try { + $NewChannel = $Request.Body.Channel + if ([string]::IsNullOrWhiteSpace($NewChannel)) { + throw 'Channel is required' + } + if ($NewChannel -notin $ValidChannels) { + throw "Invalid channel: $NewChannel. Valid channels: $($ValidChannels -join ', ')" + } + + $Subscription = Get-CIPPAzFunctionAppSubId + $RGName = $env:WEBSITE_RESOURCE_GROUP + if (-not $RGName) { + $Owner = $env:WEBSITE_OWNER_NAME + if ($Owner -match '^(?[^+]+)\+(?[^-]+(?:-[^-]+)*?)(?:-[^-]+webspace(?:-Linux)?)?$') { + $RGName = $Matches.RGName + } + } + $SiteName = $env:WEBSITE_SITE_NAME + if (-not ($Subscription -and $RGName -and $SiteName)) { + throw 'Could not determine Azure App Service details from environment' + } + + $apiVersion = '2024-11-01' + + # Read current web config + $getUri = "https://management.azure.com/subscriptions/$Subscription/resourceGroups/$RGName/providers/Microsoft.Web/sites/$SiteName/config/web?api-version=$apiVersion" + $webConfig = New-CIPPAzRestRequest -Uri $getUri -Method GET + $currentLinuxFx = $webConfig.properties.linuxFxVersion + if (-not $currentLinuxFx) { + throw 'Could not read current linuxFxVersion — is this a Linux container app?' + } + + # Replace the tag in the image reference + $currentImage = $currentLinuxFx -replace '^DOCKER\|', '' + if ($currentImage -match '^(.+):([^:]+)$') { + $imageBase = $Matches[1] + $newLinuxFx = "DOCKER|${imageBase}:${NewChannel}" + } else { + $newLinuxFx = "DOCKER|${currentImage}:${NewChannel}" + } + + # Update the web config with new image tag + $putUri = $getUri + $putBody = @{ + properties = @{ + linuxFxVersion = $newLinuxFx + } + } + New-CIPPAzRestRequest -Uri $putUri -Method PATCH -Body $putBody -ContentType 'application/json' | Out-Null + + $Result = "Release channel updated to '$NewChannel'. Image: $newLinuxFx. The container will pull the new image on next restart." + Write-LogMessage -API $APIName -headers $Headers -message "Release channel changed to $NewChannel ($newLinuxFx)" -sev Info + $Body = @{ Results = $Result } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -headers $Headers -message "Failed to update channel: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = "Failed: $($ErrorMessage.NormalizedError)" } + } + } + } + 'Restart' { + try { + Write-LogMessage -API $APIName -headers $Headers -message 'Container restart requested by super admin' -sev Info + $Body = @{ Results = 'Container restart initiated. The application will be back online shortly.' } + + # Schedule restart after response is sent + try { + [Craft.Services.AppLifecycleBridge]::RequestRestart('Restart requested by super admin via container management page') + } catch { + $Body = @{ Results = 'Restart command sent but the bridge is not available. The app may need to be restarted from the Azure Portal.' } + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -headers $Headers -message "Failed to restart: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::InternalServerError + Body = @{ Results = "Failed: $($ErrorMessage.NormalizedError)" } + } + } + } + default { + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = "Unknown action: $Action. Valid actions: Status, UpdateChannel, Restart" } + } + } + } + + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + } +} diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCIPPUsers.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCIPPUsers.ps1 new file mode 100644 index 000000000000..5ed1dff766e2 --- /dev/null +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCIPPUsers.ps1 @@ -0,0 +1,80 @@ +function Invoke-ListCIPPUsers { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.SuperAdmin.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Table = Get-CippTable -tablename 'allowedUsers' + + try { + # Get all users from the allowedUsers table + $Users = Get-CIPPAzDataTableEntity @Table | Where-Object { -not $_.RowKey.StartsWith('_') } + + # Get available roles (built-in + custom) + $CippRolesJson = Join-Path -Path $env:CIPPRootPath -ChildPath 'Config\cipp-roles.json' + $BuiltInRoles = if (Test-Path $CippRolesJson) { + ([System.IO.File]::ReadAllText($CippRolesJson) | ConvertFrom-Json).PSObject.Properties.Name + } else { + @('readonly', 'editor', 'admin', 'superadmin') + } + + $CustomRolesTable = Get-CippTable -tablename 'CustomRoles' + $CustomRoleEntities = Get-CIPPAzDataTableEntity @CustomRolesTable + $CustomRoleNames = @($CustomRoleEntities | ForEach-Object { $_.RowKey } | Where-Object { $_ }) + + # Build user list with parsed roles + $UserList = [System.Collections.Generic.List[pscustomobject]]::new() + foreach ($User in $Users) { + $ParsedRoles = @() + if ($User.Roles) { + try { + $ParsedRoles = @($User.Roles | ConvertFrom-Json -ErrorAction Stop) + } catch { + $ParsedRoles = @($User.Roles) + } + } + + $UserList.Add([pscustomobject]@{ + UPN = $User.RowKey + Roles = $ParsedRoles + }) + } + + # Build available roles list for frontend dropdown + $AvailableRoles = [System.Collections.Generic.List[pscustomobject]]::new() + foreach ($Role in $BuiltInRoles) { + $AvailableRoles.Add([pscustomobject]@{ + RoleName = $Role + Type = 'Built-In' + }) + } + foreach ($Role in $CustomRoleNames) { + $AvailableRoles.Add([pscustomobject]@{ + RoleName = $Role + Type = 'Custom' + }) + } + + $Body = @{ + Users = @($UserList) + AvailableRoles = @($AvailableRoles) + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -message "Failed to list CIPP users: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::InternalServerError + Body = @{ Results = "Failed: $($ErrorMessage.NormalizedError)" } + } + } + + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + } +} diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSSOSetup.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSSOSetup.ps1 new file mode 100644 index 000000000000..a0d29329799d --- /dev/null +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecSSOSetup.ps1 @@ -0,0 +1,531 @@ +function Invoke-ExecSSOSetup { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.AppSettings.ReadWrite + #> + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringWithPlainText', '')] + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + $Action = $Request.Body.Action ?? $Request.Query.Action ?? 'Status' + $MigrationTable = Get-CIPPTable -tablename 'SSOMigration' + + switch ($Action) { + 'Status' { + # Read live EasyAuth config from the platform-injected env var when available + if ($env:CIPPNG) { + try { + $EasyAuthEnabled = $env:WEBSITE_AUTH_ENABLED -eq 'True' + $ConfigJson = $env:WEBSITE_AUTH_V2_CONFIG_JSON + if ($EasyAuthEnabled -and $ConfigJson) { + $Config = $ConfigJson | ConvertFrom-Json -ErrorAction Stop + $AAD = $Config.identityProviders.azureActiveDirectory + $Issuer = $AAD.registration.openIdIssuer ?? '' + $ClientId = $AAD.registration.clientId ?? '' + $IsMultiTenant = $Issuer -match '/common/' + $IssuerTenantId = if (-not $IsMultiTenant -and $Issuer -match 'microsoftonline\.com/([^/]+)/') { $Matches[1] } else { $null } + $AllowedAudiences = @($AAD.validation.allowedAudiences) + $AllowedApps = @($AAD.validation.defaultAuthorizationPolicy.allowedApplications) + $ExcludedPaths = @($Config.globalValidation.excludedPaths) + + $Body = @{ + Results = @{ + configured = $true + status = 'complete' + appId = $ClientId + multiTenant = $IsMultiTenant + tenantId = $IssuerTenantId + issuer = $Issuer + audiences = $AllowedAudiences + allowedApps = $AllowedApps + excludedPaths = $ExcludedPaths + easyAuthActive = $true + } + } + } else { + $Body = @{ Results = @{ configured = $false; status = 'none'; easyAuthActive = $false } } + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -message "Failed to parse EasyAuth config: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + $Body = @{ Results = @{ configured = $false; status = 'error'; error = $ErrorMessage.NormalizedError } } + } + } else { + # Otherwise read from migration table + try { + $Migration = Get-CIPPAzDataTableEntity @MigrationTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'MigrationConfig'" -ErrorAction SilentlyContinue + if ($Migration) { + $Body = @{ + Results = @{ + configured = $true + status = $Migration.Status + appId = $Migration.AppId + multiTenant = [bool]($Migration.MultiTenant -eq 'true') + createdAt = $Migration.CreatedAt + lastChecked = $Migration.LastChecked + lastError = $Migration.LastError + } + } + } else { + $Body = @{ Results = @{ configured = $false; status = 'none' } } + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -message "Failed to get SSO status: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + $Body = @{ Results = @{ configured = $false; status = 'error'; error = $ErrorMessage.NormalizedError } } + } + } + } + + 'Create' { + $MultiTenant = [bool]($Request.Body.multiTenant) + $TargetUrl = $Request.Body.targetUrl + + # Determine redirect URI — prefer explicit targetUrl, fall back to current host + if (-not $TargetUrl) { + $TargetUrl = $Request.Headers.origin ?? $Request.Headers.referer?.TrimEnd('/') + } + if (-not $TargetUrl) { + $TargetUrl = "https://$($env:WEBSITE_HOSTNAME)" + } + + try { + # Check if already provisioned + $Existing = Get-CIPPAzDataTableEntity @MigrationTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'MigrationConfig'" -ErrorAction SilentlyContinue + if ($Existing -and $Existing.Status -eq 'complete') { + $Body = @{ + Results = @{ + message = 'SSO migration already completed.' + appId = $Existing.AppId + severity = 'info' + } + } + break + } + + # If we have an existing record that isn't complete, pick up from where we left off + $AppId = $Existing.AppId + $AppSecret = $null + + # Step 1: Create/update the app registration (idempotent) + # Pass stored AppId so we look up by clientId rather than name + $SSOAppParams = @{ + RedirectUri = $TargetUrl + MultiTenant = $MultiTenant + } + if ($AppId) { $SSOAppParams.ExistingAppId = $AppId } + + $SSOApp = New-CIPPSSOApp @SSOAppParams + $AppId = $SSOApp.AppId + $AppSecret = $SSOApp.ClientSecret + Write-LogMessage -API $APIName -headers $Headers -message "CIPP-SSO app $($SSOApp.State): $AppId" -sev Info + + # Save progress immediately + $MigrationRow = @{ + PartitionKey = 'SSO' + RowKey = 'MigrationConfig' + AppId = $AppId + MultiTenant = [string]$MultiTenant + RedirectUri = $TargetUrl + Status = 'app_created' + CreatedAt = $Existing.CreatedAt ?? (Get-Date).ToUniversalTime().ToString('o') + LastChecked = (Get-Date).ToUniversalTime().ToString('o') + LastError = '' + } + Add-CIPPAzDataTableEntity @MigrationTable -Entity $MigrationRow -Force | Out-Null + + $KV = $env:WEBSITE_DEPLOYMENT_ID + $VaultName = if ($KV) { ($KV -split '-')[0] } else { $null } + + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true' -or $env:NonLocalHostAzurite -eq 'true') { + # Dev mode — store in DevSecrets table + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'SSO'" -ErrorAction SilentlyContinue + if (-not $Secret) { $Secret = [PSCustomObject]@{} } + $Secret | Add-Member -MemberType NoteProperty -Name 'PartitionKey' -Value 'SSO' -Force + $Secret | Add-Member -MemberType NoteProperty -Name 'RowKey' -Value 'SSO' -Force + $Secret | Add-Member -MemberType NoteProperty -Name 'SSOAppId' -Value $AppId -Force + $Secret | Add-Member -MemberType NoteProperty -Name 'SSOMultiTenant' -Value ([string]$MultiTenant) -Force + if ($AppSecret) { + $Secret | Add-Member -MemberType NoteProperty -Name 'SSOAppSecret' -Value $AppSecret -Force + } + Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force | Out-Null + Write-Information '[SSO-Setup] Stored SSO credentials in DevSecrets table' + } else { + # Production — store in Key Vault + if (-not $VaultName) { + throw 'Cannot determine Key Vault name from WEBSITE_DEPLOYMENT_ID' + } + + # Step 2: Store AppId in KV (idempotent — Set overwrites) + $ExistingAppIdSecret = $null + try { + $ExistingAppIdSecret = Get-CippKeyVaultSecret -VaultName $VaultName -Name 'SSOAppId' -AsPlainText -ErrorAction Stop + } catch { } + + if (-not $ExistingAppIdSecret -or $ExistingAppIdSecret -ne $AppId) { + Set-CippKeyVaultSecret -VaultName $VaultName -Name 'SSOAppId' -SecretValue (ConvertTo-SecureString -String $AppId -AsPlainText -Force) + Write-Information "[SSO-Setup] Stored SSOAppId in Key Vault" + } + + # Update status + $UpdateRow = @{ + PartitionKey = 'SSO' + RowKey = 'MigrationConfig' + Status = 'appid_stored' + LastChecked = (Get-Date).ToUniversalTime().ToString('o') + } + Add-CIPPAzDataTableEntity @MigrationTable -Entity $UpdateRow -Force | Out-Null + + # Step 3: Store AppSecret in KV + if ($AppSecret) { + Set-CippKeyVaultSecret -VaultName $VaultName -Name 'SSOAppSecret' -SecretValue (ConvertTo-SecureString -String $AppSecret -AsPlainText -Force) + Write-Information "[SSO-Setup] Stored SSOAppSecret in Key Vault" + } + + # Step 4: Verify TenantID exists in KV (should already be there from SAM setup) + $ExistingTenantId = $null + try { + $ExistingTenantId = Get-CippKeyVaultSecret -VaultName $VaultName -Name 'TenantID' -AsPlainText -ErrorAction Stop + } catch { } + + if (-not $ExistingTenantId) { + Set-CippKeyVaultSecret -VaultName $VaultName -Name 'TenantID' -SecretValue (ConvertTo-SecureString -String $env:TenantID -AsPlainText -Force) + Write-Information "[SSO-Setup] Stored TenantID in Key Vault (was missing)" + } + + # Step 5: Store MultiTenant flag in KV (used for initial EasyAuth setup on startup) + Set-CippKeyVaultSecret -VaultName $VaultName -Name 'SSOMultiTenant' -SecretValue (ConvertTo-SecureString -String ([string]$MultiTenant) -AsPlainText -Force) + Write-Information "[SSO-Setup] Stored SSOMultiTenant=$MultiTenant in Key Vault" + } + + # Mark migration as secrets_stored + $FinalRow = @{ + PartitionKey = 'SSO' + RowKey = 'MigrationConfig' + AppId = $AppId + MultiTenant = [string]$MultiTenant + RedirectUri = $TargetUrl + Status = 'secrets_stored' + CreatedAt = $Existing.CreatedAt ?? (Get-Date).ToUniversalTime().ToString('o') + LastChecked = (Get-Date).ToUniversalTime().ToString('o') + LastError = '' + } + Add-CIPPAzDataTableEntity @MigrationTable -Entity $FinalRow -Force | Out-Null + + Write-LogMessage -API $APIName -headers $Headers -message "SSO migration credentials stored for app $AppId" -sev Info + $Body = @{ + Results = @{ + message = 'CIPP-SSO app created and credentials stored. EasyAuth will be configured automatically on next startup.' + appId = $AppId + multiTenant = $MultiTenant + severity = 'success' + } + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -headers $Headers -message "SSO setup failed: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + + # Save error state so the scheduled task can retry + $ErrorRow = @{ + PartitionKey = 'SSO' + RowKey = 'MigrationConfig' + Status = 'error' + LastChecked = (Get-Date).ToUniversalTime().ToString('o') + LastError = $ErrorMessage.NormalizedError + } + try { Add-CIPPAzDataTableEntity @MigrationTable -Entity $ErrorRow -Force | Out-Null } catch { } + + $StatusCode = [HttpStatusCode]::InternalServerError + $Body = @{ Results = "SSO setup failed: $($ErrorMessage.NormalizedError)" } + } + } + + 'Update' { + # Update existing SSO app configuration (e.g. switch single ↔ multi-tenant) + try { + $Existing = Get-CIPPAzDataTableEntity @MigrationTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'MigrationConfig'" -ErrorAction SilentlyContinue + # Fall back to live EasyAuth config if migration table has no entry + if ((-not $Existing -or -not $Existing.AppId) -and $env:CIPPNG -and $env:WEBSITE_AUTH_V2_CONFIG_JSON) { + $LiveConfig = $env:WEBSITE_AUTH_V2_CONFIG_JSON | ConvertFrom-Json -ErrorAction SilentlyContinue + $LiveAppId = $LiveConfig.identityProviders.azureActiveDirectory.registration.clientId + if ($LiveAppId) { + $Existing = [PSCustomObject]@{ AppId = $LiveAppId; Status = 'complete'; CreatedAt = $null } + } + } + if (-not $Existing -or -not $Existing.AppId) { + $StatusCode = [HttpStatusCode]::BadRequest + $Body = @{ Results = 'No SSO app has been created yet. Use the Create action first.' } + break + } + + $MultiTenant = [bool]($Request.Body.multiTenant) + $TargetUrl = $Request.Body.targetUrl + if (-not $TargetUrl) { + $TargetUrl = $Request.Headers.origin ?? $Request.Headers.referer?.TrimEnd('/') + } + if (-not $TargetUrl) { + $TargetUrl = "https://$($env:WEBSITE_HOSTNAME)" + } + + $SignInAudience = if ($MultiTenant) { 'AzureADMultipleOrgs' } else { 'AzureADMyOrg' } + $CallbackUri = $TargetUrl.TrimEnd('/') + '/.auth/login/aad/callback' + + # Look up the existing app and patch it + $AppResponse = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/applications(appId='$($Existing.AppId)')?`$select=id,appId,web,signInAudience" -NoAuthCheck $true -AsApp $true + + $PatchBody = @{ + signInAudience = $SignInAudience + web = @{ + redirectUris = @($CallbackUri) + implicitGrantSettings = @{ enableIdTokenIssuance = $true } + } + } | ConvertTo-Json -Depth 10 -Compress + + New-GraphPOSTRequest -uri "https://graph.microsoft.com/v1.0/applications/$($AppResponse.id)" -body $PatchBody -type PATCH -NoAuthCheck $true -AsApp $true + + # Update migration table + $UpdateRow = @{ + PartitionKey = 'SSO' + RowKey = 'MigrationConfig' + AppId = $Existing.AppId + MultiTenant = [string]$MultiTenant + RedirectUri = $TargetUrl + Status = $Existing.Status + CreatedAt = $Existing.CreatedAt + LastChecked = (Get-Date).ToUniversalTime().ToString('o') + LastError = '' + } + Add-CIPPAzDataTableEntity @MigrationTable -Entity $UpdateRow -Force | Out-Null + + Write-LogMessage -API $APIName -headers $Headers -message "SSO app updated: multiTenant=$MultiTenant, audience=$SignInAudience" -sev Info + + # Update SSOMultiTenant in KV so initial EasyAuth setup stays in sync + $KV = $env:WEBSITE_DEPLOYMENT_ID + $VaultName = if ($KV) { ($KV -split '-')[0] } else { $null } + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true' -or $env:NonLocalHostAzurite -eq 'true') { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'SSO'" -ErrorAction SilentlyContinue + if ($Secret) { + $Secret | Add-Member -MemberType NoteProperty -Name 'SSOMultiTenant' -Value ([string]$MultiTenant) -Force + Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force | Out-Null + } + } elseif ($VaultName) { + Set-CippKeyVaultSecret -VaultName $VaultName -Name 'SSOMultiTenant' -SecretValue (ConvertTo-SecureString -String ([string]$MultiTenant) -AsPlainText -Force) + } + + # Update EasyAuth ARM config on the App Service (issuer URL + allowed tenants) + try { + Set-CIPPSSOEasyAuth -AppId $Existing.AppId -MultiTenant $MultiTenant -TenantId $env:TenantID + } catch { + Write-Information "[SSO-Update] EasyAuth ARM update skipped (may not be in App Service): $($_.Exception.Message)" + } + + $Body = @{ + Results = @{ + message = "SSO app updated successfully. Sign-in audience is now $SignInAudience." + appId = $Existing.AppId + multiTenant = $MultiTenant + severity = 'success' + } + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -headers $Headers -message "SSO update failed: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + $Body = @{ Results = "SSO update failed: $($ErrorMessage.NormalizedError)" } + } + } + + 'RotateSecret' { + # Rotate the client secret for the SSO app + try { + $Existing = Get-CIPPAzDataTableEntity @MigrationTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'MigrationConfig'" -ErrorAction SilentlyContinue + # Fall back to live EasyAuth config if migration table has no entry + if ((-not $Existing -or -not $Existing.AppId) -and $env:CIPPNG -and $env:WEBSITE_AUTH_V2_CONFIG_JSON) { + $LiveConfig = $env:WEBSITE_AUTH_V2_CONFIG_JSON | ConvertFrom-Json -ErrorAction SilentlyContinue + $LiveAppId = $LiveConfig.identityProviders.azureActiveDirectory.registration.clientId + if ($LiveAppId) { + $Existing = [PSCustomObject]@{ AppId = $LiveAppId } + } + } + if (-not $Existing -or -not $Existing.AppId) { + $StatusCode = [HttpStatusCode]::BadRequest + $Body = @{ Results = 'No SSO app has been created yet.' } + break + } + + # Get the app object ID + $AppResponse = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/applications(appId='$($Existing.AppId)')?`$select=id" -NoAuthCheck $true -AsApp $true + + # Create new secret + $PasswordBody = '{"passwordCredential":{"displayName":"CIPP-SSO-Secret"}}' + $PasswordResult = New-GraphPOSTRequest -uri "https://graph.microsoft.com/v1.0/applications/$($AppResponse.id)/addPassword" -body $PasswordBody -type POST -NoAuthCheck $true -AsApp $true + $NewSecret = $PasswordResult.secretText + + if (-not $NewSecret) { + throw 'Failed to create new client secret' + } + + # Store new secret + $KV = $env:WEBSITE_DEPLOYMENT_ID + $VaultName = if ($KV) { ($KV -split '-')[0] } else { $null } + + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true' -or $env:NonLocalHostAzurite -eq 'true') { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'SSO'" -ErrorAction SilentlyContinue + if (-not $Secret) { $Secret = [PSCustomObject]@{} } + $Secret | Add-Member -MemberType NoteProperty -Name 'PartitionKey' -Value 'SSO' -Force + $Secret | Add-Member -MemberType NoteProperty -Name 'RowKey' -Value 'SSO' -Force + $Secret | Add-Member -MemberType NoteProperty -Name 'SSOAppSecret' -Value $NewSecret -Force + Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force | Out-Null + } else { + if (-not $VaultName) { throw 'Cannot determine Key Vault name from WEBSITE_DEPLOYMENT_ID' } + Set-CippKeyVaultSecret -VaultName $VaultName -Name 'SSOAppSecret' -SecretValue (ConvertTo-SecureString -String $NewSecret -AsPlainText -Force) + } + + # Update last checked + $UpdateRow = @{ + PartitionKey = 'SSO' + RowKey = 'MigrationConfig' + LastChecked = (Get-Date).ToUniversalTime().ToString('o') + LastError = '' + } + Add-CIPPAzDataTableEntity @MigrationTable -Entity $UpdateRow -Force | Out-Null + + Write-LogMessage -API $APIName -headers $Headers -message "SSO app secret rotated for $($Existing.AppId)" -sev Info + $Body = @{ + Results = @{ + message = 'Client secret rotated successfully. The new secret will be picked up from Key Vault on next restart.' + severity = 'success' + } + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -headers $Headers -message "SSO secret rotation failed: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + $Body = @{ Results = "Secret rotation failed: $($ErrorMessage.NormalizedError)" } + } + } + + 'Migrate' { + # Forced SSO migration. Creates the customer's own CIPP-SSO app, + # stores credentials in Key Vault, configures EasyAuth, and removes the migration + # trigger env var. The central migration app (implicit auth, no secret) is replaced + # by the customer's own app with a proper client secret. + if (-not $env:CIPP_SSO_MIGRATION_APPID) { + $Body = @{ Results = @{ message = 'No SSO migration pending.'; severity = 'info' } } + break + } + + $MultiTenant = [bool]($Request.Body.multiTenant) + $TargetUrl = "https://$($env:WEBSITE_HOSTNAME)" + + try { + # Check if we already have SSO credentials from a previous partial run + $KV = $env:WEBSITE_DEPLOYMENT_ID + $VaultName = if ($KV) { ($KV -split '-')[0] } else { $null } + $ExistingAppId = $null + + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true' -or $env:NonLocalHostAzurite -eq 'true') { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $DevSecret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'SSO'" -ErrorAction SilentlyContinue + $ExistingAppId = $DevSecret.SSOAppId + } elseif ($VaultName) { + try { $ExistingAppId = Get-CippKeyVaultSecret -VaultName $VaultName -Name 'SSOAppId' -AsPlainText -ErrorAction Stop } catch { } + } + + # Step 1: Create or update the customer's own CIPP-SSO app registration + $SSOAppParams = @{ + RedirectUri = $TargetUrl + MultiTenant = $MultiTenant + } + if ($ExistingAppId) { $SSOAppParams.ExistingAppId = $ExistingAppId } + + $SSOApp = New-CIPPSSOApp @SSOAppParams + $AppId = $SSOApp.AppId + $AppSecret = $SSOApp.ClientSecret + Write-LogMessage -API $APIName -headers $Headers -message "SSO migration: CIPP-SSO app $($SSOApp.State): $AppId" -sev Info + + # Step 2: Store credentials + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true' -or $env:NonLocalHostAzurite -eq 'true') { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'SSO'" -ErrorAction SilentlyContinue + if (-not $Secret) { $Secret = [PSCustomObject]@{} } + $Secret | Add-Member -MemberType NoteProperty -Name 'PartitionKey' -Value 'SSO' -Force + $Secret | Add-Member -MemberType NoteProperty -Name 'RowKey' -Value 'SSO' -Force + $Secret | Add-Member -MemberType NoteProperty -Name 'SSOAppId' -Value $AppId -Force + $Secret | Add-Member -MemberType NoteProperty -Name 'SSOMultiTenant' -Value ([string]$MultiTenant) -Force + if ($AppSecret) { + $Secret | Add-Member -MemberType NoteProperty -Name 'SSOAppSecret' -Value $AppSecret -Force + } + Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force | Out-Null + Write-Information '[SSO-Migrate] Stored SSO credentials in DevSecrets table' + } else { + if (-not $VaultName) { throw 'Cannot determine Key Vault name from WEBSITE_DEPLOYMENT_ID' } + + Set-CippKeyVaultSecret -VaultName $VaultName -Name 'SSOAppId' -SecretValue (ConvertTo-SecureString -String $AppId -AsPlainText -Force) + if ($AppSecret) { + Set-CippKeyVaultSecret -VaultName $VaultName -Name 'SSOAppSecret' -SecretValue (ConvertTo-SecureString -String $AppSecret -AsPlainText -Force) + } + Set-CippKeyVaultSecret -VaultName $VaultName -Name 'SSOMultiTenant' -SecretValue (ConvertTo-SecureString -String ([string]$MultiTenant) -AsPlainText -Force) + Write-Information "[SSO-Migrate] Stored SSO credentials in Key Vault ($VaultName)" + } + + # Step 3: Configure EasyAuth on the App Service + Set-CIPPSSOEasyAuth -AppId $AppId -MultiTenant $MultiTenant -TenantId $env:TenantID -UseKvReferences + + # Step 4: Remove the migration trigger env var + Remove-CIPPMigrationAppSetting -SettingName 'CIPP_SSO_MIGRATION_APPID' + + # Step 5: Track in migration table (for audit/status) + $MigrationRow = @{ + PartitionKey = 'SSO' + RowKey = 'MigrationConfig' + AppId = $AppId + MultiTenant = [string]$MultiTenant + RedirectUri = $TargetUrl + Status = 'complete' + CreatedAt = (Get-Date).ToUniversalTime().ToString('o') + LastChecked = (Get-Date).ToUniversalTime().ToString('o') + LastError = '' + MigratedFrom = 'SWA' + } + Add-CIPPAzDataTableEntity @MigrationTable -Entity $MigrationRow -Force | Out-Null + + Write-LogMessage -API $APIName -headers $Headers -message "SSO migration complete: appId=$AppId, multiTenant=$MultiTenant" -sev Info + + # Step 6: Restart to apply EasyAuth + [Craft.Services.AppLifecycleBridge]::RequestRestart('SSO migration complete — EasyAuth configured with customer CIPP-SSO app') + + $Body = @{ + Results = @{ + message = 'SSO migration complete. Your instance will restart with your own CIPP-SSO app registration. You will be redirected to log in once the instance is back online.' + appId = $AppId + multiTenant = $MultiTenant + severity = 'success' + } + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -headers $Headers -message "SSO migration failed: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + $Body = @{ Results = "SSO migration failed: $($ErrorMessage.NormalizedError)" } + } + } + + default { + $StatusCode = [HttpStatusCode]::BadRequest + $Body = @{ Results = "Unknown action: $Action. Use 'Status', 'Create', or 'Update'." } + } + } + + return [HttpResponseContext]@{ + StatusCode = $StatusCode ?? [HttpStatusCode]::OK + Body = $Body + } +} From 3adade45c14529810607f8a251d56a9c2c0ac44b Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Wed, 13 May 2026 14:21:10 +0800 Subject: [PATCH 16/38] Featureflag configs and timer changes --- Config/CIPPTimers.json | 9 + Config/FeatureFlags.json | 6 +- .../Start-ContainerUpdateCheck.ps1 | 193 +++++++++++++ .../CIPPCore/Public/Get-CIPPFeatureFlag.ps1 | 4 + .../Invoke-ExecContainerManagement.ps1 | 264 +++++++++++++++--- 5 files changed, 431 insertions(+), 45 deletions(-) create mode 100644 Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-ContainerUpdateCheck.ps1 diff --git a/Config/CIPPTimers.json b/Config/CIPPTimers.json index b9899dec6d4b..077f7d53fb0c 100644 --- a/Config/CIPPTimers.json +++ b/Config/CIPPTimers.json @@ -264,5 +264,14 @@ "RunOnProcessor": true, "TZOffset": true, "IsSystem": true + }, + { + "Id": "a3b4c5d6-e7f8-4a9b-8c1d-2e3f4a5b6c7d", + "Command": "Start-ContainerUpdateCheck", + "Description": "Check for container image updates and optionally auto-restart", + "Cron": "0 0 * * * *", + "Priority": 30, + "RunOnProcessor": false, + "IsSystem": true } ] diff --git a/Config/FeatureFlags.json b/Config/FeatureFlags.json index 858f8bc58bcf..0f0d74065933 100644 --- a/Config/FeatureFlags.json +++ b/Config/FeatureFlags.json @@ -19,7 +19,8 @@ "/tenant/standards/bpa-report", "/tenant/standards/bpa-report/builder", "/tenant/standards/bpa-report/view" - ] + ], + "Hidden": false }, { "Id": "SuperAdminNG", @@ -38,6 +39,7 @@ "/cipp/advanced/super-admin/cipp-users", "/cipp/advanced/super-admin/sso", "/cipp/advanced/super-admin/container" - ] + ], + "Hidden": true } ] diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-ContainerUpdateCheck.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-ContainerUpdateCheck.ps1 new file mode 100644 index 000000000000..381abbbc023c --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-ContainerUpdateCheck.ps1 @@ -0,0 +1,193 @@ +function Start-ContainerUpdateCheck { + <# + .SYNOPSIS + Timer function to check for container image updates + .DESCRIPTION + Reads update settings from ContainerUpdateSettings table, checks if it's time to run based + on the configured interval and check time, queries GHCR for the latest image digest, and + optionally triggers a restart if auto-update is enabled. + #> + [CmdletBinding(SupportsShouldProcess = $true)] + param() + + if ($PSCmdlet.ShouldProcess('Start-ContainerUpdateCheck', 'Check for container image updates')) { + $SettingsTable = Get-CippTable -tablename 'ContainerUpdateSettings' + $Settings = Get-CIPPAzDataTableEntity @SettingsTable -Filter "PartitionKey eq 'Settings' and RowKey eq 'UpdateConfig'" | Select-Object -First 1 + + if (-not $Settings -or $Settings.CheckInterval -eq '0' -or [string]::IsNullOrWhiteSpace($Settings.CheckInterval)) { + Write-Information 'Container update check: disabled or not configured' + return + } + + # Parse interval to determine if we're due + $IntervalHours = switch ($Settings.CheckInterval) { + '1h' { 1 } + '4h' { 4 } + '12h' { 12 } + '1d' { 24 } + default { 0 } + } + if ($IntervalHours -eq 0) { + Write-Information "Container update check: unknown interval '$($Settings.CheckInterval)'" + return + } + + # Check if preferred time applies — within 45 minutes of desired hour using CIPP timezone + $CheckTime = $Settings.CheckTime + if ($CheckTime -and [string]$CheckTime -ne '') { + $TargetHour = [int]$CheckTime + + # Load the configured CIPP timezone (same source as Get-CIPPTimerFunctions) + $ConfigTable = Get-CIPPTable -tablename Config + $TimeSettings = Get-CIPPAzDataTableEntity @ConfigTable -Filter "PartitionKey eq 'TimeSettings' and RowKey eq 'TimeSettings'" | Select-Object -First 1 + $ScheduleTimeZone = [TimeZoneInfo]::Utc + if ($TimeSettings.Timezone) { + try { + $ScheduleTimeZone = [TimeZoneInfo]::FindSystemTimeZoneById($TimeSettings.Timezone) + } catch { + Write-Information "Invalid timezone '$($TimeSettings.Timezone)' — falling back to UTC" + } + } + + # Convert current UTC time to the configured timezone + $NowUtc = [DateTime]::UtcNow + $NowLocal = [TimeZoneInfo]::ConvertTimeFromUtc($NowUtc, $ScheduleTimeZone) + $Today = $NowLocal.Date + $TargetTime = $Today.AddHours($TargetHour) + $MinutesDiff = [math]::Abs(($NowLocal - $TargetTime).TotalMinutes) + # Handle wrapping around midnight (e.g. target=23, current=0) + $MinutesDiffWrap = 1440 - $MinutesDiff + $EffectiveDiff = [math]::Min($MinutesDiff, $MinutesDiffWrap) + if ($EffectiveDiff -gt 45) { + Write-Information "Container update check: not within 45 min of preferred time ($($TargetHour):00 $($ScheduleTimeZone.Id)), current local: $($NowLocal.ToString('HH:mm')), diff: $([math]::Round($EffectiveDiff))min" + return + } + } + + # Check if enough time has elapsed since last check + $LastCheck = $Settings.LastCheck + if ($LastCheck) { + try { + $LastCheckEpoch = [int64]$LastCheck + $LastCheckTime = [DateTimeOffset]::FromUnixTimeSeconds($LastCheckEpoch).UtcDateTime + $ElapsedHours = ((Get-Date).ToUniversalTime() - $LastCheckTime).TotalHours + if ($ElapsedHours -lt ($IntervalHours * 0.9)) { + Write-Information "Container update check: last check was $([math]::Round($ElapsedHours, 1))h ago, interval is ${IntervalHours}h — skipping" + return + } + } catch { + Write-Information "Container update check: could not parse LastCheck '$LastCheck' — proceeding" + } + } + + Write-Information 'Container update check: running' + + try { + # Resolve ARM site details + $Subscription = Get-CIPPAzFunctionAppSubId + $SiteName = $env:WEBSITE_SITE_NAME + $RGName = $env:WEBSITE_RESOURCE_GROUP + if (-not $RGName) { + $Owner = $env:WEBSITE_OWNER_NAME + if ($Owner -match '^(?[^+]+)\+(?[^-]+(?:-[^-]+)*?)(?:-[^-]+webspace(?:-Linux)?)?$') { + $RGName = $Matches.RGName + } + } + + $ImageTag = $env:IMAGE_TAG ?? 'unknown' + $CurrentImage = $null + + if ($Subscription -and $RGName -and $SiteName) { + $apiVersion = '2024-11-01' + $uri = "https://management.azure.com/subscriptions/$Subscription/resourceGroups/$RGName/providers/Microsoft.Web/sites/$SiteName/config/web?api-version=$apiVersion" + $webConfig = New-CIPPAzRestRequest -Uri $uri -Method GET + $linuxFxVersion = $webConfig.properties.linuxFxVersion + if ($linuxFxVersion) { + $CurrentImage = $linuxFxVersion -replace '^DOCKER\|', '' + } + } + + if (-not $CurrentImage) { + Write-LogMessage -API 'ContainerUpdateCheck' -message 'Could not determine current container image from ARM' -sev Warning + return + } + + # Update checking only works with GHCR-hosted images + if ($CurrentImage -notmatch '^ghcr\.io/') { + Write-Information "Container update check: skipped — image '$CurrentImage' is not hosted on GHCR" + return + } + + $CheckTag = if ($CurrentImage -match ':([^:]+)$') { $Matches[1] } else { $ImageTag } + + # Parse image path for GHCR + $imagePath = $CurrentImage -replace '^ghcr\.io/', '' -replace ':.*$', '' + if (-not $imagePath) { + Write-LogMessage -API 'ContainerUpdateCheck' -message 'Could not parse image path from reference' -sev Warning + return + } + + # Get anonymous GHCR token + $tokenUri = "https://ghcr.io/token?scope=repository:${imagePath}:pull" + $tokenResp = Invoke-RestMethod -Uri $tokenUri -Method GET -ErrorAction Stop + $token = $tokenResp.token + + $digestHeaders = @{ + Authorization = "Bearer $token" + Accept = 'application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.docker.distribution.manifest.v2+json' + } + + # Get remote digest for the configured channel tag + $manifestUri = "https://ghcr.io/v2/$imagePath/manifests/$CheckTag" + $resp = Invoke-WebRequest -Uri $manifestUri -Method HEAD -Headers $digestHeaders -ErrorAction Stop + $RemoteDigest = $resp.Headers['Docker-Content-Digest'] + if ($RemoteDigest -is [array]) { $RemoteDigest = $RemoteDigest[0] } + + # Get running digest for the baked-in image tag + $RunningDigest = $null + try { + $runningUri = "https://ghcr.io/v2/$imagePath/manifests/$ImageTag" + $runResp = Invoke-WebRequest -Uri $runningUri -Method HEAD -Headers $digestHeaders -ErrorAction Stop + $RunningDigest = $runResp.Headers['Docker-Content-Digest'] + if ($RunningDigest -is [array]) { $RunningDigest = $RunningDigest[0] } + } catch { + Write-Information "Could not get running digest for tag $ImageTag" + } + + $UpdateAvailable = $false + if ($RemoteDigest -and $RunningDigest -and $RemoteDigest -ne $RunningDigest) { + $UpdateAvailable = $true + } + + # Update the settings row with results (preserve user settings) + $UpdateEntity = @{ + PartitionKey = 'Settings' + RowKey = 'UpdateConfig' + AutoUpdate = [string]($Settings.AutoUpdate ?? 'false') + CheckInterval = [string]($Settings.CheckInterval ?? '0') + CheckTime = [string]($Settings.CheckTime ?? '') + LastCheck = [string][int64](([DateTimeOffset]::UtcNow).ToUnixTimeSeconds()) + UpdateAvailable = [string]$UpdateAvailable + RunningDigest = [string]($RunningDigest ?? '') + RemoteDigest = [string]($RemoteDigest ?? '') + } + Add-CIPPAzDataTableEntity @SettingsTable -Entity $UpdateEntity -Force | Out-Null + + if ($UpdateAvailable -and $Settings.AutoUpdate -eq 'true') { + Write-LogMessage -API 'ContainerUpdateCheck' -message "Auto-update: new container image detected (running: $RunningDigest, remote: $RemoteDigest). Restarting." -sev Info + try { + [Craft.Services.AppLifecycleBridge]::RequestRestart('Auto-update: new container image available') + } catch { + Write-LogMessage -API 'ContainerUpdateCheck' -message 'Auto-restart requested but AppLifecycleBridge is not available' -sev Warning + } + } elseif ($UpdateAvailable) { + Write-LogMessage -API 'ContainerUpdateCheck' -message "Container update available (running: $RunningDigest, remote: $RemoteDigest)" -sev Info + } else { + Write-Information "Container is up to date. Digest: $RunningDigest" + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'ContainerUpdateCheck' -message "Failed to check for container update: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + } + } +} diff --git a/Modules/CIPPCore/Public/Get-CIPPFeatureFlag.ps1 b/Modules/CIPPCore/Public/Get-CIPPFeatureFlag.ps1 index f5d7963d2e59..779c3f13789a 100644 --- a/Modules/CIPPCore/Public/Get-CIPPFeatureFlag.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPFeatureFlag.ps1 @@ -45,6 +45,7 @@ function Get-CIPPFeatureFlag { Timers = $FeatureFlag.Timers Endpoints = $FeatureFlag.Endpoints Pages = $FeatureFlag.Pages + Hidden = [bool]$FeatureFlag.Hidden Enabled = $TableFlag.Enabled } } else { @@ -65,6 +66,7 @@ function Get-CIPPFeatureFlag { Timers = $FeatureFlag.Timers Endpoints = $FeatureFlag.Endpoints Pages = $FeatureFlag.Pages + Hidden = [bool]$FeatureFlag.Hidden Enabled = $FeatureFlag.Enabled } } @@ -83,6 +85,7 @@ function Get-CIPPFeatureFlag { Timers = $FeatureFlag.Timers Endpoints = $FeatureFlag.Endpoints Pages = $FeatureFlag.Pages + Hidden = [bool]$FeatureFlag.Hidden Enabled = $TableFlag.Enabled } } else { @@ -103,6 +106,7 @@ function Get-CIPPFeatureFlag { Timers = $FeatureFlag.Timers Endpoints = $FeatureFlag.Endpoints Pages = $FeatureFlag.Pages + Hidden = [bool]$FeatureFlag.Hidden Enabled = $FeatureFlag.Enabled } } diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecContainerManagement.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecContainerManagement.ps1 index da9948164016..be842ac61a90 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecContainerManagement.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecContainerManagement.ps1 @@ -13,6 +13,48 @@ function Invoke-ExecContainerManagement { $Action = $Request.Query.Action ?? $Request.Body.Action $ValidChannels = @('latest', 'dev', 'nightly') + $SettingsTable = Get-CippTable -tablename 'ContainerUpdateSettings' + + # Helper: resolve ARM site details + function Get-ContainerSiteInfo { + $info = @{ + Subscription = Get-CIPPAzFunctionAppSubId + SiteName = $env:WEBSITE_SITE_NAME + RGName = $env:WEBSITE_RESOURCE_GROUP + } + if (-not $info.RGName) { + $Owner = $env:WEBSITE_OWNER_NAME + if ($Owner -match '^(?[^+]+)\+(?[^-]+(?:-[^-]+)*?)(?:-[^-]+webspace(?:-Linux)?)?$') { + $info.RGName = $Matches.RGName + } + } + return $info + } + + # Helper: query GHCR for the image digest of a given tag + function Get-GHCRImageDigest { + param([string]$ImageRef, [string]$Tag) + + # Parse image reference: ghcr.io/owner/repo or owner/repo + $imagePath = $ImageRef -replace '^ghcr\.io/', '' -replace ':.*$', '' + if (-not $imagePath) { throw 'Could not parse image path from reference' } + + # Get anonymous token for GHCR (public packages) + $tokenUri = "https://ghcr.io/token?scope=repository:${imagePath}:pull" + $tokenResp = Invoke-RestMethod -Uri $tokenUri -Method GET -ErrorAction Stop + $token = $tokenResp.token + + # Get manifest digest via HEAD request + $manifestUri = "https://ghcr.io/v2/$imagePath/manifests/$Tag" + $digestHeaders = @{ + Authorization = "Bearer $token" + Accept = 'application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.docker.distribution.manifest.v2+json' + } + $resp = Invoke-WebRequest -Uri $manifestUri -Method HEAD -Headers $digestHeaders -ErrorAction Stop + $digest = $resp.Headers['Docker-Content-Digest'] + if ($digest -is [array]) { $digest = $digest[0] } + return [string]$digest + } switch ($Action) { 'Status' { @@ -20,31 +62,20 @@ function Invoke-ExecContainerManagement { $CurrentVersion = $env:APP_VERSION ?? 'unknown' $CommitSha = $env:COMMIT_SHA ?? 'unknown' $ImageTag = $env:IMAGE_TAG ?? 'unknown' - - # The channel is the image tag baked into the container at build time $CurrentChannel = $ImageTag - # Try to read the full container image reference from ARM + # Read the full container image reference from ARM $CurrentImage = 'unknown' - $Subscription = Get-CIPPAzFunctionAppSubId - $RGName = $env:WEBSITE_RESOURCE_GROUP - if (-not $RGName) { - $Owner = $env:WEBSITE_OWNER_NAME - if ($Owner -match '^(?[^+]+)\+(?[^-]+(?:-[^-]+)*?)(?:-[^-]+webspace(?:-Linux)?)?$') { - $RGName = $Matches.RGName - } - } - $SiteName = $env:WEBSITE_SITE_NAME - if ($Subscription -and $RGName -and $SiteName) { + $ConfiguredChannel = $CurrentChannel + $site = Get-ContainerSiteInfo + if ($site.Subscription -and $site.RGName -and $site.SiteName) { try { $apiVersion = '2024-11-01' - $uri = "https://management.azure.com/subscriptions/$Subscription/resourceGroups/$RGName/providers/Microsoft.Web/sites/$SiteName/config/web?api-version=$apiVersion" + $uri = "https://management.azure.com/subscriptions/$($site.Subscription)/resourceGroups/$($site.RGName)/providers/Microsoft.Web/sites/$($site.SiteName)/config/web?api-version=$apiVersion" $webConfig = New-CIPPAzRestRequest -Uri $uri -Method GET $linuxFxVersion = $webConfig.properties.linuxFxVersion if ($linuxFxVersion) { $CurrentImage = $linuxFxVersion -replace '^DOCKER\|', '' - # The ARM config tag may differ from the running container's baked-in tag - # if the channel was changed but the container hasn't restarted yet if ($CurrentImage -match ':([^:]+)$') { $ConfiguredChannel = $Matches[1] } @@ -54,16 +85,38 @@ function Invoke-ExecContainerManagement { } } + # Read update settings and last check result + $Settings = Get-CIPPAzDataTableEntity @SettingsTable -Filter "PartitionKey eq 'Settings' and RowKey eq 'UpdateConfig'" | Select-Object -First 1 + $UpdateInfo = @{ + AutoUpdate = $false + CheckInterval = '0' + CheckTime = $null + LastCheck = $null + UpdateAvailable = $false + RunningDigest = $null + RemoteDigest = $null + } + if ($Settings) { + $UpdateInfo.AutoUpdate = $Settings.AutoUpdate -eq 'true' + $UpdateInfo.CheckInterval = $Settings.CheckInterval ?? '0' + $UpdateInfo.CheckTime = $Settings.CheckTime ?? $null + $UpdateInfo.LastCheck = if ($Settings.LastCheck) { [int64]$Settings.LastCheck } else { $null } + $UpdateInfo.UpdateAvailable = $Settings.UpdateAvailable -eq 'true' + $UpdateInfo.RunningDigest = $Settings.RunningDigest ?? $null + $UpdateInfo.RemoteDigest = $Settings.RemoteDigest ?? $null + } + $Body = @{ Results = @{ CurrentVersion = $CurrentVersion CommitSha = $CommitSha ImageTag = $ImageTag CurrentChannel = $CurrentChannel - ConfiguredChannel = $ConfiguredChannel ?? $CurrentChannel + ConfiguredChannel = $ConfiguredChannel CurrentImage = $CurrentImage - SiteName = $SiteName + SiteName = $site.SiteName ValidChannels = $ValidChannels + UpdateSettings = $UpdateInfo } } } catch { @@ -75,6 +128,150 @@ function Invoke-ExecContainerManagement { } } } + 'CheckUpdate' { + try { + $site = Get-ContainerSiteInfo + $ImageTag = $env:IMAGE_TAG ?? 'unknown' + + # Get the current image reference from ARM + $CurrentImage = $null + if ($site.Subscription -and $site.RGName -and $site.SiteName) { + $apiVersion = '2024-11-01' + $uri = "https://management.azure.com/subscriptions/$($site.Subscription)/resourceGroups/$($site.RGName)/providers/Microsoft.Web/sites/$($site.SiteName)/config/web?api-version=$apiVersion" + $webConfig = New-CIPPAzRestRequest -Uri $uri -Method GET + $linuxFxVersion = $webConfig.properties.linuxFxVersion + if ($linuxFxVersion) { + $CurrentImage = $linuxFxVersion -replace '^DOCKER\|', '' + } + } + if (-not $CurrentImage) { + throw 'Could not determine current container image from ARM config' + } + + # Update checking only works with GHCR-hosted images + if ($CurrentImage -notmatch '^ghcr\.io/') { + $Body = @{ + Results = @{ + Message = "Update checking is only supported for GHCR-hosted images. Current image: $CurrentImage" + UpdateAvailable = $false + RunningDigest = $null + RemoteDigest = $null + CheckedTag = $null + } + } + break + } + + # Determine the tag to check + $CheckTag = if ($CurrentImage -match ':([^:]+)$') { $Matches[1] } else { $ImageTag } + + # Query GHCR for the remote digest + $RemoteDigest = Get-GHCRImageDigest -ImageRef $CurrentImage -Tag $CheckTag + + # Get the running container's digest — query for the baked-in tag to get what we're running + $RunningDigest = $null + try { + $RunningDigest = Get-GHCRImageDigest -ImageRef $CurrentImage -Tag $ImageTag + } catch { + Write-Information "Could not get running digest for tag $ImageTag — may be first check" + } + + $UpdateAvailable = $false + if ($RemoteDigest -and $RunningDigest -and $RemoteDigest -ne $RunningDigest) { + $UpdateAvailable = $true + } + + # Store result + $Entity = @{ + PartitionKey = 'Settings' + RowKey = 'UpdateConfig' + LastCheck = [string][int64](([DateTimeOffset]::UtcNow).ToUnixTimeSeconds()) + UpdateAvailable = [string]$UpdateAvailable + RunningDigest = [string]($RunningDigest ?? '') + RemoteDigest = [string]($RemoteDigest ?? '') + } + # Merge with existing settings (preserve AutoUpdate, CheckInterval, CheckTime) + $Existing = Get-CIPPAzDataTableEntity @SettingsTable -Filter "PartitionKey eq 'Settings' and RowKey eq 'UpdateConfig'" | Select-Object -First 1 + if ($Existing) { + $Entity.AutoUpdate = $Existing.AutoUpdate ?? 'false' + $Entity.CheckInterval = $Existing.CheckInterval ?? '0' + $Entity.CheckTime = $Existing.CheckTime ?? '' + } + Add-CIPPAzDataTableEntity @SettingsTable -Entity $Entity -Force | Out-Null + + # Auto-restart if enabled and update is available + $Settings = Get-CIPPAzDataTableEntity @SettingsTable -Filter "PartitionKey eq 'Settings' and RowKey eq 'UpdateConfig'" | Select-Object -First 1 + if ($UpdateAvailable -and $Settings.AutoUpdate -eq 'true') { + Write-LogMessage -API $APIName -headers $Headers -message "Auto-update: new container image detected (running: $RunningDigest, remote: $RemoteDigest). Restarting." -sev Info + try { [Craft.Services.AppLifecycleBridge]::RequestRestart('Auto-update: new container image available') } catch {} + $Result = "Update available — container restart initiated (auto-update enabled). Running digest: $RunningDigest, Remote digest: $RemoteDigest" + } elseif ($UpdateAvailable) { + $Result = "Update available. Running digest: $RunningDigest, Remote digest: $RemoteDigest. Restart the container to apply." + Write-LogMessage -API $APIName -headers $Headers -message "Container update available (running: $RunningDigest, remote: $RemoteDigest)" -sev Info + } else { + $Result = "Container is up to date. Digest: $RunningDigest" + } + $Body = @{ + Results = @{ + Message = $Result + UpdateAvailable = $UpdateAvailable + RunningDigest = $RunningDigest + RemoteDigest = $RemoteDigest + CheckedTag = $CheckTag + } + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -headers $Headers -message "Failed to check for update: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::InternalServerError + Body = @{ Results = "Failed: $($ErrorMessage.NormalizedError)" } + } + } + } + 'SaveUpdateSettings' { + try { + $AutoUpdate = [bool]($Request.Body.AutoUpdate) + $CheckInterval = $Request.Body.CheckInterval ?? '0' + $CheckTime = $Request.Body.CheckTime + $ValidIntervals = @('0', '1h', '4h', '12h', '1d') + if ($CheckInterval -notin $ValidIntervals) { + throw "Invalid check interval: $CheckInterval. Valid: $($ValidIntervals -join ', ')" + } + if ($CheckTime -and ($CheckTime -lt 0 -or $CheckTime -gt 23)) { + throw "Invalid check time: $CheckTime. Must be 0-23 (UTC hour)." + } + + # Read existing settings to preserve check results + $Existing = Get-CIPPAzDataTableEntity @SettingsTable -Filter "PartitionKey eq 'Settings' and RowKey eq 'UpdateConfig'" | Select-Object -First 1 + $Entity = @{ + PartitionKey = 'Settings' + RowKey = 'UpdateConfig' + AutoUpdate = [string]$AutoUpdate + CheckInterval = [string]$CheckInterval + CheckTime = [string]($CheckTime ?? '') + LastCheck = [string]($Existing.LastCheck ?? '') + UpdateAvailable = [string]($Existing.UpdateAvailable ?? 'false') + RunningDigest = [string]($Existing.RunningDigest ?? '') + RemoteDigest = [string]($Existing.RemoteDigest ?? '') + } + Add-CIPPAzDataTableEntity @SettingsTable -Entity $Entity -Force | Out-Null + + $IntervalLabel = if ($CheckInterval -eq '0') { 'disabled' } else { "every $CheckInterval" } + $AutoLabel = if ($AutoUpdate) { 'auto-restart enabled' } else { 'manual restart' } + $TimeLabel = if ($CheckTime -and $CheckInterval -ne '0') { " at ${CheckTime}:00 UTC" } else { '' } + $Result = "Update settings saved. Check interval: ${IntervalLabel}${TimeLabel}, $AutoLabel." + Write-LogMessage -API $APIName -headers $Headers -message $Result -sev Info + $Body = @{ Results = $Result } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -headers $Headers -message "Failed to save update settings: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = "Failed: $($ErrorMessage.NormalizedError)" } + } + } + } 'UpdateChannel' { try { $NewChannel = $Request.Body.Channel @@ -85,30 +282,19 @@ function Invoke-ExecContainerManagement { throw "Invalid channel: $NewChannel. Valid channels: $($ValidChannels -join ', ')" } - $Subscription = Get-CIPPAzFunctionAppSubId - $RGName = $env:WEBSITE_RESOURCE_GROUP - if (-not $RGName) { - $Owner = $env:WEBSITE_OWNER_NAME - if ($Owner -match '^(?[^+]+)\+(?[^-]+(?:-[^-]+)*?)(?:-[^-]+webspace(?:-Linux)?)?$') { - $RGName = $Matches.RGName - } - } - $SiteName = $env:WEBSITE_SITE_NAME - if (-not ($Subscription -and $RGName -and $SiteName)) { + $site = Get-ContainerSiteInfo + if (-not ($site.Subscription -and $site.RGName -and $site.SiteName)) { throw 'Could not determine Azure App Service details from environment' } $apiVersion = '2024-11-01' - - # Read current web config - $getUri = "https://management.azure.com/subscriptions/$Subscription/resourceGroups/$RGName/providers/Microsoft.Web/sites/$SiteName/config/web?api-version=$apiVersion" + $getUri = "https://management.azure.com/subscriptions/$($site.Subscription)/resourceGroups/$($site.RGName)/providers/Microsoft.Web/sites/$($site.SiteName)/config/web?api-version=$apiVersion" $webConfig = New-CIPPAzRestRequest -Uri $getUri -Method GET $currentLinuxFx = $webConfig.properties.linuxFxVersion if (-not $currentLinuxFx) { throw 'Could not read current linuxFxVersion — is this a Linux container app?' } - # Replace the tag in the image reference $currentImage = $currentLinuxFx -replace '^DOCKER\|', '' if ($currentImage -match '^(.+):([^:]+)$') { $imageBase = $Matches[1] @@ -117,14 +303,8 @@ function Invoke-ExecContainerManagement { $newLinuxFx = "DOCKER|${currentImage}:${NewChannel}" } - # Update the web config with new image tag - $putUri = $getUri - $putBody = @{ - properties = @{ - linuxFxVersion = $newLinuxFx - } - } - New-CIPPAzRestRequest -Uri $putUri -Method PATCH -Body $putBody -ContentType 'application/json' | Out-Null + $putBody = @{ properties = @{ linuxFxVersion = $newLinuxFx } } + New-CIPPAzRestRequest -Uri $getUri -Method PATCH -Body $putBody -ContentType 'application/json' | Out-Null $Result = "Release channel updated to '$NewChannel'. Image: $newLinuxFx. The container will pull the new image on next restart." Write-LogMessage -API $APIName -headers $Headers -message "Release channel changed to $NewChannel ($newLinuxFx)" -sev Info @@ -142,8 +322,6 @@ function Invoke-ExecContainerManagement { try { Write-LogMessage -API $APIName -headers $Headers -message 'Container restart requested by super admin' -sev Info $Body = @{ Results = 'Container restart initiated. The application will be back online shortly.' } - - # Schedule restart after response is sent try { [Craft.Services.AppLifecycleBridge]::RequestRestart('Restart requested by super admin via container management page') } catch { @@ -161,7 +339,7 @@ function Invoke-ExecContainerManagement { default { return [HttpResponseContext]@{ StatusCode = [HttpStatusCode]::BadRequest - Body = @{ Results = "Unknown action: $Action. Valid actions: Status, UpdateChannel, Restart" } + Body = @{ Results = "Unknown action: $Action. Valid actions: Status, CheckUpdate, SaveUpdateSettings, UpdateChannel, Restart" } } } } From 93c80812f29762f375ed0ea28b03e59f8d956017 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Wed, 13 May 2026 15:52:56 +0800 Subject: [PATCH 17/38] skip replacement if not value set for variable --- .../CIPPCore/Public/Get-CIPPTextReplacement.ps1 | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Modules/CIPPCore/Public/Get-CIPPTextReplacement.ps1 b/Modules/CIPPCore/Public/Get-CIPPTextReplacement.ps1 index 3b2db7623b7e..f96bef07090c 100644 --- a/Modules/CIPPCore/Public/Get-CIPPTextReplacement.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPTextReplacement.ps1 @@ -65,11 +65,12 @@ function Get-CIPPTextReplacement { $Vars = @{} if ($GlobalMap) { foreach ($Var in $GlobalMap) { + if (-not $Var.PSObject.Properties['Value']) { continue } + $Val = $Var.Value if ($EscapeForJson.IsPresent) { - # Escape quotes for JSON if not already escaped - $Var.Value = $Var.Value -replace '(? Date: Wed, 13 May 2026 16:47:18 +0800 Subject: [PATCH 18/38] strip return characters --- Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 b/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 index deb66894da52..db1d5e455da1 100644 --- a/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1 @@ -280,9 +280,11 @@ function New-CIPPAlertTemplate { } if ($Format -eq 'html') { + $AssembledHtml = $HTMLTemplate -f $Title, $IntroText, $ButtonUrl, $ButtonText, $AfterButtonText, $AuditLogLink + $AssembledHtml = $AssembledHtml -replace '\r\n', '' -replace '\n', '' return [pscustomobject]@{ title = $Title - htmlcontent = $HTMLTemplate -f $Title, $IntroText, $ButtonUrl, $ButtonText, $AfterButtonText, $AuditLogLink + htmlcontent = $AssembledHtml } } elseif ($Format -eq 'json') { if ($InputObject -eq 'auditlog') { From d480cf74f7bea7180136c74d1e351b4b93b7d06a Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Wed, 13 May 2026 17:06:47 +0800 Subject: [PATCH 19/38] Add Apps and SP to universal search --- Modules/CIPPCore/Public/Search-CIPPDbData.ps1 | 2 +- .../HTTP Functions/Invoke-ExecUniversalSearchV2.ps1 | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Search-CIPPDbData.ps1 b/Modules/CIPPCore/Public/Search-CIPPDbData.ps1 index cf09305a8dd6..ab03c35f5771 100644 --- a/Modules/CIPPCore/Public/Search-CIPPDbData.ps1 +++ b/Modules/CIPPCore/Public/Search-CIPPDbData.ps1 @@ -69,7 +69,7 @@ function Search-CIPPDbData { 'Groups', 'Roles', 'LicenseOverview', 'IntuneDeviceCompliancePolicies', 'SecureScore', 'SecureScoreControlProfiles', 'Mailboxes', 'CASMailbox', 'MailboxPermissions', 'OneDriveUsage', 'MailboxUsage', 'Devices', 'AllRoles', 'Licenses', 'DeviceCompliancePolicies', - 'BitlockerKeys' + 'BitlockerKeys', 'Apps', 'ServicePrincipals' )] [string[]]$Types, diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Invoke-ExecUniversalSearchV2.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Invoke-ExecUniversalSearchV2.ps1 index 6bcb3befbb49..8c3b9d954fb1 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Invoke-ExecUniversalSearchV2.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Invoke-ExecUniversalSearchV2.ps1 @@ -28,6 +28,9 @@ function Invoke-ExecUniversalSearchV2 { 'Groups' { $Results = Search-CIPPDbData -SearchTerms $SearchTerms -Types 'Groups' -Limit $Limit -Properties 'id', 'displayName', 'mail', 'mailEnabled', 'securityEnabled', 'groupTypes', 'description' -TenantFilter $TenantFilter } + 'Applications' { + $Results = Search-CIPPDbData -SearchTerms $SearchTerms -Types 'Apps', 'ServicePrincipals' -Limit $Limit -Properties 'id', 'appId', 'displayName', 'publisherName', 'appOwnerOrganizationId' -TenantFilter $TenantFilter + } default { $Results = Search-CIPPDbData -SearchTerms $SearchTerms -Types 'Users' -Limit $Limit -Properties 'id', 'userPrincipalName', 'displayName' -TenantFilter $TenantFilter } From 9011dd63e2a4ac6aef393aab54893b791e06caa0 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Wed, 13 May 2026 18:53:59 +0800 Subject: [PATCH 20/38] Nice CA policy editor and template creator/editor --- .../Invoke-ExecCreateCATemplate.ps1 | 54 ++++++++++++++++ .../Invoke-ExecEditCAPolicyFull.ps1 | 64 +++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCreateCATemplate.ps1 create mode 100644 Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecEditCAPolicyFull.ps1 diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCreateCATemplate.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCreateCATemplate.ps1 new file mode 100644 index 000000000000..28d932d2d8aa --- /dev/null +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecCreateCATemplate.ps1 @@ -0,0 +1,54 @@ +function Invoke-ExecCreateCATemplate { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + Tenant.ConditionalAccess.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + + try { + $Body = $Request.Body + $DisplayName = $Body.displayName ?? $Body.name + if ([string]::IsNullOrWhiteSpace($DisplayName)) { + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = 'Error: displayName is required' } + } + } + + $GUID = (New-Guid).GUID + + # Strip any read-only or internal properties before storing + $Template = $Body | Select-Object -Property * -ExcludeProperty GUID, id, createdDateTime, modifiedDateTime, templateId + + $JSON = ConvertTo-Json -InputObject $Template -Depth 100 -Compress + + $Table = Get-CippTable -tablename 'templates' + $Table.Force = $true + Add-CIPPAzDataTableEntity @Table -Entity @{ + JSON = "$JSON" + RowKey = "$GUID" + PartitionKey = 'CATemplate' + GUID = "$GUID" + } + + $Result = "Successfully created CA template '$DisplayName' with GUID $GUID" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Info' + $StatusCode = [HttpStatusCode]::OK + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to create CA template: $($ErrorMessage.NormalizedError)" + Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Error' -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + return [HttpResponseContext]@{ + StatusCode = $StatusCode + Body = @{ Results = $Result } + } +} diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecEditCAPolicyFull.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecEditCAPolicyFull.ps1 new file mode 100644 index 000000000000..40c347946fe2 --- /dev/null +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Tenant/Conditional/Invoke-ExecEditCAPolicyFull.ps1 @@ -0,0 +1,64 @@ +function Invoke-ExecEditCAPolicyFull { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Tenant.ConditionalAccess.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Headers = $Request.Headers + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter + + if ([string]::IsNullOrWhiteSpace($TenantFilter)) { + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = 'Error: tenantFilter is required' } + } + } + + $PolicyId = $Request.Query.PolicyId ?? $Request.Body.PolicyId + if ([string]::IsNullOrWhiteSpace($PolicyId)) { + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = 'Error: PolicyId is required' } + } + } + + try { + $PolicyBody = $Request.Body.PolicyBody + if ($null -eq $PolicyBody) { + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = 'Error: PolicyBody is required' } + } + } + + # Strip read-only properties that cannot be PATCHed + $CleanBody = $PolicyBody | Select-Object -Property * -ExcludeProperty id, createdDateTime, modifiedDateTime, templateId + $RawJSON = ConvertTo-Json -InputObject $CleanBody -Depth 20 -Compress + + $null = New-GraphPOSTRequest ` + -uri "https://graph.microsoft.com/beta/identity/conditionalAccess/policies/$PolicyId" ` + -tenantid $TenantFilter ` + -type PATCH ` + -body $RawJSON ` + -asApp $true + + $DisplayName = $PolicyBody.displayName ?? $PolicyId + $Result = "Successfully updated CA policy '$DisplayName' for $TenantFilter" + Write-LogMessage -API $APIName -tenant $TenantFilter -headers $Headers -message $Result -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + $Result = "Failed to update CA policy $PolicyId for ${TenantFilter}: $($ErrorMessage.NormalizedError)" + Write-LogMessage -API $APIName -tenant $TenantFilter -headers $Headers -message $Result -sev Error -LogData $ErrorMessage + $StatusCode = [HttpStatusCode]::InternalServerError + } + + return [HttpResponseContext]@{ + StatusCode = $StatusCode ?? [HttpStatusCode]::OK + Body = @{ Results = $Result } + } +} From 897dfaa4f07443e0f05f8f2aefa5b0a92fc91a9c Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 13 May 2026 21:18:48 +0200 Subject: [PATCH 21/38] fixed #5997 --- .../Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 index a8d9e29000bf..438a3d34ebd4 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 @@ -161,6 +161,7 @@ function Invoke-CIPPStandardSpamFilterPolicy { $RuleStateIsCorrect = ($RuleState.Name -eq $PolicyName) -and ($RuleState.HostedContentFilterPolicy -eq $PolicyName) -and + ($RuleState.State -eq 'Enabled') -and ($RuleState.Priority -eq 0) -and (!(Compare-Object -ReferenceObject $RuleState.RecipientDomainIs -DifferenceObject $AcceptedDomains.Name)) @@ -255,6 +256,15 @@ function Invoke-CIPPStandardSpamFilterPolicy { } catch { Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Failed to update Spam Filter rule $PolicyName." -sev Error -LogData $_ } + + if ($RuleState.State -eq 'Disabled') { + try { + $null = New-ExoRequest -TenantId $Tenant -cmdlet 'Enable-HostedContentFilterRule' -cmdParams @{ Identity = $PolicyName } -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Enabled Spam Filter rule $PolicyName." -sev Info + } catch { + Write-LogMessage -API 'Standards' -Tenant $Tenant -message "Failed to enable Spam Filter rule $PolicyName." -sev Error -LogData $_ + } + } } else { try { $cmdParams.Add('Name', "$PolicyName") From b1363008db683132524711ec2932afe9a12f0342 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 13 May 2026 21:19:03 +0200 Subject: [PATCH 22/38] #5997 --- .../Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 index 438a3d34ebd4..f01a369d3406 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 @@ -86,7 +86,7 @@ function Invoke-CIPPStandardSpamFilterPolicy { try { $CurrentState = New-ExoRequest -TenantId $Tenant -cmdlet 'Get-HostedContentFilterPolicy' | - Where-Object -Property Name -EQ $PolicyName + Where-Object -Property Name -EQ $PolicyName } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Could not get the SpamFilterPolicy state for $Tenant. Error: $ErrorMessage" -Sev Error @@ -157,7 +157,7 @@ function Invoke-CIPPStandardSpamFilterPolicy { $AcceptedDomains = New-ExoRequest -TenantId $Tenant -cmdlet 'Get-AcceptedDomain' $RuleState = New-ExoRequest -TenantId $Tenant -cmdlet 'Get-HostedContentFilterRule' | - Where-Object -Property Name -EQ $PolicyName + Where-Object -Property Name -EQ $PolicyName $RuleStateIsCorrect = ($RuleState.Name -eq $PolicyName) -and ($RuleState.HostedContentFilterPolicy -eq $PolicyName) -and From e060fa22b10156d59bed43c7b22f965a768379e5 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar <49186168+KelvinTegelaar@users.noreply.github.com> Date: Wed, 13 May 2026 21:47:17 +0200 Subject: [PATCH 23/38] implements #5981 --- Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 | 85 ++++++++++++++++++- .../CIPPCore/Public/New-CIPPCATemplate.ps1 | 24 ++++++ 2 files changed, 108 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 index 01c10ce4a745..bed989dc48dc 100644 --- a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 @@ -167,6 +167,19 @@ function New-CIPPCAPolicy { } } + # Get authentication context class references once if needed + $AllAuthContexts = $null + if ($JSONobj.AuthContextInfo) { + try { + Write-Information 'Fetching authentication context class references...' + $AllAuthContexts = New-GraphGETRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/authenticationContextClassReferences' -tenantid $TenantFilter -asApp $true + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-Information "Error fetching authentication context class references: $($ErrorMessage | ConvertTo-Json -Depth 10 -Compress)" + throw "Failed to fetch authentication context class references: $($ErrorMessage.NormalizedError)" + } + } + # Get service principals once if needed $AllServicePrincipals = $null if (($JSONobj.conditions.applications.includeApplications -and $JSONobj.conditions.applications.includeApplications -notcontains 'All') -or ($JSONobj.conditions.applications.excludeApplications -and $JSONobj.conditions.applications.excludeApplications -notcontains 'All')) { @@ -218,6 +231,75 @@ function New-CIPPCAPolicy { } } + # Handle authentication context class references - create if missing, replace displayNames with IDs + if ($JSONobj.AuthContextInfo) { + $AuthContextLookupTable = foreach ($authContext in $JSONobj.AuthContextInfo) { + if (-not $authContext.displayName) { continue } + $ExistingContext = $AllAuthContexts | Where-Object -Property displayName -EQ $authContext.displayName + if ($ExistingContext) { + Write-LogMessage -Tenant $TenantFilter -Headers $Headers -API $APIName -message "Matched authentication context: $($authContext.displayName)" -Sev 'Info' + [pscustomobject]@{ + id = $ExistingContext.id + displayName = $ExistingContext.displayName + templateId = $authContext.id + } + } else { + # Find the next available ID (c1-c99) + $UsedIds = @($AllAuthContexts.id) + $NewId = $null + for ($i = 1; $i -le 99; $i++) { + $candidateId = "c$i" + if ($candidateId -notin $UsedIds) { + $NewId = $candidateId + break + } + } + if (-not $NewId) { + throw "No available authentication context IDs (c1-c99) in tenant $TenantFilter" + } + $Body = @{ + id = $NewId + displayName = $authContext.displayName + description = if ($authContext.description) { $authContext.description } else { '' } + isAvailable = $true + } | ConvertTo-Json -Compress + try { + $GraphRequest = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/authenticationContextClassReferences' -body $Body -Type POST -tenantid $TenantFilter -asApp $true + Write-LogMessage -Tenant $TenantFilter -Headers $Headers -API $APIName -message "Created new Authentication Context: $($authContext.displayName) with ID $NewId" -Sev 'Info' + # Add to the list so subsequent contexts can see it + $AllAuthContexts = @($AllAuthContexts) + @([pscustomobject]@{ id = $NewId; displayName = $authContext.displayName }) + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-Information "Error creating authentication context: $($ErrorMessage | ConvertTo-Json -Depth 10 -Compress)" + throw "Failed to create authentication context '$($authContext.displayName)': $($ErrorMessage.NormalizedError)" + } + [pscustomobject]@{ + id = $NewId + displayName = $authContext.displayName + templateId = $authContext.id + } + } + } + + Write-Information 'Auth Context Lookup Table:' + Write-Information ($AuthContextLookupTable | ConvertTo-Json -Depth 10) + + # Replace display names with actual IDs in the policy + if ($AuthContextLookupTable -and $JSONobj.conditions.applications.includeAuthenticationContextClassReferences) { + $ResolvedContextIds = [System.Collections.Generic.List[string]]::new() + foreach ($ref in $JSONobj.conditions.applications.includeAuthenticationContextClassReferences) { + $lookup = $AuthContextLookupTable | Where-Object { $_.displayName -eq $ref -or $_.templateId -eq $ref } | Select-Object -First 1 + if ($lookup) { + $ResolvedContextIds.Add($lookup.id) + } else { + # Keep the original value if no match found (might already be an ID) + $ResolvedContextIds.Add($ref) + } + } + $JSONobj.conditions.applications.includeAuthenticationContextClassReferences = @($ResolvedContextIds) + } + } + #for each of the locations, check if they exist, if not create them. These are in $JSONobj.LocationInfo $NewLocationsCreated = $false $LocationLookupTable = foreach ($locations in $JSONobj.LocationInfo) { @@ -386,6 +468,7 @@ function New-CIPPCAPolicy { } } $JSONobj.PSObject.Properties.Remove('LocationInfo') + $JSONobj.PSObject.Properties.Remove('AuthContextInfo') foreach ($condition in $JSONobj.conditions.users.PSObject.Properties.Name) { $value = $JSONobj.conditions.users.$condition if ($null -eq $value) { @@ -451,7 +534,7 @@ function New-CIPPCAPolicy { # Preserve any exclusion groups named "Vacation Exclusion - " from existing policy try { $ExistingVacationGroup = New-GraphGETRequest -uri "https://graph.microsoft.com/beta/groups?`$filter=startsWith(displayName,'Vacation Exclusion')&`$select=id,displayName&`$top=999&`$count=true" -ComplexFilter -tenantid $TenantFilter -asApp $true | - Where-Object { $CheckExisting.conditions.users.excludeGroups -contains $_.id } + Where-Object { $CheckExisting.conditions.users.excludeGroups -contains $_.id } if ($ExistingVacationGroup) { if (-not ($JSONobj.conditions.users.PSObject.Properties.Name -contains 'excludeGroups')) { $JSONobj.conditions.users | Add-Member -NotePropertyName 'excludeGroups' -NotePropertyValue @() -Force diff --git a/Modules/CIPPCore/Public/New-CIPPCATemplate.ps1 b/Modules/CIPPCore/Public/New-CIPPCATemplate.ps1 index 6103d5ad945c..677377cbaee0 100644 --- a/Modules/CIPPCore/Public/New-CIPPCATemplate.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPCATemplate.ps1 @@ -38,6 +38,12 @@ function New-CIPPCATemplate { } } + # Fetch authentication context class references if the policy uses them + $authContexts = $null + if ($JSON.conditions.applications.includeAuthenticationContextClassReferences) { + $authContexts = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/authenticationContextClassReferences' -tenantid $TenantFilter + } + $AllLocations = [system.collections.generic.list[object]]::new() $includelocations = [system.collections.generic.list[object]]::new() @@ -113,6 +119,24 @@ function New-CIPPCATemplate { # Remove duplicates based on displayName to avoid Select-Object -Unique issues with complex objects $UniqueLocations = $AllLocations | Group-Object -Property displayName | ForEach-Object { $_.Group[0] } $JSON | Add-Member -NotePropertyName 'LocationInfo' -NotePropertyValue @($UniqueLocations) -Force + + # Convert authentication context class reference IDs to display names and store full objects + if ($authContexts -and $JSON.conditions.applications.includeAuthenticationContextClassReferences) { + $AllAuthContexts = [System.Collections.Generic.List[object]]::new() + $authContextDisplayNames = [System.Collections.Generic.List[object]]::new() + foreach ($acr in $JSON.conditions.applications.includeAuthenticationContextClassReferences) { + $acrInfo = $authContexts | Where-Object -Property id -EQ $acr | Select-Object id, displayName, description, isAvailable + if ($acrInfo) { + $authContextDisplayNames.Add($acrInfo.displayName) + $AllAuthContexts.Add($acrInfo) + } else { + $authContextDisplayNames.Add($acr) + } + } + $JSON.conditions.applications.includeAuthenticationContextClassReferences = @($authContextDisplayNames) + $JSON | Add-Member -NotePropertyName 'AuthContextInfo' -NotePropertyValue @($AllAuthContexts) -Force + } + $JSON = (ConvertTo-Json -Compress -Depth 100 -InputObject $JSON) return $JSON } From f5f7ae7064404c314d6cd5694ee1260d1e543c0f Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Thu, 14 May 2026 15:09:35 +1000 Subject: [PATCH 24/38] fixes duplicate test calls in some cases --- .../CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 | 14 ++++++++++++-- .../CIPPCore/Public/Invoke-CIPPTestCollection.ps1 | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 b/Modules/CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 index 60fcb1878353..6c2e1ee6f951 100644 --- a/Modules/CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPAzDataTableEntity.ps1 @@ -40,6 +40,7 @@ function Add-CIPPAzDataTableEntity { $MaxRowSize = 500000 - 100 $MaxSize = 30kb $BatchQueue = [System.Collections.Generic.List[object]]::new() + $BatchKeys = [System.Collections.Generic.Dictionary[string,int]]::new() foreach ($SingleEnt in @($Entity)) { try { @@ -90,8 +91,14 @@ function Add-CIPPAzDataTableEntity { $entityBytes = [System.Text.Encoding]::UTF8.GetByteCount($($SingleEnt | ConvertTo-Json -Compress)) if ($entityBytes -lt $MaxSize) { - # Small entity - add to batch queue - $BatchQueue.Add($SingleEnt) + # Small entity - add to batch queue, dedup by PartitionKey+RowKey (last-in wins) + $batchKey = "$($SingleEnt.PartitionKey)|$($SingleEnt.RowKey)" + if ($BatchKeys.ContainsKey($batchKey)) { + $BatchQueue[$BatchKeys[$batchKey]] = $SingleEnt + } else { + $BatchKeys[$batchKey] = $BatchQueue.Count + $BatchQueue.Add($SingleEnt) + } if ($BatchQueue.Count -ge 100) { try { Add-AzDataTableEntity @Parameters -Entity $BatchQueue.ToArray() -ErrorAction Stop @@ -103,6 +110,7 @@ function Add-CIPPAzDataTableEntity { } } $BatchQueue.Clear() + $BatchKeys.Clear() } continue } @@ -118,6 +126,7 @@ function Add-CIPPAzDataTableEntity { } } $BatchQueue.Clear() + $BatchKeys.Clear() } Add-AzDataTableEntity @Parameters -Entity $SingleEnt -ErrorAction Stop @@ -284,5 +293,6 @@ function Add-CIPPAzDataTableEntity { } } $BatchQueue.Clear() + $BatchKeys.Clear() } } diff --git a/Modules/CIPPCore/Public/Invoke-CIPPTestCollection.ps1 b/Modules/CIPPCore/Public/Invoke-CIPPTestCollection.ps1 index 48514b19b36e..3c9ca9619568 100644 --- a/Modules/CIPPCore/Public/Invoke-CIPPTestCollection.ps1 +++ b/Modules/CIPPCore/Public/Invoke-CIPPTestCollection.ps1 @@ -146,7 +146,7 @@ function Invoke-CIPPTestCollection { # Standard suites: discover functions by name pattern via Get-Command $Pattern = $SuitePatterns[$SuiteName] - $TestFunctions = @(Get-Command -Name $Pattern -ErrorAction SilentlyContinue) + $TestFunctions = @(Get-Command -Name $Pattern -Module CIPPTests -ErrorAction SilentlyContinue) if ($TestFunctions.Count -eq 0) { Write-Information "No test functions found for suite $SuiteName (pattern: $Pattern) — skipping" return @{ From b4a5215251751201733eb04fda5a464e462b88d8 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Thu, 14 May 2026 15:37:16 +1000 Subject: [PATCH 25/38] Fix tenant group scope cache --- Config/FeatureFlags.json | 6 +- .../Public/TenantGroups/Get-TenantGroups.ps1 | 32 ++-- .../Settings/Invoke-ListContainerLogs.ps1 | 147 ++++++++++++++++++ 3 files changed, 167 insertions(+), 18 deletions(-) create mode 100644 Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListContainerLogs.ps1 diff --git a/Config/FeatureFlags.json b/Config/FeatureFlags.json index 0f0d74065933..618c8c242094 100644 --- a/Config/FeatureFlags.json +++ b/Config/FeatureFlags.json @@ -33,12 +33,14 @@ "ExecCIPPUsers", "ListCIPPUsers", "ExecSSOSetup", - "ExecContainerManagement" + "ExecContainerManagement", + "ListContainerLogs" ], "Pages": [ "/cipp/advanced/super-admin/cipp-users", "/cipp/advanced/super-admin/sso", - "/cipp/advanced/super-admin/container" + "/cipp/advanced/super-admin/container", + "/cipp/advanced/container-logs" ], "Hidden": true } diff --git a/Modules/CIPPCore/Public/TenantGroups/Get-TenantGroups.ps1 b/Modules/CIPPCore/Public/TenantGroups/Get-TenantGroups.ps1 index 424891f4d555..96f70c91f1db 100644 --- a/Modules/CIPPCore/Public/TenantGroups/Get-TenantGroups.ps1 +++ b/Modules/CIPPCore/Public/TenantGroups/Get-TenantGroups.ps1 @@ -1,19 +1,3 @@ -if (-not $script:TenantGroupsCache) { - $script:TenantGroupsCache = @{ - Groups = $null - Members = $null - LastRefresh = $null - MembersByGroup = $null # Dictionary: GroupId -> members array - } -} - -# Result cache: keyed by "GroupId|TenantFilter|Dynamic" -if (-not $script:TenantGroupsResultCache) { - $script:TenantGroupsResultCache = @{} -} - -$script:TenantGroupsCacheTTL = (New-TimeSpan -Minutes 5) - function Get-TenantGroups { <# .SYNOPSIS @@ -35,6 +19,22 @@ function Get-TenantGroups { [switch]$Dynamic, [switch]$SkipCache ) + + if (-not $script:TenantGroupsCache) { + $script:TenantGroupsCache = @{ + Groups = $null + Members = $null + LastRefresh = $null + MembersByGroup = $null + } + } + if (-not $script:TenantGroupsResultCache) { + $script:TenantGroupsResultCache = @{} + } + if (-not $script:TenantGroupsCacheTTL) { + $script:TenantGroupsCacheTTL = (New-TimeSpan -Minutes 5) + } + $CacheKey = "$GroupId|$TenantFilter|$($Dynamic.IsPresent)" if ($SkipCache) { diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListContainerLogs.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListContainerLogs.ps1 new file mode 100644 index 000000000000..86214b70074b --- /dev/null +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListContainerLogs.ps1 @@ -0,0 +1,147 @@ +function Invoke-ListContainerLogs { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.SuperAdmin.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Action = $Request.Query.Action ?? 'ReadLog' + + try { + switch ($Action) { + 'ListFiles' { + $Results = [Craft.Services.LogBridge]::GetLogFiles() + $Body = @{ Results = @($Results) } + } + 'ReadLog' { + $Tail = [int]($Request.Query.Tail ?? '500') + $Level = $Request.Query.Level + $Search = $Request.Query.Search + $File = $Request.Query.File + + # Date range parsing + $From = $null + $To = $null + if ($Request.Query.From) { + $From = [DateTime]::Parse($Request.Query.From).ToUniversalTime() + } + if ($Request.Query.To) { + $To = [DateTime]::Parse($Request.Query.To).ToUniversalTime() + } + + # Resolve nullable params + $LevelParam = if ([string]::IsNullOrEmpty($Level)) { $null } else { $Level } + $SearchParam = if ([string]::IsNullOrEmpty($Search)) { $null } else { $Search } + $FileParam = if ([string]::IsNullOrEmpty($File)) { $null } else { $File } + + $Lines = [Craft.Services.LogBridge]::ReadLog($Tail, $LevelParam, $SearchParam, $FileParam, $From, $To) + + # Parse log lines into structured objects for the table + $Results = foreach ($Line in $Lines) { + if ([string]::IsNullOrWhiteSpace($Line)) { continue } + # Continuation lines (exception details) — skip, they were attached to previous + if ($Line.Length -gt 0 -and [char]::IsWhiteSpace($Line[0])) { continue } + + # Parse: "2026-05-13 10:30:00.000 [INF] message text" + if ($Line -match '^\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d{3})\s+\[(\w+)\]\s+(.*)$') { + [PSCustomObject]@{ + Timestamp = "$($Matches[1].Replace(' ', 'T'))Z" + Level = $Matches[2] + Message = $Matches[3] + Raw = $Line + } + } elseif ($Line -match '^\s*(\d{2}:\d{2}:\d{2}\.\d{3})\s+\[(\w+)\]\s+(.*)$') { + # Legacy time-only format + [PSCustomObject]@{ + Timestamp = "$($Matches[1])Z" + Level = $Matches[2] + Message = $Matches[3] + Raw = $Line + } + } else { + [PSCustomObject]@{ + Timestamp = '' + Level = '' + Message = $Line + Raw = $Line + } + } + } + $Body = @{ Results = @($Results) } + } + 'SearchAll' { + $Search = $Request.Query.Search + $Level = $Request.Query.Level + $Tail = [int]($Request.Query.Tail ?? '500') + + $From = $null + $To = $null + if ($Request.Query.From) { + $From = [DateTime]::Parse($Request.Query.From).ToUniversalTime() + } + if ($Request.Query.To) { + $To = [DateTime]::Parse($Request.Query.To).ToUniversalTime() + } + + $SearchParam = if ([string]::IsNullOrEmpty($Search)) { $null } else { $Search } + $LevelParam = if ([string]::IsNullOrEmpty($Level)) { $null } else { $Level } + + $Lines = [Craft.Services.LogBridge]::SearchAllFiles($SearchParam, $LevelParam, $From, $To, $Tail) + + $Results = foreach ($Line in $Lines) { + if ([string]::IsNullOrWhiteSpace($Line)) { continue } + if ($Line.Length -gt 0 -and [char]::IsWhiteSpace($Line[0])) { continue } + + if ($Line -match '^\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d{3})\s+\[(\w+)\]\s+(.*)$') { + [PSCustomObject]@{ + Timestamp = "$($Matches[1].Replace(' ', 'T'))Z" + Level = $Matches[2] + Message = $Matches[3] + Raw = $Line + } + } else { + [PSCustomObject]@{ + Timestamp = '' + Level = '' + Message = $Line + Raw = $Line + } + } + } + $Body = @{ Results = @($Results) } + } + 'GetInfo' { + $Body = @{ + Results = @{ + CurrentFile = [Craft.Services.LogBridge]::GetCurrentLogPath() + LogDirectory = [Craft.Services.LogBridge]::GetLogDirectory() + Files = @([Craft.Services.LogBridge]::GetLogFiles()) + } + } + } + default { + $Body = @{ Results = "Unknown action: $Action" } + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = $Body + } + } + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -message "Container logs error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::InternalServerError + Body = @{ Results = "Failed: $($ErrorMessage.NormalizedError)" } + } + } + + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + } +} From dbd7fcb3486342ae02f5cc914343052a7bdec645 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Thu, 14 May 2026 18:09:21 +1000 Subject: [PATCH 26/38] logging improvements --- .../Settings/Invoke-ListContainerLogs.ps1 | 287 ++++++++++++++---- 1 file changed, 220 insertions(+), 67 deletions(-) diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListContainerLogs.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListContainerLogs.ps1 index 86214b70074b..a98c001c05b8 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListContainerLogs.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListContainerLogs.ps1 @@ -11,6 +11,182 @@ function Invoke-ListContainerLogs { $APIName = $Request.Params.CIPPEndpoint $Action = $Request.Query.Action ?? 'ReadLog' + # ── Helper: parse raw log lines into structured objects ── + function ConvertTo-LogEntry { + param([string[]]$Lines) + foreach ($Line in $Lines) { + if ([string]::IsNullOrWhiteSpace($Line)) { continue } + if ($Line.Length -gt 0 -and [char]::IsWhiteSpace($Line[0])) { continue } + # ISO 8601: "2026-05-13T10:30:00.000Z [INF] message" + if ($Line -match '^\s*(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\s+\[(\w+)\]\s+(.*)$') { + [PSCustomObject]@{ + Timestamp = $Matches[1] + Level = $Matches[2] + Message = $Matches[3] + Raw = $Line + } + # Legacy: "2026-05-13 10:30:00.000 [INF] message" + } elseif ($Line -match '^\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d{3})\s+\[(\w+)\]\s+(.*)$') { + [PSCustomObject]@{ + Timestamp = "$($Matches[1].Replace(' ', 'T'))Z" + Level = $Matches[2] + Message = $Matches[3] + Raw = $Line + } + } else { + [PSCustomObject]@{ + Timestamp = '' + Level = '' + Message = $Line + Raw = $Line + } + } + } + } + + # ── Helper: parse a KQL-subset query into LogBridge parameters ── + # Supported syntax: + # where Level == "ERR" + # where Level in ("ERR", "CRT", "WRN") + # where Message contains "timeout" + # where Message !contains "heartbeat" + # where Message matches regex "error|fail" + # where Timestamp > ago(1h) + # where Timestamp > ago(30m) + # where Timestamp > ago(2d) + # where Timestamp between (ago(2h) .. ago(1h)) + # where Timestamp > datetime(2026-05-14 10:00) + # take 500 + # sort by Timestamp desc + # sort by Timestamp asc + function ConvertFrom-LogQuery { + param([string]$Query) + + $params = @{ + Tail = 500 + Level = $null + Search = $null + Exclude = $null + RegexPattern = $null + From = $null + To = $null + File = $null + SearchAll = $false + SortNewest = $true + } + + # Split on pipe, trim each clause + $clauses = $Query -split '\|' | ForEach-Object { $_.Trim() } | Where-Object { $_ } + + foreach ($clause in $clauses) { + # take N + if ($clause -match '^\s*take\s+(\d+)\s*$') { + $params.Tail = [int]$Matches[1] + continue + } + + # sort by Timestamp asc/desc + if ($clause -match '^\s*sort\s+by\s+\w+\s+(asc|desc)\s*$') { + $params.SortNewest = ($Matches[1] -eq 'desc') + continue + } + + # search all files + if ($clause -match '^\s*search\s+all(\s+files)?\s*$') { + $params.SearchAll = $true + continue + } + + # where clauses + if ($clause -match '^\s*where\s+(.+)$') { + $condition = $Matches[1].Trim() + + # Level == "X" + if ($condition -match '^Level\s*==\s*"(\w+)"\s*$') { + $params.Level = $Matches[1] + } + # Level in ("X", "Y", ...) + elseif ($condition -match '^Level\s+in\s*\(\s*(.+)\s*\)\s*$') { + $items = $Matches[1] -split ',' | ForEach-Object { $_.Trim().Trim('"', "'", ' ') } | Where-Object { $_ } + $params.Level = $items -join ',' + } + # Level != "X" + elseif ($condition -match '^Level\s*!=\s*"(\w+)"\s*$') { + # Exclude this level by including all others + $allLevels = @('TRC', 'DBG', 'INF', 'WRN', 'ERR', 'CRT') + $excluded = $Matches[1].ToUpper() + $params.Level = ($allLevels | Where-Object { $_ -ne $excluded }) -join ',' + } + # Message contains "text" + elseif ($condition -match '^Message\s+contains\s+"(.+)"\s*$') { + $params.Search = $Matches[1] + } + # Message !contains "text" + elseif ($condition -match '^Message\s+!contains\s+"(.+)"\s*$') { + $params.Exclude = $Matches[1] + } + # Message matches regex "pattern" + elseif ($condition -match '^Message\s+matches\s+regex\s+"(.+)"\s*$') { + $params.RegexPattern = $Matches[1] + } + # Timestamp > ago(Xh/m/d/s) + elseif ($condition -match '^Timestamp\s*>\s*ago\((\d+)([smhdw])\)\s*$') { + $amount = [int]$Matches[1] + $unit = $Matches[2] + $params.From = switch ($unit) { + 's' { [DateTime]::UtcNow.AddSeconds(-$amount) } + 'm' { [DateTime]::UtcNow.AddMinutes(-$amount) } + 'h' { [DateTime]::UtcNow.AddHours(-$amount) } + 'd' { [DateTime]::UtcNow.AddDays(-$amount) } + 'w' { [DateTime]::UtcNow.AddDays(-$amount * 7) } + } + } + # Timestamp between (ago(Xh) .. ago(Yh)) + elseif ($condition -match '^Timestamp\s+between\s*\(\s*ago\((\d+)([smhdw])\)\s*\.\.\s*ago\((\d+)([smhdw])\)\s*\)\s*$') { + $fromAmount = [int]$Matches[1]; $fromUnit = $Matches[2] + $toAmount = [int]$Matches[3]; $toUnit = $Matches[4] + $params.From = switch ($fromUnit) { + 's' { [DateTime]::UtcNow.AddSeconds(-$fromAmount) } + 'm' { [DateTime]::UtcNow.AddMinutes(-$fromAmount) } + 'h' { [DateTime]::UtcNow.AddHours(-$fromAmount) } + 'd' { [DateTime]::UtcNow.AddDays(-$fromAmount) } + 'w' { [DateTime]::UtcNow.AddDays(-$fromAmount * 7) } + } + $params.To = switch ($toUnit) { + 's' { [DateTime]::UtcNow.AddSeconds(-$toAmount) } + 'm' { [DateTime]::UtcNow.AddMinutes(-$toAmount) } + 'h' { [DateTime]::UtcNow.AddHours(-$toAmount) } + 'd' { [DateTime]::UtcNow.AddDays(-$toAmount) } + 'w' { [DateTime]::UtcNow.AddDays(-$toAmount * 7) } + } + } + # Timestamp between (ago(Xh) .. now()) + elseif ($condition -match '^Timestamp\s+between\s*\(\s*ago\((\d+)([smhdw])\)\s*\.\.\s*now\(\)\s*\)\s*$') { + $amount = [int]$Matches[1]; $unit = $Matches[2] + $params.From = switch ($unit) { + 's' { [DateTime]::UtcNow.AddSeconds(-$amount) } + 'm' { [DateTime]::UtcNow.AddMinutes(-$amount) } + 'h' { [DateTime]::UtcNow.AddHours(-$amount) } + 'd' { [DateTime]::UtcNow.AddDays(-$amount) } + 'w' { [DateTime]::UtcNow.AddDays(-$amount * 7) } + } + } + # Timestamp > datetime(2026-05-14) or datetime(2026-05-14 10:00) + elseif ($condition -match '^Timestamp\s*>\s*datetime\((.+)\)\s*$') { + $params.From = [DateTime]::Parse($Matches[1]).ToUniversalTime() + } + # Timestamp < datetime(...) + elseif ($condition -match '^Timestamp\s*<\s*datetime\((.+)\)\s*$') { + $params.To = [DateTime]::Parse($Matches[1]).ToUniversalTime() + } + # Unrecognized where clause — ignore + } + # Unrecognized clause — ignore + } + + return $params + } + try { switch ($Action) { 'ListFiles' { @@ -22,96 +198,73 @@ function Invoke-ListContainerLogs { $Level = $Request.Query.Level $Search = $Request.Query.Search $File = $Request.Query.File + $Exclude = $Request.Query.Exclude + $Regex = $Request.Query.Regex + $SortDesc = $Request.Query.SortDesc - # Date range parsing $From = $null $To = $null - if ($Request.Query.From) { - $From = [DateTime]::Parse($Request.Query.From).ToUniversalTime() - } - if ($Request.Query.To) { - $To = [DateTime]::Parse($Request.Query.To).ToUniversalTime() - } + if ($Request.Query.From) { $From = [DateTime]::Parse($Request.Query.From).ToUniversalTime() } + if ($Request.Query.To) { $To = [DateTime]::Parse($Request.Query.To).ToUniversalTime() } - # Resolve nullable params $LevelParam = if ([string]::IsNullOrEmpty($Level)) { $null } else { $Level } $SearchParam = if ([string]::IsNullOrEmpty($Search)) { $null } else { $Search } $FileParam = if ([string]::IsNullOrEmpty($File)) { $null } else { $File } + $ExcludeParam = if ([string]::IsNullOrEmpty($Exclude)) { $null } else { $Exclude } + $RegexParam = if ([string]::IsNullOrEmpty($Regex)) { $null } else { $Regex } + $SortNewest = $SortDesc -eq 'true' - $Lines = [Craft.Services.LogBridge]::ReadLog($Tail, $LevelParam, $SearchParam, $FileParam, $From, $To) - - # Parse log lines into structured objects for the table - $Results = foreach ($Line in $Lines) { - if ([string]::IsNullOrWhiteSpace($Line)) { continue } - # Continuation lines (exception details) — skip, they were attached to previous - if ($Line.Length -gt 0 -and [char]::IsWhiteSpace($Line[0])) { continue } - - # Parse: "2026-05-13 10:30:00.000 [INF] message text" - if ($Line -match '^\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d{3})\s+\[(\w+)\]\s+(.*)$') { - [PSCustomObject]@{ - Timestamp = "$($Matches[1].Replace(' ', 'T'))Z" - Level = $Matches[2] - Message = $Matches[3] - Raw = $Line - } - } elseif ($Line -match '^\s*(\d{2}:\d{2}:\d{2}\.\d{3})\s+\[(\w+)\]\s+(.*)$') { - # Legacy time-only format - [PSCustomObject]@{ - Timestamp = "$($Matches[1])Z" - Level = $Matches[2] - Message = $Matches[3] - Raw = $Line - } - } else { - [PSCustomObject]@{ - Timestamp = '' - Level = '' - Message = $Line - Raw = $Line - } - } - } + $Lines = [Craft.Services.LogBridge]::ReadLog($Tail, $LevelParam, $SearchParam, $FileParam, $From, $To, $ExcludeParam, $RegexParam, $SortNewest) + $Results = ConvertTo-LogEntry -Lines $Lines $Body = @{ Results = @($Results) } } 'SearchAll' { $Search = $Request.Query.Search $Level = $Request.Query.Level $Tail = [int]($Request.Query.Tail ?? '500') + $Exclude = $Request.Query.Exclude + $Regex = $Request.Query.Regex + $SortDesc = $Request.Query.SortDesc $From = $null $To = $null - if ($Request.Query.From) { - $From = [DateTime]::Parse($Request.Query.From).ToUniversalTime() - } - if ($Request.Query.To) { - $To = [DateTime]::Parse($Request.Query.To).ToUniversalTime() - } + if ($Request.Query.From) { $From = [DateTime]::Parse($Request.Query.From).ToUniversalTime() } + if ($Request.Query.To) { $To = [DateTime]::Parse($Request.Query.To).ToUniversalTime() } $SearchParam = if ([string]::IsNullOrEmpty($Search)) { $null } else { $Search } $LevelParam = if ([string]::IsNullOrEmpty($Level)) { $null } else { $Level } + $ExcludeParam = if ([string]::IsNullOrEmpty($Exclude)) { $null } else { $Exclude } + $RegexParam = if ([string]::IsNullOrEmpty($Regex)) { $null } else { $Regex } + $SortNewest = $SortDesc -eq 'true' - $Lines = [Craft.Services.LogBridge]::SearchAllFiles($SearchParam, $LevelParam, $From, $To, $Tail) - - $Results = foreach ($Line in $Lines) { - if ([string]::IsNullOrWhiteSpace($Line)) { continue } - if ($Line.Length -gt 0 -and [char]::IsWhiteSpace($Line[0])) { continue } - - if ($Line -match '^\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d{3})\s+\[(\w+)\]\s+(.*)$') { - [PSCustomObject]@{ - Timestamp = "$($Matches[1].Replace(' ', 'T'))Z" - Level = $Matches[2] - Message = $Matches[3] - Raw = $Line - } - } else { - [PSCustomObject]@{ - Timestamp = '' - Level = '' - Message = $Line - Raw = $Line - } + $Lines = [Craft.Services.LogBridge]::SearchAllFiles($SearchParam, $LevelParam, $From, $To, $Tail, $ExcludeParam, $RegexParam, $SortNewest) + $Results = ConvertTo-LogEntry -Lines $Lines + $Body = @{ Results = @($Results) } + } + 'Query' { + $Query = $Request.Query.Query ?? $Request.Body.Query + if ([string]::IsNullOrWhiteSpace($Query)) { + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = 'Query parameter is required' } } } + + $p = ConvertFrom-LogQuery -Query $Query + + $LevelParam = if ([string]::IsNullOrEmpty($p.Level)) { $null } else { $p.Level } + $SearchParam = if ([string]::IsNullOrEmpty($p.Search)) { $null } else { $p.Search } + $ExcludeParam = if ([string]::IsNullOrEmpty($p.Exclude)) { $null } else { $p.Exclude } + $RegexParam = if ([string]::IsNullOrEmpty($p.RegexPattern)) { $null } else { $p.RegexPattern } + $FileParam = if ([string]::IsNullOrEmpty($p.File)) { $null } else { $p.File } + + if ($p.SearchAll) { + $Lines = [Craft.Services.LogBridge]::SearchAllFiles($SearchParam, $LevelParam, $p.From, $p.To, $p.Tail, $ExcludeParam, $RegexParam, $p.SortNewest) + } else { + $Lines = [Craft.Services.LogBridge]::ReadLog($p.Tail, $LevelParam, $SearchParam, $FileParam, $p.From, $p.To, $ExcludeParam, $RegexParam, $p.SortNewest) + } + + $Results = ConvertTo-LogEntry -Lines $Lines $Body = @{ Results = @($Results) } } 'GetInfo' { From bc7de0c1a41134baa87c8d45ee2f13fb8d96b979 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Thu, 14 May 2026 18:09:59 +1000 Subject: [PATCH 27/38] when running a standard manually still process all standards for precedence overrides --- .../Public/Standards/Get-CIPPStandards.ps1 | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 index 71c231d4360c..f94b227967a0 100644 --- a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 +++ b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 @@ -22,6 +22,9 @@ function Get-CIPPStandards { # 1. Get all JSON-based templates from the "templates" table $Table = Get-CippTable -tablename 'templates' $Filter = "PartitionKey eq 'StandardsTemplateV2'" + # Always load ALL templates so the three-tier merge (AllTenants → Group → Tenant-Specific) + # can compute correct precedence. The $TemplateId filter is applied after merge so that + # manual runs of a single template don't bypass tenant-specific overrides. $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter | Sort-Object TimeStamp).JSON | ForEach-Object { try { @@ -31,7 +34,7 @@ function Get-CIPPStandards { } catch {} } | Where-Object { - $_.GUID -like $TemplateId -and $_.runManually -eq $runManually + $_.runManually -eq $runManually } # 1.5. Expand templates that contain TemplateList-Tags into multiple standards @@ -128,7 +131,7 @@ function Get-CIPPStandards { # 3. If -ListAllTenants, build standards for "AllTenants" only if ($ListAllTenants.IsPresent) { $AllTenantsTemplates = $Templates | Where-Object { - $_.tenantFilter.value -contains 'AllTenants' + $_.tenantFilter.value -contains 'AllTenants' -and $_.GUID -like $TemplateId } foreach ($Template in $AllTenantsTemplates) { @@ -505,6 +508,15 @@ function Get-CIPPStandards { $StandardName = $Key -replace '\|.*$', '' # Preserve TemplateId before removing $PreservedTemplateId = $Standard.TemplateId + + # When a specific TemplateId was requested, only emit standards that + # this template actually won after the three-tier merge. This prevents + # a group template manual run from executing standards that a + # tenant-specific template has overridden. + if ($TemplateId -ne '*' -and $PreservedTemplateId -notlike $TemplateId) { + continue + } + $Standard.PSObject.Properties.Remove('TemplateId') | Out-Null $Normalized = ConvertTo-CippStandardObject $Standard From 7ae35c2bd5c8f11169722651e69c18224dc8fde8 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Fri, 15 May 2026 02:28:44 -0500 Subject: [PATCH 28/38] post exec tweaks for dedupe queue names --- Config/FeatureFlags.json | 6 +- .../Push-CIPPDBCacheApplyBatch.ps1 | 3 +- .../Tests/Push-CIPPTestsApplyBatch.ps1 | 3 +- .../Start-CIPPDBTestsRun.ps1 | 6 +- .../CIPP/Settings/Invoke-ListWorkerHealth.ps1 | 110 ++++++++++++++++++ .../HTTP Functions/Invoke-ExecTestRun.ps1 | 3 +- 6 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListWorkerHealth.ps1 diff --git a/Config/FeatureFlags.json b/Config/FeatureFlags.json index 618c8c242094..35c51a44e865 100644 --- a/Config/FeatureFlags.json +++ b/Config/FeatureFlags.json @@ -34,13 +34,15 @@ "ListCIPPUsers", "ExecSSOSetup", "ExecContainerManagement", - "ListContainerLogs" + "ListContainerLogs", + "ListWorkerHealth" ], "Pages": [ "/cipp/advanced/super-admin/cipp-users", "/cipp/advanced/super-admin/sso", "/cipp/advanced/super-admin/container", - "/cipp/advanced/container-logs" + "/cipp/advanced/container-logs", + "/cipp/advanced/worker-health" ], "Hidden": true } diff --git a/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-CIPPDBCacheApplyBatch.ps1 b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-CIPPDBCacheApplyBatch.ps1 index 52b60b72436a..5a277a22d886 100644 --- a/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-CIPPDBCacheApplyBatch.ps1 +++ b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-CIPPDBCacheApplyBatch.ps1 @@ -35,8 +35,9 @@ function Push-CIPPDBCacheApplyBatch { Write-Information "Aggregated $($AllTasks.Count) cache tasks from all tenants" # Start a single flat orchestrator to execute all cache tasks + $TenantSuffix = if ($Item.Parameters.TenantFilter) { "_$($Item.Parameters.TenantFilter)" } else { '' } $InputObject = [PSCustomObject]@{ - OrchestratorName = 'CIPPDBCacheExecute' + OrchestratorName = "CIPPDBCacheExecute$TenantSuffix" Batch = @($AllTasks) SkipLog = $true } diff --git a/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Tests/Push-CIPPTestsApplyBatch.ps1 b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Tests/Push-CIPPTestsApplyBatch.ps1 index aa12830a0a06..41236b25c316 100644 --- a/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Tests/Push-CIPPTestsApplyBatch.ps1 +++ b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Tests/Push-CIPPTestsApplyBatch.ps1 @@ -35,8 +35,9 @@ function Push-CIPPTestsApplyBatch { Write-Information "Aggregated $($AllTasks.Count) test tasks from all tenants" # Start a single flat orchestrator to execute all test tasks + $TenantSuffix = if ($Item.Parameters.TenantFilter) { "_$($Item.Parameters.TenantFilter)" } else { '' } $InputObject = [PSCustomObject]@{ - OrchestratorName = 'CIPPTestsExecute' + OrchestratorName = "CIPPTestsExecute$TenantSuffix" Batch = @($AllTasks) SkipLog = $true } diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-CIPPDBTestsRun.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-CIPPDBTestsRun.ps1 index abf3057fb386..f310233164ba 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-CIPPDBTestsRun.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-CIPPDBTestsRun.ps1 @@ -69,12 +69,16 @@ function Start-CIPPDBTestsRun { Write-Information "Built batch of $($Batch.Count) tenant test list activities" # Phase 2 via PostExecution: Aggregate all task lists and start flat execution orchestrator + $NameSuffix = if ($TenantFilter -ne 'allTenants') { "-$TenantFilter" } else { '' } $InputObject = [PSCustomObject]@{ - OrchestratorName = 'TestsList' + OrchestratorName = "TestsList$NameSuffix" Batch = @($Batch) SkipLog = $true PostExecution = @{ FunctionName = 'CIPPTestsApplyBatch' + Parameters = @{ + TenantFilter = $TenantFilter + } } } diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListWorkerHealth.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListWorkerHealth.ps1 new file mode 100644 index 000000000000..66862547597b --- /dev/null +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListWorkerHealth.ps1 @@ -0,0 +1,110 @@ +function Invoke-ListWorkerHealth { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.SuperAdmin.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + $Action = $Request.Query.Action ?? 'Snapshot' + + try { + switch ($Action) { + 'Snapshot' { + $Snapshot = [Craft.Services.WorkerMetricsBridge]::GetSnapshot() + $Body = @{ Results = $Snapshot } + } + 'Summary' { + $Summary = [Craft.Services.WorkerMetricsBridge]::GetSummary() + $Body = @{ Results = $Summary } + } + 'Pool' { + $PoolType = $Request.Query.PoolType ?? 'http' + $Pool = [Craft.Services.WorkerMetricsBridge]::GetPoolMetrics($PoolType) + $Body = @{ Results = $Pool } + } + 'Jobs' { + $RunName = $Request.Query.RunName + $Status = $Request.Query.Status + $Limit = if ($Request.Query.Limit) { [int]$Request.Query.Limit } else { 100 } + $Jobs = [Craft.Services.WorkerMetricsBridge]::GetJobDetails($RunName, $Status, $Limit) + $Body = @{ Results = $Jobs } + } + 'Runs' { + $Runs = [Craft.Services.WorkerMetricsBridge]::GetRunSummaries() + $Body = @{ Results = $Runs } + } + 'CancelJob' { + $JobId = $Request.Query.JobId ?? $Request.Body.JobId + if (-not $JobId) { + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = 'JobId is required' } + } + } + $Result = [Craft.Services.WorkerMetricsBridge]::CancelJob($JobId) + $Body = @{ Results = @{ Success = $Result; JobId = $JobId } } + } + 'CancelRun' { + $RunName = $Request.Query.RunName ?? $Request.Body.RunName + if (-not $RunName) { + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = 'RunName is required' } + } + } + $Cancelled = [Craft.Services.WorkerMetricsBridge]::CancelRun($RunName) + $Body = @{ Results = @{ Success = $true; RunName = $RunName; CancelledCount = $Cancelled } } + } + 'DeleteJob' { + $JobId = $Request.Query.JobId ?? $Request.Body.JobId + if (-not $JobId) { + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = 'JobId is required' } + } + } + $Result = [Craft.Services.WorkerMetricsBridge]::DeleteJob($JobId) + $Body = @{ Results = @{ Success = $Result; JobId = $JobId } } + } + 'PurgeCompleted' { + $Purged = [Craft.Services.WorkerMetricsBridge]::PurgeCompleted() + $Body = @{ Results = @{ Success = $true; PurgedCount = $Purged } } + } + 'ChangePriority' { + $JobId = $Request.Query.JobId ?? $Request.Body.JobId + $NewPriority = $Request.Query.Priority ?? $Request.Body.Priority + if (-not $JobId -or $null -eq $NewPriority) { + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = 'JobId and Priority are required' } + } + } + $Result = [Craft.Services.WorkerMetricsBridge]::ChangePriority($JobId, [int]$NewPriority) + $Body = @{ Results = @{ Success = $Result; JobId = $JobId; NewPriority = [int]$NewPriority } } + } + default { + $Body = @{ Results = "Unknown action: $Action" } + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = $Body + } + } + } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API $APIName -message "Worker health error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::InternalServerError + Body = @{ Results = "Failed: $($ErrorMessage.NormalizedError)" } + } + } + + return [HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + } +} diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Invoke-ExecTestRun.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Invoke-ExecTestRun.ps1 index bd7fe721f34e..47eac1c03f7d 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Invoke-ExecTestRun.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Invoke-ExecTestRun.ps1 @@ -17,12 +17,11 @@ function Invoke-ExecTestRun { @{ FunctionName = 'CIPPDBCacheData' TenantFilter = $TenantFilter - QueueId = $Queue.RowKey QueueName = "Cache - $TenantFilter" } ) $InputObject = [PSCustomObject]@{ - OrchestratorName = 'TestDataCollectionAndRun' + OrchestratorName = "TestDataCollectionAndRun-$TenantFilter" Batch = $Batch SkipLog = $false PostExecution = @{ From 90b6457d590ea6f6b96c62e8e0315ccd1f56f640 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Mon, 18 May 2026 07:16:57 -0400 Subject: [PATCH 29/38] Add AutoExpandingArchiveScope property showing org-level vs mailbox-level enablement --- .../Users/Invoke-ListUserMailboxDetails.ps1 | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 index 2cc8b8d3978e..01d95a67a2d5 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListUserMailboxDetails.ps1 @@ -83,11 +83,16 @@ function Invoke-ListUserMailboxDetails { $ArchiveEnabled = $false } - # Get organization config of auto-expanding archive if it's disabled on user level - if (-not $MailboxDetailedRequest.AutoExpandingArchiveEnabled -and $ArchiveEnabled) { - $AutoExpandingArchiveEnabled = $OrgConfig.AutoExpandingArchiveEnabled + # Check org-level first; if enabled org-wide, report that. Otherwise use mailbox-specific value. + if ($OrgConfig.AutoExpandingArchiveEnabled) { + $AutoExpandingArchiveEnabled = $true + $AutoExpandingArchiveScope = 'Organization' + } elseif ($MailboxDetailedRequest.AutoExpandingArchiveEnabled) { + $AutoExpandingArchiveEnabled = $true + $AutoExpandingArchiveScope = 'Mailbox' } else { - $AutoExpandingArchiveEnabled = $MailboxDetailedRequest.AutoExpandingArchiveEnabled + $AutoExpandingArchiveEnabled = $false + $AutoExpandingArchiveScope = 'None' } } catch { $ArchiveEnabled = $false @@ -260,6 +265,7 @@ function Invoke-ListUserMailboxDetails { BlockedForSpam = $BlockedForSpam ArchiveMailBox = $ArchiveEnabled AutoExpandingArchive = $AutoExpandingArchiveEnabled + AutoExpandingArchiveScope = $AutoExpandingArchiveScope RecipientTypeDetails = $MailboxDetailedRequest.RecipientTypeDetails Mailbox = $MailboxDetailedRequest RetentionPolicy = $MailboxDetailedRequest.RetentionPolicy From ab83a2bb5dbcfba32770827466b17a882398898d Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Mon, 18 May 2026 07:56:08 -0400 Subject: [PATCH 30/38] Update Update-CIPPSAMRedirectUri.ps1 --- .../Public/Authentication/Update-CIPPSAMRedirectUri.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/CIPPCore/Public/Authentication/Update-CIPPSAMRedirectUri.ps1 b/Modules/CIPPCore/Public/Authentication/Update-CIPPSAMRedirectUri.ps1 index 356e922c876d..d6ed545baf51 100644 --- a/Modules/CIPPCore/Public/Authentication/Update-CIPPSAMRedirectUri.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Update-CIPPSAMRedirectUri.ps1 @@ -29,7 +29,7 @@ function Update-CIPPSAMRedirectUri { ) try { - $AppResponse = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/applications(appId='$($env:ApplicationID)')?`$select=id,web" -tenantid $env:TenantID -NoAuthCheck $true + $AppResponse = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/applications(appId='$($env:ApplicationID)')?`$select=id,web" -tenantid $env:TenantID -NoAuthCheck $true -AsApp $true $ExistingUris = @($AppResponse.web.redirectUris) $MissingUris = $RequiredUris | Where-Object { $_ -notin $ExistingUris } @@ -46,7 +46,7 @@ function Update-CIPPSAMRedirectUri { web = @{ redirectUris = $UpdatedUris } } | ConvertTo-Json -Depth 5 - New-GraphPOSTRequest -uri "https://graph.microsoft.com/v1.0/applications/$($AppResponse.id)" -body $Body -tenantid $env:TenantID -type PATCH -NoAuthCheck $true + New-GraphPOSTRequest -uri "https://graph.microsoft.com/v1.0/applications/$($AppResponse.id)" -body $Body -tenantid $env:TenantID -type PATCH -NoAuthCheck $true -AsApp $true Write-Information "[SAM-Redirect] Added redirect URIs: $($MissingUris -join ', ')" Write-LogMessage -API 'SAM-Redirect' -message "Added redirect URIs: $($MissingUris -join ', ')" -sev Info } catch { From d7cda8a309a9c133e98de54257482bb4ef399abc Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Mon, 18 May 2026 07:57:41 -0400 Subject: [PATCH 31/38] Update Initialize-CIPPAuth.ps1 --- .../Authentication/Initialize-CIPPAuth.ps1 | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Authentication/Initialize-CIPPAuth.ps1 b/Modules/CIPPCore/Public/Authentication/Initialize-CIPPAuth.ps1 index f5f48e325add..9f618899c237 100644 --- a/Modules/CIPPCore/Public/Authentication/Initialize-CIPPAuth.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Initialize-CIPPAuth.ps1 @@ -108,7 +108,58 @@ function Initialize-CIPPAuth { } } - # 5. Post-migration cleanup: if CIPP_SSO_MIGRATION_APPID is still set but EasyAuth + # 5. Reconcile EasyAuth issuer with SSOMultiTenant setting: if EasyAuth is already + # configured, check whether the issuer URL matches the current SSOMultiTenant value + # from Key Vault. If it changed (e.g. toggled from single to multi-tenant), update + # the EasyAuth config via ARM and restart. + if ($EasyAuthEnabled -and $AuthState.HasSAMCredentials -and -not $env:CIPP_SSO_MIGRATION_APPID) { + try { + $AuthConfigJson = $env:WEBSITE_AUTH_V2_CONFIG_JSON + if ($AuthConfigJson) { + $AuthConfig = $AuthConfigJson | ConvertFrom-Json -ErrorAction Stop + $CurrentIssuer = $AuthConfig.identityProviders.azureActiveDirectory.registration.openIdIssuer + $ConfiguredAppId = $AuthConfig.identityProviders.azureActiveDirectory.registration.clientId + + if ($CurrentIssuer -and $ConfiguredAppId) { + # Read SSOMultiTenant from KV/DevSecrets + $SSOMultiTenant = $false + if ($env:AzureWebJobsStorage -eq 'UseDevelopmentStorage=true' -or $env:NonLocalHostAzurite -eq 'true') { + try { + $DevSecretsTable = Get-CIPPTable -tablename 'DevSecrets' + $Secret = Get-CIPPAzDataTableEntity @DevSecretsTable -Filter "PartitionKey eq 'SSO' and RowKey eq 'SSO'" -ErrorAction SilentlyContinue + $SSOMultiTenant = $Secret.SSOMultiTenant -eq 'True' + } catch { } + } elseif ($KVName) { + try { + $MtVal = Get-CippKeyVaultSecret -VaultName $KVName -Name 'SSOMultiTenant' -AsPlainText -ErrorAction Stop + $SSOMultiTenant = $MtVal -eq 'True' + } catch { } + } + + $ExpectedIssuer = if ($SSOMultiTenant) { + 'https://login.microsoftonline.com/common/v2.0' + } else { + "https://login.microsoftonline.com/$($env:TenantID)/v2.0" + } + + if ($CurrentIssuer -ne $ExpectedIssuer) { + Write-Information "[Auth-Init] EasyAuth issuer mismatch: current=$CurrentIssuer expected=$ExpectedIssuer — updating" + $Configured = Set-CIPPSSOEasyAuth -AppId $ConfiguredAppId -MultiTenant $SSOMultiTenant -TenantId $env:TenantID + if ($Configured) { + Write-Information '[Auth-Init] EasyAuth issuer updated — requesting container restart' + [Craft.Services.AppLifecycleBridge]::RequestRestart('EasyAuth issuer updated to match SSOMultiTenant setting during warmup') + } + } else { + Write-Information "[Auth-Init] EasyAuth issuer matches SSOMultiTenant setting ($SSOMultiTenant) — no update needed" + } + } + } + } catch { + Write-Information "[Auth-Init] EasyAuth issuer reconciliation failed (non-fatal): $_" + } + } + + # 6. Post-migration cleanup: if CIPP_SSO_MIGRATION_APPID is still set but EasyAuth # is now configured, check whether the EasyAuth clientId still matches the migration # app. If it differs, the customer's own CIPP-SSO app is active and we can remove # the migration trigger env var. From ab5e5155681acb8e14994a80fd287a17f1aa3544 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Mon, 18 May 2026 09:24:48 -0400 Subject: [PATCH 32/38] Switch to app auth for authentication changes standard --- Modules/CIPPCore/Public/Set-CIPPAuthenticationPolicy.ps1 | 4 ++-- ...nvoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Set-CIPPAuthenticationPolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPAuthenticationPolicy.ps1 index 75d7971388a4..b3fedd2310ab 100644 --- a/Modules/CIPPCore/Public/Set-CIPPAuthenticationPolicy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPAuthenticationPolicy.ps1 @@ -21,7 +21,7 @@ function Set-CIPPAuthenticationPolicy { $State = if ($Enabled) { 'enabled' } else { 'disabled' } # Get current state of the called authentication method and Set state of authentication method to input state try { - $CurrentInfo = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/$AuthenticationMethodId" -tenantid $Tenant + $CurrentInfo = New-GraphGetRequest -Uri "https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/$AuthenticationMethodId" -tenantid $Tenant -AsApp $True $CurrentInfo.state = $State } catch { $ErrorMessage = Get-CippException -Exception $_ @@ -137,7 +137,7 @@ function Set-CIPPAuthenticationPolicy { try { if ($PSCmdlet.ShouldProcess($AuthenticationMethodId, "Set state to $State $OptionalLogMessage")) { # Convert body to JSON and send request - $null = New-GraphPostRequest -tenantid $Tenant -Uri "https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/$AuthenticationMethodId" -Type PATCH -Body (ConvertTo-Json -InputObject $CurrentInfo -Compress -Depth 10) -ContentType 'application/json' + $null = New-GraphPostRequest -tenantid $Tenant -Uri "https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/$AuthenticationMethodId" -Type PATCH -Body (ConvertTo-Json -InputObject $CurrentInfo -Compress -Depth 10) -ContentType 'application/json' -AsApp $True Write-LogMessage -headers $Headers -API $APIName -tenant $Tenant -message "Set $AuthenticationMethodId state to $State $OptionalLogMessage" -sev Info } return "Set $AuthenticationMethodId state to $State $OptionalLogMessage" diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 index f698d0753527..6f40f3945f2f 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPWdisplayAppInformationRequiredState.ps1 @@ -48,7 +48,7 @@ function Invoke-CIPPStandardPWdisplayAppInformationRequiredState { param($Tenant, $Settings) try { - $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator' -tenantid $Tenant + $CurrentState = New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator' -tenantid $Tenant -AsApp $True } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Could not get the PWdisplayAppInformationRequiredState state for $Tenant. Error: $ErrorMessage" -Sev Error From 1b1ee689e9442896d9767f1cba736d6aa8b5d56f Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Tue, 19 May 2026 07:20:16 -0400 Subject: [PATCH 33/38] cache PowerShell enabled status and use cached data for standard --- .../DBCache/Set-CIPPDBCacheMailboxes.ps1 | 34 ++++++++++++------- ...tandardDisableExchangeOnlinePowerShell.ps1 | 4 +-- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMailboxes.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMailboxes.ps1 index 5a75850f7412..4da4e1784514 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMailboxes.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMailboxes.ps1 @@ -25,19 +25,26 @@ function Set-CIPPDBCacheMailboxes { try { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching mailboxes' -sev Debug - # Get mailboxes with select properties - $Select = 'id,ExchangeGuid,ArchiveGuid,UserPrincipalName,DisplayName,PrimarySMTPAddress,RecipientType,RecipientTypeDetails,EmailAddresses,WhenSoftDeleted,IsInactiveMailbox,ForwardingSmtpAddress,DeliverToMailboxAndForward,ForwardingAddress,HiddenFromAddressListsEnabled,ExternalDirectoryObjectId,MessageCopyForSendOnBehalfEnabled,MessageCopyForSentAsEnabled,GrantSendOnBehalfTo,PersistedCapabilities,LitigationHoldEnabled,LitigationHoldDate,LitigationHoldDuration,ComplianceTagHoldApplied,RetentionHoldEnabled,InPlaceHolds,RetentionPolicy' - $ExoRequest = @{ - tenantid = $TenantFilter - cmdlet = 'Get-Mailbox' - cmdParams = @{} - Select = $Select + # Get mailboxes and user details in a single bulk request + $Select = 'id,ExchangeGuid,ArchiveGuid,UserPrincipalName,DisplayName,PrimarySMTPAddress,RecipientType,RecipientTypeDetails,EmailAddresses,WhenSoftDeleted,IsInactiveMailbox,ForwardingSmtpAddress,DeliverToMailboxAndForward,ForwardingAddress,HiddenFromAddressListsEnabled,ExternalDirectoryObjectId,MessageCopyForSendOnBehalfEnabled,MessageCopyForSentAsEnabled,GrantSendOnBehalfTo,PersistedCapabilities,LitigationHoldEnabled,LitigationHoldDate,LitigationHoldDuration,ComplianceTagHoldApplied,RetentionHoldEnabled,InPlaceHolds,RetentionPolicy,RemotePowerShellEnabled,Guid,Identity' + $BulkRequests = @( + @{ CmdletInput = @{ CmdletName = 'Get-Mailbox'; Parameters = @{} } } + @{ CmdletInput = @{ CmdletName = 'Get-User'; Parameters = @{} } } + ) + $BulkResults = New-ExoBulkRequest -tenantid $TenantFilter -cmdletArray $BulkRequests -useSystemMailbox $true -Select $Select -ReturnWithCommand $true + + # Build a lookup hashtable from Get-User results for O(1) matching + $UserLookup = @{} + foreach ($User in @($BulkResults.'Get-User')) { + if ($User.ExternalDirectoryObjectId) { + $UserLookup[$User.ExternalDirectoryObjectId] = $User + } } - # Use Generic List for better memory efficiency with large datasets - $Mailboxes = [System.Collections.Generic.List[PSObject]]::new() - $RawMailboxes = New-ExoRequest @ExoRequest - foreach ($Mailbox in $RawMailboxes) { + # Transform Get-Mailbox results and merge Get-User properties + $Mailboxes = [System.Collections.Generic.List[PSObject]]::new() + foreach ($Mailbox in @($BulkResults.'Get-Mailbox')) { + $MatchedUser = $UserLookup[$Mailbox.ExternalDirectoryObjectId] $Mailboxes.Add(($Mailbox | Select-Object id, ExchangeGuid, ArchiveGuid, WhenSoftDeleted, @{ Name = 'UPN'; Expression = { $_.'UserPrincipalName' } }, @{ Name = 'displayName'; Expression = { $_.'DisplayName' } }, @@ -60,7 +67,10 @@ function Set-CIPPDBCacheMailboxes { RetentionHoldEnabled, InPlaceHolds, RetentionPolicy, - GrantSendOnBehalfTo)) + GrantSendOnBehalfTo, + @{ Name = 'RemotePowerShellEnabled'; Expression = { $MatchedUser.RemotePowerShellEnabled } }, + @{ Name = 'Guid'; Expression = { $MatchedUser.Guid } }, + @{ Name = 'Identity'; Expression = { $MatchedUser.Identity } })) } $Mailboxes | Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Mailboxes' -AddCount diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExchangeOnlinePowerShell.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExchangeOnlinePowerShell.ps1 index c801a9924e67..e19319160827 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExchangeOnlinePowerShell.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExchangeOnlinePowerShell.ps1 @@ -66,7 +66,7 @@ function Invoke-CIPPStandardDisableExchangeOnlinePowerShell { } $AdminUsers = @($DirectAdminUPNs) + @($GroupMemberUPNs) | Where-Object { $_ } | Select-Object -Unique - $UsersWithPowerShell = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-User' -Select 'userPrincipalName, identity, guid, remotePowerShellEnabled' | Where-Object { $_.RemotePowerShellEnabled -eq $true -and $_.userPrincipalName -notin $AdminUsers } + $UsersWithPowerShell = New-CIPPDbRequest -TenantFilter $Tenant -Type 'Mailboxes' | Where-Object { $_.RemotePowerShellEnabled -eq $true -and $_.UPN -notin $AdminUsers } $PowerShellEnabledCount = ($UsersWithPowerShell | Measure-Object).Count $StateIsCorrect = $PowerShellEnabledCount -eq 0 } catch { @@ -83,7 +83,7 @@ function Invoke-CIPPStandardDisableExchangeOnlinePowerShell { @{ CmdletInput = @{ CmdletName = 'Set-User' - Parameters = @{Identity = $User.Guid; RemotePowerShellEnabled = $false } + Parameters = @{Identity = $User.Guid ?? $User.UPN; RemotePowerShellEnabled = $false } } } } From 6b8ebd4814625fa4902844dca619cb6deb1720eb Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Tue, 19 May 2026 07:40:37 -0400 Subject: [PATCH 34/38] refactor calls to use new onepass method to store DB data --- .../DBCache/Set-CIPPDBCacheAdminConsentRequestPolicy.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheAppRoleAssignments.ps1 | 3 +-- Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheApps.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheAuthenticationFlowsPolicy.ps1 | 3 +-- .../Set-CIPPDBCacheAuthenticationMethodsPolicy.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheAuthorizationPolicy.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheB2BManagementPolicy.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheBitlockerKeys.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 | 9 +++------ .../DBCache/Set-CIPPDBCacheCopilotReadinessActivity.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheCopilotUsageUserDetail.ps1 | 5 ++--- .../DBCache/Set-CIPPDBCacheCopilotUserCountSummary.ps1 | 5 ++--- .../DBCache/Set-CIPPDBCacheCopilotUserCountTrend.ps1 | 5 ++--- .../Set-CIPPDBCacheCredentialUserRegistrationDetails.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheCrossTenantAccessPolicy.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheCsExternalAccessPolicy.ps1 | 3 +-- .../Set-CIPPDBCacheCsTeamsAppPermissionPolicy.ps1 | 3 +-- .../Set-CIPPDBCacheCsTeamsClientConfiguration.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheCsTeamsMeetingPolicy.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheCsTeamsMessagingPolicy.ps1 | 3 +-- .../Set-CIPPDBCacheCsTenantFederationConfiguration.ps1 | 3 +-- .../Set-CIPPDBCacheDefaultAppManagementPolicy.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheDetectedApps.ps1 | 9 +++------ .../DBCache/Set-CIPPDBCacheDeviceRegistrationPolicy.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheDeviceSettings.ps1 | 3 +-- Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDevices.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheDirectoryRecommendations.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheDlpCompliancePolicies.ps1 | 3 +-- Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDomains.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheExoAcceptedDomains.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheExoAdminAuditLogConfig.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheExoAntiPhishPolicies.ps1 | 6 ++---- .../DBCache/Set-CIPPDBCacheExoAtpPolicyForO365.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheExoDkimSigningConfig.ps1 | 3 +-- .../Set-CIPPDBCacheExoHostedContentFilterPolicy.ps1 | 3 +-- .../Set-CIPPDBCacheExoHostedOutboundSpamFilterPolicy.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheExoMalwareFilterPolicies.ps1 | 6 ++---- .../DBCache/Set-CIPPDBCacheExoOrganizationConfig.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheExoPresetSecurityPolicy.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheExoQuarantinePolicy.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheExoRemoteDomain.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheExoSafeAttachmentPolicies.ps1 | 6 ++---- .../DBCache/Set-CIPPDBCacheExoSafeLinksPolicies.ps1 | 6 ++---- .../Public/DBCache/Set-CIPPDBCacheExoSharingPolicy.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheExoTenantAllowBlockList.ps1 | 6 ++---- .../Public/DBCache/Set-CIPPDBCacheExoTransportRules.ps1 | 3 +-- Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheGroups.ps1 | 6 ++---- Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheGuests.ps1 | 3 +-- .../Set-CIPPDBCacheIntuneAppProtectionPolicies.ps1 | 9 +++------ .../Public/DBCache/Set-CIPPDBCacheIntuneApplications.ps1 | 6 ++---- .../DBCache/Set-CIPPDBCacheIntuneAssignmentFilters.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheIntuneCompliancePolicies.ps1 | 6 ++---- .../Public/DBCache/Set-CIPPDBCacheIntunePolicies.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheIntuneReusableSettings.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheIntuneScripts.ps1 | 6 ++---- .../Public/DBCache/Set-CIPPDBCacheLicenseOverview.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheMDEOnboarding.ps1 | 3 +-- .../CIPPDB/Public/DBCache/Set-CIPPDBCacheMFAState.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheMailboxUsage.ps1 | 3 +-- .../Set-CIPPDBCacheManagedDeviceEncryptionStates.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheManagedDevices.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheOAuth2PermissionGrants.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheOfficeActivations.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheOneDriveUsage.ps1 | 6 ++---- .../Public/DBCache/Set-CIPPDBCacheOrganization.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheOwaMailboxPolicy.ps1 | 3 +-- .../CIPPDB/Public/DBCache/Set-CIPPDBCachePIMSettings.ps1 | 6 ++---- .../DBCache/Set-CIPPDBCacheReportSubmissionPolicy.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheRiskDetections.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheRiskyServicePrincipals.ps1 | 3 +-- .../CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskyUsers.ps1 | 3 +-- .../Set-CIPPDBCacheRoleAssignmentScheduleInstances.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheRoleEligibilitySchedules.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheRoleManagementPolicies.ps1 | 3 +-- Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoles.ps1 | 6 ++---- .../CIPPDB/Public/DBCache/Set-CIPPDBCacheSPOTenant.ps1 | 3 +-- .../Set-CIPPDBCacheSPOTenantSyncClientRestriction.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheSensitivityLabels.ps1 | 3 +-- .../Set-CIPPDBCacheServicePrincipalRiskDetections.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheServicePrincipals.ps1 | 3 +-- .../CIPPDB/Public/DBCache/Set-CIPPDBCacheSettings.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheSharePointSiteUsage.ps1 | 6 ++---- Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeams.ps1 | 3 +-- .../Public/DBCache/Set-CIPPDBCacheTeamsActivity.ps1 | 3 +-- .../CIPPDB/Public/DBCache/Set-CIPPDBCacheTeamsVoice.ps1 | 3 +-- .../DBCache/Set-CIPPDBCacheUserRegistrationDetails.ps1 | 3 +-- 86 files changed, 108 insertions(+), 213 deletions(-) diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAdminConsentRequestPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAdminConsentRequestPolicy.ps1 index b14ae9e2113d..66f32dbde1c0 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAdminConsentRequestPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAdminConsentRequestPolicy.ps1 @@ -19,8 +19,7 @@ function Set-CIPPDBCacheAdminConsentRequestPolicy { try { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching admin consent request policy' -sev Debug $ConsentPolicy = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/adminConsentRequestPolicy' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AdminConsentRequestPolicy' -Data @($ConsentPolicy) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AdminConsentRequestPolicy' -Data @($ConsentPolicy) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AdminConsentRequestPolicy' -Data @($ConsentPolicy) -AddCount $ConsentPolicy = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached admin consent request policy successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAppRoleAssignments.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAppRoleAssignments.ps1 index 93433d6c27f9..6db0d82a8769 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAppRoleAssignments.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAppRoleAssignments.ps1 @@ -39,8 +39,7 @@ function Set-CIPPDBCacheAppRoleAssignments { } if ($AllAppRoleAssignments.Count -gt 0) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AppRoleAssignments' -Data $AllAppRoleAssignments - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AppRoleAssignments' -Data $AllAppRoleAssignments -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AppRoleAssignments' -Data $AllAppRoleAssignments -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($AllAppRoleAssignments.Count) app role assignments" -sev Debug } $AllAppRoleAssignments = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheApps.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheApps.ps1 index ef8acc12acf4..56b65c6c07d1 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheApps.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheApps.ps1 @@ -21,8 +21,7 @@ function Set-CIPPDBCacheApps { $Apps = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/applications?$top=999&expand=owners' -tenantid $TenantFilter if (!$Apps) { $Apps = @() } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Apps' -Data $Apps - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Apps' -Data $Apps -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Apps' -Data $Apps -AddCount $Apps = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached applications successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAuthenticationFlowsPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAuthenticationFlowsPolicy.ps1 index cac9230929b9..d25be4186873 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAuthenticationFlowsPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAuthenticationFlowsPolicy.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheAuthenticationFlowsPolicy { $AuthFlowPolicy = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/authenticationFlowsPolicy' -tenantid $TenantFilter -AsApp $true if ($AuthFlowPolicy) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthenticationFlowsPolicy' -Data @($AuthFlowPolicy) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthenticationFlowsPolicy' -Data @($AuthFlowPolicy) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthenticationFlowsPolicy' -Data @($AuthFlowPolicy) -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached authentication flows policy successfully' -sev Debug } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAuthenticationMethodsPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAuthenticationMethodsPolicy.ps1 index 2ae7c00b416b..e1b63f15b8ca 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAuthenticationMethodsPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAuthenticationMethodsPolicy.ps1 @@ -19,8 +19,7 @@ function Set-CIPPDBCacheAuthenticationMethodsPolicy { try { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching authentication methods policy' -sev Debug $AuthMethodsPolicy = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/authenticationMethodsPolicy' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthenticationMethodsPolicy' -Data @($AuthMethodsPolicy) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthenticationMethodsPolicy' -Data @($AuthMethodsPolicy) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthenticationMethodsPolicy' -Data @($AuthMethodsPolicy) -AddCount $AuthMethodsPolicy = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached authentication methods policy successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAuthorizationPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAuthorizationPolicy.ps1 index 6aedd8b765c4..7811b92867b9 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAuthorizationPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheAuthorizationPolicy.ps1 @@ -19,8 +19,7 @@ function Set-CIPPDBCacheAuthorizationPolicy { try { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching authorization policy' -sev Debug $AuthPolicy = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/authorizationPolicy' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthorizationPolicy' -Data @($AuthPolicy) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthorizationPolicy' -Data @($AuthPolicy) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthorizationPolicy' -Data @($AuthPolicy) -AddCount $AuthPolicy = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached authorization policy successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheB2BManagementPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheB2BManagementPolicy.ps1 index b85af4dac1c1..0a3b901af6f2 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheB2BManagementPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheB2BManagementPolicy.ps1 @@ -23,8 +23,7 @@ function Set-CIPPDBCacheB2BManagementPolicy { $B2BManagementPolicy = $LegacyPolicies if ($B2BManagementPolicy) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'B2BManagementPolicy' -Data @($B2BManagementPolicy) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'B2BManagementPolicy' -Data @($B2BManagementPolicy) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'B2BManagementPolicy' -Data @($B2BManagementPolicy) -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached B2B management policy successfully' -sev Debug } else { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'No B2B management policy found' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheBitlockerKeys.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheBitlockerKeys.ps1 index 8bb2bf9971fd..71b70fd9a250 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheBitlockerKeys.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheBitlockerKeys.ps1 @@ -21,8 +21,7 @@ function Set-CIPPDBCacheBitlockerKeys { $BitlockerKeys = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/informationProtection/bitlocker/recoveryKeys' -tenantid $TenantFilter if (!$BitlockerKeys) { $BitlockerKeys = @() } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'BitlockerKeys' -Data $BitlockerKeys - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'BitlockerKeys' -Data $BitlockerKeys -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'BitlockerKeys' -Data $BitlockerKeys -AddCount $BitlockerKeys = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached BitLocker recovery keys successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 index d5bd3ec19cde..a4407e0b82d3 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 @@ -29,8 +29,7 @@ function Set-CIPPDBCacheConditionalAccessPolicies { try { $CAPolicies = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/policies?$top=999' -tenantid $TenantFilter if ($CAPolicies) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ConditionalAccessPolicies' -Data $CAPolicies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ConditionalAccessPolicies' -Data $CAPolicies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ConditionalAccessPolicies' -Data $CAPolicies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($CAPolicies.Count) CA policies" -sev Debug } $CAPolicies = $null @@ -42,8 +41,7 @@ function Set-CIPPDBCacheConditionalAccessPolicies { $NamedLocations = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/namedLocations?$top=999' -tenantid $TenantFilter if ($NamedLocations) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'NamedLocations' -Data $NamedLocations - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'NamedLocations' -Data $NamedLocations -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'NamedLocations' -Data $NamedLocations -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($NamedLocations.Count) named locations" -sev Debug } $NamedLocations = $null @@ -55,8 +53,7 @@ function Set-CIPPDBCacheConditionalAccessPolicies { $AuthStrengths = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/identity/conditionalAccess/authenticationStrength/policies' -tenantid $TenantFilter if ($AuthStrengths) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthenticationStrengths' -Data $AuthStrengths - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthenticationStrengths' -Data $AuthStrengths -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'AuthenticationStrengths' -Data $AuthStrengths -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($AuthStrengths.Count) authentication strengths" -sev Debug } $AuthStrengths = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotReadinessActivity.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotReadinessActivity.ps1 index c055e34ef989..48131fe4b39b 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotReadinessActivity.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotReadinessActivity.ps1 @@ -44,8 +44,7 @@ function Set-CIPPDBCacheCopilotReadinessActivity { } } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotReadinessActivity' -Data $FlattenedData - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotReadinessActivity' -Data $FlattenedData -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotReadinessActivity' -Data $FlattenedData -AddCount $FlattenedData = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached Copilot readiness activity successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotUsageUserDetail.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotUsageUserDetail.ps1 index 7f3be5239050..04757c42bda0 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotUsageUserDetail.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotUsageUserDetail.ps1 @@ -22,12 +22,11 @@ function Set-CIPPDBCacheCopilotUsageUserDetail { $Data = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getMicrosoft365CopilotUsageUserDetail(period='D30')" -tenantid $TenantFilter -AsApp $true if ($Data) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUsageUserDetail' -Data $Data - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUsageUserDetail' -Data $Data -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUsageUserDetail' -Data $Data -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($Data.Count) Copilot usage user detail records" -sev Debug } else { # Write an empty marker so tests can distinguish "no data yet" from "cache not run" - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUsageUserDetail' -Data @() -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUsageUserDetail' -Data @() -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Copilot usage user detail: no records returned (no active Copilot usage)' -sev Debug } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotUserCountSummary.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotUserCountSummary.ps1 index a667626c32b4..4fc0c9f40265 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotUserCountSummary.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotUserCountSummary.ps1 @@ -22,11 +22,10 @@ function Set-CIPPDBCacheCopilotUserCountSummary { $Data = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getMicrosoft365CopilotUserCountSummary(period='D30')" -tenantid $TenantFilter -AsApp $true if ($Data) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUserCountSummary' -Data $Data - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUserCountSummary' -Data $Data -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUserCountSummary' -Data $Data -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached Copilot user count summary' -sev Debug } else { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUserCountSummary' -Data @() -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUserCountSummary' -Data @() -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Copilot user count summary: no records returned (no active Copilot usage)' -sev Debug } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotUserCountTrend.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotUserCountTrend.ps1 index 6f6034b958c3..227402889db4 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotUserCountTrend.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCopilotUserCountTrend.ps1 @@ -22,11 +22,10 @@ function Set-CIPPDBCacheCopilotUserCountTrend { $Data = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getMicrosoft365CopilotUserCountTrend(period='D7')?`$format=application/json" -tenantid $TenantFilter -AsApp $true if ($Data) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUserCountTrend' -Data $Data - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUserCountTrend' -Data $Data -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUserCountTrend' -Data $Data -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($Data.Count) Copilot user count trend records" -sev Debug } else { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUserCountTrend' -Data @() -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CopilotUserCountTrend' -Data @() -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Copilot user count trend: no records returned (no active Copilot usage)' -sev Debug } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCredentialUserRegistrationDetails.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCredentialUserRegistrationDetails.ps1 index 5242dffdbbf7..198e467ebcc2 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCredentialUserRegistrationDetails.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCredentialUserRegistrationDetails.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheCredentialUserRegistrationDetails { $CredentialUserRegistrationDetails = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/reports/credentialUserRegistrationDetails' -tenantid $TenantFilter if ($CredentialUserRegistrationDetails) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CredentialUserRegistrationDetails' -Data $CredentialUserRegistrationDetails - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CredentialUserRegistrationDetails' -Data $CredentialUserRegistrationDetails -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CredentialUserRegistrationDetails' -Data $CredentialUserRegistrationDetails -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($CredentialUserRegistrationDetails.Count) credential user registration details" -sev Debug } $CredentialUserRegistrationDetails = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCrossTenantAccessPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCrossTenantAccessPolicy.ps1 index 1578be33762c..beeacb65cfba 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCrossTenantAccessPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCrossTenantAccessPolicy.ps1 @@ -19,8 +19,7 @@ function Set-CIPPDBCacheCrossTenantAccessPolicy { try { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching cross-tenant access policy' -sev Debug $CrossTenantPolicy = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/crossTenantAccessPolicy/default' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CrossTenantAccessPolicy' -Data @($CrossTenantPolicy) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CrossTenantAccessPolicy' -Data @($CrossTenantPolicy) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CrossTenantAccessPolicy' -Data @($CrossTenantPolicy) -AddCount $CrossTenantPolicy = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached cross-tenant access policy successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsExternalAccessPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsExternalAccessPolicy.ps1 index 9889b37b7a6c..96afe6b7eab9 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsExternalAccessPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsExternalAccessPolicy.ps1 @@ -28,8 +28,7 @@ function Set-CIPPDBCacheCsExternalAccessPolicy { if ($ExternalAccess) { $Data = @($ExternalAccess) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsExternalAccessPolicy' -Data $Data - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsExternalAccessPolicy' -Data $Data -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsExternalAccessPolicy' -Data $Data -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached Teams External Access Policy' -sev Debug } $ExternalAccess = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsAppPermissionPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsAppPermissionPolicy.ps1 index 206c1a806741..66c2a171aeca 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsAppPermissionPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsAppPermissionPolicy.ps1 @@ -28,8 +28,7 @@ function Set-CIPPDBCacheCsTeamsAppPermissionPolicy { if ($AppPermissionPolicies) { $Data = @($AppPermissionPolicies) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTeamsAppPermissionPolicy' -Data $Data - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTeamsAppPermissionPolicy' -Data $Data -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTeamsAppPermissionPolicy' -Data $Data -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($Data.Count) Teams App Permission Policies" -sev Debug } $AppPermissionPolicies = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsClientConfiguration.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsClientConfiguration.ps1 index de1d018ff9c9..1db2ec626fe9 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsClientConfiguration.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsClientConfiguration.ps1 @@ -29,8 +29,7 @@ function Set-CIPPDBCacheCsTeamsClientConfiguration { if ($ClientConfig) { $Data = @($ClientConfig) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTeamsClientConfiguration' -Data $Data - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTeamsClientConfiguration' -Data $Data -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTeamsClientConfiguration' -Data $Data -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached Teams Client Configuration' -sev Debug } $ClientConfig = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsMeetingPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsMeetingPolicy.ps1 index 7dcea7b968ee..5a67acdb1ddb 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsMeetingPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsMeetingPolicy.ps1 @@ -28,8 +28,7 @@ function Set-CIPPDBCacheCsTeamsMeetingPolicy { if ($MeetingPolicy) { $Data = @($MeetingPolicy) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTeamsMeetingPolicy' -Data $Data - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTeamsMeetingPolicy' -Data $Data -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTeamsMeetingPolicy' -Data $Data -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached Teams Meeting Policy' -sev Debug } $MeetingPolicy = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsMessagingPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsMessagingPolicy.ps1 index e3696593c918..2fc1ef784c23 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsMessagingPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTeamsMessagingPolicy.ps1 @@ -29,8 +29,7 @@ function Set-CIPPDBCacheCsTeamsMessagingPolicy { if ($MessagingPolicy) { $Data = @($MessagingPolicy) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTeamsMessagingPolicy' -Data $Data - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTeamsMessagingPolicy' -Data $Data -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTeamsMessagingPolicy' -Data $Data -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached Teams Messaging Policy' -sev Debug } $MessagingPolicy = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTenantFederationConfiguration.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTenantFederationConfiguration.ps1 index b5d76c0f89e5..47d09881239e 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTenantFederationConfiguration.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheCsTenantFederationConfiguration.ps1 @@ -29,8 +29,7 @@ function Set-CIPPDBCacheCsTenantFederationConfiguration { if ($Federation) { $Data = @($Federation) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTenantFederationConfiguration' -Data $Data - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTenantFederationConfiguration' -Data $Data -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'CsTenantFederationConfiguration' -Data $Data -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached Teams Tenant Federation Configuration' -sev Debug } $Federation = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDefaultAppManagementPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDefaultAppManagementPolicy.ps1 index c8126a8744d2..56886caa2735 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDefaultAppManagementPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDefaultAppManagementPolicy.ps1 @@ -19,8 +19,7 @@ function Set-CIPPDBCacheDefaultAppManagementPolicy { try { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching default app management policy' -sev Debug $AppMgmtPolicy = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/defaultAppManagementPolicy' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DefaultAppManagementPolicy' -Data @($AppMgmtPolicy) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DefaultAppManagementPolicy' -Data @($AppMgmtPolicy) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DefaultAppManagementPolicy' -Data @($AppMgmtPolicy) -AddCount $AppMgmtPolicy = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached default app management policy successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDetectedApps.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDetectedApps.ps1 index c79b183c09c8..8783690f4b61 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDetectedApps.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDetectedApps.ps1 @@ -60,8 +60,7 @@ function Set-CIPPDBCacheDetectedApps { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Retrieved $($DetectedApps.Count) detected apps (expected $TotalCount)" -sev Debug if ($DetectedApps.Count -eq 0) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DetectedApps' -Data @() - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DetectedApps' -Data @() -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DetectedApps' -Data @() -AddCount return } @@ -85,13 +84,11 @@ function Set-CIPPDBCacheDetectedApps { $App } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DetectedApps' -Data $DetectedAppsWithDevices - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DetectedApps' -Data $DetectedAppsWithDevices -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DetectedApps' -Data $DetectedAppsWithDevices -AddCount $DetectedApps = $null $DetectedAppsWithDevices = $null } else { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DetectedApps' -Data $DetectedApps - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DetectedApps' -Data $DetectedApps -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DetectedApps' -Data $DetectedApps -AddCount $DetectedApps = $null } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDeviceRegistrationPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDeviceRegistrationPolicy.ps1 index 3ef85cfe05c6..876244bae3dc 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDeviceRegistrationPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDeviceRegistrationPolicy.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheDeviceRegistrationPolicy { $DeviceRegistrationPolicy = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/deviceRegistrationPolicy' -tenantid $TenantFilter if ($DeviceRegistrationPolicy) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DeviceRegistrationPolicy' -Data @($DeviceRegistrationPolicy) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DeviceRegistrationPolicy' -Data @($DeviceRegistrationPolicy) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DeviceRegistrationPolicy' -Data @($DeviceRegistrationPolicy) -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached device registration policy successfully' -sev Debug } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDeviceSettings.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDeviceSettings.ps1 index 2a0b4a480d91..79dd4c4cff82 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDeviceSettings.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDeviceSettings.ps1 @@ -20,8 +20,7 @@ function Set-CIPPDBCacheDeviceSettings { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching device settings' -sev Debug $DeviceSettings = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/directory/deviceLocalCredentials' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DeviceSettings' -Data @($DeviceSettings) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DeviceSettings' -Data @($DeviceSettings) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DeviceSettings' -Data @($DeviceSettings) -AddCount $DeviceSettings = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached device settings successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDevices.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDevices.ps1 index c0d056617209..cb2bec81698f 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDevices.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDevices.ps1 @@ -21,8 +21,7 @@ function Set-CIPPDBCacheDevices { $Devices = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/devices?$top=999&$select=id,displayName,operatingSystem,operatingSystemVersion,trustType,accountEnabled,approximateLastSignInDateTime' -tenantid $TenantFilter if (!$Devices) { $Devices = @() } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Devices' -Data $Devices - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Devices' -Data $Devices -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Devices' -Data $Devices -AddCount $Devices = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached Azure AD devices successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDirectoryRecommendations.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDirectoryRecommendations.ps1 index 1a1e973cd695..75074c9ab3b4 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDirectoryRecommendations.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDirectoryRecommendations.ps1 @@ -20,8 +20,7 @@ function Set-CIPPDBCacheDirectoryRecommendations { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching directory recommendations' -sev Debug $Recommendations = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/directory/recommendations?$top=999' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DirectoryRecommendations' -Data $Recommendations - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DirectoryRecommendations' -Data $Recommendations -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DirectoryRecommendations' -Data $Recommendations -AddCount $Recommendations = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached directory recommendations successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDlpCompliancePolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDlpCompliancePolicies.ps1 index 776b868f163d..13d9a9927377 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDlpCompliancePolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDlpCompliancePolicies.ps1 @@ -30,8 +30,7 @@ function Set-CIPPDBCacheDlpCompliancePolicies { $Policies = New-ExoRequest -TenantId $Tenant.customerId -cmdlet 'Get-DlpCompliancePolicy' -Compliance -Select 'Name,DisplayName,Mode,Enabled,Workload,CreatedBy,WhenCreatedUTC,WhenChangedUTC' if ($Policies) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DlpCompliancePolicies' -Data $Policies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DlpCompliancePolicies' -Data $Policies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'DlpCompliancePolicies' -Data $Policies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($Policies.Count) DLP compliance policies" -sev Debug } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDomains.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDomains.ps1 index 405342b9eefa..0a67432e77b8 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDomains.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheDomains.ps1 @@ -19,8 +19,7 @@ function Set-CIPPDBCacheDomains { try { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching domains' -sev Debug $Domains = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/domains' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Domains' -Data @($Domains) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Domains' -Data @($Domains) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Domains' -Data @($Domains) -AddCount $Domains = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached domains successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAcceptedDomains.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAcceptedDomains.ps1 index b2af3cdbe3b8..be47cf4c3714 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAcceptedDomains.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAcceptedDomains.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheExoAcceptedDomains { $AcceptedDomains = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-AcceptedDomain' if ($AcceptedDomains) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAcceptedDomains' -Data $AcceptedDomains - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAcceptedDomains' -Data $AcceptedDomains -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAcceptedDomains' -Data $AcceptedDomains -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($AcceptedDomains.Count) Accepted Domains" -sev Debug } $AcceptedDomains = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAdminAuditLogConfig.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAdminAuditLogConfig.ps1 index 2c0b2a10e863..d51a81c26ba2 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAdminAuditLogConfig.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAdminAuditLogConfig.ps1 @@ -24,8 +24,7 @@ function Set-CIPPDBCacheExoAdminAuditLogConfig { if ($AuditConfig) { # AdminAuditLogConfig returns a single object, wrap in array for consistency $AuditConfigArray = @($AuditConfig) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAdminAuditLogConfig' -Data $AuditConfigArray - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAdminAuditLogConfig' -Data $AuditConfigArray -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAdminAuditLogConfig' -Data $AuditConfigArray -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached Exchange Admin Audit Log configuration' -sev Debug } $AuditConfig = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAntiPhishPolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAntiPhishPolicies.ps1 index f35ba843e566..2e7fa2dbee1b 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAntiPhishPolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAntiPhishPolicies.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheExoAntiPhishPolicies { # Get Anti-Phishing policies $AntiPhishPolicies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-AntiPhishPolicy' if ($AntiPhishPolicies) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAntiPhishPolicies' -Data $AntiPhishPolicies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAntiPhishPolicies' -Data $AntiPhishPolicies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAntiPhishPolicies' -Data $AntiPhishPolicies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($AntiPhishPolicies.Count) Anti-Phishing policies" -sev Debug } $AntiPhishPolicies = $null @@ -31,8 +30,7 @@ function Set-CIPPDBCacheExoAntiPhishPolicies { # Get Anti-Phishing rules $AntiPhishRules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-AntiPhishRule' if ($AntiPhishRules) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAntiPhishRules' -Data $AntiPhishRules - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAntiPhishRules' -Data $AntiPhishRules -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAntiPhishRules' -Data $AntiPhishRules -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($AntiPhishRules.Count) Anti-Phishing rules" -sev Debug } $AntiPhishRules = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAtpPolicyForO365.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAtpPolicyForO365.ps1 index c48fd4baab3a..b93320868475 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAtpPolicyForO365.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoAtpPolicyForO365.ps1 @@ -21,8 +21,7 @@ function Set-CIPPDBCacheExoAtpPolicyForO365 { $AtpPolicies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-AtpPolicyForO365' if ($AtpPolicies) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAtpPolicyForO365' -Data $AtpPolicies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAtpPolicyForO365' -Data $AtpPolicies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoAtpPolicyForO365' -Data $AtpPolicies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($AtpPolicies.Count) ATP policies for Office 365" -sev Debug } $AtpPolicies = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoDkimSigningConfig.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoDkimSigningConfig.ps1 index aa7ea3bd4561..a0e3b6b2350a 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoDkimSigningConfig.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoDkimSigningConfig.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheExoDkimSigningConfig { $DkimConfig = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-DkimSigningConfig' if ($DkimConfig) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoDkimSigningConfig' -Data $DkimConfig - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoDkimSigningConfig' -Data $DkimConfig -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoDkimSigningConfig' -Data $DkimConfig -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($DkimConfig.Count) DKIM configurations" -sev Debug } $DkimConfig = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoHostedContentFilterPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoHostedContentFilterPolicy.ps1 index cd71f9a00bc5..958648690c0e 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoHostedContentFilterPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoHostedContentFilterPolicy.ps1 @@ -20,8 +20,7 @@ function Set-CIPPDBCacheExoHostedContentFilterPolicy { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching Exchange Hosted Content Filter policies' -sev Debug $HostedContentFilterPolicies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-HostedContentFilterPolicy' if ($HostedContentFilterPolicies) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoHostedContentFilterPolicy' -Data $HostedContentFilterPolicies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoHostedContentFilterPolicy' -Data $HostedContentFilterPolicies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoHostedContentFilterPolicy' -Data $HostedContentFilterPolicies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($HostedContentFilterPolicies.Count) Hosted Content Filter policies" -sev Debug } $HostedContentFilterPolicies = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoHostedOutboundSpamFilterPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoHostedOutboundSpamFilterPolicy.ps1 index a550c9031c8e..2a53545a2405 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoHostedOutboundSpamFilterPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoHostedOutboundSpamFilterPolicy.ps1 @@ -21,8 +21,7 @@ function Set-CIPPDBCacheExoHostedOutboundSpamFilterPolicy { $HostedOutboundSpamFilterPolicies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-HostedOutboundSpamFilterPolicy' if ($HostedOutboundSpamFilterPolicies) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoHostedOutboundSpamFilterPolicy' -Data $HostedOutboundSpamFilterPolicies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoHostedOutboundSpamFilterPolicy' -Data $HostedOutboundSpamFilterPolicies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoHostedOutboundSpamFilterPolicy' -Data $HostedOutboundSpamFilterPolicies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($HostedOutboundSpamFilterPolicies.Count) Hosted Outbound Spam Filter policies" -sev Debug } $HostedOutboundSpamFilterPolicies = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoMalwareFilterPolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoMalwareFilterPolicies.ps1 index 23f6b1f775ef..7d71ab954e5e 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoMalwareFilterPolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoMalwareFilterPolicies.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheExoMalwareFilterPolicies { # Get Malware Filter policies $MalwarePolicies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-MalwareFilterPolicy' if ($MalwarePolicies) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoMalwareFilterPolicies' -Data $MalwarePolicies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoMalwareFilterPolicies' -Data $MalwarePolicies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoMalwareFilterPolicies' -Data $MalwarePolicies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($MalwarePolicies.Count) Malware Filter policies" -sev Debug } $MalwarePolicies = $null @@ -31,8 +30,7 @@ function Set-CIPPDBCacheExoMalwareFilterPolicies { # Get Malware Filter rules $MalwareRules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-MalwareFilterRule' if ($MalwareRules) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoMalwareFilterRules' -Data $MalwareRules - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoMalwareFilterRules' -Data $MalwareRules -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoMalwareFilterRules' -Data $MalwareRules -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($MalwareRules.Count) Malware Filter rules" -sev Debug } $MalwareRules = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoOrganizationConfig.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoOrganizationConfig.ps1 index 27a8c481a7da..c07c203edaef 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoOrganizationConfig.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoOrganizationConfig.ps1 @@ -24,8 +24,7 @@ function Set-CIPPDBCacheExoOrganizationConfig { if ($OrgConfig) { # OrganizationConfig returns a single object, wrap in array for consistency $OrgConfigArray = @($OrgConfig) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoOrganizationConfig' -Data $OrgConfigArray - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoOrganizationConfig' -Data $OrgConfigArray -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoOrganizationConfig' -Data $OrgConfigArray -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached Exchange Organization configuration' -sev Debug } $OrgConfig = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoPresetSecurityPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoPresetSecurityPolicy.ps1 index 0810cf69ade7..7930ec943f18 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoPresetSecurityPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoPresetSecurityPolicy.ps1 @@ -38,8 +38,7 @@ function Set-CIPPDBCacheExoPresetSecurityPolicy { } if ($AllRules.Count -gt 0) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoPresetSecurityPolicy' -Data $AllRules - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoPresetSecurityPolicy' -Data $AllRules -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoPresetSecurityPolicy' -Data $AllRules -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($AllRules.Count) Preset Security Policy rules" -sev Debug } $EOPRules = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoQuarantinePolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoQuarantinePolicy.ps1 index b4bcdd7ac011..cd7fb1afbbd1 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoQuarantinePolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoQuarantinePolicy.ps1 @@ -21,8 +21,7 @@ function Set-CIPPDBCacheExoQuarantinePolicy { $QuarantinePolicies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-QuarantinePolicy' if ($QuarantinePolicies) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoQuarantinePolicy' -Data $QuarantinePolicies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoQuarantinePolicy' -Data $QuarantinePolicies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoQuarantinePolicy' -Data $QuarantinePolicies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($QuarantinePolicies.Count) Quarantine policies" -sev Debug } $QuarantinePolicies = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoRemoteDomain.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoRemoteDomain.ps1 index e9b32337a9ee..dd9fb277b99a 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoRemoteDomain.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoRemoteDomain.ps1 @@ -21,8 +21,7 @@ function Set-CIPPDBCacheExoRemoteDomain { $RemoteDomains = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-RemoteDomain' if ($RemoteDomains) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoRemoteDomain' -Data $RemoteDomains - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoRemoteDomain' -Data $RemoteDomains -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoRemoteDomain' -Data $RemoteDomains -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($RemoteDomains.Count) Remote Domains" -sev Debug } $RemoteDomains = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoSafeAttachmentPolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoSafeAttachmentPolicies.ps1 index 28d8f587afc3..07867a4caff3 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoSafeAttachmentPolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoSafeAttachmentPolicies.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheExoSafeAttachmentPolicies { # Get Safe Attachment policies $SafeAttachmentPolicies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SafeAttachmentPolicy' if ($SafeAttachmentPolicies) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSafeAttachmentPolicies' -Data $SafeAttachmentPolicies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSafeAttachmentPolicies' -Data $SafeAttachmentPolicies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSafeAttachmentPolicies' -Data $SafeAttachmentPolicies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($SafeAttachmentPolicies.Count) Safe Attachment policies" -sev Debug } $SafeAttachmentPolicies = $null @@ -31,8 +30,7 @@ function Set-CIPPDBCacheExoSafeAttachmentPolicies { # Get Safe Attachment rules $SafeAttachmentRules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SafeAttachmentRule' if ($SafeAttachmentRules) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSafeAttachmentRules' -Data $SafeAttachmentRules - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSafeAttachmentRules' -Data $SafeAttachmentRules -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSafeAttachmentRules' -Data $SafeAttachmentRules -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($SafeAttachmentRules.Count) Safe Attachment rules" -sev Debug } $SafeAttachmentRules = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoSafeLinksPolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoSafeLinksPolicies.ps1 index f78468844344..65403b187268 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoSafeLinksPolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoSafeLinksPolicies.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheExoSafeLinksPolicies { # Get Safe Links policies $SafeLinksPolicies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SafeLinksPolicy' if ($SafeLinksPolicies) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSafeLinksPolicies' -Data $SafeLinksPolicies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSafeLinksPolicies' -Data $SafeLinksPolicies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSafeLinksPolicies' -Data $SafeLinksPolicies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($SafeLinksPolicies.Count) Safe Links policies" -sev Debug } $SafeLinksPolicies = $null @@ -31,8 +30,7 @@ function Set-CIPPDBCacheExoSafeLinksPolicies { # Get Safe Links rules $SafeLinksRules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SafeLinksRule' if ($SafeLinksRules) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSafeLinksRules' -Data $SafeLinksRules - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSafeLinksRules' -Data $SafeLinksRules -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSafeLinksRules' -Data $SafeLinksRules -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($SafeLinksRules.Count) Safe Links rules" -sev Debug } $SafeLinksRules = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoSharingPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoSharingPolicy.ps1 index ffaaed92ed0a..368c1dca953c 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoSharingPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoSharingPolicy.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheExoSharingPolicy { $SharingPolicies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-SharingPolicy' if ($SharingPolicies) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSharingPolicy' -Data $SharingPolicies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSharingPolicy' -Data $SharingPolicies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoSharingPolicy' -Data $SharingPolicies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($SharingPolicies.Count) Sharing Policies" -sev Debug } $SharingPolicies = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoTenantAllowBlockList.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoTenantAllowBlockList.ps1 index 3906bf3d55f8..a73dfafa7e2e 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoTenantAllowBlockList.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoTenantAllowBlockList.ps1 @@ -36,13 +36,11 @@ function Set-CIPPDBCacheExoTenantAllowBlockList { } if ($AllItems.Count -gt 0) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoTenantAllowBlockList' -Data $AllItems - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoTenantAllowBlockList' -Data $AllItems -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoTenantAllowBlockList' -Data $AllItems -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($AllItems.Count) Tenant Allow/Block List items" -sev Debug } else { # Even if empty, store an empty array so test knows cache was populated - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoTenantAllowBlockList' -Data @() - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoTenantAllowBlockList' -Data @() -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoTenantAllowBlockList' -Data @() -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached empty Tenant Allow/Block List' -sev Debug } $SenderItems = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoTransportRules.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoTransportRules.ps1 index f08860ac00c6..a557947d4ce0 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoTransportRules.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheExoTransportRules.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheExoTransportRules { $TransportRules = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-TransportRule' if ($TransportRules) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoTransportRules' -Data $TransportRules - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoTransportRules' -Data $TransportRules -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ExoTransportRules' -Data $TransportRules -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($TransportRules.Count) Transport Rules" -sev Debug } $TransportRules = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheGroups.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheGroups.ps1 index b0857fd24d21..03c843a41ce0 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheGroups.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheGroups.ps1 @@ -59,8 +59,7 @@ function Set-CIPPDBCacheGroups { $Group } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Groups' -Data $GroupsWithMembers - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Groups' -Data $GroupsWithMembers -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Groups' -Data $GroupsWithMembers -AddCount $Groups = $null $GroupsWithMembers = $null } else { @@ -82,8 +81,7 @@ function Set-CIPPDBCacheGroups { $Group | Add-Member -NotePropertyName 'calculatedGroupType' -NotePropertyValue $calculatedGroupType -Force $Group } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Groups' -Data $Groups - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Groups' -Data $Groups -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Groups' -Data $Groups -AddCount $Groups = $null } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheGuests.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheGuests.ps1 index 867d45b791cd..7a25235e6946 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheGuests.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheGuests.ps1 @@ -21,8 +21,7 @@ function Set-CIPPDBCacheGuests { $Guests = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users?`$filter=userType eq 'Guest'&`$expand=sponsors&`$top=999" -tenantid $TenantFilter if (!$Guests) { $Guests = @() } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Guests' -Data $Guests - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Guests' -Data $Guests -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Guests' -Data $Guests -AddCount $Guests = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached guest users successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAppProtectionPolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAppProtectionPolicies.ps1 index d3dd14ad33fa..418d5a277852 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAppProtectionPolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAppProtectionPolicies.ps1 @@ -74,12 +74,9 @@ function Set-CIPPDBCacheIntuneAppProtectionPolicies { if (-not $Groups) { $Groups = @() } if (-not $MobileAppConfigs) { $MobileAppConfigs = @() } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneAppProtectionPolicyGroups' -Data @($Groups) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneAppProtectionPolicyGroups' -Data @($Groups) -Count - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneAppProtectionManagedAppPolicies' -Data @($ManagedAppPoliciesWithAssignments) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneAppProtectionManagedAppPolicies' -Data @($ManagedAppPoliciesWithAssignments) -Count - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneAppProtectionMobileAppConfigurations' -Data @($MobileAppConfigs) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneAppProtectionMobileAppConfigurations' -Data @($MobileAppConfigs) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneAppProtectionPolicyGroups' -Data @($Groups) -AddCount + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneAppProtectionManagedAppPolicies' -Data @($ManagedAppPoliciesWithAssignments) -AddCount + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneAppProtectionMobileAppConfigurations' -Data @($MobileAppConfigs) -AddCount $TotalCount = (($ManagedAppPoliciesWithAssignments | Measure-Object).Count + ($MobileAppConfigs | Measure-Object).Count) Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $TotalCount app protection/configuration policies" -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneApplications.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneApplications.ps1 index 811f2af821d3..8594bc640137 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneApplications.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneApplications.ps1 @@ -34,10 +34,8 @@ function Set-CIPPDBCacheIntuneApplications { if (-not $Groups) { $Groups = @() } if (-not $Apps) { $Apps = @() } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneApplicationGroups' -Data @($Groups) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneApplicationGroups' -Data @($Groups) -Count - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneApplications' -Data @($Apps) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneApplications' -Data @($Apps) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneApplicationGroups' -Data @($Groups) -AddCount + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneApplications' -Data @($Apps) -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $(($Apps | Measure-Object).Count) Intune applications" -sev Debug } catch { diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAssignmentFilters.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAssignmentFilters.ps1 index 882021cfb4ea..e6037b1f1061 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAssignmentFilters.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneAssignmentFilters.ps1 @@ -17,8 +17,7 @@ function Set-CIPPDBCacheIntuneAssignmentFilters { $AssignmentFilters = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/assignmentFilters' -tenantid $TenantFilter if (-not $AssignmentFilters) { $AssignmentFilters = @() } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneAssignmentFilters' -Data @($AssignmentFilters) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneAssignmentFilters' -Data @($AssignmentFilters) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneAssignmentFilters' -Data @($AssignmentFilters) -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $(($AssignmentFilters | Measure-Object).Count) assignment filters" -sev Debug } catch { diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneCompliancePolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneCompliancePolicies.ps1 index 80256d0ce92c..04ea2689982f 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneCompliancePolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneCompliancePolicies.ps1 @@ -34,10 +34,8 @@ function Set-CIPPDBCacheIntuneCompliancePolicies { if (-not $Groups) { $Groups = @() } if (-not $Policies) { $Policies = @() } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneCompliancePolicyGroups' -Data @($Groups) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneCompliancePolicyGroups' -Data @($Groups) -Count - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneDeviceCompliancePolicies' -Data @($Policies) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneDeviceCompliancePolicies' -Data @($Policies) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneCompliancePolicyGroups' -Data @($Groups) -AddCount + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneDeviceCompliancePolicies' -Data @($Policies) -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $(($Policies | Measure-Object).Count) compliance policies" -sev Debug } catch { diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntunePolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntunePolicies.ps1 index 427965a7b3a0..4acc51cee07a 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntunePolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntunePolicies.ps1 @@ -104,8 +104,7 @@ function Set-CIPPDBCacheIntunePolicies { } } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type "Intune$($PolicyType.Type)" -Data $Policies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type "Intune$($PolicyType.Type)" -Data $Policies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type "Intune$($PolicyType.Type)" -Data $Policies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($Policies.Count) $($PolicyType.Type)" -sev Debug # Fetch device statuses for compliance policies using bulk requests diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneReusableSettings.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneReusableSettings.ps1 index 77a964147403..437bcd6607db 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneReusableSettings.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneReusableSettings.ps1 @@ -29,8 +29,7 @@ function Set-CIPPDBCacheIntuneReusableSettings { $Settings = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/deviceManagement/reusablePolicySettings$SelectQuery" -tenantid $TenantFilter if (-not $Settings) { $Settings = @() } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneReusableSettings' -Data @($Settings) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneReusableSettings' -Data @($Settings) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneReusableSettings' -Data @($Settings) -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $(($Settings | Measure-Object).Count) reusable settings" -sev Debug } catch { diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneScripts.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneScripts.ps1 index 8fb780b7d4ff..1052c9505b9d 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneScripts.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheIntuneScripts.ps1 @@ -46,8 +46,7 @@ function Set-CIPPDBCacheIntuneScripts { $Groups = ($BulkResults | Where-Object { $_.id -eq 'Groups' }).body.value if (-not $Groups) { $Groups = @() } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneScriptGroups' -Data @($Groups) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneScriptGroups' -Data @($Groups) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'IntuneScriptGroups' -Data @($Groups) -AddCount $TypeMap = @{ Windows = 'IntuneWindowsScripts' @@ -75,8 +74,7 @@ function Set-CIPPDBCacheIntuneScripts { }) } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type $TypeMap[$scriptId] -Data @($Scripts) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type $TypeMap[$scriptId] -Data @($Scripts) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type $TypeMap[$scriptId] -Data @($Scripts) -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $(($Scripts | Measure-Object).Count) $scriptId scripts" -sev Debug } } catch { diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheLicenseOverview.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheLicenseOverview.ps1 index cb28201d7746..57b31b3702c1 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheLicenseOverview.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheLicenseOverview.ps1 @@ -20,8 +20,7 @@ function Set-CIPPDBCacheLicenseOverview { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching license overview' -sev Debug $LicenseOverview = Get-CIPPLicenseOverview -TenantFilter $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'LicenseOverview' -Data @($LicenseOverview) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'LicenseOverview' -Data @($LicenseOverview) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'LicenseOverview' -Data @($LicenseOverview) -AddCount $LicenseOverview = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached license overview successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMDEOnboarding.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMDEOnboarding.ps1 index 6a0db7384460..ea251b0c8ff7 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMDEOnboarding.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMDEOnboarding.ps1 @@ -37,8 +37,7 @@ function Set-CIPPDBCacheMDEOnboarding { ) } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'MDEOnboarding' -Data @($Result) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'MDEOnboarding' -Data @($Result) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'MDEOnboarding' -Data @($Result) -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached MDE onboarding status successfully' -sev Debug } catch { diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMFAState.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMFAState.ps1 index ccd489fe14ce..6b3bfa8cf340 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMFAState.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMFAState.ps1 @@ -20,8 +20,7 @@ function Set-CIPPDBCacheMFAState { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching MFA state' -sev Debug $MFAState = Get-CIPPMFAState -TenantFilter $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'MFAState' -Data @($MFAState) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'MFAState' -Data @($MFAState) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'MFAState' -Data @($MFAState) -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($MFAState.Count) MFA state records successfully" -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMailboxUsage.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMailboxUsage.ps1 index bd13f0b2da02..1488af0eda4c 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMailboxUsage.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheMailboxUsage.ps1 @@ -20,8 +20,7 @@ function Set-CIPPDBCacheMailboxUsage { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching mailbox usage' -sev Debug $MailboxUsage = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getMailboxUsageDetail(period='D7')?`$format=application%2fjson" -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'MailboxUsage' -Data $MailboxUsage - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'MailboxUsage' -Data $MailboxUsage -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'MailboxUsage' -Data $MailboxUsage -AddCount $MailboxUsage = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached mailbox usage successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheManagedDeviceEncryptionStates.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheManagedDeviceEncryptionStates.ps1 index 7dd8764854ff..23f28f1f673e 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheManagedDeviceEncryptionStates.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheManagedDeviceEncryptionStates.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheManagedDeviceEncryptionStates { $ManagedDeviceEncryptionStates = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/managedDeviceEncryptionStates?$top=999' -tenantid $TenantFilter if ($ManagedDeviceEncryptionStates) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ManagedDeviceEncryptionStates' -Data $ManagedDeviceEncryptionStates - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ManagedDeviceEncryptionStates' -Data $ManagedDeviceEncryptionStates -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ManagedDeviceEncryptionStates' -Data $ManagedDeviceEncryptionStates -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($ManagedDeviceEncryptionStates.Count) managed device encryption states" -sev Debug } $ManagedDeviceEncryptionStates = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheManagedDevices.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheManagedDevices.ps1 index 5190fd72c24f..5c462e1d91e3 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheManagedDevices.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheManagedDevices.ps1 @@ -20,8 +20,7 @@ function Set-CIPPDBCacheManagedDevices { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching managed devices' -sev Debug $ManagedDevices = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/deviceManagement/managedDevices?$top=999' -tenantid $TenantFilter if (!$ManagedDevices) { $ManagedDevices = @() } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ManagedDevices' -Data $ManagedDevices - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ManagedDevices' -Data $ManagedDevices -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ManagedDevices' -Data $ManagedDevices -AddCount $ManagedDevices = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached managed devices successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOAuth2PermissionGrants.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOAuth2PermissionGrants.ps1 index 6fe33e93d378..404d7c7189ad 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOAuth2PermissionGrants.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOAuth2PermissionGrants.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheOAuth2PermissionGrants { $OAuth2PermissionGrants = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/oauth2PermissionGrants?$top=999' -tenantid $TenantFilter if ($OAuth2PermissionGrants) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OAuth2PermissionGrants' -Data $OAuth2PermissionGrants - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OAuth2PermissionGrants' -Data $OAuth2PermissionGrants -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OAuth2PermissionGrants' -Data $OAuth2PermissionGrants -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($OAuth2PermissionGrants.Count) OAuth2 permission grants" -sev Debug } $OAuth2PermissionGrants = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOfficeActivations.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOfficeActivations.ps1 index 208b4ce0261b..272f1fc317d6 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOfficeActivations.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOfficeActivations.ps1 @@ -20,8 +20,7 @@ function Set-CIPPDBCacheOfficeActivations { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching Office activations' -sev Debug $Activations = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/reports/getOffice365ActivationsUserDetail?`$format=application%2fjson" -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OfficeActivations' -Data $Activations - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OfficeActivations' -Data $Activations -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OfficeActivations' -Data $Activations -AddCount $Activations = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached Office activations successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOneDriveUsage.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOneDriveUsage.ps1 index 4dedf324a0c2..2000025ebd5d 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOneDriveUsage.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOneDriveUsage.ps1 @@ -56,11 +56,9 @@ function Set-CIPPDBCacheOneDriveUsage { }) } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OneDriveSiteListing' -Data @($OneDriveListing) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OneDriveSiteListing' -Data @($OneDriveListing) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OneDriveSiteListing' -Data @($OneDriveListing) -AddCount - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OneDriveUsage' -Data @($OneDriveUsage) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OneDriveUsage' -Data @($OneDriveUsage) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OneDriveUsage' -Data @($OneDriveUsage) -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached OneDrive site listing and usage successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOrganization.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOrganization.ps1 index a5e8607ab14f..80b4dea03bf4 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOrganization.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOrganization.ps1 @@ -20,8 +20,7 @@ function Set-CIPPDBCacheOrganization { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching organization data' -sev Debug $Organization = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/organization' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Organization' -Data $Organization - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Organization' -Data $Organization -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Organization' -Data $Organization -AddCount $Organization = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached organization data successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOwaMailboxPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOwaMailboxPolicy.ps1 index 6bb55b05780f..b29ad6bfa0e9 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOwaMailboxPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheOwaMailboxPolicy.ps1 @@ -28,8 +28,7 @@ function Set-CIPPDBCacheOwaMailboxPolicy { $OwaMailboxPolicies = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Get-OwaMailboxPolicy' if ($OwaMailboxPolicies) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OwaMailboxPolicy' -Data $OwaMailboxPolicies - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OwaMailboxPolicy' -Data $OwaMailboxPolicies -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'OwaMailboxPolicy' -Data $OwaMailboxPolicies -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($OwaMailboxPolicies.Count) OWA Mailbox Policies" -sev Debug } $OwaMailboxPolicies = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCachePIMSettings.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCachePIMSettings.ps1 index d5da952cec5c..01057595b165 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCachePIMSettings.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCachePIMSettings.ps1 @@ -30,8 +30,7 @@ function Set-CIPPDBCachePIMSettings { $PIMRoleSettings = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/roleManagementPolicyAssignments?$top=999' -tenantid $TenantFilter if ($PIMRoleSettings) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'PIMRoleSettings' -Data $PIMRoleSettings - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'PIMRoleSettings' -Data $PIMRoleSettings -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'PIMRoleSettings' -Data $PIMRoleSettings -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($PIMRoleSettings.Count) PIM role settings" -sev Debug } $PIMRoleSettings = $null @@ -43,8 +42,7 @@ function Set-CIPPDBCachePIMSettings { $PIMAssignments = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/roleManagement/directory/roleEligibilityScheduleInstances?$top=999' -tenantid $TenantFilter if ($PIMAssignments) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'PIMAssignments' -Data $PIMAssignments - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'PIMAssignments' -Data $PIMAssignments -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'PIMAssignments' -Data $PIMAssignments -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($PIMAssignments.Count) PIM assignments" -sev Debug } $PIMAssignments = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheReportSubmissionPolicy.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheReportSubmissionPolicy.ps1 index b3de00a9591b..fb0e24beae0c 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheReportSubmissionPolicy.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheReportSubmissionPolicy.ps1 @@ -28,8 +28,7 @@ function Set-CIPPDBCacheReportSubmissionPolicy { if ($ReportSubmissionPolicies) { $Data = @($ReportSubmissionPolicies) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ReportSubmissionPolicy' -Data $Data - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ReportSubmissionPolicy' -Data $Data -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ReportSubmissionPolicy' -Data $Data -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($Data.Count) Report Submission Policies" -sev Debug } $ReportSubmissionPolicies = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskDetections.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskDetections.ps1 index f7878e2f9edb..6abdfd46ff95 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskDetections.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskDetections.ps1 @@ -23,8 +23,7 @@ function Set-CIPPDBCacheRiskDetections { $RiskDetections = New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/identityProtection/riskDetections' -tenantid $TenantFilter if ($RiskDetections) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RiskDetections' -Data $RiskDetections - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RiskDetections' -Data $RiskDetections -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RiskDetections' -Data $RiskDetections -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($RiskDetections.Count) risk detections successfully" -sev Debug } else { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'No risk detections found or Identity Protection not available' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskyServicePrincipals.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskyServicePrincipals.ps1 index 4efcfce693a1..921208f6fff3 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskyServicePrincipals.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskyServicePrincipals.ps1 @@ -23,8 +23,7 @@ function Set-CIPPDBCacheRiskyServicePrincipals { $RiskyServicePrincipals = New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/identityProtection/riskyServicePrincipals' -tenantid $TenantFilter if ($RiskyServicePrincipals) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RiskyServicePrincipals' -Data $RiskyServicePrincipals - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RiskyServicePrincipals' -Data $RiskyServicePrincipals -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RiskyServicePrincipals' -Data $RiskyServicePrincipals -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($RiskyServicePrincipals.Count) risky service principals successfully" -sev Debug } else { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'No risky service principals found or Workload Identity Protection not available' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskyUsers.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskyUsers.ps1 index 6e29032f0b03..7e47e3b66ba5 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskyUsers.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRiskyUsers.ps1 @@ -23,8 +23,7 @@ function Set-CIPPDBCacheRiskyUsers { $RiskyUsers = New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/identityProtection/riskyUsers' -tenantid $TenantFilter if ($RiskyUsers) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RiskyUsers' -Data $RiskyUsers - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RiskyUsers' -Data $RiskyUsers -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RiskyUsers' -Data $RiskyUsers -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($RiskyUsers.Count) risky users successfully" -sev Debug } else { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'No risky users found or Identity Protection not available' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoleAssignmentScheduleInstances.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoleAssignmentScheduleInstances.ps1 index aa2b914bf794..04b802332c70 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoleAssignmentScheduleInstances.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoleAssignmentScheduleInstances.ps1 @@ -19,8 +19,7 @@ function Set-CIPPDBCacheRoleAssignmentScheduleInstances { try { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching role assignment schedule instances' -sev Debug $RoleAssignmentScheduleInstances = New-GraphGetRequest -Uri 'https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignmentScheduleInstances' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RoleAssignmentScheduleInstances' -Data @($RoleAssignmentScheduleInstances) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RoleAssignmentScheduleInstances' -Data @($RoleAssignmentScheduleInstances) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RoleAssignmentScheduleInstances' -Data @($RoleAssignmentScheduleInstances) -AddCount $RoleAssignmentScheduleInstances = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached role assignment schedule instances successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoleEligibilitySchedules.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoleEligibilitySchedules.ps1 index 1bcffb691b27..3a3b4208ced5 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoleEligibilitySchedules.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoleEligibilitySchedules.ps1 @@ -19,8 +19,7 @@ function Set-CIPPDBCacheRoleEligibilitySchedules { try { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching role eligibility schedules' -sev Debug $RoleEligibilitySchedules = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/roleManagement/directory/roleEligibilitySchedules' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RoleEligibilitySchedules' -Data @($RoleEligibilitySchedules) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RoleEligibilitySchedules' -Data @($RoleEligibilitySchedules) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RoleEligibilitySchedules' -Data @($RoleEligibilitySchedules) -AddCount $RoleEligibilitySchedules = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached role eligibility schedules successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoleManagementPolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoleManagementPolicies.ps1 index 23c7b5fe5ff8..6d88d55f0259 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoleManagementPolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoleManagementPolicies.ps1 @@ -19,8 +19,7 @@ function Set-CIPPDBCacheRoleManagementPolicies { try { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching role management policies' -sev Debug $RoleManagementPolicies = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/roleManagementPolicies' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RoleManagementPolicies' -Data @($RoleManagementPolicies) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RoleManagementPolicies' -Data @($RoleManagementPolicies) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'RoleManagementPolicies' -Data @($RoleManagementPolicies) -AddCount $RoleManagementPolicies = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached role management policies successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoles.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoles.ps1 index bcc10c993b20..3668cdaf18f6 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoles.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheRoles.ps1 @@ -49,13 +49,11 @@ function Set-CIPPDBCacheRoles { } } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Roles' -Data $RolesWithMembers - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Roles' -Data $RolesWithMembers -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Roles' -Data $RolesWithMembers -AddCount $Roles = $null $RolesWithMembers = $null } else { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Roles' -Data $Roles - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Roles' -Data $Roles -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Roles' -Data $Roles -AddCount $Roles = $null } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSPOTenant.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSPOTenant.ps1 index 3181f7399c60..0fcd2cd9f808 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSPOTenant.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSPOTenant.ps1 @@ -30,8 +30,7 @@ function Set-CIPPDBCacheSPOTenant { if ($SPOTenant) { $SPOTenantArray = @($SPOTenant) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SPOTenant' -Data $SPOTenantArray - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SPOTenant' -Data $SPOTenantArray -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SPOTenant' -Data $SPOTenantArray -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached SharePoint Online tenant configuration' -sev Debug } $SPOTenant = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSPOTenantSyncClientRestriction.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSPOTenantSyncClientRestriction.ps1 index 1c74c5c3fa3f..65b6b242fa9b 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSPOTenantSyncClientRestriction.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSPOTenantSyncClientRestriction.ps1 @@ -39,8 +39,7 @@ function Set-CIPPDBCacheSPOTenantSyncClientRestriction { TenantFilter = $TenantFilter } $Data = @($SyncRestriction) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SPOTenantSyncClientRestriction' -Data $Data - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SPOTenantSyncClientRestriction' -Data $Data -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SPOTenantSyncClientRestriction' -Data $Data -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached SharePoint sync client restriction' -sev Debug } $SPOTenant = $null diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSensitivityLabels.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSensitivityLabels.ps1 index b9d89242742a..307bc5e87913 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSensitivityLabels.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSensitivityLabels.ps1 @@ -29,8 +29,7 @@ function Set-CIPPDBCacheSensitivityLabels { $Labels = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/security/informationProtection/sensitivityLabels' -tenantid $TenantFilter -AsApp $true if ($Labels) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SensitivityLabels' -Data $Labels - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SensitivityLabels' -Data $Labels -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SensitivityLabels' -Data $Labels -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($Labels.Count) sensitivity labels" -sev Debug } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheServicePrincipalRiskDetections.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheServicePrincipalRiskDetections.ps1 index bcd4cfba838e..892e19511701 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheServicePrincipalRiskDetections.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheServicePrincipalRiskDetections.ps1 @@ -23,8 +23,7 @@ function Set-CIPPDBCacheServicePrincipalRiskDetections { $ServicePrincipalRiskDetections = New-GraphGetRequest -uri 'https://graph.microsoft.com/v1.0/identityProtection/servicePrincipalRiskDetections' -tenantid $TenantFilter if ($ServicePrincipalRiskDetections) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ServicePrincipalRiskDetections' -Data $ServicePrincipalRiskDetections - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ServicePrincipalRiskDetections' -Data $ServicePrincipalRiskDetections -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ServicePrincipalRiskDetections' -Data $ServicePrincipalRiskDetections -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($ServicePrincipalRiskDetections.Count) service principal risk detections successfully" -sev Debug } else { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'No service principal risk detections found or Workload Identity Protection not available' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheServicePrincipals.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheServicePrincipals.ps1 index af887bf31342..166b6cac7fd6 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheServicePrincipals.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheServicePrincipals.ps1 @@ -20,8 +20,7 @@ function Set-CIPPDBCacheServicePrincipals { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Caching service principals' -sev Debug $ServicePrincipals = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/servicePrincipals' -tenantid $TenantFilter - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ServicePrincipals' -Data $ServicePrincipals - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ServicePrincipals' -Data $ServicePrincipals -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'ServicePrincipals' -Data $ServicePrincipals -AddCount $ServicePrincipals = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached service principals successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSettings.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSettings.ps1 index d1951058c3d2..ce2c02bfa7de 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSettings.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSettings.ps1 @@ -21,8 +21,7 @@ function Set-CIPPDBCacheSettings { $Settings = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/settings?$top=999' -tenantid $TenantFilter if (!$Settings) { $Settings = @() } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Settings' -Data $Settings - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Settings' -Data $Settings -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Settings' -Data $Settings -AddCount $Settings = $null Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached directory settings successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSharePointSiteUsage.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSharePointSiteUsage.ps1 index 5722f962b7a0..561a01721236 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSharePointSiteUsage.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheSharePointSiteUsage.ps1 @@ -90,11 +90,9 @@ function Set-CIPPDBCacheSharePointSiteUsage { $Site.AutoMapUrl = "tenantId=$($TenantId)&webId={$($Site.sharepointIds.webId)}&siteid={$($Site.sharepointIds.siteId)}&webUrl=$($Site.webUrl)&listId={$($ListId)}" } - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SharePointSiteListing' -Data @($SiteListing) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SharePointSiteListing' -Data @($SiteListing) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SharePointSiteListing' -Data @($SiteListing) -AddCount - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SharePointSiteUsage' -Data @($UsageRows) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SharePointSiteUsage' -Data @($UsageRows) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SharePointSiteUsage' -Data @($UsageRows) -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached SharePoint site listing and usage successfully' -sev Debug diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeams.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeams.ps1 index ac91707e2cbc..3e0a1e5d69ac 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeams.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeams.ps1 @@ -12,8 +12,7 @@ function Set-CIPPDBCacheTeams { $Teams = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups?`$filter=resourceProvisioningOptions/Any(x:x eq 'Team')&`$select=id,displayName,description,visibility,mailNickname" -tenantid $TenantFilter | Sort-Object -Property displayName - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Teams' -Data @($Teams) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Teams' -Data @($Teams) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'Teams' -Data @($Teams) -AddCount } catch { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Failed to cache Teams list: $($_.Exception.Message)" -sev Error -LogData (Get-CippException -Exception $_) } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeamsActivity.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeamsActivity.ps1 index a8482de6c30f..1ecb5d42b00b 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeamsActivity.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeamsActivity.ps1 @@ -18,8 +18,7 @@ function Set-CIPPDBCacheTeamsActivity { @{ Name = 'MeetingCount'; Expression = { $_.'Meeting Count' } } $DbType = "TeamsActivity$Type" - Add-CIPPDbItem -TenantFilter $TenantFilter -Type $DbType -Data @($TeamsActivity) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type $DbType -Data @($TeamsActivity) -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type $DbType -Data @($TeamsActivity) -AddCount } catch { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Failed to cache Teams activity: $($_.Exception.Message)" -sev Error -LogData (Get-CippException -Exception $_) } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeamsVoice.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeamsVoice.ps1 index edc41533d438..37b9be41b2a8 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeamsVoice.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheTeamsVoice.ps1 @@ -37,8 +37,7 @@ function Set-CIPPDBCacheTeamsVoice { } while ($Data.Count -eq 999) $PhoneNumbers = @($AllNumbers | Where-Object { $_.TelephoneNumber }) - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'TeamsVoice' -Data $PhoneNumbers - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'TeamsVoice' -Data $PhoneNumbers -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'TeamsVoice' -Data $PhoneNumbers -AddCount } catch { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Failed to cache Teams Voice phone numbers: $($_.Exception.Message)" -sev Error -LogData (Get-CippException -Exception $_) } diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheUserRegistrationDetails.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheUserRegistrationDetails.ps1 index 64e596f669c9..121f6d62a17b 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheUserRegistrationDetails.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheUserRegistrationDetails.ps1 @@ -22,8 +22,7 @@ function Set-CIPPDBCacheUserRegistrationDetails { $UserRegistrationDetails = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/reports/authenticationMethods/userRegistrationDetails' -tenantid $TenantFilter if ($UserRegistrationDetails) { - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'UserRegistrationDetails' -Data $UserRegistrationDetails - Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'UserRegistrationDetails' -Data $UserRegistrationDetails -Count + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'UserRegistrationDetails' -Data $UserRegistrationDetails -AddCount Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached $($UserRegistrationDetails.Count) user registration details" -sev Debug } $UserRegistrationDetails = $null From e3e82cd95b9597706f1edc3ccde5776695abe820 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Tue, 19 May 2026 07:51:16 -0400 Subject: [PATCH 35/38] Cache Security Defaults --- Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 | 37 +++++++++++++------ ...t-CIPPDBCacheConditionalAccessPolicies.ps1 | 10 +++++ ...-CIPPStandardConditionalAccessTemplate.ps1 | 24 ++++++------ 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 index bed989dc48dc..478bd5e79bf9 100644 --- a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 @@ -12,7 +12,8 @@ function New-CIPPCAPolicy { $APIName = 'Create CA Policy', $Headers, $PreloadedCAPolicies = $null, - $PreloadedLocations = $null + $PreloadedLocations = $null, + $PreloadedSecurityDefaults = $null ) # Helper function to replace group display names with GUIDs @@ -490,16 +491,30 @@ function New-CIPPCAPolicy { } } if ($DisableSD -eq $true) { - #Send request to disable security defaults. - $body = '{ "isEnabled": false }' - try { - $null = New-GraphPostRequest -tenantid $TenantFilter -Uri 'https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy' -Type patch -Body $body -asApp $true - Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message "Disabled Security Defaults for tenant $($TenantFilter)" -Sev 'Info' - Start-Sleep 3 - } catch { - $ErrorMessage = Get-CippException -Exception $_ - Write-Information "Error disabling security defaults: $($ErrorMessage | ConvertTo-Json -Depth 10 -Compress)" - Write-Information "Failed to disable security defaults for tenant $($TenantFilter): $($ErrorMessage.NormalizedError)" + # Check if Security Defaults is already disabled using preloaded or live data + $SDPolicy = $PreloadedSecurityDefaults + if ($null -eq $SDPolicy) { + try { + $SDPolicy = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy' -tenantid $TenantFilter -AsApp $true + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-Information "Error fetching Security Defaults status: $($ErrorMessage | ConvertTo-Json -Depth 10 -Compress)" + } + } + + if ($SDPolicy.isEnabled -eq $false) { + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message 'Security Defaults already disabled, skipping.' -Sev 'Info' + } else { + $body = '{ "isEnabled": false }' + try { + $null = New-GraphPostRequest -tenantid $TenantFilter -Uri 'https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy' -Type patch -Body $body -asApp $true + Write-LogMessage -Headers $Headers -API $APIName -tenant $TenantFilter -message "Disabled Security Defaults for tenant $($TenantFilter)" -Sev 'Info' + Start-Sleep 3 + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-Information "Error disabling security defaults: $($ErrorMessage | ConvertTo-Json -Depth 10 -Compress)" + Write-Information "Failed to disable security defaults for tenant $($TenantFilter): $($ErrorMessage.NormalizedError)" + } } } $RawJSON = ConvertTo-Json -InputObject $JSONobj -Depth 10 -Compress diff --git a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 index a4407e0b82d3..7e11accd8824 100644 --- a/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 +++ b/Modules/CIPPDB/Public/DBCache/Set-CIPPDBCacheConditionalAccessPolicies.ps1 @@ -61,6 +61,16 @@ function Set-CIPPDBCacheConditionalAccessPolicies { Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Failed to cache authentication strengths: $($_.Exception.Message)" -sev Warning } + try { + $SecurityDefaults = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy' -tenantid $TenantFilter -AsApp $true + if ($SecurityDefaults) { + Add-CIPPDbItem -TenantFilter $TenantFilter -Type 'SecurityDefaults' -Data @($SecurityDefaults) + Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Cached Security Defaults policy (isEnabled=$($SecurityDefaults.isEnabled))" -sev Debug + } + } catch { + Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message "Failed to cache Security Defaults: $($_.Exception.Message)" -sev Warning + } + Write-LogMessage -API 'CIPPDBCache' -tenant $TenantFilter -message 'Cached CA data successfully' -sev Debug } catch { diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 index 4d5c8447da02..549396edce9b 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 @@ -60,6 +60,7 @@ function Invoke-CIPPStandardConditionalAccessTemplate { #Get from DB, as we just downloaded the latest before the standard runs. $AllCAPolicies = New-CIPPDbRequest -TenantFilter $tenant -Type 'ConditionalAccessPolicies' $PreloadedLocations = New-CIPPDbRequest -TenantFilter $tenant -Type 'NamedLocations' + $PreloadedSecurityDefaults = New-CIPPDbRequest -TenantFilter $tenant -Type 'SecurityDefaults' } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Could not get the ConditionalAccessTemplate state for $Tenant. Error: $ErrorMessage" -Sev Error @@ -80,17 +81,18 @@ function Invoke-CIPPStandardConditionalAccessTemplate { } } $NewCAPolicy = @{ - replacePattern = 'displayName' - TenantFilter = $Tenant - state = $Settings.state - RawJSON = $JSONObj - Overwrite = $true - APIName = 'Standards' - Headers = $Request.Headers - DisableSD = $Settings.DisableSD - CreateGroups = $Settings.CreateGroups ?? $false - PreloadedCAPolicies = $AllCAPolicies - PreloadedLocations = $PreloadedLocations + replacePattern = 'displayName' + TenantFilter = $Tenant + state = $Settings.state + RawJSON = $JSONObj + Overwrite = $true + APIName = 'Standards' + Headers = $Request.Headers + DisableSD = $Settings.DisableSD + CreateGroups = $Settings.CreateGroups ?? $false + PreloadedCAPolicies = $AllCAPolicies + PreloadedLocations = $PreloadedLocations + PreloadedSecurityDefaults = $PreloadedSecurityDefaults } $null = New-CIPPCAPolicy @NewCAPolicy From 9ba48711c614be8e2452ffff2e539b5b1a11b534 Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Tue, 19 May 2026 10:01:24 -0400 Subject: [PATCH 36/38] correct incorrect default value --- Config/standards.json | 2 +- .../Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/standards.json b/Config/standards.json index 6230b383dab5..ce9752a56d19 100644 --- a/Config/standards.json +++ b/Config/standards.json @@ -3746,7 +3746,7 @@ "type": "number", "name": "standards.IntuneComplianceSettings.deviceComplianceCheckinThresholdDays", "label": "Compliance status validity period (days)", - "defaultValue": 130, + "defaultValue": 120, "validators": { "min": { "value": 1, "message": "Minimum value is 1" }, "max": { "value": 120, "message": "Maximum value is 120" } diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 index 8baa105848d6..ebd612ffac70 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardIntuneComplianceSettings.ps1 @@ -17,7 +17,7 @@ function Invoke-CIPPStandardIntuneComplianceSettings { Configures how the system treats devices that don't have specific compliance policies and sets how often devices must check in to maintain their compliance status. This ensures proper security oversight of all corporate devices and maintains current compliance information. ADDEDCOMPONENT {"type":"autoComplete","required":true,"multiple":false,"creatable":false,"name":"standards.IntuneComplianceSettings.secureByDefault","label":"Mark devices with no compliance policy as","options":[{"label":"Compliant","value":"false"},{"label":"Non-Compliant","value":"true"}]} - {"type":"number","name":"standards.IntuneComplianceSettings.deviceComplianceCheckinThresholdDays","label":"Compliance status validity period (days)","defaultValue":130,"validators":{"min":{"value":1,"message":"Minimum value is 1"},"max":{"value":120,"message":"Maximum value is 120"}}} + {"type":"number","name":"standards.IntuneComplianceSettings.deviceComplianceCheckinThresholdDays","label":"Compliance status validity period (days)","defaultValue":120,"validators":{"min":{"value":1,"message":"Minimum value is 1"},"max":{"value":120,"message":"Maximum value is 120"}}} IMPACT Low Impact ADDEDDATE From 73f83719d8d6123db9e450248f55dc97acfdc0ea Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Tue, 19 May 2026 10:01:41 -0400 Subject: [PATCH 37/38] add logging to geoip lookip --- Modules/CIPPCore/Public/Get-CIPPGeoIPLocation.ps1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Get-CIPPGeoIPLocation.ps1 b/Modules/CIPPCore/Public/Get-CIPPGeoIPLocation.ps1 index 754454529e3d..b6eaabf73f71 100644 --- a/Modules/CIPPCore/Public/Get-CIPPGeoIPLocation.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPGeoIPLocation.ps1 @@ -12,7 +12,10 @@ function Get-CIPPGeoIPLocation { return ($GeoIP.Data | ConvertFrom-Json) } $location = Invoke-CIPPRestMethod -Uri "https://geoipdb.azurewebsites.net/api/GetIPInfo?IP=$IP" - if ($location.status -eq 'FAIL') { throw "Could not get location for $IP" } + if ($location.status -eq 'FAIL') { + Write-logMessage -API GeoIPLocation -message "Failed to get location for $IP. API returned status 'FAIL' with message: $($location.message)" -sev Warning + throw "Could not get location for $IP" + } $CacheGeo = @{ PartitionKey = 'IP' RowKey = $IP From cfa144d6b00b6641720c18bde34537227965a7fd Mon Sep 17 00:00:00 2001 From: Zacgoose <107489668+Zacgoose@users.noreply.github.com> Date: Fri, 22 May 2026 12:51:10 -0400 Subject: [PATCH 38/38] Update Invoke-ListWorkerHealth.ps1 --- .../CIPP/Settings/Invoke-ListWorkerHealth.ps1 | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListWorkerHealth.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListWorkerHealth.ps1 index 66862547597b..f1753f41d93b 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListWorkerHealth.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListWorkerHealth.ps1 @@ -26,6 +26,24 @@ function Invoke-ListWorkerHealth { $Pool = [Craft.Services.WorkerMetricsBridge]::GetPoolMetrics($PoolType) $Body = @{ Results = $Pool } } + 'History' { + $Minutes = if ($Request.Query.Minutes) { [int]$Request.Query.Minutes } else { 60 } + $MaxPoints = if ($Request.Query.MaxPoints) { [int]$Request.Query.MaxPoints } else { $null } + $History = [Craft.Services.StatsHistoryBridge]::GetHistory($Minutes, $MaxPoints) + $Count = [Craft.Services.StatsHistoryBridge]::GetCount() + $Body = @{ + Results = @{ + TotalPoints = $Count + ReturnedPoints = $History.Count + RangeMinutes = $Minutes + Data = $History + } + } + } + 'Startup' { + $StartupInfo = [Craft.Services.StartupInfoBridge]::GetInfo() + $Body = @{ Results = $StartupInfo } + } 'Jobs' { $RunName = $Request.Query.RunName $Status = $Request.Query.Status