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 113a6bbaadb8..7363a4f936f9 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/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 61a49d453458..35c51a44e865 100644 --- a/Config/FeatureFlags.json +++ b/Config/FeatureFlags.json @@ -19,6 +19,31 @@ "/tenant/standards/bpa-report", "/tenant/standards/bpa-report/builder", "/tenant/standards/bpa-report/view" - ] + ], + "Hidden": false + }, + { + "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", + "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/worker-health" + ], + "Hidden": true } ] 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/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/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/Push-CIPPDBCacheData.ps1 b/Modules/CIPPActivityTriggers/Public/Entrypoints/Activity Triggers/Push-CIPPDBCacheData.ps1 index 79cae558e007..625eff841975 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/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 { 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) { 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 08c62d8d6863..e59f70ba4a02 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 @@ -249,7 +249,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/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/CIPPAlerts/Public/Alerts/Get-CIPPAlertIntunePolicyConflicts.ps1 b/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertIntunePolicyConflicts.ps1 index 071f65cff4e7..99d2fb1ad5fe 100644 --- a/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertIntunePolicyConflicts.ps1 +++ b/Modules/CIPPAlerts/Public/Alerts/Get-CIPPAlertIntunePolicyConflicts.ps1 @@ -57,14 +57,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 } 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/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 + } +} 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/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..9f618899c237 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,150 @@ 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. 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. + 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-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 { 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/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/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/Functions/Test-CIPPStandardLicense.ps1 b/Modules/CIPPCore/Public/Functions/Test-CIPPStandardLicense.ps1 index 851822afe56c..4a998a6e6a9f 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,48 @@ 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', 'DefenderForOffice365')] + [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') + 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)) { + 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 effd7c8dd5b3..a4e159bbfbce 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' # Load only IntuneTemplate partition for tag resolution and display name lookup 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/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 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 '(?" 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 } 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/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/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 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/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 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/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-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 bb516877c6c8..7e11accd8824 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 @@ -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 @@ -64,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/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 52df23f538dd..13d9a9927377 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 @@ -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 5476d515bbe9..7930ec943f18 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 @@ -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 97696ddf8b52..418d5a277852 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 @@ -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 35b802197442..8594bc640137 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 @@ -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 6edfc3d9704e..e6037b1f1061 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 @@ -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 6f0a7770b308..04ea2689982f 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 @@ -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 f770d4c37cea..4acc51cee07a 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 @@ -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 e27fe5770dc4..437bcd6607db 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 @@ -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 47a074116886..1052c9505b9d 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 @@ -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-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/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 768525f69e94..01057595b165 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 @@ -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 deafb9b25f9c..307bc5e87913 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 @@ -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 90ab81351b7a..561a01721236 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) { @@ -82,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 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/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..be842ac61a90 --- /dev/null +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecContainerManagement.ps1 @@ -0,0 +1,351 @@ +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') + $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' { + try { + $CurrentVersion = $env:APP_VERSION ?? 'unknown' + $CommitSha = $env:COMMIT_SHA ?? 'unknown' + $ImageTag = $env:IMAGE_TAG ?? 'unknown' + $CurrentChannel = $ImageTag + + # Read the full container image reference from ARM + $CurrentImage = 'unknown' + $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/$($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 ($CurrentImage -match ':([^:]+)$') { + $ConfiguredChannel = $Matches[1] + } + } + } catch { + Write-Information "Could not read container config from ARM: $_" + } + } + + # 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 + CurrentImage = $CurrentImage + SiteName = $site.SiteName + ValidChannels = $ValidChannels + UpdateSettings = $UpdateInfo + } + } + } 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)" } + } + } + } + '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 + if ([string]::IsNullOrWhiteSpace($NewChannel)) { + throw 'Channel is required' + } + if ($NewChannel -notin $ValidChannels) { + throw "Invalid channel: $NewChannel. Valid channels: $($ValidChannels -join ', ')" + } + + $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' + $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?' + } + + $currentImage = $currentLinuxFx -replace '^DOCKER\|', '' + if ($currentImage -match '^(.+):([^:]+)$') { + $imageBase = $Matches[1] + $newLinuxFx = "DOCKER|${imageBase}:${NewChannel}" + } else { + $newLinuxFx = "DOCKER|${currentImage}:${NewChannel}" + } + + $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 + $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.' } + 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, CheckUpdate, SaveUpdateSettings, 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/Settings/Invoke-ListContainerLogs.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListContainerLogs.ps1 new file mode 100644 index 000000000000..a98c001c05b8 --- /dev/null +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListContainerLogs.ps1 @@ -0,0 +1,300 @@ +function Invoke-ListContainerLogs { + <# + .FUNCTIONALITY + Entrypoint,AnyTenant + .ROLE + CIPP.SuperAdmin.Read + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $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' { + $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 + $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() } + + $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, $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() } + + $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, $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' { + $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 + } +} 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/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 + } +} 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..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 @@ -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 'usage' -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 {} } 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/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 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 = @{ 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 } 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 + } +} 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 } 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 } + } +} diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1 index a802210209ea..647323917e74 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 4280118eb153..855f555caf19 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 48382dd29d15..e6de258ac65a 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 f868752f4f53..4e63aaaa7d95 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 94a87652da86..e89461cf1430 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAtpPolicyForO365.ps1 @@ -40,14 +40,14 @@ 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) { 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-CIPPStandardAuditLog.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAuditLog.ps1 index f36021febb7b..81e089878460 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-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-CIPPStandardAutoArchive.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardAutoArchive.ps1 index 703363e49f57..55830e0b5179 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 5953686c5793..662d28b3d0b8 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 dc59e3dc4bac..111b785dc0da 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 4c70f0a60951..f8f1e723eef5 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/alignment/templates/available-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 d141d5a8f3c2..f6e6e73dd123 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/alignment/templates/available-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 16b2ae4abd0d..9173dd91b51d 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 2a3be6f4fe6b..fc1c34e5be27 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 5c45a2da45a5..0d2b67f55a5a 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 da1bfd5178e5..34ca096ac19a 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 f62298b0a57d..549396edce9b 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardConditionalAccessTemplate.ps1 @@ -48,7 +48,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 @@ -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 @@ -72,7 +73,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 @@ -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 @@ -113,7 +115,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 7ccc99824d66..427bff282481 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 e1bfe0fd8f14..1299880d7ed3 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 66d6b1d5e393..7a82cb1e947a 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 b7a757b2e5a2..35b7259a707e 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 c54beb8ba6bc..bf21fb3ff637 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 413c5b6f9594..01469ff25668 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployCheckChromeExtension.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployCheckChromeExtension.ps1 @@ -64,7 +64,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 @@ -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' } ) diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployContactTemplates.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDeployContactTemplates.ps1 index f346b1487141..3290eeacc133 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 8dc54cd98995..a6ddad102a4d 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 c8db2e7c65a7..45e9517e989b 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 897e873c457a..1bb71fa818d1 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 bee985a717b8..64c39c224c69 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 a0bbb6de3d3c..27d90969379c 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 f069cb8a5b66..e19319160827 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 @@ -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 } } } } diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardDisableExternalCalendarSharing.ps1 index a238e9444f9b..dc3ecc0b6e28 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 c5388256bd53..aaecff145875 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 1de0b8efe605..43f21d705d6b 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 cb9dcaac9a24..6038fd170770 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 d526a2799051..3822b3087fa9 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 1935547c5908..041c7e215e25 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 ffe16e224402..2a14009825a0 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 8777d4739cc3..66b8ef6c8cac 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 70c46d6ccfcc..979bef30ca9e 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-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 diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 index 95d5cd6c97c5..17e24bef9696 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 5be60254dc55..aa9380da7d0f 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-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-CIPPStandardEnableExchangeCloudManagement.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnableExchangeCloudManagement.ps1 index 157fab38e93b..da1af84b41ac 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 18ed72de321f..ca507e5c4ada 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 8e466a01bd21..8b7e8b2c958a 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 e860f83158b6..9f34f19c89e0 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 f636c6ddc721..be62e135c6dd 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-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-CIPPStandardEnrollmentWindowsHelloForBusinessConfiguration.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardEnrollmentWindowsHelloForBusinessConfiguration.ps1 index 6aeef7791f42..b3328394d715 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 c987dbce8c8c..5656ab3f1bd5 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/alignment/templates/available-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 8122d47ef442..04bf7499b5e7 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-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-CIPPStandardFocusedInbox.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardFocusedInbox.ps1 index 8e57cd541f97..823750b3ef0e 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 3ac6a729e2cd..de4176e64cf1 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/alignment/templates/available-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 a246bdcc200d..2785b1fe9443 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/alignment/templates/available-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 4c7e40d2deb3..de45554c3c5b 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 df487937539a..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 @@ -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 92d909ca3405..1d1c05158750 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 30069fbb830a..db17a2f05cc0 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 5098f8c1f676..01d9c241122b 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 e3978dd418c4..f60b86449f21 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 ce7fbc2faada..3d2e2ce054f2 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 ad43bb3ffe43..1bc199ba4537 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 ab7195227d0e..558d01163e2f 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 ce0edb82308d..89d81c020bbe 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 39cb11965a5d..e7879f4e62ad 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-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 diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardPhishProtection.ps1 index 68f947447a7f..97e4306f878b 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 b7ff79e0be4b..2725af0a918a 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 a7d16f46532e..2cd299511211 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 a009e8f0acd1..8d7b5def8487 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 eeed05571d08..6bf45cd7ee53 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 ff20224468dd..d0c0d0213682 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 573a5ab8c48d..bb2db7e31eaa 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 b7b73b6042ea..aa9ede0c285b 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 4cec77dcda3e..c03242b0d0c7 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 ff8ffa317e8c..f2bf28002dee 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 9c824d9996a1..334029b39daa 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 9da12268a0ba..a138b2efec37 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 7f5dfac5b923..805453d49c0d 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 0945cf6e4047..49c13f27f511 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/alignment/templates/available-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 ae770fa8b793..0339550bcad7 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 d83e676965ca..92b624ffb2bd 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 f989f5451ada..ade01fe5781a 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 b6e9c3d2fd4a..90ca95ac03f8 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 24f821847e2d..78a90454f745 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 4b08283dac8d..694770223d2f 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 ac5ab95dbff1..61b515a26761 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeAttachmentPolicy.ps1 @@ -47,13 +47,13 @@ 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 } #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 742704fe886f..3e10dc15f1d8 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 @@ -61,13 +61,13 @@ 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 } #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 0f0f703d6724..475de0053c67 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 @@ -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. diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeSendersDisable.ps1 index afbc4d0ee03d..de271d07ab10 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 c5c269dcb31e..d6fd2c15157f 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 f10fc0222928..0443552cd728 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 fe1d4b98cade..c9f1b96850cd 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 02de560f8713..f01a369d3406 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 @@ -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,10 +157,11 @@ 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 + ($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") diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSpoofWarn.ps1 index 39d6ca1865b2..ff57beeb65a1 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 b48b48fc2fc3..3ad06b586dea 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 826f5e5a26b4..93eccf035e10 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 d3bc8653f835..fe913f850dac 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 000c47e283ba..3748d8d67a03 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 4055445346a6..a6014c5fec2a 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 11e974546851..f4772514fb92 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 f267e5f63c62..1d29eb41f6fa 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 8e6f9036ff5a..4bebc295e2ee 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 382a2216e988..64f368e07dbc 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/alignment/templates/available-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 53a8c8a33f71..082638fd09fd 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 3e17c4090870..d1ae1626cafb 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 30118bed5e2b..e13384d13c8d 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 89aa5d85e5e3..5549004d5028 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 c264233f6cb8..31a6384293c4 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-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 { diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTenantAllowBlockListTemplate.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardTenantAllowBlockListTemplate.ps1 index 2b1459c31275..5efb88b9210d 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 803b905e1ff6..ec5836391ad5 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 5a757cacccf9..4c6801d28e02 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/alignment/templates/available-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 61336c9964e2..91e88460f848 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 834f49c502b8..7c5c3d8c8e16 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 df798e9a854b..3f03cb9cad1c 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 389de7084762..6a7d9836a392 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 c0263f63f4b2..f5373e945d40 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 f99e7c48d9c6..2624bed22cdc 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 2e32e5f8cca9..ec7dd58175c8 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 e2958d7fef17..d0184eabe354 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 c0ba257ab116..33c7b9209a1b 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 bccd721bdf66..6bec4a3e9c6c 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 b48002c97a0f..23c1207c5fc4 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 6d92b2e60649..b7ff54a7e933 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']) { 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