diff --git a/Modules/CIPPCore/Public/Add-CIPPWin32LobAppContent.ps1 b/Modules/CIPPCore/Public/Add-CIPPWin32LobAppContent.ps1 index 1b238870e6226..2b9b7393d9c49 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 58ed3b035407e..b20096d590208 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 2279b20ce1107..f7103fbca239e 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 8d86e31a27a34..faca0853ea6f8 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 7f0243f4d9c98..eacb976bf70ed 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 22607cb0841bc..a7744b0a1af0e 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 be60e04ec9b2f..b5d04c9de3378 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 c38ece6e144cb..eb7dc72736808 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 bd2a682429acb..4fc1b2f5575c8 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 d138555690a54..930c54b297d9e 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 d512c090da285..e77018c09ffc1 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 202d6e4dc1826..f7ca33f56c56d 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 84b79cff13bea..d3a188c2211ce 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 9abe8a741a252..05ae42c1ed520 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 bdb783995d9b2..5c1b8e2e52d08 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 562fb1dd2f924..24f88d8cd971c 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 75877cbbdb9ca..ad659857cc751 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 4d768e96cc1a7..5e051053f90be 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 d785b015f940d..7780f90588eb9 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 ad2c5d7c54665..74d66cea6d1a7 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 dd2de9d523e0d..7f8777f948999 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 6da71f0a98bf4..b36cf8ea39871 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 35bbd95139cad..868208b51e87e 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 aa5ad886758e6..3a99bf6d73372 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 e0ac56a8f294e..ae25c9b97c188 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 c97f52617d00a..3efb129e21ebb 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 0000000000000..76268bd14dcb5 --- /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 a48db0eaccafc..2c02b5b70942c 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 f3fa33bcaa460..4f124a557e9a1 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 dbf3790b30903..dafc18eb2dcc1 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 8c4ec6595652b..e679b579b329e 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 89840a6a07edb..5f8167531d3eb 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 a683b153c5081..df68186545450 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 23315d7eb700f..520536881638a 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 c0fa299b54660..e114d1a329775 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 07018acad177b..17f648740620e 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 63b639e3769e9..0d6b2b52c592b 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 6c0581ad0c8e8..27a369092a08a 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 1bf2c4bfaabc4..e1fe3dc11a16b 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 8c4d4953bdf05..bd708947c66f3 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 ed00a0292aa1c..b8edf3aedd943 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 74f620e133e1d..771e9d66363c4 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 a2a6553fb2503..b0eac304e54c0 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 85726be4607aa..fd46b76e72b59 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 0b961c534385e..2cfabcdc42f29 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 23b0e59d3dc73..be328974d1e27 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 d2ac97fb88397..d637e0d7c6c87 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 1c5e20ae81df5..5a44d65fddd57 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 76fba584da6d1..d637c614e88df 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 d750ce6cdea9e..4ef75831b7033 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 402eca0145b9f..9a547a29f1ec5 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 527de771990e7..bec2daa302b3a 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 0b8927896be96..b3bbee4351029 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 1f470021a92be..9559f97eb0a72 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 eadfeef81f398..680ac28c9adf3 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 e99ead09a19da..06dc1d126e597 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 1285bbf1f402b..0513553aaa3c7 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 03845d7a4d032..1a5bad508ffb7 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 e804e605ce61d..b06b0567df97f 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 0ae5d1e92eab7..d703bf2c5569a 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 265959e7ce6ad..6a949fad057f7 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 0000000000000..178db7c71abf8 --- /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 51dda90f7ff4f..271ce8a186b0f 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 3bc4693fe6ed9..9dd9380336608 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 ad58593c9676d..1991b90598ae1 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 2af179e475df5..e215e52d22059 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 4149c39eec6fa..23127993ac054 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -10.1.0 +10.1.1