diff --git a/Modules/CIPPCore/Public/Add-CIPPWin32LobAppContent.ps1 b/Modules/CIPPCore/Public/Add-CIPPWin32LobAppContent.ps1 index 1b238870e622..2b9b7393d9c4 100644 --- a/Modules/CIPPCore/Public/Add-CIPPWin32LobAppContent.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPWin32LobAppContent.ps1 @@ -138,7 +138,7 @@ function Add-CIPPWin32LobAppContent { if ($CommitStateReq.uploadState -like '*fail*') { $errorMsg = "Commit failed. Upload state: $($CommitStateReq.uploadState)" if ($Headers) { - Write-LogMessage -Headers $Headers -API $APIName -message $errorMsg -Sev 'Warning' -tenant $TenantFilter + Write-LogMessage -Headers $Headers -API $APIName -message $errorMsg -sev 'Warn' -tenant $TenantFilter } throw $errorMsg } diff --git a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuarantineReleaseRequests.ps1 b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuarantineReleaseRequests.ps1 index 58ed3b035407..b20096d59020 100644 --- a/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuarantineReleaseRequests.ps1 +++ b/Modules/CIPPCore/Public/Alerts/Get-CIPPAlertQuarantineReleaseRequests.ps1 @@ -14,7 +14,7 @@ #Add rerun protection: This Monitor can only run once every hour. $Rerun = Test-CIPPRerun -TenantFilter $TenantFilter -Type 'ExchangeMonitor' -API 'Get-CIPPAlertQuarantineReleaseRequests' if ($Rerun) { - return $true + return } $HasLicense = Test-CIPPStandardLicense -StandardName 'QuarantineReleaseRequests' -TenantFilter $TenantFilter -RequiredCapabilities @( 'EXCHANGE_S_STANDARD', @@ -25,7 +25,7 @@ ) if (-not $HasLicense) { - return $true + return } try { diff --git a/Modules/CIPPCore/Public/Authentication/Test-IpInRange.ps1 b/Modules/CIPPCore/Public/Authentication/Test-IpInRange.ps1 index 2279b20ce110..f7103fbca239 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-IpInRange.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-IpInRange.ps1 @@ -31,7 +31,8 @@ function Test-IpInRange { $IP = [System.Net.IPAddress]::Parse($IPAddress) $rangeParts = $Range -split '/' $networkAddr = [System.Net.IPAddress]::Parse($rangeParts[0]) - $prefix = [int]$rangeParts[1] + $maxBits = if ($networkAddr.AddressFamily -eq 'InterNetworkV6') { 128 } else { 32 } + $prefix = if ($rangeParts.Count -gt 1) { [int]$rangeParts[1] } else { $maxBits } if ($networkAddr.AddressFamily -ne $IP.AddressFamily) { return $false @@ -39,7 +40,6 @@ function Test-IpInRange { $ipBig = ConvertIpToBigInteger $IP $netBig = ConvertIpToBigInteger $networkAddr - $maxBits = if ($networkAddr.AddressFamily -eq 'InterNetworkV6') { 128 } else { 32 } $shift = $maxBits - $prefix $mask = [System.Numerics.BigInteger]::Pow(2, $shift) - [System.Numerics.BigInteger]::One $invertedMask = [System.Numerics.BigInteger]::MinusOne -bxor $mask diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-CIPPOffboardingComplete.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-CIPPOffboardingComplete.ps1 index 8d86e31a27a3..faca0853ea6f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-CIPPOffboardingComplete.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-CIPPOffboardingComplete.ps1 @@ -15,6 +15,7 @@ function Push-CIPPOffboardingComplete { $TaskInfo = $Item.Parameters.TaskInfo $TenantFilter = $Item.Parameters.TenantFilter $Username = $Item.Parameters.Username + $Headers = $Item.Parameters.Headers $Results = $Item.Results # Results come from orchestrator, not Parameters try { @@ -102,19 +103,19 @@ function Push-CIPPOffboardingComplete { TaskState = 'Completed' } - Write-LogMessage -API 'Offboarding' -tenant $TenantFilter -message "Offboarding completed successfully for $Username" -sev Info + Write-LogMessage -API 'Offboarding' -tenant $TenantFilter -message "Offboarding completed successfully for $Username" -sev Info -headers $Headers # Send post-execution alerts if configured if ($TaskInfo.PostExecution -and $ProcessedResults) { Send-CIPPScheduledTaskAlert -Results $ProcessedResults -TaskInfo $TaskInfo -TenantFilter $TenantFilter } } - + Write-LogMessage -API 'Offboarding' -tenant $TenantFilter -message "Offboarding completed for $Username" -sev Info -headers $Headers return "Offboarding completed for $Username" } catch { $ErrorMsg = "Failed to complete offboarding for $Username : $($_.Exception.Message)" - Write-LogMessage -API 'Offboarding' -tenant $TenantFilter -message $ErrorMsg -sev Error + Write-LogMessage -API 'Offboarding' -tenant $TenantFilter -message $ErrorMsg -sev Error -headers $Headers -LogData (Get-CippException -Exception $_) throw $ErrorMsg } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-CIPPOffboardingTask.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-CIPPOffboardingTask.ps1 index 7f0243f4d9c9..eacb976bf70e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-CIPPOffboardingTask.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-CIPPOffboardingTask.ps1 @@ -19,7 +19,7 @@ function Push-CIPPOffboardingTask { Write-Information "Executing offboarding cmdlet: $Cmdlet" # Check if cmdlet exists - $CmdletInfo = Get-Command -Name $Cmdlet -ErrorAction SilentlyContinue + $CmdletInfo = Get-Command -Name $Cmdlet -Module CIPPCore -ErrorAction SilentlyContinue if (-not $CmdletInfo) { throw "Cmdlet $Cmdlet does not exist" } diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 index 22607cb0841b..a7744b0a1af0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 @@ -317,13 +317,12 @@ function Push-ExecScheduledCommand { } Write-LogMessage -API 'Scheduler_UserTasks' -tenant $Tenant -tenantid $TenantInfo.customerId -message "Failed to execute task $($task.Name): $errorMessage" -sev Error -LogData (Get-CippExceptionData -Exception $_.Exception) } - Write-Information 'Sending task results to target. Updating the task state.' # For orchestrator-based commands, skip post-execution alerts as they will be handled by the orchestrator's post-execution function if ($Results -and $Item.Command -notin $OrchestratorBasedCommands) { + Write-Information "Sending task results to post execution target(s): $($Task.PostExecution -join ', ')." Send-CIPPScheduledTaskAlert -Results $Results -TaskInfo $task -TenantFilter $Tenant -TaskType $TaskType } - Write-Information 'Sent the results to the target. Updating the task state.' try { # For orchestrator-based commands, skip task state update as it will be handled by post-execution diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItemDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItemDetails.ps1 index be60e04ec9b2..b5d04c9de337 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItemDetails.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItemDetails.ps1 @@ -119,7 +119,7 @@ function Invoke-ListScheduledItemDetails { } } catch { # If JSON parsing fails, use raw value - Write-LogMessage -API $APIName -message "Error parsing Task.Results as JSON: $_" -Sev 'Warning' + Write-LogMessage -API $APIName -message "Error parsing Task.Results as JSON: $_" -sev 'Warn' $ResultData = $Task.Results } } else { @@ -155,7 +155,7 @@ function Invoke-ListScheduledItemDetails { try { $ParsedResults = $Result.Results | ConvertFrom-Json -ErrorAction Stop } catch { - Write-LogMessage -API $APIName -message "Failed to parse result as JSON: $_" -Sev 'Warning' + Write-LogMessage -API $APIName -message "Failed to parse result as JSON: $_" -sev 'Warn' # On failure, keep as string $ParsedResults = $Result.Results } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecApiClient.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecApiClient.ps1 index c38ece6e144c..eb7dc7273680 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecApiClient.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecApiClient.ps1 @@ -192,7 +192,7 @@ function Invoke-ExecApiClient { $Body = @{ Results = "API client $ClientId not found or not a valid CIPP-API application" } } } catch { - Write-LogMessage -headers $Request.Headers -API 'ExecApiClient' -message "Failed to remove app registration for $ClientId" -Sev 'Warning' + Write-LogMessage -headers $Request.Headers -API 'ExecApiClient' -message "Failed to remove app registration for $ClientId" -sev 'Warn' } } default { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCreateDefaultGroups.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCreateDefaultGroups.ps1 index bd2a682429ac..4fc1b2f5575c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCreateDefaultGroups.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecCreateDefaultGroups.ps1 @@ -16,7 +16,7 @@ function Invoke-ExecCreateDefaultGroups { $Table = Get-CippTable -tablename 'TenantGroups' $Results = [System.Collections.Generic.List[object]]::new() $ExistingGroups = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'TenantGroup' and Type eq 'dynamic'" - $DefaultGroups = '[{"PartitionKey":"TenantGroup","RowKey":"369d985e-0fba-48f9-844f-9f793b10a12c","Description":"This group does not have a license for intune, nor a license for Entra ID Premium","Description@type":null,"DynamicRules":"[{\"property\":\"availableServicePlan\",\"operator\":\"notIn\",\"value\":[{\"label\":\"Microsoft Intune\",\"value\":\"INTUNE_A\",\"id\":\"c1ec4a95-1f05-45b3-a911-aa3fa01094f5\"}]},{\"property\":\"availableServicePlan\",\"operator\":\"notIn\",\"value\":[{\"label\":\"Microsoft Entra ID P1\",\"value\":\"AAD_PREMIUM\",\"id\":\"41781fb2-bc02-4b7c-bd55-b576c07bb09d\"}]}]","DynamicRules@type":null,"GroupType":"dynamic","GroupType@type":null,"RuleLogic":"and","RuleLogic@type":null,"Name":"Not Intune and Entra Premium Capable","Name@type":null},{"PartitionKey":"TenantGroup","RowKey":"4dbca08b-7dc5-4e0f-bc25-14a90c8e0941","Description":"This group has atleast one Business Premium License available","Description@type":null,"DynamicRules":"[{\"property\":\"availableLicense\",\"operator\":\"in\",\"value\":[{\"label\":\"Microsoft 365 Business Premium\",\"value\":\"SPB\"}]},{\"property\":\"availableLicense\",\"operator\":\"in\",\"value\":[{\"label\":\"Microsoft 365 Business Premium (no Teams)\",\"value\":\"Microsoft_365_ Business_ Premium_(no Teams)\"}]},{\"property\":\"availableLicense\",\"operator\":\"in\",\"value\":[{\"label\":\"Microsoft 365 Business Premium Donation\",\"value\":\"Microsoft_365_Business_Premium_Donation_(Non_Profit_Pricing)\"}]},{\"property\":\"availableLicense\",\"operator\":\"in\",\"value\":[{\"label\":\"Microsoft 365 Business Premium EEA (no Teams)\",\"value\":\"Office_365_w\/o_Teams_Bundle_Business_Premium\"}]}]","DynamicRules@type":null,"GroupType":"dynamic","GroupType@type":null,"RuleLogic":"or","RuleLogic@type":null,"Name":"Business Premium License available","Name@type":null},{"PartitionKey":"TenantGroup","RowKey":"703c0e69-84a8-4dcf-a1c2-4986d2ccc850","Description":"This group does have a license for Entra Premium but does not have a license for Intune","Description@type":null,"DynamicRules":"[{\"property\":\"availableServicePlan\",\"operator\":\"in\",\"value\":[{\"label\":\"Microsoft Entra ID P1\",\"value\":\"AAD_PREMIUM\",\"id\":\"41781fb2-bc02-4b7c-bd55-b576c07bb09d\"}]},{\"property\":\"availableServicePlan\",\"operator\":\"notIn\",\"value\":[{\"label\":\"Microsoft Intune\",\"value\":\"INTUNE_A\",\"id\":\"c1ec4a95-1f05-45b3-a911-aa3fa01094f5\"}]}]","DynamicRules@type":null,"GroupType":"dynamic","GroupType@type":null,"RuleLogic":"and","RuleLogic@type":null,"Name":"Entra Premium Capable, Not Intune Capable","Name@type":null},{"PartitionKey":"TenantGroup","RowKey":"c1dadbc0-f0b4-448c-a2e6-e1938ba102e0","Description":"This group has Intune and Entra ID Premium available","Description@type":null,"DynamicRules":"{\"property\":\"availableServicePlan\",\"operator\":\"in\",\"value\":[{\"label\":\"Microsoft Intune\",\"value\":\"INTUNE_A\"},{\"label\":\"Microsoft Entra ID P1\",\"value\":\"AAD_PREMIUM\"}]}","DynamicRules@type":null,"GroupType":"dynamic","GroupType@type":null,"RuleLogic":"and","RuleLogic@type":null,"Name":"Entra ID Premium and Intune Capable","Name@type":null}]' | ConvertFrom-Json + $DefaultGroups = '[{"PartitionKey":"TenantGroup","RowKey":"369d985e-0fba-48f9-844f-9f793b10a12c","Description":"This group does not have a license for intune, nor a license for Entra ID Premium","Description@type":null,"DynamicRules":"[{\"property\":\"availableServicePlan\",\"operator\":\"notIn\",\"value\":[{\"label\":\"Microsoft Intune\",\"value\":\"INTUNE_A\",\"id\":\"c1ec4a95-1f05-45b3-a911-aa3fa01094f5\"}]},{\"property\":\"availableServicePlan\",\"operator\":\"notIn\",\"value\":[{\"label\":\"Microsoft Entra ID P1\",\"value\":\"AAD_PREMIUM\",\"id\":\"41781fb2-bc02-4b7c-bd55-b576c07bb09d\"}]}]","DynamicRules@type":null,"GroupType":"dynamic","GroupType@type":null,"RuleLogic":"and","RuleLogic@type":null,"Name":"Not Intune and Entra Premium Capable","Name@type":null},{"PartitionKey":"TenantGroup","RowKey":"4dbca08b-7dc5-4e0f-bc25-14a90c8e0941","Description":"This group has atleast one Business Premium License available","DynamicRules":"{\"property\":\"availableLicense\",\"operator\":\"in\",\"value\":[{\"label\":\"Microsoft 365 Business Premium\",\"value\":\"SPB\",\"guid\":\"cbdc14ab-d96c-4c30-b9f4-6ada7cdc1d46\"},{\"label\":\"Microsoft 365 Business Premium (no Teams)\",\"value\":\"Microsoft_365_ Business_ Premium_(no Teams)\",\"guid\":\"00e1ec7b-e4a3-40d1-9441-b69b597ab222\"},{\"label\":\"Microsoft 365 Business Premium Donation\",\"value\":\"Microsoft_365_Business_Premium_Donation_(Non_Profit_Pricing)\",\"guid\":\"24c35284-d768-4e53-84d9-b7ae73dddf69\"},{\"label\":\"Microsoft 365 Business Premium EEA (no Teams)\",\"value\":\"Office_365_w/o_Teams_Bundle_Business_Premium\",\"guid\":\"a3f586b6-8cce-4d9b-99d6-55238397f77a\"}]}","GroupType":"dynamic","Name":"Business Premium License available","RuleLogic":"or"},{"PartitionKey":"TenantGroup","RowKey":"703c0e69-84a8-4dcf-a1c2-4986d2ccc850","Description":"This group does have a license for Entra Premium but does not have a license for Intune","Description@type":null,"DynamicRules":"[{\"property\":\"availableServicePlan\",\"operator\":\"in\",\"value\":[{\"label\":\"Microsoft Entra ID P1\",\"value\":\"AAD_PREMIUM\",\"id\":\"41781fb2-bc02-4b7c-bd55-b576c07bb09d\"}]},{\"property\":\"availableServicePlan\",\"operator\":\"notIn\",\"value\":[{\"label\":\"Microsoft Intune\",\"value\":\"INTUNE_A\",\"id\":\"c1ec4a95-1f05-45b3-a911-aa3fa01094f5\"}]}]","DynamicRules@type":null,"GroupType":"dynamic","GroupType@type":null,"RuleLogic":"and","RuleLogic@type":null,"Name":"Entra Premium Capable, Not Intune Capable","Name@type":null},{"PartitionKey":"TenantGroup","RowKey":"c1dadbc0-f0b4-448c-a2e6-e1938ba102e0","Description":"This group has Intune and Entra ID Premium available","Description@type":null,"DynamicRules":"{\"property\":\"availableServicePlan\",\"operator\":\"in\",\"value\":[{\"label\":\"Microsoft Intune\",\"value\":\"INTUNE_A\"},{\"label\":\"Microsoft Entra ID P1\",\"value\":\"AAD_PREMIUM\"}]}","DynamicRules@type":null,"GroupType":"dynamic","GroupType@type":null,"RuleLogic":"and","RuleLogic@type":null,"Name":"Entra ID Premium and Intune Capable","Name@type":null}]' | ConvertFrom-Json foreach ($Group in $DefaultGroups) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecGDAPTrace.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecGDAPTrace.ps1 index d138555690a5..930c54b297d9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecGDAPTrace.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ExecGDAPTrace.ps1 @@ -163,7 +163,7 @@ function Invoke-ExecAccessTest { # Filter didn't work, try direct lookup by UPN (works if UPN is unique identifier) $User = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$UPN" -tenantid $env:TenantID -NoAuthCheck $true } catch { - Write-LogMessage -Headers $Headers -API $APIName -message "Could not find user $UPN in partner tenant: $($_.Exception.Message)" -Sev 'Warning' + Write-LogMessage -Headers $Headers -API $APIName -message "Could not find user $UPN in partner tenant: $($_.Exception.Message)" -sev 'Warn' } # If user not found, return error @@ -212,7 +212,7 @@ function Invoke-ExecAccessTest { } } } catch { - Write-LogMessage -Headers $Headers -API $APIName -message "Could not get user group memberships: $($_.Exception.Message)" -Sev 'Warning' + Write-LogMessage -Headers $Headers -API $APIName -message "Could not get user group memberships: $($_.Exception.Message)" -sev 'Warn' } # ============================================================================ @@ -296,7 +296,7 @@ function Invoke-ExecAccessTest { }) } } catch { - Write-LogMessage -Headers $Headers -API $APIName -message "Could not get access assignments for relationship ${RelationshipName}: $($_.Exception.Message)" -Sev 'Warning' + Write-LogMessage -Headers $Headers -API $APIName -message "Could not get access assignments for relationship ${RelationshipName}: $($_.Exception.Message)" -sev 'Warn' } } @@ -346,7 +346,7 @@ function Invoke-ExecAccessTest { Write-LogMessage -Headers $Headers -API $APIName -message "Fetched $($AllGroups.Count) total groups, $($GroupLookup.Count) in lookup" -Sev 'Debug' } catch { - Write-LogMessage -Headers $Headers -API $APIName -message "Could not fetch all groups: $($_.Exception.Message). Will use fallback for missing groups." -Sev 'Warning' + Write-LogMessage -Headers $Headers -API $APIName -message "Could not fetch all groups: $($_.Exception.Message). Will use fallback for missing groups." -sev 'Warn' } # ======================================================================== @@ -387,12 +387,12 @@ function Invoke-ExecAccessTest { $GroupId = $Assignment.value.accessContainer.accessContainerId $Assignment = $Assignment.value } else { - Write-LogMessage -Headers $Headers -API $APIName -message "Access assignment missing accessContainer: $($Assignment | ConvertTo-Json -Compress)" -Sev 'Warning' + Write-LogMessage -Headers $Headers -API $APIName -message "Access assignment missing accessContainer: $($Assignment | ConvertTo-Json -Compress)" -sev 'Warn' continue } if ([string]::IsNullOrWhiteSpace($GroupId)) { - Write-LogMessage -Headers $Headers -API $APIName -message "Access assignment has empty accessContainerId: $($Assignment | ConvertTo-Json -Compress)" -Sev 'Warning' + Write-LogMessage -Headers $Headers -API $APIName -message "Access assignment has empty accessContainerId: $($Assignment | ConvertTo-Json -Compress)" -sev 'Warn' continue } @@ -405,7 +405,7 @@ function Invoke-ExecAccessTest { } if (-not $Roles -or $Roles.Count -eq 0) { - Write-LogMessage -Headers $Headers -API $APIName -message "Access assignment for group $GroupId has no roles assigned" -Sev 'Warning' + Write-LogMessage -Headers $Headers -API $APIName -message "Access assignment for group $GroupId has no roles assigned" -sev 'Warn' $Roles = @() } @@ -420,7 +420,7 @@ function Invoke-ExecAccessTest { id = $GroupId displayName = "Unknown Group ($GroupId)" } - Write-LogMessage -Headers $Headers -API $APIName -message "Group $GroupId not found in lookup, using fallback" -Sev 'Warning' + Write-LogMessage -Headers $Headers -API $APIName -message "Group $GroupId not found in lookup, using fallback" -sev 'Warn' } # Process the assignment even if group lookup failed - we still have the group ID and roles @@ -585,12 +585,12 @@ function Invoke-ExecAccessTest { } elseif ($Role -is [string]) { $RoleId = $Role } else { - Write-LogMessage -Headers $Headers -API $APIName -message "Role object missing roleDefinitionId: $($Role | ConvertTo-Json -Compress)" -Sev 'Warning' + Write-LogMessage -Headers $Headers -API $APIName -message "Role object missing roleDefinitionId: $($Role | ConvertTo-Json -Compress)" -sev 'Warn' continue } if ([string]::IsNullOrWhiteSpace($RoleId)) { - Write-LogMessage -Headers $Headers -API $APIName -message "Role has empty roleDefinitionId for group $GroupId" -Sev 'Warning' + Write-LogMessage -Headers $Headers -API $APIName -message "Role has empty roleDefinitionId for group $GroupId" -sev 'Warn' continue } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCustomVariables.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCustomVariables.ps1 index d512c090da28..e77018c09ffc 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCustomVariables.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Settings/Invoke-ListCustomVariables.ps1 @@ -242,7 +242,7 @@ function Invoke-ListCustomVariables { } } } catch { - Write-LogMessage -API $APIName -message "Could not retrieve tenant-specific variables for $TenantFilter : $($_.Exception.Message)" -Sev 'Warning' + Write-LogMessage -API $APIName -message "Could not retrieve tenant-specific variables for $TenantFilter : $($_.Exception.Message)" -sev 'Warn' } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 index 202d6e4dc182..f7ca33f56c56 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecCreateSAMApp.ps1 @@ -70,7 +70,8 @@ function Invoke-ExecCreateSAMApp { } try { - $AppPolicyStatus = Update-AppManagementPolicy + + $AppPolicyStatus = Update-AppManagementPolicy -Headers @{ authorization = "Bearer $($Token.access_token)" } -ApplicationId $appId.appId Write-Information $AppPolicyStatus.PolicyAction } catch { Write-Warning "Error updating app management policy $($_.Exception.Message)." @@ -88,10 +89,8 @@ function Invoke-ExecCreateSAMApp { $Secret | Add-Member -MemberType NoteProperty -Name 'tenantid' -Value $TenantId -Force $Secret | Add-Member -MemberType NoteProperty -Name 'applicationid' -Value $AppId.appId -Force $Secret | Add-Member -MemberType NoteProperty -Name 'applicationsecret' -Value $AppPassword -Force - Write-Information ($Secret | ConvertTo-Json -Depth 5) Add-CIPPAzDataTableEntity @DevSecretsTable -Entity $Secret -Force } else { - Set-CippKeyVaultSecret -VaultName $kv -Name 'tenantid' -SecretValue (ConvertTo-SecureString -String $TenantId -AsPlainText -Force) Set-CippKeyVaultSecret -VaultName $kv -Name 'applicationid' -SecretValue (ConvertTo-SecureString -String $Appid.appId -AsPlainText -Force) Set-CippKeyVaultSecret -VaultName $kv -Name 'applicationsecret' -SecretValue (ConvertTo-SecureString -String $AppPassword -AsPlainText -Force) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Contacts/Invoke-DeployContactTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Contacts/Invoke-DeployContactTemplates.ps1 index 84b79cff13be..d3a188c2211c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Contacts/Invoke-DeployContactTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Contacts/Invoke-DeployContactTemplates.ps1 @@ -24,7 +24,7 @@ Function Invoke-DeployContactTemplates { if ($TenantItem.value) { $SelectedTenants.Add($TenantItem.value) } else { - Write-LogMessage -headers $Headers -API $APIName -message "Tenant item missing value property: $($TenantItem | ConvertTo-Json -Compress)" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message "Tenant item missing value property: $($TenantItem | ConvertTo-Json -Compress)" -sev 'Warn' } } @@ -46,7 +46,7 @@ Function Invoke-DeployContactTemplates { if ($TemplateItem.value) { $ContactTemplates.Add($TemplateItem.value) } else { - Write-LogMessage -headers $Headers -API $APIName -message "Template item missing value property: $($TemplateItem | ConvertTo-Json -Compress)" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message "Template item missing value property: $($TemplateItem | ConvertTo-Json -Compress)" -sev 'Warn' } } } else { @@ -74,7 +74,7 @@ Function Invoke-DeployContactTemplates { $ContactExists = $ExistingContacts | Where-Object { $_.ExternalEmailAddress -eq $ContactTemplate.email } if ($ContactExists) { - Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Contact with email '$($ContactTemplate.email)' already exists in tenant $TenantFilter" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Contact with email '$($ContactTemplate.email)' already exists in tenant $TenantFilter" -sev 'Warn' "Contact '$($ContactTemplate.displayName)' with email '$($ContactTemplate.email)' already exists in tenant $TenantFilter" continue } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Contacts/Invoke-ListContactTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Contacts/Invoke-ListContactTemplates.ps1 index 9abe8a741a25..05ae42c1ed52 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Contacts/Invoke-ListContactTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Contacts/Invoke-ListContactTemplates.ps1 @@ -37,7 +37,7 @@ Function Invoke-ListContactTemplates { } if (-not $Templates) { - Write-LogMessage -headers $Headers -API $APIName -message "Template with ID $RequestedID not found" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message "Template with ID $RequestedID not found" -sev 'Warn' return ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::NotFound Body = @{ Error = "Template with ID $RequestedID not found" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecHVEUser.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecHVEUser.ps1 index bdb783995d9b..5c1b8e2e52d0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecHVEUser.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecHVEUser.ps1 @@ -75,7 +75,7 @@ function Invoke-ExecHVEUser { } catch { $ErrorMessage = Get-CippException -Exception $_ $Message = "Failed to exclude from CA policy '$($Policy.displayName)': $($ErrorMessage.NormalizedError)" - Write-LogMessage -Headers $Headers -API $APIName -tenant $Tenant -message $Message -Sev 'Warning' -LogData $ErrorMessage + Write-LogMessage -Headers $Headers -API $APIName -tenant $Tenant -message $Message -sev 'Warn' -LogData $ErrorMessage $Results.Add($Message) } } @@ -85,7 +85,7 @@ function Invoke-ExecHVEUser { } catch { $ErrorMessage = Get-CippException -Exception $_ $Message = "Failed to check/update Conditional Access policies: $($ErrorMessage.NormalizedError)" - Write-LogMessage -Headers $Headers -API $APIName -tenant $Tenant -message $Message -Sev 'Warning' -LogData $ErrorMessage + Write-LogMessage -Headers $Headers -API $APIName -tenant $Tenant -message $Message -sev 'Warn' -LogData $ErrorMessage $Results.Add($Message) } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyCalPerms.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyCalPerms.ps1 index 562fb1dd2f92..24f88d8cd971 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyCalPerms.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyCalPerms.ps1 @@ -105,7 +105,7 @@ function Invoke-ExecModifyCalPerms { } if ($Results.Count -eq 0) { - Write-LogMessage -headers $Headers -API $APIName -message 'No results were generated from the operation' -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message 'No results were generated from the operation' -sev 'Warn' $Results.Add('No results were generated from the operation. Please check the logs for more details.') $HasErrors = $true } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyContactPerms.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyContactPerms.ps1 index 75877cbbdb9c..ad659857cc75 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyContactPerms.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyContactPerms.ps1 @@ -104,7 +104,7 @@ function Invoke-ExecModifyContactPerms { } if ($Results.Count -eq 0) { - Write-LogMessage -headers $Headers -API $APIName -message 'No results were generated from the operation' -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message 'No results were generated from the operation' -sev 'Warn' $Results.Add('No results were generated from the operation. Please check the logs for more details.') $HasErrors = $true } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyMBPerms.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyMBPerms.ps1 index 4d768e96cc1a..5e051053f90b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyMBPerms.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyMBPerms.ps1 @@ -293,7 +293,7 @@ Function Invoke-ExecModifyMBPerms { } if ($CmdletArray.Count -eq 0) { - Write-LogMessage -headers $Request.Headers -API $APINAME -message 'No valid cmdlets to process' -Sev 'Warning' -tenant $TenantFilter + Write-LogMessage -headers $Request.Headers -API $APINAME -message 'No valid cmdlets to process' -sev 'Warn' -tenant $TenantFilter $body = [pscustomobject]@{'Results' = @("No valid permission changes to process") } return ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK @@ -327,7 +327,7 @@ Function Invoke-ExecModifyMBPerms { Write-LogMessage -headers $Request.Headers -API $APINAME -message "Success for operation $operationGuid`: $($metadata.ExpectedResult)" -Sev 'Info' -tenant $TenantFilter } } else { - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Could not map result to operation. GUID: $operationGuid, Available GUIDs: $($GuidToMetadataMap.Keys -join ', ')" -Sev 'Warning' -tenant $TenantFilter + Write-LogMessage -headers $Request.Headers -API $APINAME -message "Could not map result to operation. GUID: $operationGuid, Available GUIDs: $($GuidToMetadataMap.Keys -join ', ')" -sev 'Warn' -tenant $TenantFilter # Fallback for unmapped results if ($result.error) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListMailQuarantine.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListMailQuarantine.ps1 index d785b015f940..7780f90588eb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListMailQuarantine.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Spamfilter/Invoke-ListMailQuarantine.ps1 @@ -16,8 +16,9 @@ function Invoke-ListMailQuarantine { } else { $Table = Get-CIPPTable -TableName cacheQuarantineMessages $PartitionKey = 'QuarantineMessage' - $Filter = "PartitionKey eq '$PartitionKey'" - $Rows = Get-CIPPAzDataTableEntity @Table -filter $Filter | Where-Object -Property Timestamp -GT (Get-Date).AddMinutes(-30) + $30MinutesAgo = (Get-Date).AddMinutes(-30).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') + $Filter = "PartitionKey eq '$PartitionKey' and Timestamp gt datetime'$30MinutesAgo'" + $Rows = Get-CIPPAzDataTableEntity @Table -filter $Filter $QueueReference = '{0}-{1}' -f $TenantFilter, $PartitionKey $RunningQueue = Invoke-ListCippQueue -Reference $QueueReference | Where-Object { $_.Status -notmatch 'Completed' -and $_.Status -notmatch 'Failed' } # If a queue is running, we will not start a new one diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 index ad2c5d7c5466..74d66cea6d1a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/MEM/Invoke-AddIntuneTemplate.ps1 @@ -19,21 +19,21 @@ function Invoke-AddIntuneTemplate { $reusableTemplateRefs = @() $object = [PSCustomObject]@{ - Displayname = $Request.Body.displayName - Description = $Request.Body.description - RAWJson = $Request.Body.RawJSON - Type = $Request.Body.TemplateType - GUID = $GUID - ReusableSettings = $reusableTemplateRefs + Displayname = $Request.Body.displayName + Description = $Request.Body.description + RAWJson = $Request.Body.RawJSON + Type = $Request.Body.TemplateType + GUID = $GUID + ReusableSettings = $reusableTemplateRefs } | ConvertTo-Json $Table = Get-CippTable -tablename 'templates' $Table.Force = $true Add-CIPPAzDataTableEntity @Table -Entity @{ - JSON = "$object" + JSON = "$object" ReusableSettingsCount = $reusableTemplateRefs.Count - RowKey = "$GUID" - PartitionKey = 'IntuneTemplate' - GUID = "$GUID" + RowKey = "$GUID" + PartitionKey = 'IntuneTemplate' + GUID = "$GUID" } Write-LogMessage -headers $Headers -API $APIName -message "Created intune policy template named $($Request.Body.displayName) with GUID $GUID" -Sev 'Debug' @@ -56,8 +56,7 @@ function Invoke-AddIntuneTemplate { Type = $Template.Type GUID = $GUID ReusableSettings = $reusableTemplateRefs - } - + } | ConvertTo-Json -Compress $Table = Get-CippTable -tablename 'templates' $Table.Force = $true Add-CIPPAzDataTableEntity @Table -Entity @{ diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddJITAdminTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddJITAdminTemplate.ps1 index dd2de9d523e0..7f8777f94899 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddJITAdminTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-AddJITAdminTemplate.ps1 @@ -61,7 +61,7 @@ function Invoke-AddJITAdminTemplate { Write-LogMessage -headers $Headers -API $APIName -message "Unset default flag for existing template: $($data.templateName)" -Sev 'Info' } } catch { - Write-LogMessage -headers $Headers -API $APIName -message "Failed to update existing template: $($_.Exception.Message)" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message "Failed to update existing template: $($_.Exception.Message)" -sev 'Warn' } } } @@ -104,7 +104,7 @@ function Invoke-AddJITAdminTemplate { if (![string]::IsNullOrWhiteSpace($Request.Body.defaultUserName)) { $TemplateObject.defaultUserName = $Request.Body.defaultUserName } - + # defaultDomain is only saved for specific tenant templates (not AllTenants) if ($TenantFilter -ne 'AllTenants' -and $Request.Body.defaultDomain) { if ($Request.Body.defaultDomain -is [string]) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-CIPPOffboardingJob.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-CIPPOffboardingJob.ps1 index 6da71f0a98bf..b36cf8ea3987 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-CIPPOffboardingJob.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-CIPPOffboardingJob.ps1 @@ -16,7 +16,6 @@ function Invoke-CIPPOffboardingJob { } Write-Information "Starting offboarding job for $Username in tenant $TenantFilter" - Write-LogMessage -API 'Offboarding' -tenant $TenantFilter -message "Starting offboarding orchestration for user $Username" -sev Info # Get user information needed for various tasks $User = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($Username)?`$select=id,displayName,onPremisesSyncEnabled,onPremisesImmutableId" -tenantid $TenantFilter @@ -36,6 +35,7 @@ function Invoke-CIPPOffboardingJob { username = $Username userid = $UserID APIName = $APIName + Headers = $Headers } } @{ @@ -46,6 +46,7 @@ function Invoke-CIPPOffboardingJob { DisplayName = $DisplayName UserID = $Username APIName = $APIName + Headers = $Headers } } @{ @@ -56,6 +57,7 @@ function Invoke-CIPPOffboardingJob { userid = $Username AccountEnabled = $false APIName = $APIName + Headers = $Headers } } @{ @@ -66,6 +68,7 @@ function Invoke-CIPPOffboardingJob { UserID = $Username hidefromgal = $true APIName = $APIName + Headers = $Headers } } @{ @@ -76,6 +79,7 @@ function Invoke-CIPPOffboardingJob { tenantFilter = $TenantFilter APIName = $APIName Username = $Username + Headers = $Headers } } @{ @@ -87,6 +91,7 @@ function Invoke-CIPPOffboardingJob { tenantFilter = $TenantFilter APIName = $APIName RemoveAllRules = $true + Headers = $Headers } } @{ @@ -97,6 +102,7 @@ function Invoke-CIPPOffboardingJob { username = $Username tenantFilter = $TenantFilter APIName = $APIName + Headers = $Headers } } @{ @@ -107,6 +113,7 @@ function Invoke-CIPPOffboardingJob { Username = $Username TenantFilter = $TenantFilter APIName = $APIName + Headers = $Headers } } @{ @@ -119,6 +126,7 @@ function Invoke-CIPPOffboardingJob { ExternalMessage = $Options.OOO APIName = $APIName state = 'Enabled' + Headers = $Headers } } @{ @@ -131,6 +139,7 @@ function Invoke-CIPPOffboardingJob { Forward = $Options.forward.value KeepCopy = [bool]$Options.KeepCopy APIName = $APIName + Headers = $Headers } } @{ @@ -142,6 +151,7 @@ function Invoke-CIPPOffboardingJob { tenantFilter = $TenantFilter Disable = $true APIName = $APIName + Headers = $Headers } } @{ @@ -152,6 +162,7 @@ function Invoke-CIPPOffboardingJob { userid = $Username OnedriveAccessUser = $Options.OnedriveAccess APIName = $APIName + Headers = $Headers } } @{ @@ -164,6 +175,7 @@ function Invoke-CIPPOffboardingJob { Automap = $false AccessRights = @('FullAccess') APIName = $APIName + Headers = $Headers } } @{ @@ -176,6 +188,7 @@ function Invoke-CIPPOffboardingJob { Automap = $true AccessRights = @('FullAccess') APIName = $APIName + Headers = $Headers } } @{ @@ -186,6 +199,7 @@ function Invoke-CIPPOffboardingJob { TenantFilter = $TenantFilter UseCache = $true APIName = $APIName + Headers = $Headers } } @{ @@ -196,6 +210,7 @@ function Invoke-CIPPOffboardingJob { TenantFilter = $TenantFilter UseCache = $true APIName = $APIName + Headers = $Headers } } @{ @@ -207,6 +222,7 @@ function Invoke-CIPPOffboardingJob { username = $Username MailboxType = 'Shared' APIName = $APIName + Headers = $Headers } } @{ @@ -215,6 +231,8 @@ function Invoke-CIPPOffboardingJob { Parameters = @{ UserPrincipalName = $Username TenantFilter = $TenantFilter + APIName = $APIName + Headers = $Headers } } @{ @@ -225,6 +243,7 @@ function Invoke-CIPPOffboardingJob { username = $Username tenantFilter = $TenantFilter APIName = $APIName + Headers = $Headers } } @{ @@ -236,6 +255,7 @@ function Invoke-CIPPOffboardingJob { tenantFilter = $TenantFilter APIName = $APIName Schedule = $true + Headers = $Headers } } @{ @@ -247,6 +267,7 @@ function Invoke-CIPPOffboardingJob { TenantFilter = $TenantFilter User = $User APIName = $APIName + Headers = $Headers } } @{ @@ -257,6 +278,7 @@ function Invoke-CIPPOffboardingJob { Username = $Username TenantFilter = $TenantFilter APIName = $APIName + Headers = $Headers } } ) @@ -273,7 +295,7 @@ function Invoke-CIPPOffboardingJob { } if ($Batch.Count -eq 0) { - Write-LogMessage -API 'Offboarding' -tenant $TenantFilter -message "No offboarding tasks selected for user $Username" -sev Warning + Write-LogMessage -API $APIName -tenant $TenantFilter -message "No offboarding tasks selected for user $Username" -sev Warning return "No offboarding tasks were selected for $Username" } @@ -288,20 +310,19 @@ function Invoke-CIPPOffboardingJob { } # Add post-execution handler if TaskInfo is provided (from scheduled task) - if ($TaskInfo) { - $InputObject | Add-Member -NotePropertyName PostExecution -NotePropertyValue @{ - FunctionName = 'CIPPOffboardingComplete' - Parameters = @{ - TaskInfo = $TaskInfo - TenantFilter = $TenantFilter - Username = $Username - } + $InputObject | Add-Member -NotePropertyName PostExecution -NotePropertyValue @{ + FunctionName = 'CIPPOffboardingComplete' + Parameters = @{ + TaskInfo = $TaskInfo ?? $null + TenantFilter = $TenantFilter + Username = $Username + Headers = $Headers } } $InstanceId = Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($InputObject | ConvertTo-Json -Depth 10 -Compress) Write-Information "Started offboarding job for $Username with ID = '$InstanceId'" - Write-LogMessage -API 'Offboarding' -tenant $TenantFilter -message "Started offboarding job for $Username with $($Batch.Count) tasks. Instance ID: $InstanceId" -sev Info + Write-LogMessage -API $APIName -tenant $TenantFilter -message "Started offboarding job for $Username with $($Batch.Count) tasks. Instance ID: $InstanceId" -sev Info return "Offboarding job started for $Username with $($Batch.Count) tasks" diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditJITAdminTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditJITAdminTemplate.ps1 index 35bbd95139ca..868208b51e87 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditJITAdminTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-EditJITAdminTemplate.ps1 @@ -76,7 +76,7 @@ function Invoke-EditJITAdminTemplate { Write-LogMessage -headers $Headers -API $APIName -message "Unset default flag for existing template: $($data.templateName)" -Sev 'Info' } } catch { - Write-LogMessage -headers $Headers -API $APIName -message "Failed to update existing template: $($_.Exception.Message)" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message "Failed to update existing template: $($_.Exception.Message)" -sev 'Warn' } } } @@ -121,7 +121,7 @@ function Invoke-EditJITAdminTemplate { if (![string]::IsNullOrWhiteSpace($Request.Body.defaultUserName)) { $TemplateObject.defaultUserName = $Request.Body.defaultUserName } - + # defaultDomain is only saved for specific tenant templates (not AllTenants) if ($TenantFilter -ne 'AllTenants' -and $Request.Body.defaultDomain) { if ($Request.Body.defaultDomain -is [string]) { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListJITAdminTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListJITAdminTemplates.ps1 index aa5ad886758e..3a99bf6d7337 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListJITAdminTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-ListJITAdminTemplates.ps1 @@ -34,7 +34,7 @@ function Invoke-ListJITAdminTemplates { $data | Add-Member -NotePropertyName 'RowKey' -NotePropertyValue $row.RowKey -Force $data } catch { - Write-LogMessage -headers $Headers -API $APIName -message "Failed to process JIT Admin template: $($row.RowKey) - $($_.Exception.Message)" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message "Failed to process JIT Admin template: $($row.RowKey) - $($_.Exception.Message)" -sev 'Warn' } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveJITAdminTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveJITAdminTemplate.ps1 index e0ac56a8f294..ae25c9b97c18 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveJITAdminTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveJITAdminTemplate.ps1 @@ -13,7 +13,7 @@ function Invoke-RemoveJITAdminTemplate { try { $ID = $Request.Query.ID ?? $Request.Body.ID - + if ([string]::IsNullOrWhiteSpace($ID)) { throw 'ID is required' } @@ -29,7 +29,7 @@ function Invoke-RemoveJITAdminTemplate { $StatusCode = [HttpStatusCode]::OK } else { $Result = "JIT Admin Template with ID $ID not found" - Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message $Result -sev 'Warn' $StatusCode = [HttpStatusCode]::NotFound } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveUserDefaultTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveUserDefaultTemplate.ps1 index c97f52617d00..3efb129e21eb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveUserDefaultTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Identity/Administration/Users/Invoke-RemoveUserDefaultTemplate.ps1 @@ -24,7 +24,7 @@ function Invoke-RemoveUserDefaultTemplate { $StatusCode = [HttpStatusCode]::OK } else { $Result = "User Default Template with ID $ID not found" - Write-LogMessage -headers $Headers -API $APIName -message $Result -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message $Result -sev 'Warn' $StatusCode = [HttpStatusCode]::NotFound } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Invoke-ListDBCache.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Invoke-ListDBCache.ps1 new file mode 100644 index 000000000000..76268bd14dcb --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Invoke-ListDBCache.ps1 @@ -0,0 +1,46 @@ +function Invoke-ListDBCache { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + CIPP.Core.Read + #> + [CmdletBinding()] + param ( + $Request, + $TriggerMetadata + ) + + $TenantFilter = $Request.Query.tenantFilter + $Type = $Request.Query.type + + if (-not $TenantFilter) { + return ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ Results = 'Error: tenantFilter query parameter is required' } + }) + } + + if (-not $Type) { + $Types = Get-CIPPDbItem -CountsOnly -TenantFilter $TenantFilter | Select-Object -ExpandProperty RowKey + $Types = $Types | ForEach-Object { $_ -replace '-Count$', '' } | Sort-Object + + return ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = @{ + Results = 'Error: type query parameter is required' + AvailableTypes = $Types + } + }) + } + + $Tenant = Get-Tenants -TenantFilter $TenantFilter + if ($Tenant) { + $Results = New-CIPPDbRequest -TenantFilter $TenantFilter -Type $Type + } + + return ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = @{ Results = $Results } + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-AddSafeLinksPolicyFromTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-AddSafeLinksPolicyFromTemplate.ps1 index a48db0eaccaf..2c02b5b70942 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-AddSafeLinksPolicyFromTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-AddSafeLinksPolicyFromTemplate.ps1 @@ -82,13 +82,13 @@ Function Invoke-AddSafeLinksPolicyFromTemplate { # Check if policy already exists if (Test-PolicyExists -TenantFilter $TenantFilter -PolicyName $PolicyName) { - Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Policy '$PolicyName' already exists" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Policy '$PolicyName' already exists" -sev 'Warn' return "Policy '$PolicyName' already exists in tenant $TenantFilter" } # Check if rule already exists if (Test-RuleExists -TenantFilter $TenantFilter -RuleName $RuleName) { - Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Rule '$RuleName' already exists" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Rule '$RuleName' already exists" -sev 'Warn' return "Rule '$RuleName' already exists in tenant $TenantFilter" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ExecDeleteSafeLinksPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ExecDeleteSafeLinksPolicy.ps1 index f3fa33bcaa46..4f124a557e9a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ExecDeleteSafeLinksPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ExecDeleteSafeLinksPolicy.ps1 @@ -39,7 +39,7 @@ function Invoke-ExecDeleteSafeLinksPolicy { catch { $ErrorMessage = Get-CippException -Exception $_ $ResultMessages.Add("Failed to delete SafeLinks rule '$RuleName'. Error: $($ErrorMessage.NormalizedError)") | Out-Null - Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Failed to delete SafeLinks rule '$RuleName'. Error: $($ErrorMessage.NormalizedError)" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Failed to delete SafeLinks rule '$RuleName'. Error: $($ErrorMessage.NormalizedError)" -sev 'Warn' } } else { @@ -66,7 +66,7 @@ function Invoke-ExecDeleteSafeLinksPolicy { catch { $ErrorMessage = Get-CippException -Exception $_ $ResultMessages.Add("Failed to delete SafeLinks policy '$PolicyName'. Error: $($ErrorMessage.NormalizedError)") | Out-Null - Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Failed to delete SafeLinks policy '$PolicyName'. Error: $($ErrorMessage.NormalizedError)" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Failed to delete SafeLinks policy '$PolicyName'. Error: $($ErrorMessage.NormalizedError)" -sev 'Warn' } } else { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ExecNewSafeLinksPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ExecNewSafeLinksPolicy.ps1 index dbf3790b3090..dafc18eb2dcc 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ExecNewSafeLinksPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ExecNewSafeLinksPolicy.ps1 @@ -124,13 +124,13 @@ function Invoke-ExecNewSafeLinksPolicy { try { # Check if policy already exists if (Test-PolicyExists -TenantFilter $TenantFilter -PolicyName $PolicyName) { - Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Policy '$PolicyName' already exists" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Policy '$PolicyName' already exists" -sev 'Warn' return "Policy '$PolicyName' already exists in tenant $TenantFilter" } # Check if rule already exists if (Test-RuleExists -TenantFilter $TenantFilter -RuleName $RuleName) { - Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Rule '$RuleName' already exists" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Rule '$RuleName' already exists" -sev 'Warn' return "Rule '$RuleName' already exists in tenant $TenantFilter" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ListSafeLinksPolicy.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ListSafeLinksPolicy.ps1 index 8c4ec6595652..e679b579b329 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ListSafeLinksPolicy.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ListSafeLinksPolicy.ps1 @@ -179,7 +179,7 @@ Function Invoke-ListSafeLinksPolicy { $BuiltInOnlyConfigs = ($SortedOutput | Where-Object { $_.ConfigurationStatus -like "*Built-In Rule Only*" }).Count if ($PolicyOnlyConfigs -gt 0 -or $RuleOnlyConfigs -gt 0) { - Write-LogMessage -headers $Headers -API $APIName -message "Found $($PolicyOnlyConfigs + $RuleOnlyConfigs) orphaned SafeLinks configurations that may need attention" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message "Found $($PolicyOnlyConfigs + $RuleOnlyConfigs) orphaned SafeLinks configurations that may need attention" -sev 'Warn' } $StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ListSafeLinksPolicyDetails.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ListSafeLinksPolicyDetails.ps1 index 89840a6a07ed..5f8167531d3e 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ListSafeLinksPolicyDetails.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Security/Safe-Links-Policy/Invoke-ListSafeLinksPolicyDetails.ps1 @@ -43,7 +43,7 @@ function Invoke-ListSafeLinksPolicyDetails { catch { $ErrorMessage = Get-CippException -Exception $_ $LogMessages.Add("Failed to retrieve details for SafeLinks policy '$PolicyName'. Error: $($ErrorMessage.NormalizedError)") | Out-Null - Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Failed to retrieve details for SafeLinks policy '$PolicyName'. Error: $($ErrorMessage.NormalizedError)" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Failed to retrieve details for SafeLinks policy '$PolicyName'. Error: $($ErrorMessage.NormalizedError)" -sev 'Warn' $Result.PolicyError = "Failed to retrieve: $($ErrorMessage.NormalizedError)" } } @@ -72,7 +72,7 @@ function Invoke-ListSafeLinksPolicyDetails { catch { $ErrorMessage = Get-CippException -Exception $_ $LogMessages.Add("Failed to retrieve details for SafeLinks rule '$RuleName'. Error: $($ErrorMessage.NormalizedError)") | Out-Null - Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Failed to retrieve details for SafeLinks rule '$RuleName'. Error: $($ErrorMessage.NormalizedError)" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -tenant $TenantFilter -message "Failed to retrieve details for SafeLinks rule '$RuleName'. Error: $($ErrorMessage.NormalizedError)" -sev 'Warn' $Result.RuleError = "Failed to retrieve: $($ErrorMessage.NormalizedError)" } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-AddAlert.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-AddAlert.ps1 index a683b153c508..df6818654545 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-AddAlert.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Alerts/Invoke-AddAlert.ps1 @@ -1,4 +1,4 @@ -Function Invoke-AddAlert { +function Invoke-AddAlert { <# .FUNCTIONALITY Entrypoint @@ -27,6 +27,7 @@ Function Invoke-AddAlert { $WebhookTable = Get-CippTable -TableName 'WebhookRules' Add-CIPPAzDataTableEntity @WebhookTable -Entity $CompleteObject -Force $Results = "Added Audit Log Alert for $($Tenants.count) tenants. It may take up to four hours before Microsoft starts delivering these alerts." + Write-LogMessage -API 'AddAlert' -message $Results -sev Info -LogData $CompleteObject -headers $Request.Headers return ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecCreateAppTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecCreateAppTemplate.ps1 index 23315d7eb700..520536881638 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecCreateAppTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Application Approval/Invoke-ExecCreateAppTemplate.ps1 @@ -123,7 +123,7 @@ function Invoke-ExecCreateAppTemplate { $Permissions = @($DelegateResourceAccess) + @($ApplicationResourceAccess) | Where-Object { $_ -ne $null } if ($Permissions.Count -eq 0) { - Write-LogMessage -headers $Request.headers -API $APINAME -message "No permissions found for $AppId via any method" -Sev 'Warning' + Write-LogMessage -headers $Request.headers -API $APINAME -message "No permissions found for $AppId via any method" -sev 'Warn' } else { Write-LogMessage -headers $Request.headers -API $APINAME -message "Extracted $($Permissions.Count) resource permission(s) from service principal grants" -Sev 'Info' } @@ -245,7 +245,7 @@ function Invoke-ExecCreateAppTemplate { }) $RequestIndex++ } else { - Write-LogMessage -headers $Request.headers -API $APINAME -message "Service principal not found in tenant for appId: $ResourceAppId" -Sev 'Warning' + Write-LogMessage -headers $Request.headers -API $APINAME -message "Service principal not found in tenant for appId: $ResourceAppId" -sev 'Warn' } } @@ -274,7 +274,7 @@ function Invoke-ExecCreateAppTemplate { $ResourceSP = $SPLookup[$ResourceAppId] if (!$ResourceSP) { - Write-LogMessage -headers $Request.headers -API $APINAME -message "Service principal not found for appId: $ResourceAppId - skipping permission translation" -Sev 'Warning' + Write-LogMessage -headers $Request.headers -API $APINAME -message "Service principal not found for appId: $ResourceAppId - skipping permission translation" -sev 'Warn' continue } @@ -291,7 +291,7 @@ function Invoke-ExecCreateAppTemplate { } [void]$AppPerms.Add($PermObj) } else { - Write-LogMessage -headers $Request.headers -API $APINAME -message "Application permission $($Access.id) not found in $ResourceAppId appRoles" -Sev 'Warning' + Write-LogMessage -headers $Request.headers -API $APINAME -message "Application permission $($Access.id) not found in $ResourceAppId appRoles" -sev 'Warn' } } elseif ($Access.type -eq 'Scope') { Write-Information "Processing delegated permission with id $($Access.id) for resource appId $ResourceAppId" @@ -364,14 +364,14 @@ function Invoke-ExecCreateAppTemplate { $PermissionSetId = $TemplateData.PermissionSetId Write-LogMessage -headers $Request.headers -API $APINAME -message "Found existing permission set ID: $PermissionSetId in template" -Sev 'Info' } else { - Write-LogMessage -headers $Request.headers -API $APINAME -message 'Existing template found but has no PermissionSetId' -Sev 'Warning' + Write-LogMessage -headers $Request.headers -API $APINAME -message 'Existing template found but has no PermissionSetId' -sev 'Warn' } break } } } catch { # Ignore lookup errors - Write-LogMessage -headers $Request.headers -API $APINAME -message "Error during template lookup: $($_.Exception.Message)" -Sev 'Warning' + Write-LogMessage -headers $Request.headers -API $APINAME -message "Error during template lookup: $($_.Exception.Message)" -sev 'Warn' } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 index c0fa299b5466..e114d1a32977 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Administration/Tenant/Invoke-ListTenants.ps1 @@ -94,7 +94,7 @@ function Invoke-ListTenants { try { $Tenant | Add-Member -MemberType NoteProperty -Name 'offboardingDefaults' -Value ($TenantDefaults.Value | ConvertFrom-Json) -Force } catch { - Write-LogMessage -headers $Headers -API $APIName -message "Failed to parse offboarding defaults for tenant $($Tenant.customerId): $($_.Exception.Message)" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message "Failed to parse offboarding defaults for tenant $($Tenant.customerId): $($_.Exception.Message)" -sev 'Warn' $Tenant | Add-Member -MemberType NoteProperty -Name 'offboardingDefaults' -Value $null -Force } } else { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRoleTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRoleTemplate.ps1 index 07018acad177..17f648740620 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRoleTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/GDAP/Invoke-ExecGDAPRoleTemplate.ps1 @@ -18,7 +18,7 @@ function Invoke-ExecGDAPRoleTemplate { if ($Request.Query.TemplateId) { $Template = $Templates | Where-Object -Property RowKey -EQ $Request.Query.TemplateId if (!$Template) { - Write-LogMessage -headers $Headers -API $APIName -message "GDAP role template '$($Request.Query.TemplateId)' not found" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message "GDAP role template '$($Request.Query.TemplateId)' not found" -sev 'Warn' $Body = @{} } else { Write-LogMessage -headers $Headers -API $APIName -message "Retrieved GDAP role template '$($Request.Query.TemplateId)'" -Sev 'Info' @@ -50,7 +50,7 @@ function Invoke-ExecGDAPRoleTemplate { $Template = $Templates | Where-Object -Property RowKey -EQ $OriginalRowKey if ($Template) { $RoleMappings = $Request.Body.RoleMappings - + # If the template ID is being changed, delete the old one and create a new one if ($OriginalRowKey -ne $NewRowKey) { Remove-AzDataTableEntity -Force @Table -Entity $Template @@ -68,7 +68,7 @@ function Invoke-ExecGDAPRoleTemplate { } } } else { - Write-LogMessage -headers $Headers -API $APIName -message "GDAP role template '$OriginalRowKey' not found for editing" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message "GDAP role template '$OriginalRowKey' not found for editing" -sev 'Warn' $Body = @{ Results = "Template $OriginalRowKey not found" } @@ -84,7 +84,7 @@ function Invoke-ExecGDAPRoleTemplate { Results = "Deleted template $RowKey" } } else { - Write-LogMessage -headers $Headers -API $APIName -message "GDAP role template '$RowKey' not found for deletion" -Sev 'Warning' + Write-LogMessage -headers $Headers -API $APIName -message "GDAP role template '$RowKey' not found for deletion" -sev 'Warn' $Body = @{ Results = "Template $RowKey not found" } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ExecUpdateDriftDeviation.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ExecUpdateDriftDeviation.ps1 index 63b639e3769e..0d6b2b52c592 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ExecUpdateDriftDeviation.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ExecUpdateDriftDeviation.ps1 @@ -58,9 +58,9 @@ function Invoke-ExecUpdateDriftDeviation { $Settings = $StandardTemplate } else { $StandardTemplate = $StandardTemplate.standardSettings.$Setting - $StandardTemplate.standards.$Setting | Add-Member -MemberType NoteProperty -Name 'remediate' -Value $true -Force - $StandardTemplate.standards.$Setting | Add-Member -MemberType NoteProperty -Name 'report' -Value $true -Force - $Settings = $StandardTemplate.standards.$Setting + $StandardTemplate | Add-Member -MemberType NoteProperty -Name 'remediate' -Value $true -Force + $StandardTemplate | Add-Member -MemberType NoteProperty -Name 'report' -Value $true -Force + $Settings = $StandardTemplate } $TaskBody = @{ TenantFilter = $TenantFilter @@ -100,7 +100,7 @@ function Invoke-ExecUpdateDriftDeviation { Write-LogMessage -tenant $TenantFilter -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Deleted Policy with ID $($ID)" -Sev 'Info' } else { "could not find policy with ID $($ID)" - Write-LogMessage -tenant $TenantFilter -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not find Policy with ID $($ID) to delete for remediation" -Sev 'Warning' + Write-LogMessage -tenant $TenantFilter -user $request.headers.'x-ms-client-principal' -API $APINAME -message "Could not find Policy with ID $($ID) to delete for remediation" -sev 'Warn' } diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 index 6c0581ad0c8e..27a369092a08 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ExecListAppId.ps1 @@ -83,13 +83,13 @@ function Invoke-ExecListAppId { Invoke-GraphRequest -Method PATCH -Url "https://graph.microsoft.com/v1.0/applications/$($AppResponse.body.id)" -Body $AppUpdateBody -tenantid $env:TenantID -NoAuthCheck $true Write-LogMessage -message "Updated redirect URIs for application $($env:ApplicationID) to include $NewRedirectUri" -Sev 'Info' } catch { - Write-LogMessage -message "Failed to update redirect URIs for application $($env:ApplicationID)" -LogData (Get-CippException -Exception $_) -Sev 'Warning' + Write-LogMessage -message "Failed to update redirect URIs for application $($env:ApplicationID)" -LogData (Get-CippException -Exception $_) -sev 'Warn' } } } } } catch { - Write-LogMessage -message 'Failed to retrieve organization info and authenticated user' -LogData (Get-CippException -Exception $_) -Sev 'Warning' + Write-LogMessage -message 'Failed to retrieve organization info and authenticated user' -LogData (Get-CippException -Exception $_) -sev 'Warn' } $Results = @{ diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1 index 1bf2c4bfaabc..e1fe3dc11a16 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListExternalTenantInfo.ps1 @@ -22,10 +22,24 @@ function Invoke-ListExternalTenantInfo { if ($TenantId) { $GraphRequest = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId(tenantId='$TenantId')" -NoAuthCheck $true -tenantid $env:TenantID + + + # New API call to retrieve branding details + $brandingBody = @{ + username = "completelymadeupdoesnthavetobevalid@$($GraphRequest.defaultDomainName)" + } | ConvertTo-Json + + $brandingHeaders = @{ + "Content-Type" = "application/json" + } + + $brandingResponse = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/common/GetCredentialType" -Body $brandingBody -Headers $brandingHeaders + $StatusCode = [HttpStatusCode]::OK $HttpResponse.Body = [PSCustomObject]@{ GraphRequest = $GraphRequest OpenIdConfig = $OpenIdConfig + UserTenantBranding = $brandingResponse.EstsProperties.UserTenantBranding } } else { $HttpResponse.StatusCode = [HttpStatusCode]::BadRequest diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 index 8c4d4953bdf0..bd708947c66f 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 @@ -82,7 +82,7 @@ function Invoke-ListLogs { } } else { if ($request.Query.Filter -eq 'True') { - $LogLevel = if ($Request.Query.Severity) { ($Request.query.Severity).split(',') } else { 'Info', 'Warn', 'Error', 'Critical', 'Alert' } + $LogLevel = if ($Request.Query.Severity) { ($Request.query.Severity).split(',') } else { 'Info', 'Warn', 'Warning', 'Error', 'Critical', 'Alert' } $PartitionKey = $Request.Query.DateFilter $username = $Request.Query.User ?? '*' $TenantFilter = $Request.Query.Tenant @@ -102,7 +102,7 @@ function Invoke-ListLogs { $Filter = "PartitionKey eq '{0}'" -f (Get-Date -UFormat '%Y%m%d') } } else { - $LogLevel = 'Info', 'Warn', 'Error', 'Critical', 'Alert' + $LogLevel = 'Info', 'Warn', 'Warning', 'Error', 'Critical', 'Alert' $PartitionKey = Get-Date -UFormat '%Y%m%d' $username = '*' $TenantFilter = $null diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-BackupRetentionCleanup.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-BackupRetentionCleanup.ps1 index ed00a0292aa1..b8edf3aedd94 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-BackupRetentionCleanup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-BackupRetentionCleanup.ps1 @@ -64,7 +64,7 @@ function Start-BackupRetentionCleanup { $BlobDeletedCount++ Write-Host "Deleted blob: $BlobPath" } catch { - Write-LogMessage -API 'BackupRetentionCleanup' -message "Failed to delete blob $($Backup.Backup): $($_.Exception.Message)" -Sev 'Warning' + Write-LogMessage -API 'BackupRetentionCleanup' -message "Failed to delete blob $($Backup.Backup): $($_.Exception.Message)" -sev 'Warn' } } } @@ -124,7 +124,7 @@ function Start-BackupRetentionCleanup { $BlobDeletedCount++ Write-Host "Deleted blob: $BlobPath" } catch { - Write-LogMessage -API 'BackupRetentionCleanup' -message "Failed to delete blob $($Backup.Backup): $($_.Exception.Message)" -Sev 'Warning' + Write-LogMessage -API 'BackupRetentionCleanup' -message "Failed to delete blob $($Backup.Backup): $($_.Exception.Message)" -sev 'Warn' } } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 index 74f620e133e1..771e9d66363c 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-TableCleanup.ps1 @@ -75,6 +75,16 @@ function Start-TableCleanup { Property = @('PartitionKey', 'RowKey', 'ETag') } } + @{ + FunctionName = 'TableCleanupTask' + Type = 'CleanupRule' + TableName = 'cacheQuarantineMessages' + DataTableProps = @{ + Filter = "PartitionKey eq 'QuarantineMessage' and Timestamp lt datetime'$((Get-Date).AddDays(-1).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ'))'" + First = 10000 + Property = @('PartitionKey', 'RowKey', 'ETag') + } + } @{ FunctionName = 'TableCleanupTask' Type = 'DeleteTable' diff --git a/Modules/CIPPCore/Public/Functions/Get-CIPPTenantAlignment.ps1 b/Modules/CIPPCore/Public/Functions/Get-CIPPTenantAlignment.ps1 index a2a6553fb250..b0eac304e54c 100644 --- a/Modules/CIPPCore/Public/Functions/Get-CIPPTenantAlignment.ps1 +++ b/Modules/CIPPCore/Public/Functions/Get-CIPPTenantAlignment.ps1 @@ -128,8 +128,8 @@ function Get-CIPPTenantAlignment { $TenantValues.Add($filterItem.value) } } -` - if ($TenantValues -contains 'AllTenants') { + + if ($TenantValues -contains 'AllTenants') { $AppliestoAllTenants = $true } elseif ($TenantValues.Count -gt 0) { $TemplateAssignedTenants = @($TenantValues) diff --git a/Modules/CIPPCore/Public/Functions/Remove-EmptyArrays.ps1 b/Modules/CIPPCore/Public/Functions/Remove-EmptyArrays.ps1 index 85726be4607a..fd46b76e72b5 100644 --- a/Modules/CIPPCore/Public/Functions/Remove-EmptyArrays.ps1 +++ b/Modules/CIPPCore/Public/Functions/Remove-EmptyArrays.ps1 @@ -1,40 +1,11 @@ -function Remove-EmptyArrays { - <# - .SYNOPSIS - Recursively removes empty arrays and null properties from objects - .DESCRIPTION - This function recursively traverses an object (Array, Hashtable, or PSCustomObject) and removes: - - Empty arrays - - Null properties - The function modifies the object in place. - .PARAMETER Object - The object to process (can be Array, Hashtable, or PSCustomObject) - .FUNCTIONALITY - Internal - .EXAMPLE - $obj = @{ items = @(); name = "test"; value = $null } - Remove-EmptyArrays -Object $obj - .EXAMPLE - $obj = [PSCustomObject]@{ items = @(); name = "test" } - Remove-EmptyArrays -Object $obj - #> - [CmdletBinding()] - param( - [Parameter(Mandatory = $true)] - [object]$Object - ) - +function Remove-EmptyArrays ($Object) { if ($Object -is [Array]) { - foreach ($Item in $Object) { - Remove-EmptyArrays -Object $Item - } + foreach ($Item in $Object) { Remove-EmptyArrays $Item } } elseif ($Object -is [HashTable]) { foreach ($Key in @($Object.get_Keys())) { if ($Object[$Key] -is [Array] -and $Object[$Key].get_Count() -eq 0) { $Object.Remove($Key) - } else { - Remove-EmptyArrays -Object $Object[$Key] - } + } else { Remove-EmptyArrays $Object[$Key] } } } elseif ($Object -is [PSCustomObject]) { foreach ($Name in @($Object.PSObject.Properties.Name)) { @@ -42,9 +13,7 @@ function Remove-EmptyArrays { $Object.PSObject.Properties.Remove($Name) } elseif ($null -eq $Object.$Name) { $Object.PSObject.Properties.Remove($Name) - } else { - Remove-EmptyArrays -Object $Object.$Name - } + } else { Remove-EmptyArrays $Object.$Name } } } } diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 index 0b961c534385..2cfabcdc42f2 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphBulkRequest.ps1 @@ -12,11 +12,16 @@ function New-GraphBulkRequest { $Requests, $NoPaginateIds = @(), [ValidateSet('v1.0', 'beta')] - $Version = 'beta' + $Version = 'beta', + $Headers ) if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { - $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp + if ($Headers) { + $Headers = $Headers + } else { + $Headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp + } if ($script:XMsThrottlePriority) { $headers['x-ms-throttle-priority'] = $script:XMsThrottlePriority @@ -56,13 +61,14 @@ function New-GraphBulkRequest { } Write-Host 'Getting more' Write-Host $MoreData.body.'@odata.nextLink' - $AdditionalValues = New-GraphGetRequest -ComplexFilter -uri $MoreData.body.'@odata.nextLink' -tenantid $tenantid -NoAuthCheck $NoAuthCheck -scope $scope -AsApp $asapp + $AdditionalValues = New-GraphGetRequest -ComplexFilter -uri $MoreData.body.'@odata.nextLink' -tenantid $tenantid -NoAuthCheck $NoAuthCheck -scope $scope -AsApp $asapp -headers $Headers $NewValues = [System.Collections.Generic.List[PSCustomObject]]$MoreData.body.value $AdditionalValues | ForEach-Object { $NewValues.add($_) } $MoreData.body.value = $NewValues } } catch { + Write-Host 'updating graph table because something failed.' # Try to parse ErrorDetails.Message as JSON if ($_.ErrorDetails.Message) { try { @@ -91,7 +97,6 @@ function New-GraphBulkRequest { $Tenant.LastGraphError = '' } Update-AzDataTableEntity -Force @TenantsTable -Entity $Tenant - return $ReturnedData.responses } else { Write-Error 'Not allowed. You cannot manage your own tenant or tenants not under your scope' diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 index 23b0e59d3dc7..be328974d1e2 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphGetRequest.ps1 @@ -17,7 +17,8 @@ function New-GraphGetRequest { [switch]$CountOnly, [switch]$IncludeResponseHeaders, [hashtable]$extraHeaders, - [switch]$ReturnRawResponse + [switch]$ReturnRawResponse, + $Headers ) if ($NoAuthCheck -eq $false) { @@ -27,12 +28,15 @@ function New-GraphGetRequest { } if ($NoAuthCheck -eq $true -or $IsAuthorised) { - if ($scope -eq 'ExchangeOnline') { - $headers = Get-GraphToken -tenantid $tenantid -scope 'https://outlook.office365.com/.default' -AsApp $asapp -SkipCache $skipTokenCache + if ($headers) { + $headers = $Headers } else { - $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp -SkipCache $skipTokenCache + if ($scope -eq 'ExchangeOnline') { + $headers = Get-GraphToken -tenantid $tenantid -scope 'https://outlook.office365.com/.default' -AsApp $asapp -SkipCache $skipTokenCache + } else { + $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp -SkipCache $skipTokenCache + } } - if ($ComplexFilter) { $headers['ConsistencyLevel'] = 'eventual' } diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 index d2ac97fb8839..d637e0d7c6c8 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 @@ -18,11 +18,16 @@ function New-GraphPOSTRequest { $IgnoreErrors = $false, $returnHeaders = $false, $maxRetries = 3, - $ScheduleRetry = $false + $ScheduleRetry = $false, + $headers ) if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { - $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp -SkipCache $skipTokenCache + if ($Headers) { + $Headers = $Headers + } else { + $Headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp -SkipCache $skipTokenCache + } if ($AddedHeaders) { foreach ($header in $AddedHeaders.GetEnumerator()) { $headers.Add($header.Key, $header.Value) @@ -36,8 +41,8 @@ function New-GraphPOSTRequest { if (!$contentType) { $contentType = 'application/json; charset=utf-8' } - - $body = Get-CIPPTextReplacement -TenantFilter $tenantid -Text $body -EscapeForJson + #Only do text replacement if no headers are set. + if (!$headers) { $body = Get-CIPPTextReplacement -TenantFilter $tenantid -Text $body -EscapeForJson } $RetryCount = 0 $RequestSuccessful = $false diff --git a/Modules/CIPPCore/Public/GraphHelper/Update-AppManagementPolicy.ps1 b/Modules/CIPPCore/Public/GraphHelper/Update-AppManagementPolicy.ps1 index 1c5e20ae81df..5a44d65fddd5 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Update-AppManagementPolicy.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Update-AppManagementPolicy.ps1 @@ -15,7 +15,8 @@ function Update-AppManagementPolicy { [CmdletBinding()] param( $TenantFilter = $env:TenantID, - $ApplicationId = $env:ApplicationID + $ApplicationId = $env:ApplicationID, + $headers ) try { @@ -39,8 +40,7 @@ function Update-AppManagementPolicy { ) # Execute bulk request - $Results = New-GraphBulkRequest -Requests $Requests -NoAuthCheck $true -asapp $true -tenantid $TenantFilter - + $Results = New-GraphBulkRequest -Requests $Requests -NoAuthCheck $true -asapp $true -tenantid $TenantFilter -headers $headers # Parse results $DefaultPolicy = ($Results | Where-Object { $_.id -eq 'defaultPolicy' }).body $AppPolicies = ($Results | Where-Object { $_.id -eq 'appPolicies' }).body.value @@ -60,8 +60,7 @@ function Update-AppManagementPolicy { }) if ($AppliesToRequests.Count -gt 0) { - $AppliesToResults = New-GraphBulkRequest -Requests $AppliesToRequests -NoAuthCheck $true -asapp $true -tenantid $TenantFilter - + $AppliesToResults = New-GraphBulkRequest -Requests $AppliesToRequests -NoAuthCheck $true -asapp $true -tenantid $TenantFilter -headers $headers # Find which policy (if any) targets the app $CIPPPolicyResult = $AppliesToResults | Where-Object { $_.body.value.appId -contains $ApplicationId } | Select-Object -First 1 if ($CIPPPolicyResult) { @@ -171,18 +170,18 @@ function Update-AppManagementPolicy { if ($CIPPAppPolicyId) { # Update existing policy that's already assigned to the app - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/policies/appManagementPolicies/$CIPPAppPolicyId" -type PATCH -body ($PolicyBody | ConvertTo-Json -Depth 10) -asapp $true -NoAuthCheck $true -tenantid $TenantFilter + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/policies/appManagementPolicies/$CIPPAppPolicyId" -type PATCH -body ($PolicyBody | ConvertTo-Json -Depth 10) -asapp $true -NoAuthCheck $true -tenantid $TenantFilter -headers $headers $PolicyAction = "Updated existing policy $CIPPAppPolicyId to allow credentials" } elseif ($ExistingExemptionPolicy) { # Exemption policy exists but not assigned to app - update and assign it - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/policies/appManagementPolicies/$($ExistingExemptionPolicy.id)" -type PATCH -body ($PolicyBody | ConvertTo-Json -Depth 10) -asapp $true -NoAuthCheck $true + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/v1.0/policies/appManagementPolicies/$($ExistingExemptionPolicy.id)" -type PATCH -body ($PolicyBody | ConvertTo-Json -Depth 10) -asapp $true -NoAuthCheck $true -headers $headers if ($CIPPApp.id) { # Assign existing policy to CIPP-SAM application $AssignBody = @{ '@odata.id' = "https://graph.microsoft.com/beta/policies/appManagementPolicies/$($ExistingExemptionPolicy.id)" } - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/applications/$($CIPPApp.id)/appManagementPolicies/`$ref" -type POST -body ($AssignBody | ConvertTo-Json) -asapp $true -NoAuthCheck $true -tenantid $TenantFilter + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/applications/$($CIPPApp.id)/appManagementPolicies/`$ref" -type POST -body ($AssignBody | ConvertTo-Json) -asapp $true -NoAuthCheck $true -tenantid $TenantFilter -headers $headers $PolicyAction = "Updated and assigned existing policy $($ExistingExemptionPolicy.id) to CIPP-SAM" $CIPPAppPolicyId = $ExistingExemptionPolicy.id $CIPPAppTargeted = $true @@ -191,14 +190,14 @@ function Update-AppManagementPolicy { } } else { # Create new policy and assign to CIPP-SAM app - $CreatedPolicy = New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/policies/appManagementPolicies' -type POST -body ($PolicyBody | ConvertTo-Json -Depth 10) -asapp $true -NoAuthCheck $true + $CreatedPolicy = New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/policies/appManagementPolicies' -type POST -body ($PolicyBody | ConvertTo-Json -Depth 10) -asapp $true -NoAuthCheck $true -headers $headers if ($CIPPApp.id) { # Assign policy to CIPP-SAM application using beta endpoint $AssignBody = @{ '@odata.id' = "https://graph.microsoft.com/beta/policies/appManagementPolicies/$($CreatedPolicy.id)" } - $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/applications/$($CIPPApp.id)/appManagementPolicies/`$ref" -type POST -body ($AssignBody | ConvertTo-Json) -asapp $true -NoAuthCheck $true + $null = New-GraphPostRequest -uri "https://graph.microsoft.com/beta/applications/$($CIPPApp.id)/appManagementPolicies/`$ref" -type POST -body ($AssignBody | ConvertTo-Json) -asapp $true -NoAuthCheck $true -headers $headers $PolicyAction = "Created new policy $($CreatedPolicy.id) and assigned to CIPP-SAM" $CIPPAppPolicyId = $CreatedPolicy.id $CIPPAppTargeted = $true diff --git a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 index 76fba584da6d..d637c614e88d 100644 --- a/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPCAPolicy.ps1 @@ -89,7 +89,7 @@ function New-CIPPCAPolicy { $displayName = ($RawJSON | ConvertFrom-Json).displayName $JSONobj = $RawJSON | ConvertFrom-Json | Select-Object * -ExcludeProperty ID, GUID, *time* - Remove-EmptyArrays -Object $JSONobj + Remove-EmptyArrays $JSONobj #Remove context as it does not belong in the payload. try { if ($JSONobj.grantControls) { diff --git a/Modules/CIPPCore/Public/New-CIPPRestoreTask.ps1 b/Modules/CIPPCore/Public/New-CIPPRestoreTask.ps1 index d750ce6cdea9..4ef75831b703 100644 --- a/Modules/CIPPCore/Public/New-CIPPRestoreTask.ps1 +++ b/Modules/CIPPCore/Public/New-CIPPRestoreTask.ps1 @@ -103,7 +103,7 @@ function New-CIPPRestoreTask { } } catch { $restorationStats['CustomVariables'].failed++ - Write-LogMessage -message "Failed to restore custom variable $($variable.RowKey): $($_.Exception.Message)" -Sev 'Warning' + Write-LogMessage -message "Failed to restore custom variable $($variable.RowKey): $($_.Exception.Message)" -sev 'Warn' $RestoreData.Add("Failed to restore custom variable $($variable.RowKey)") } } diff --git a/Modules/CIPPCore/Public/Remove-CIPPCalendarPermissions.ps1 b/Modules/CIPPCore/Public/Remove-CIPPCalendarPermissions.ps1 index 402eca0145b9..9a547a29f1ec 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPCalendarPermissions.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPCalendarPermissions.ps1 @@ -112,9 +112,9 @@ function Remove-CIPPCalendarPermissions { } catch { Write-Verbose "Failed to sync cache: $_" } - + $ErrorMsg = "Failed to remove $UserToRemove from calendar $($CalPermEntry.CalendarUPN): $($_.Exception.Message)" - Write-LogMessage -headers $Headers -API $APIName -message $ErrorMsg -Sev 'Warning' -tenant $TenantFilter + Write-LogMessage -headers $Headers -API $APIName -message $ErrorMsg -sev 'Warn' -tenant $TenantFilter $Results.Add($ErrorMsg) } } @@ -156,7 +156,7 @@ function Remove-CIPPCalendarPermissions { # Sync cache even on error (permission might not exist) $MailboxUPN = if ($CalendarIdentity -match '^([^:]+):') { $Matches[1] } else { $CalendarIdentity } $Folder = if ($CalendarIdentity -match ':\\(.+)$') { $Matches[1] } else { $FolderName } - + try { Sync-CIPPCalendarPermissionCache -TenantFilter $TenantFilter -MailboxIdentity $MailboxUPN -FolderName $Folder -User $UserToRemove -Action 'Remove' } catch { diff --git a/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 b/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 index 527de771990e..bec2daa302b3 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPGroups.ps1 @@ -8,78 +8,111 @@ function Remove-CIPPGroups { $UserID ) - if (-not $userid) { - $UserID = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($Username)" -tenantid $TenantFilter).id - } - $AllGroups = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/groups/?`$select=displayName,mailEnabled,id,groupTypes,assignedLicenses,onPremisesSyncEnabled,membershipRule&`$top=999" -tenantid $TenantFilter) + try { - # Get user's groups - $UserGroups = (New-GraphPostRequest -uri "https://graph.microsoft.com/beta/users/$($UserID)/GetMemberGroups" -tenantid $TenantFilter -type POST -body '{"securityEnabledOnly": false}').value + $BulkInfoRequests = [System.Collections.Generic.List[object]]::new() - if (-not $UserGroups) { - $Returnval = "$($Username) is not a member of any groups." - Write-LogMessage -headers $Headers -API $APIName -message "$($Username) is not a member of any groups" -Sev 'Info' -tenant $TenantFilter - return $Returnval - } + if (-not $UserID) { + $BulkInfoRequests.Add(@{ + id = 'getUserID' + method = 'GET' + url = "users/$($Username)?`$select=id" + }) + } + + $BulkInfoRequests.Add( + @{ + id = 'getAllGroups' + method = 'GET' + url = "groups/?`$select=displayName,mailEnabled,id,groupTypes,assignedLicenses,onPremisesSyncEnabled,membershipRule&`$top=999" + }) + $BulkInfoRequests.Add(@{ + id = 'getUserGroups' + method = 'GET' + url = "users/$($UserID ?? $Username)/memberOf/microsoft.graph.group?`$select=id" + }) + + $BulkGetResults = New-GraphBulkRequest -tenantid $TenantFilter -Requests @($BulkInfoRequests) + + $UserInfo = ($BulkGetResults | Where-Object { $_.id -eq 'getUserID' }).body + if ($UserInfo) { + $UserID = $UserInfo.id + } + $AllGroups = ($BulkGetResults | Where-Object { $_.id -eq 'getAllGroups' }).body.value + $UserGroups = ($BulkGetResults | Where-Object { $_.id -eq 'getUserGroups' }).body.value + + #users/$($User.id)/memberOf/microsoft.graph.directoryRole + if (-not $UserGroups) { + $Returnval = "$($Username) is not a member of any groups." + Write-LogMessage -headers $Headers -API $APIName -message "$($Username) is not a member of any groups" -Sev 'Info' -tenant $TenantFilter + return $Returnval + } + + Write-Information "Initiating group membership removal for user: $Username in tenant: $TenantFilter" + + # Initialize bulk request arrays and results + $BulkRequests = [System.Collections.Generic.List[object]]::new() + $ExoBulkRequests = [System.Collections.Generic.List[object]]::new() + $GraphLogs = [System.Collections.Generic.List[object]]::new() + $ExoLogs = [System.Collections.Generic.List[object]]::new() + $Results = [System.Collections.Generic.List[string]]::new() + + # Process each group and prepare bulk requests + foreach ($Group in $UserGroups) { + $GroupInfo = $AllGroups | Where-Object -Property id -EQ $Group.id + $GroupName = $GroupInfo.displayName + $IsMailEnabled = $GroupInfo.mailEnabled + $IsM365Group = $GroupInfo.groupTypes -and $GroupInfo.groupTypes -contains 'Unified' + $IsLicensed = $GroupInfo.assignedLicenses.Count -gt 0 + $IsDynamic = -not [string]::IsNullOrWhiteSpace($GroupInfo.membershipRule) - # Initialize bulk request arrays and results - $BulkRequests = [System.Collections.Generic.List[object]]::new() - $ExoBulkRequests = [System.Collections.Generic.List[object]]::new() - $GraphLogs = [System.Collections.Generic.List[object]]::new() - $ExoLogs = [System.Collections.Generic.List[object]]::new() - $Results = [System.Collections.Generic.List[string]]::new() - - # Process each group and prepare bulk requests - foreach ($Group in $UserGroups) { - $GroupInfo = $AllGroups | Where-Object -Property id -EQ $Group - $GroupName = $GroupInfo.displayName - $IsMailEnabled = $GroupInfo.mailEnabled - $IsM365Group = $null -ne ($AllGroups | Where-Object { $_.id -eq $Group -and $_.groupTypes -contains 'Unified' }) - $IsLicensed = $GroupInfo.assignedLicenses.Count -gt 0 - $IsDynamic = -not [string]::IsNullOrWhiteSpace($GroupInfo.membershipRule) - - if ($IsLicensed) { - $Results.Add("Could not remove $Username from group '$GroupName' because it has assigned licenses. These groups are removed during the license removal step.") - Write-LogMessage -headers $Headers -API $APIName -message "Could not remove $Username from group '$GroupName' because it has assigned licenses. These groups are removed during the license removal step." -Sev 'Warning' -tenant $TenantFilter - } elseif ($IsDynamic) { - $Results.Add("Error: Could not remove $Username from group '$GroupName' because it is a Dynamic Group.") - Write-LogMessage -headers $Headers -API $APIName -message "Could not remove $Username from group '$GroupName' because it is a Dynamic Group." -Sev 'Warning' -tenant $TenantFilter - } elseif ($GroupInfo.onPremisesSyncEnabled) { - $Results.Add("Error: Could not remove $Username from group '$GroupName' because it is synced with Active Directory.") - Write-LogMessage -headers $Headers -API $APIName -message "Could not remove $Username from group '$GroupName' because it is synced with Active Directory." -Sev 'Warning' -tenant $TenantFilter - } else { - if ($IsM365Group -or (-not $IsMailEnabled)) { - # Use Graph API for M365 Groups and Security Groups - $BulkRequests.Add(@{ - id = "removeFromGroup-$Group" - method = 'DELETE' - url = "groups/$Group/members/$UserID/`$ref" - }) - $GraphLogs.Add(@{ - message = "Removed $Username from $GroupName" - id = "removeFromGroup-$Group" - groupName = $GroupName - }) - } elseif ($IsMailEnabled) { - # Use Exchange Online for Distribution Lists - $Params = @{ - Identity = $GroupName - Member = $UserID - BypassSecurityGroupManagerCheck = $true + if ($IsLicensed) { + $Results.Add("Could not remove $Username from group '$GroupName' because it has assigned licenses. These groups are removed during the license removal step.") + Write-LogMessage -headers $Headers -API $APIName -message "Could not remove $Username from group '$GroupName' because it has assigned licenses. These groups are removed during the license removal step." -sev 'Warn' -tenant $TenantFilter + } elseif ($IsDynamic) { + $Results.Add("Error: Could not remove $Username from group '$GroupName' because it is a Dynamic Group.") + Write-LogMessage -headers $Headers -API $APIName -message "Could not remove $Username from group '$GroupName' because it is a Dynamic Group." -sev 'Warn' -tenant $TenantFilter + } elseif ($GroupInfo.onPremisesSyncEnabled) { + $Results.Add("Error: Could not remove $Username from group '$GroupName' because it is synced with Active Directory.") + Write-LogMessage -headers $Headers -API $APIName -message "Could not remove $Username from group '$GroupName' because it is synced with Active Directory." -sev 'Warn' -tenant $TenantFilter + } else { + if ($IsM365Group -or (-not $IsMailEnabled)) { + # Use Graph API for M365 Groups and Security Groups + $BulkRequests.Add(@{ + id = "removeFromGroup-$($Group.id)" + method = 'DELETE' + url = "groups/$($Group.id)/members/$UserID/`$ref" + }) + $GraphLogs.Add(@{ + message = "Removed $Username from $GroupName" + id = "removeFromGroup-$($Group.id)" + groupName = $GroupName + }) + } elseif ($IsMailEnabled) { + # Use Exchange Online for Distribution Lists + $Params = @{ + Identity = $GroupName + Member = $UserID + BypassSecurityGroupManagerCheck = $true + } + $ExoBulkRequests.Add(@{ + CmdletInput = @{ + CmdletName = 'Remove-DistributionGroupMember' + Parameters = $Params + } + }) + $ExoLogs.Add(@{ + message = "Removed $Username from $GroupName" + target = $UserID + groupName = $GroupName + }) } - $ExoBulkRequests.Add(@{ - CmdletInput = @{ - CmdletName = 'Remove-DistributionGroupMember' - Parameters = $Params - } - }) - $ExoLogs.Add(@{ - message = "Removed $Username from $GroupName" - target = $UserID - groupName = $GroupName - }) } } + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -headers $Headers -API $APIName -message "Error preparing bulk group removal requests: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage + return "Error preparing bulk group removal requests: $($ErrorMessage.NormalizedError)" } # Execute Graph bulk requests @@ -100,8 +133,7 @@ function Remove-CIPPGroups { } } catch { $ErrorMessage = Get-CippException -Exception $_ - Write-LogMessage -headers $Headers -API $APIName -message "Error executing Graph bulk requests: $($ErrorMessage.NormalizedError)" -Sev 'Error' -tenant $TenantFilter -LogData $ErrorMessage - $Results.Add("Error executing bulk removal requests: $($ErrorMessage.NormalizedError)") + Write-Information "Error executing bulk Graph requests: $($ErrorMessage | ConvertTo-Json -Depth 5)" } } diff --git a/Modules/CIPPCore/Public/Remove-CIPPMailboxPermissions.ps1 b/Modules/CIPPCore/Public/Remove-CIPPMailboxPermissions.ps1 index 0b8927896be9..b3bbee435102 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPMailboxPermissions.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPMailboxPermissions.ps1 @@ -43,7 +43,7 @@ function Remove-CIPPMailboxPermissions { } } catch { $ErrorMsg = "Failed to remove permissions from $MailboxUPN for $AccessUser : $($_.Exception.Message)" - Write-LogMessage -headers $Headers -API $APIName -message $ErrorMsg -Sev 'Warning' -tenant $TenantFilter + Write-LogMessage -headers $Headers -API $APIName -message $ErrorMsg -sev 'Warn' -tenant $TenantFilter $Results.Add($ErrorMsg) } } diff --git a/Modules/CIPPCore/Public/Remove-CIPPMailboxRule.ps1 b/Modules/CIPPCore/Public/Remove-CIPPMailboxRule.ps1 index 1f470021a92b..9559f97eb0a7 100644 --- a/Modules/CIPPCore/Public/Remove-CIPPMailboxRule.ps1 +++ b/Modules/CIPPCore/Public/Remove-CIPPMailboxRule.ps1 @@ -46,7 +46,7 @@ function Remove-CIPPMailboxRule { try { Remove-CIPPDbItem -TenantFilter $TenantFilter -Type 'MailboxRules' -ItemId $RuleId } catch { - Write-LogMessage -headers $Headers -API $APIName -message "Rule deleted but failed to remove from cache: $($_.Exception.Message)" -Sev 'Warning' -tenant $TenantFilter + Write-LogMessage -headers $Headers -API $APIName -message "Rule deleted but failed to remove from cache: $($_.Exception.Message)" -sev 'Warn' -tenant $TenantFilter } return $Message diff --git a/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 b/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 index eadfeef81f39..680ac28c9adf 100644 --- a/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPAssignedPolicy.ps1 @@ -31,7 +31,7 @@ function Set-CIPPAssignedPolicy { Write-Host "Found assignment filter: $($MatchingFilter.displayName) with ID: $ResolvedFilterId" } else { $ErrorMessage = "No assignment filter found matching the name: $AssignmentFilterName. Policy assigned without filter." - Write-LogMessage -headers $Headers -API $APIName -message $ErrorMessage -Sev 'Warning' -tenant $TenantFilter + Write-LogMessage -headers $Headers -API $APIName -message $ErrorMessage -sev 'Warn' -tenant $TenantFilter Write-Host $ErrorMessage } } @@ -95,7 +95,7 @@ function Set-CIPPAssignedPolicy { if (-not $resolvedGroupIds -or $resolvedGroupIds.Count -eq 0) { $ErrorMessage = "No groups found matching the specified name(s): $GroupName. Policy not assigned." - Write-LogMessage -headers $Headers -API $APIName -message $ErrorMessage -Sev 'Warning' -tenant $TenantFilter + Write-LogMessage -headers $Headers -API $APIName -message $ErrorMessage -sev 'Warn' -tenant $TenantFilter throw $ErrorMessage } diff --git a/Modules/CIPPCore/Public/Set-CIPPMailboxRule.ps1 b/Modules/CIPPCore/Public/Set-CIPPMailboxRule.ps1 index e99ead09a19d..06dc1d126e59 100644 --- a/Modules/CIPPCore/Public/Set-CIPPMailboxRule.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPMailboxRule.ps1 @@ -32,7 +32,7 @@ Enabled = $EnabledValue } } catch { - Write-LogMessage -headers $Headers -API $APIName -message "Rule updated but failed to update cache: $($_.Exception.Message)" -Sev 'Warning' -tenant $TenantFilter + Write-LogMessage -headers $Headers -API $APIName -message "Rule updated but failed to update cache: $($_.Exception.Message)" -sev 'Warn' -tenant $TenantFilter } return "Successfully set mailbox rule $($RuleName) for $($Username) to $($State)d" diff --git a/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 b/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 index 1285bbf1f402..0513553aaa3c 100644 --- a/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPResetPassword.ps1 @@ -30,7 +30,7 @@ function Set-CIPPResetPassword { } } catch { - Write-LogMessage -headers $Headers -API $APIName -message "Failed to create PwPush link, using plain password. Error: $($_.Exception.Message)" -Sev 'Warning' -tenant $TenantFilter + Write-LogMessage -headers $Headers -API $APIName -message "Failed to create PwPush link, using plain password. Error: $($_.Exception.Message)" -sev 'Warn' -tenant $TenantFilter } Write-LogMessage -headers $Headers -API $APIName -message "Successfully reset the password for $DisplayName, $($UserID). User must change password is set to $forceChangePasswordNextSignIn" -Sev 'Info' -tenant $TenantFilter diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 index 03845d7a4d03..1a5bad508ffb 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSelfServiceLicenses.ps1 @@ -45,41 +45,54 @@ function Invoke-CIPPStandardDisableSelfServiceLicenses { throw $Message } - if ($settings.exclusions -like '*;*') { $exclusions = $settings.Exclusions -split (';') } else { $exclusions = $settings.Exclusions -split (',') } + $CurrentValues = $selfServiceItems | Select-Object -Property productName, productId, policyValue + $ExpectedValues = [System.Collections.Generic.List[PSCustomObject]]::new() + foreach ($Item in $selfServiceItems) { + if ($Item.productId -in $exclusions) { - $Item.policyValue = "Enabled" - $ExpectedValues.add(($Item | Select-Object -Property productName, productId, policyValue)) - Write-LogMessage -API 'Standards' -tenant $Tenant -message "Exclusion present for self-service license '$($Item.productName) - $($Item.productId)'" + $desiredPolicyValue = "Enabled" + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Exclusion present for self-service license '$($Item.productName) - $($Item.productId)'" } else { - $Item.policyValue = "Disabled" - $ExpectedValues.add(($Item | Select-Object -Property productName, productId, policyValue)) + $desiredPolicyValue = "Disabled" } - } - $CurrentValues = $selfServiceItems | Select-Object -Property productName, productId, policyValue + $ExpectedValues.Add([PSCustomObject]@{ + productName = $Item.productName + productId = $Item.productId + policyValue = $desiredPolicyValue + }) + } if ($settings.remediate) { + $Compare = Compare-Object -ReferenceObject $ExpectedValues -DifferenceObject $CurrentValues -Property productName, productId, policyValue if (!$Compare) { Write-LogMessage -API 'Standards' -tenant $Tenant -message 'self service licenses are already set correctly.' -sev Info } else { - $NeedsUpdate = $Compare | Where-Object {$_.SideIndicator -eq "<="} + + $NeedsUpdate = $Compare | Where-Object { $_.SideIndicator -eq "<=" } + foreach ($Item in $NeedsUpdate) { try { - $body = @{policyValue=$Item.policyValue} | ConvertTo-Json -Compress + + $currentItem = $CurrentValues | Where-Object { $_.productId -eq $Item.productId } | Select-Object -First 1 + $currentValue = if ($currentItem) { $currentItem.policyValue } else { "" } + + $body = @{ policyValue = $Item.policyValue } | ConvertTo-Json -Compress New-GraphPOSTRequest -scope 'aeb86249-8ea3-49e2-900b-54cc8e308f85/.default' -uri "https://licensing.m365.microsoft.com/v1.0/policies/AllowSelfServicePurchase/products/$($Item.productId)" -tenantid $Tenant -body $body -type PUT - Write-LogMessage -API 'Standards' -tenant $tenant -message "Changed Self Service status for product '$($Item.productName) - $($Item.productId)' to '$($Item.policyValue)'" + + Write-LogMessage -API 'Standards' -tenant $tenant -message "Changed Self Service status for product '$($Item.productName) - $($Item.productId)' from '$currentValue' to '$($Item.policyValue)'" -sev Info } catch { Write-LogMessage -API 'Standards' -tenant $tenant -message "Failed to set product status for '$($Item.productName) - $($Item.productId)' with body $($body) for reason: $($_.Exception.Message)" -sev Error } @@ -100,12 +113,13 @@ function Invoke-CIPPStandardDisableSelfServiceLicenses { } if ($Settings.report -eq $true) { + $StateIsCorrect = !(Compare-Object -ReferenceObject $ExpectedValues -DifferenceObject $CurrentValues -Property productName, productId, policyValue) $ExpectedValuesHash = @{} foreach ($Item in $ExpectedValues) { $ExpectedValuesHash[$Item.productName] = [PSCustomObject]@{ - Id = $Item.productId + Id = $Item.productId Value = $Item.policyValue } } @@ -114,7 +128,7 @@ function Invoke-CIPPStandardDisableSelfServiceLicenses { $CurrentValuesHash = @{} foreach ($Item in $CurrentValues) { $CurrentValuesHash[$Item.productName] = [PSCustomObject]@{ - Id = $Item.productId + Id = $Item.productId Value = $Item.policyValue } } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 index e804e605ce61..b06b0567df97 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardMailContacts.ps1 @@ -106,12 +106,12 @@ function Invoke-CIPPStandardMailContacts { } if ($Settings.report -eq $true) { $CurrentValue = @{ - marketingNotificationEmails = $CurrentInfo.marketingNotificationEmails + marketingNotificationEmails = @($CurrentInfo.marketingNotificationEmails) technicalNotificationMails = @($CurrentInfo.technicalNotificationMails) contactEmail = $CurrentInfo.privacyProfile.contactEmail } $ExpectedValue = @{ - marketingNotificationEmails = $Contacts.MarketingContact + marketingNotificationEmails = @($Contacts.MarketingContact) technicalNotificationMails = @($Contacts.SecurityContact, $Contacts.TechContact) | Where-Object { $_ -ne $null } contactEmail = $Contacts.GeneralContact } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 index 0ae5d1e92eab..d703bf2c5569 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardOutBoundSpamAlert.ps1 @@ -76,7 +76,7 @@ function Invoke-CIPPStandardOutBoundSpamAlert { Add-CIPPBPAField -FieldName 'OutboundSpamAlert' -FieldValue $CurrentInfo.NotifyOutboundSpam -StoreAs bool -Tenant $tenant $CurrentValue = @{ NotifyOutboundSpam = $CurrentInfo.NotifyOutboundSpam - NotifyOutboundSpamRecipients = $CurrentInfo.NotifyOutboundSpamRecipients + NotifyOutboundSpamRecipients = ($CurrentInfo.NotifyOutboundSpamRecipients -join ', ') } $ExpectedValue = @{ NotifyOutboundSpam = $true diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 index 265959e7ce6a..6a949fad057f 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 @@ -70,8 +70,11 @@ function Invoke-CIPPStandardUserSubmissions { $PolicyIsCorrect = ($PolicyState.EnableReportToMicrosoft -eq $true) -and ($PolicyState.ReportJunkToCustomizedAddress -eq $false) -and ($PolicyState.ReportNotJunkToCustomizedAddress -eq $false) -and - ($PolicyState.ReportPhishToCustomizedAddress -eq $false) - $RuleIsCorrect = $true + ($PolicyState.ReportPhishToCustomizedAddress -eq $false) -and + ($PolicyState.ReportJunkAddresses.Count -eq 0) -and + ($PolicyState.ReportNotJunkAddresses.Count -eq 0) -and + ($PolicyState.ReportPhishAddresses.Count -eq 0) + $RuleIsCorrect = ($RuleState.length -eq 0) -or ($RuleState.State -ne 'Enabled') } else { $PolicyIsCorrect = ($PolicyState.EnableReportToMicrosoft -eq $true) -and ($PolicyState.ReportJunkToCustomizedAddress -eq $true) -and @@ -91,8 +94,11 @@ function Invoke-CIPPStandardUserSubmissions { $PolicyIsCorrect = ($PolicyState.EnableReportToMicrosoft -eq $false) -and ($PolicyState.ReportJunkToCustomizedAddress -eq $false) -and ($PolicyState.ReportNotJunkToCustomizedAddress -eq $false) -and - ($PolicyState.ReportPhishToCustomizedAddress -eq $false) - $RuleIsCorrect = $true + ($PolicyState.ReportPhishToCustomizedAddress -eq $false) -and + ($PolicyState.ReportJunkAddresses.Count -eq 0) -and + ($PolicyState.ReportNotJunkAddresses.Count -eq 0) -and + ($PolicyState.ReportPhishAddresses.Count -eq 0) + $RuleIsCorrect = ($RuleState.length -eq 0) -or ($RuleState.State -ne 'Enabled') } } @@ -132,8 +138,11 @@ function Invoke-CIPPStandardUserSubmissions { $PolicyParams = @{ EnableReportToMicrosoft = $false ReportJunkToCustomizedAddress = $false + ReportJunkAddresses = $null ReportNotJunkToCustomizedAddress = $false + ReportNotJunkAddresses = $null ReportPhishToCustomizedAddress = $false + ReportPhishAddresses = $null } } @@ -177,6 +186,14 @@ function Invoke-CIPPStandardUserSubmissions { Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to enable User Submission rule. Error: $($ErrorMessage.NormalizedError)" -sev Error } } + } elseif ($RuleState.length -gt 0 -and $RuleState.State -eq 'Enabled') { + try { + $null = New-ExoRequest -tenantid $Tenant -cmdlet 'Remove-ReportSubmissionRule' -cmdParams @{ Identity = 'DefaultReportSubmissionRule' } -UseSystemMailbox $true + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'User Submission rule removed.' -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to remove User Submission rule. Error: $($ErrorMessage.NormalizedError)" -sev Error + } } } } @@ -211,12 +228,12 @@ function Invoke-CIPPStandardUserSubmissions { ReportJunkToCustomizedAddress = $PolicyState.ReportJunkToCustomizedAddress ReportNotJunkToCustomizedAddress = $PolicyState.ReportNotJunkToCustomizedAddress ReportPhishToCustomizedAddress = $PolicyState.ReportPhishToCustomizedAddress - ReportJunkAddresses = $PolicyState.ReportJunkAddresses - ReportNotJunkAddresses = $PolicyState.ReportNotJunkAddresses - ReportPhishAddresses = $PolicyState.ReportPhishAddresses + ReportJunkAddresses = @($PolicyState.ReportJunkAddresses) + ReportNotJunkAddresses = @($PolicyState.ReportNotJunkAddresses) + ReportPhishAddresses = @($PolicyState.ReportPhishAddresses) RuleState = @{ - State = $RuleState.State - SentTo = $RuleState.SentTo + State = if ($RuleState.length -eq 0) { 'Disabled' } else { $RuleState.State } + SentTo = if ($RuleState.length -eq 0) { $null } else { @($RuleState.SentTo) } } } $ExpectedValue = @{ @@ -224,10 +241,10 @@ function Invoke-CIPPStandardUserSubmissions { ReportJunkToCustomizedAddress = if ([string]::IsNullOrWhiteSpace($Email)) { $false } else { $true } ReportNotJunkToCustomizedAddress = if ([string]::IsNullOrWhiteSpace($Email)) { $false } else { $true } ReportPhishToCustomizedAddress = if ([string]::IsNullOrWhiteSpace($Email)) { $false } else { $true } - ReportJunkAddresses = if ([string]::IsNullOrWhiteSpace($Email)) { $null } else { @($Email) } - ReportNotJunkAddresses = if ([string]::IsNullOrWhiteSpace($Email)) { $null } else { @($Email) } - ReportPhishAddresses = if ([string]::IsNullOrWhiteSpace($Email)) { $null } else { @($Email) } - RuleState = if ([string]::IsNullOrWhiteSpace($Email)) { + ReportJunkAddresses = @(if (-not [string]::IsNullOrWhiteSpace($Email)) { $Email }) + ReportNotJunkAddresses = @(if (-not [string]::IsNullOrWhiteSpace($Email)) { $Email }) + ReportPhishAddresses = @(if (-not [string]::IsNullOrWhiteSpace($Email)) { $Email }) + RuleState = if ([string]::IsNullOrWhiteSpace($Email) -or $state -eq 'disable') { @{ State = 'Disabled' SentTo = $null diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRegLocalAdmins.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRegLocalAdmins.ps1 new file mode 100644 index 000000000000..178db7c71abf --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardintuneDeviceRegLocalAdmins.ps1 @@ -0,0 +1,101 @@ +function Invoke-CIPPStandardintuneDeviceRegLocalAdmins { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) intuneDeviceRegLocalAdmins + .SYNOPSIS + (Label) Configure local administrator rights for users joining devices + .DESCRIPTION + (Helptext) Controls whether users who register Microsoft Entra joined devices are granted local administrator rights on those devices and if Global Administrators are added as local admins. + (DocsDescription) Configures the Device Registration Policy local administrator behavior for registering users. When enabled, users who register devices are not granted local administrator rights, you can also configure if Global Administrators are added as local admins. + .NOTES + CAT + Entra (AAD) Standards + TAG + EXECUTIVETEXT + Controls whether employees who enroll devices automatically receive local administrator access. Disabling registering-user admin rights follows least-privilege principles and reduces security risk from over-privileged endpoints. + ADDEDCOMPONENT + {"type":"switch","name":"standards.intuneDeviceRegLocalAdmins.disableRegisteringUsers","label":"Disable registering users as local administrators","defaultValue":true} + {"type":"switch","name":"standards.intuneDeviceRegLocalAdmins.enableGlobalAdmins","label":"Allow Global Administrators to be local administrators","defaultValue":true} + IMPACT + Medium Impact + ADDEDDATE + 2026-02-23 + POWERSHELLEQUIVALENT + Update-MgBetaPolicyDeviceRegistrationPolicy + RECOMMENDEDBY + UPDATECOMMENTBLOCK + Run the Tools\Update-StandardsComments.ps1 script to update this comment block + .LINK + https://docs.cipp.app/user-documentation/tenant/standards/list-standards + #> + + param($Tenant, $Settings) + + try { + $PreviousSetting = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/policies/deviceRegistrationPolicy' -tenantid $Tenant + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -Tenant $Tenant -Message "Could not get the intuneDeviceRegLocalAdmins state for $Tenant. Error: $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage + return + } + # Current M365 Config + $CurrentOdataType = $PreviousSetting.azureADJoin.localAdmins.registeringUsers.'@odata.type' + $CurrentEnableGlobalAdmins = [bool]$PreviousSetting.azureADJoin.localAdmins.enableGlobalAdmins + + # Standards Config + $DisableRegisteringUsers = [bool]$Settings.disableRegisteringUsers + $EnableGlobalAdmins = [bool]$Settings.enableGlobalAdmins + + # State comparison + $DesiredOdataType = if ($DisableRegisteringUsers) { '#microsoft.graph.noDeviceRegistrationMembership' } else { '#microsoft.graph.allDeviceRegistrationMembership' } + $StateIsCorrect = ($CurrentOdataType -eq $DesiredOdataType) -and ($CurrentEnableGlobalAdmins -eq $EnableGlobalAdmins) + $DesiredStateText = if ($DisableRegisteringUsers) { 'disabled' } else { 'enabled' } + $DesiredGlobalAdminsText = if ($EnableGlobalAdmins) { 'enabled' } else { 'disabled' } + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Local administrator settings are already configured (registering users: $DesiredStateText, global admins: $DesiredGlobalAdminsText)." -sev Info + } else { + try { + $PreviousSetting.azureADJoin.localAdmins.registeringUsers = @{ '@odata.type' = $DesiredOdataType } + $PreviousSetting.azureADJoin.localAdmins.enableGlobalAdmins = $EnableGlobalAdmins + $NewBody = ConvertTo-Json -Compress -InputObject $PreviousSetting -Depth 10 + New-GraphPostRequest -tenantid $Tenant -Uri 'https://graph.microsoft.com/beta/policies/deviceRegistrationPolicy' -Type PUT -Body $NewBody -ContentType 'application/json' + $CurrentOdataType = $DesiredOdataType + $CurrentEnableGlobalAdmins = $EnableGlobalAdmins + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Set local administrator settings (registering users: $DesiredStateText, global admins: $DesiredGlobalAdminsText)." -sev Info + } catch { + $ErrorMessage = Get-CippException -Exception $_ + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set local administrator settings (registering users: $DesiredStateText, global admins: $DesiredGlobalAdminsText). Error: $($ErrorMessage.NormalizedError)" -sev Error -LogData $ErrorMessage + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Local administrator settings are configured as expected (registering users: $DesiredStateText, global admins: $DesiredGlobalAdminsText)." -sev Info + } else { + Write-StandardsAlert -message "Local administrator settings are not configured as expected (registering users: $DesiredStateText, global admins: $DesiredGlobalAdminsText)" -object @{ current = @{ registeringUsers = $CurrentOdataType; enableGlobalAdmins = $CurrentEnableGlobalAdmins }; desired = @{ registeringUsers = $DesiredOdataType; enableGlobalAdmins = $EnableGlobalAdmins } } -tenant $Tenant -standardName 'intuneDeviceRegLocalAdmins' -standardId $Settings.standardId + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Local administrator settings are not configured as expected (registering users: $DesiredStateText, global admins: $DesiredGlobalAdminsText)." -sev Info + } + } + + if ($Settings.report -eq $true) { + $CurrentValue = @{ + registeringUsers = @{ + '@odata.type' = $CurrentOdataType + } + enableGlobalAdmins = $CurrentEnableGlobalAdmins + } + $ExpectedValue = @{ + registeringUsers = @{ + '@odata.type' = $DesiredOdataType + } + enableGlobalAdmins = $EnableGlobalAdmins + } + Set-CIPPStandardsCompareField -FieldName 'standards.intuneDeviceRegLocalAdmins' -CurrentValue $CurrentValue -ExpectedValue $ExpectedValue -TenantFilter $Tenant + Add-CIPPBPAField -FieldName 'intuneDeviceRegLocalAdmins' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + } +} diff --git a/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 b/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 index 51dda90f7ff4..271ce8a186b0 100644 --- a/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 +++ b/Modules/CIPPCore/Public/Test-CIPPAccessTenant.ps1 @@ -135,7 +135,7 @@ function Test-CIPPAccessTenant { Write-Warning "Found $($MissingRoles.Count) missing Organization Management roles in Exchange" $ExchangeStatus = $false $ExchangeTest = 'Connected to Exchange but missing permissions in Organization Management. This may impact the ability to manage Exchange features' - Write-LogMessage -headers $Headers -API $APINAME -tenant $tenant.defaultDomainName -message 'Tenant access check for Exchange failed: Missing Organization Management roles' -Sev 'Warning' -LogData $MissingOrgMgmtRoles + Write-LogMessage -headers $Headers -API $APINAME -tenant $tenant.defaultDomainName -message 'Tenant access check for Exchange failed: Missing Organization Management roles' -sev 'Warn' -LogData $MissingOrgMgmtRoles } else { Write-Warning 'All available Organization Management roles are present in Exchange' $ExchangeStatus = $true diff --git a/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 index 3bc4693fe6ed..9dd938033660 100644 --- a/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 +++ b/Modules/CIPPCore/Public/Webhooks/Invoke-CIPPGraphWebhookRenewal.ps1 @@ -19,7 +19,7 @@ function Invoke-CippGraphWebhookRenewal { try { $TenantFilter = $UpdateSub.PartitionKey if ($Tenants.defaultDomainName -notcontains $TenantFilter -and $Tenants.customerId -notcontains $TenantFilter) { - Write-LogMessage -API 'Renew_Graph_Subscriptions' -message "Removing Subscription Renewal for $($UpdateSub.SubscriptionID) as tenant $TenantFilter is not in the tenant list." -Sev 'Warning' -tenant $TenantFilter + Write-LogMessage -API 'Renew_Graph_Subscriptions' -message "Removing Subscription Renewal for $($UpdateSub.SubscriptionID) as tenant $TenantFilter is not in the tenant list." -sev 'Warn' -tenant $TenantFilter Remove-AzDataTableEntity -Force @WebhookTable -Entity $UpdateSub continue } diff --git a/Modules/CippExtensions/Public/PwPush/New-PwPushLink.ps1 b/Modules/CippExtensions/Public/PwPush/New-PwPushLink.ps1 index ad58593c9676..1991b90598ae 100644 --- a/Modules/CippExtensions/Public/PwPush/New-PwPushLink.ps1 +++ b/Modules/CippExtensions/Public/PwPush/New-PwPushLink.ps1 @@ -55,7 +55,7 @@ function New-PwPushLink { 'Exception' = Get-CippException -Exception $_ } Write-LogMessage -API PwPush -Message "Failed to create a new PwPush link: $($_.Exception.Message)" -Sev 'Error' -LogData $LogData - Write-LogMessage -API PwPush -Message "Continuing without PwPush link due to error" -Sev 'Warning' + Write-LogMessage -API PwPush -Message "Continuing without PwPush link due to error" -sev 'Warn' return $false } } catch { diff --git a/host.json b/host.json index 2af179e475df..e215e52d2205 100644 --- a/host.json +++ b/host.json @@ -16,7 +16,7 @@ "distributedTracingEnabled": false, "version": "None" }, - "defaultVersion": "10.0.9", + "defaultVersion": "10.1.1", "versionMatchStrategy": "Strict", "versionFailureStrategy": "Fail" } diff --git a/version_latest.txt b/version_latest.txt index 4149c39eec6f..23127993ac05 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -10.1.0 +10.1.1