From 019f62b7a11e6a37290fa67697dc8c1445144618 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 29 Jul 2026 09:29:08 +0000 Subject: [PATCH] Merge pull request #103 from CyberDrain/dev Dev to docs update and clean branch Synced from CyberDrain/CIPP@f15aa8452c0f435adb0e91b48cb26344ebdf684c --- Modules/CIPPCore/Public/Get-CIPPDrift.ps1 | 4 ++ .../CIPP/Core/Invoke-ExecSnoozeAlert.ps1 | 5 +++ .../CIPP/Core/Invoke-ListSnoozedAlerts.ps1 | 1 + .../Groups/Invoke-EditGroup.ps1 | 40 +++++++++++++++++++ .../Invoke-CIPPStandardSafeLinksPolicy.ps1 | 8 ++-- 5 files changed, 55 insertions(+), 3 deletions(-) diff --git a/Modules/CIPPCore/Public/Get-CIPPDrift.ps1 b/Modules/CIPPCore/Public/Get-CIPPDrift.ps1 index 48fa3e511dfaf..e04da1b423117 100644 --- a/Modules/CIPPCore/Public/Get-CIPPDrift.ps1 +++ b/Modules/CIPPCore/Public/Get-CIPPDrift.ps1 @@ -429,6 +429,10 @@ function Get-CIPPDrift { # unmanagedSync standard). They are system-managed, cannot be templated and come # back when deleted, so they are never a deviation. if (([string]$TenantCAPolicy.displayName).StartsWith('[SharePoint admin center]')) { continue } + # Microsoft-managed CA policies cannot be deleted, only disabled. Once turned off + # they are not actionable, so a disabled Microsoft-managed policy is never a + # deviation. Enabled or report-only ones still are. + if (([string]$TenantCAPolicy.displayName).StartsWith('Microsoft-managed', [System.StringComparison]::OrdinalIgnoreCase) -and $TenantCAPolicy.state -eq 'disabled') { continue } $PolicyFound = $false foreach ($TemplateCAPolicy in $TemplateCATemplates) { diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSnoozeAlert.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSnoozeAlert.ps1 index 1cc28caaf8a49..fc57f7ab116f8 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSnoozeAlert.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecSnoozeAlert.ps1 @@ -16,6 +16,7 @@ function Invoke-ExecSnoozeAlert { $TenantFilter = $Request.Body.TenantFilter $AlertItem = $Request.Body.AlertItem $Duration = [int]$Request.Body.Duration + $Reason = [string]$Request.Body.Reason $SnoozedBy = try { ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Request.Headers.'x-ms-client-principal')) | ConvertFrom-Json).userDetails } catch { 'Unknown' } @@ -56,6 +57,7 @@ function Invoke-ExecSnoozeAlert { SnoozedAt = [string]$CurrentUnixTime ContentPreview = [string]$HashResult.ContentPreview SnoozeKey = [string]$HashResult.RawKey + SnoozeReason = [string]$Reason } Add-CIPPAzDataTableEntity @SnoozeTable -Entity $SnoozeEntity -Force | Out-Null @@ -63,6 +65,9 @@ function Invoke-ExecSnoozeAlert { $DurationLabel = if ($Duration -eq -1) { 'forever' } else { "$Duration days" } $ContentPreview = $HashResult.ContentPreview $Result = "Successfully snoozed alert for ${DurationLabel}: ${ContentPreview}" + if (-not [string]::IsNullOrWhiteSpace($Reason)) { + $Result = "$Result - Reason: $Reason" + } Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Info' -tenant $TenantFilter diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListSnoozedAlerts.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListSnoozedAlerts.ps1 index 0f689058aa179..7829191267d9d 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListSnoozedAlerts.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ListSnoozedAlerts.ps1 @@ -43,6 +43,7 @@ function Invoke-ListSnoozedAlerts { Tenant = $_.Tenant ContentHash = $_.ContentHash ContentPreview = $_.ContentPreview + SnoozeReason = $_.SnoozeReason SnoozedBy = $_.SnoozedBy SnoozedAt = $_.SnoozedAt SnoozeUntil = $_.SnoozeUntil diff --git a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-EditGroup.ps1 b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-EditGroup.ps1 index 3d4ee59f05e22..f1f2db4e980e9 100644 --- a/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-EditGroup.ps1 +++ b/Modules/CIPPHTTP/Public/Entrypoints/HTTP Functions/Identity/Administration/Groups/Invoke-EditGroup.ps1 @@ -124,6 +124,46 @@ function Invoke-EditGroup { } } + $AddDevices = $UserObj.AddDevice + if ($AddDevices) { + $AddDevices | ForEach-Object { + $Device = $_ + try { + $DeviceLabel = $Device.label ?? $Device.addedFields.deviceName ?? $Device.value + if ($GroupType -eq 'Distribution List' -or $GroupType -eq 'Mail-Enabled Security') { + $Results.Add("Error - Devices cannot be added to a $GroupType group") + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantId -message "Cannot add device $DeviceLabel to $($GroupName): devices are not supported in a $GroupType group" -Sev 'Error' + } else { + # Intune device rows carry the Entra deviceId (azureADDeviceId) rather than the + # directory object id - resolve it via the devices alternate key + $DeviceID = $Device.value + if ($Device.addedFields.azureADDeviceId) { + $DeviceID = (New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/devices(deviceId='$($Device.addedFields.azureADDeviceId)')?`$select=id" -tenantid $TenantId).id + } + + $AddDeviceBody = @{ + 'members@odata.bind' = @($MemberODataBindString -f $DeviceID) + } + $BulkRequests.Add(@{ + id = "addDevice-$DeviceID" + method = 'PATCH' + url = "groups/$($GroupId)" + body = $AddDeviceBody + headers = @{ + 'Content-Type' = 'application/json' + } + }) + $GraphLogs.Add(@{ + message = "Added device $DeviceLabel to $($GroupName) group" + id = "addDevice-$DeviceID" + }) + } + } catch { + Write-Warning "Error in AddDevices: $($_.Exception.Message)" + $Results.Add("Error - Failed to add device $DeviceLabel to $($GroupName): $($_.Exception.Message)") + } + } + } $AddContacts = $UserObj.AddContact if ($AddContacts) { diff --git a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 index 3e10dc15f1d88..3acb8aab1a6ed 100644 --- a/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 +++ b/Modules/CIPPStandards/Public/Standards/Invoke-CIPPStandardSafeLinksPolicy.ps1 @@ -100,9 +100,11 @@ function Invoke-CIPPStandardSafeLinksPolicy { # Use existing policy name if found $PolicyName = $ExistingPolicy.Name } - # Derive rule name from policy name, but check for old names for backward compatibility - $DesiredRuleName = "$PolicyName Rule" - $RuleList = @($DesiredRuleName, 'CIPP Default SafeLinks Rule', 'CIPP Default SafeLinks Policy') + # Derive rule name from policy name using the same convention as the Safe Links page and + # templates (PolicyName_Rule), but check for old names for backward compatibility so rules + # created as "PolicyName Rule" by earlier versions of this standard are adopted, not duplicated + $DesiredRuleName = "$($PolicyName)_Rule" + $RuleList = @($DesiredRuleName, "$PolicyName Rule", 'CIPP Default SafeLinks Rule', 'CIPP Default SafeLinks Policy') $ExistingRule = $AllSafeLinksRule | Where-Object -Property Name -In $RuleList | Select-Object -First 1 if ($null -eq $ExistingRule.Name) { # No existing rule - use the derived name