diff --git a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccessUserRole.ps1 b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccessUserRole.ps1 index 5410d7312142..ec7bf596ca37 100644 --- a/Modules/CIPPCore/Public/Authentication/Test-CIPPAccessUserRole.ps1 +++ b/Modules/CIPPCore/Public/Authentication/Test-CIPPAccessUserRole.ps1 @@ -20,9 +20,15 @@ function Test-CIPPAccessUserRole { $User ) $Roles = @() - $Table = Get-CippTable -TableName cacheAccessUserRoles - $Filter = "PartitionKey eq 'AccessUser' and RowKey eq '$($User.userDetails)' and Timestamp ge datetime'$((Get-Date).AddMinutes(-15).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ'))'" - $UserRole = Get-CIPPAzDataTableEntity @Table -Filter $Filter + + try { + $Table = Get-CippTable -TableName cacheAccessUserRoles + $Filter = "PartitionKey eq 'AccessUser' and RowKey eq '$($User.userDetails)' and Timestamp ge datetime'$((Get-Date).AddMinutes(-15).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fffZ'))'" + $UserRole = Get-CIPPAzDataTableEntity @Table -Filter $Filter + } catch { + Write-Information "Could not access cached user roles table. $($_.Exception.Message)" + $UserRole = $null + } if ($UserRole) { Write-Information "Found cached user role for $($User.userDetails)" $Roles = $UserRole.Role | ConvertFrom-Json @@ -59,12 +65,16 @@ function Test-CIPPAccessUserRole { } if (($Roles | Measure-Object).Count -gt 2) { - $UserRole = [PSCustomObject]@{ - PartitionKey = 'AccessUser' - RowKey = [string]$User.userDetails - Role = [string](ConvertTo-Json -Compress -InputObject $Roles) + try { + $UserRole = [PSCustomObject]@{ + PartitionKey = 'AccessUser' + RowKey = [string]$User.userDetails + Role = [string](ConvertTo-Json -Compress -InputObject $Roles) + } + Add-CIPPAzDataTableEntity @Table -Entity $UserRole -Force + } catch { + Write-Information "Could not cache user roles for $($User.userDetails). $($_.Exception.Message)" } - Add-CIPPAzDataTableEntity @Table -Entity $UserRole -Force } } $User.userRoles = $Roles diff --git a/Modules/CIPPCore/Public/Clear-CippDurables.ps1 b/Modules/CIPPCore/Public/Clear-CippDurables.ps1 index 44c77f74e82c..6b0edd1a0caa 100644 --- a/Modules/CIPPCore/Public/Clear-CippDurables.ps1 +++ b/Modules/CIPPCore/Public/Clear-CippDurables.ps1 @@ -1,6 +1,6 @@ function Clear-CippDurables { [CmdletBinding(SupportsShouldProcess = $true)] - Param() + param() # Collect info $StorageContext = New-AzStorageContext -ConnectionString $env:AzureWebJobsStorage $FunctionName = $env:WEBSITE_SITE_NAME -replace '-', '' @@ -8,6 +8,13 @@ function Clear-CippDurables { # Get orchestrators $InstancesTable = Get-CippTable -TableName ('{0}Instances' -f $FunctionName) $HistoryTable = Get-CippTable -TableName ('{0}History' -f $FunctionName) + $QueueTable = Get-CippTable -TableName 'CippQueue' + $CippQueueTasks = Get-CippTable -TableName 'CippQueueTasks' + + Remove-AzDataTable @InstancesTable + Remove-AzDataTable @HistoryTable + Remove-AzDataTable @QueueTable + Remove-AzDataTable @CippQueueTasks $Queues = Get-AzStorageQueue -Context $StorageContext -Name ('{0}*' -f $FunctionName) | Select-Object -Property Name, ApproximateMessageCount, QueueClient @@ -19,8 +26,6 @@ function Clear-CippDurables { } } - Remove-AzDataTable @InstancesTable - Remove-AzDataTable @HistoryTable $BlobContainer = '{0}-largemessages' -f $FunctionName if (Get-AzStorageContainer -Name $BlobContainer -Context $StorageContext -ErrorAction SilentlyContinue) { Write-Information "- Removing blob container: $BlobContainer" @@ -29,32 +34,6 @@ function Clear-CippDurables { } } - $QueueTable = Get-CippTable -TableName 'CippQueue' - $CippQueue = Invoke-ListCippQueue - $QueueEntities = foreach ($Queue in $CippQueue) { - if ($Queue.Status -eq 'Running') { - $Queue.TotalTasks = $Queue.CompletedTasks - $Queue | Select-Object -Property PartitionKey, RowKey, TotalTasks - } - } - if (($QueueEntities | Measure-Object).Count -gt 0) { - if ($PSCmdlet.ShouldProcess('Queues', 'Mark Failed')) { - Update-AzDataTableEntity -Force @QueueTable -Entity $QueueEntities - } - } - - $CippQueueTasks = Get-CippTable -TableName 'CippQueueTasks' - $RunningTasks = Get-CIPPAzDataTableEntity @CippQueueTasks -Filter "PartitionKey eq 'Task' and Status eq 'Running'" -Property RowKey, PartitionKey, Status - if (($RunningTasks | Measure-Object).Count -gt 0) { - if ($PSCmdlet.ShouldProcess('Tasks', 'Mark Failed')) { - $UpdatedTasks = foreach ($Task in $RunningTasks) { - $Task.Status = 'Failed' - $Task - } - Update-AzDataTableEntity -Force @CippQueueTasks -Entity $UpdatedTasks - } - } - $null = Get-CippTable -TableName ('{0}History' -f $FunctionName) Write-Information 'Durable Orchestrators and Queues have been cleared' return $true diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 index ab3b168e593e..7614842279e4 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecScheduledCommand.ps1 @@ -7,6 +7,8 @@ function Push-ExecScheduledCommand { $item = $Item | ConvertTo-Json -Depth 100 | ConvertFrom-Json Write-Information "We are going to be running a scheduled task: $($Item.TaskInfo | ConvertTo-Json -Depth 10)" + $script:ScheduledTaskId = $Item.TaskInfo.RowKey + $Table = Get-CippTable -tablename 'ScheduledTasks' $task = $Item.TaskInfo $commandParameters = $Item.Parameters | ConvertTo-Json -Depth 10 | ConvertFrom-Json -AsHashtable @@ -21,10 +23,12 @@ function Push-ExecScheduledCommand { $CurrentTask = Get-AzDataTableEntity @Table -Filter "PartitionKey eq '$($task.PartitionKey)' and RowKey eq '$($task.RowKey)'" if (!$CurrentTask) { Write-Information "The task $($task.Name) for tenant $($task.Tenant) does not exist in the ScheduledTasks table. Exiting." + Remove-Variable -Name ScheduledTaskId -Scope Script -ErrorAction SilentlyContinue return } if ($CurrentTask.TaskState -eq 'Completed') { Write-Information "The task $($task.Name) for tenant $($task.Tenant) is already completed. Skipping execution." + Remove-Variable -Name ScheduledTaskId -Scope Script -ErrorAction SilentlyContinue return } @@ -69,6 +73,7 @@ function Push-ExecScheduledCommand { TaskState = 'Planned' ScheduledTime = [string]$nextRunUnixTime } + Remove-Variable -Name ScheduledTaskId -Scope Script -ErrorAction SilentlyContinue return } } @@ -94,6 +99,7 @@ function Push-ExecScheduledCommand { } Write-LogMessage -API 'Scheduler_UserTasks' -tenant $Tenant -tenantid $TenantInfo.customerId -message "Failed to execute task $($task.Name): The command $($Item.Command) does not exist." -sev Error + Remove-Variable -Name ScheduledTaskId -Scope Script -ErrorAction SilentlyContinue return } @@ -330,4 +336,5 @@ function Push-ExecScheduledCommand { if ($TaskType -ne 'Alert') { Write-LogMessage -API 'Scheduler_UserTasks' -tenant $Tenant -tenantid $TenantInfo.customerId -message "Successfully executed task: $($task.Name)" -sev Info } + Remove-Variable -Name ScheduledTaskId -Scope Script -ErrorAction SilentlyContinue } diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 index af92934a2aa7..b48f9f42b954 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Standards/Push-CIPPStandard.ps1 @@ -56,5 +56,7 @@ function Push-CIPPStandard { Write-Warning "Error running standard $($Standard) for tenant $($Tenant) - $($_.Exception.Message)" Write-Information $_.InvocationInfo.PositionMessage throw $_.Exception.Message + } finally { + Remove-Variable -Name StandardInfo -Scope Script -ErrorAction SilentlyContinue } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecEditTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecEditTemplate.ps1 index e2e14b3a6ee9..5b47b16aceeb 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecEditTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Core/Invoke-ExecEditTemplate.ps1 @@ -20,6 +20,9 @@ function Invoke-ExecEditTemplate { $Template = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq 'IntuneTemplate' and RowKey eq '$GUID'" $OriginalJSON = $Template.JSON + $TemplateData = $Template.JSON | ConvertFrom-Json + $TemplateType = $TemplateData.Type + if ($Template.SHA) { $NewGuid = [guid]::NewGuid().ToString() } else { @@ -36,7 +39,7 @@ function Invoke-ExecEditTemplate { RawJson = $RawJSON DisplayName = $Request.Body.displayName Description = $Request.Body.description - templateType = $Template.Type + templateType = $TemplateType Package = $Template.Package Headers = $Request.Headers } 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 7e3b75de8e8f..c38ece6e144c 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 @@ -148,7 +148,7 @@ function Invoke-ExecApiClient { if (!$Client) { $Results = @{ resultText = 'API client not found' - severity = 'error' + state = 'error' } } else { $ApiConfig = New-CIPPAPIConfig -ResetSecret -AppId $Request.Body.ClientId -Headers $Request.Headers diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 index f40d2fb092d1..fcaa4156c323 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Setup/Invoke-ExecUpdateRefreshToken.ps1 @@ -1,4 +1,4 @@ -Function Invoke-ExecUpdateRefreshToken { +function Invoke-ExecUpdateRefreshToken { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -49,16 +49,21 @@ Function Invoke-ExecUpdateRefreshToken { $TenantName = $request.body.tenantId } $Results = @{ - 'message' = "Successfully updated the credentials for $($TenantName). You may continue to the next step, or add additional tenants if required." - 'severity' = 'success' + 'resultText' = "Successfully updated the credentials for $($TenantName). You may continue to the next step, or add additional tenants if required." + 'state' = 'success' } } catch { - $Results = [pscustomobject]@{'Results' = "Failed. $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.message)"; severity = 'failed' } - } + $Results = [pscustomobject]@{ + 'Results' = @{ + resultText = "Failed. $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.message)" + state = 'failed' + } + } - return ([HttpResponseContext]@{ - StatusCode = [HttpStatusCode]::OK - Body = $Results - }) + return ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Results + }) + } } diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecCopyForSent.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecCopyForSent.ps1 index 0b31105cf10c..e676500b27bd 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecCopyForSent.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecCopyForSent.ps1 @@ -1,4 +1,4 @@ -Function Invoke-ExecCopyForSent { +function Invoke-ExecCopyForSent { <# .FUNCTIONALITY Entrypoint @@ -13,13 +13,21 @@ Function Invoke-ExecCopyForSent { # Interact with query parameters or the body of the request. - $TenantFilter = $Request.Query.TenantFilter ?? $Request.Body.TenantFilter + $TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter $UserID = $Request.Query.ID ?? $Request.Body.ID - $MessageCopyForSentAsEnabled = $Request.Query.MessageCopyForSentAsEnabled ?? $Request.Body.MessageCopyForSentAsEnabled - $MessageCopyForSentAsEnabled = [System.Convert]::ToBoolean($MessageCopyForSentAsEnabled) + $MessageCopyState = $Request.Query.messageCopyState ?? $Request.Body.messageCopyState + $MessageCopyState = [System.Convert]::ToBoolean($MessageCopyState) - Try { - $Result = Set-CIPPMessageCopy -userid $UserID -tenantFilter $TenantFilter -APIName $APIName -Headers $Headers -MessageCopyForSentAsEnabled $MessageCopyForSentAsEnabled + try { + $params = @{ + UserId = $UserID + TenantFilter = $TenantFilter + APIName = $APIName + Headers = $Headers + MessageCopyForSentAsEnabled = $MessageCopyState + MessageCopyForSendOnBehalfEnabled = $MessageCopyState + } + $Result = Set-CIPPMessageCopy @params $StatusCode = [HttpStatusCode]::OK } catch { $Result = "$($_.Exception.Message)" diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddEditTransportRule.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddEditTransportRule.ps1 index 519244db10bb..6d0cae8a4d61 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddEditTransportRule.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddEditTransportRule.ps1 @@ -42,8 +42,10 @@ function Invoke-AddEditTransportRule { # Extract condition fields $From = $Request.Body.From $FromScope = $Request.Body.FromScope + $FromMemberOf = $Request.Body.FromMemberOf $SentTo = $Request.Body.SentTo $SentToScope = $Request.Body.SentToScope + $SentToMemberOf = $Request.Body.SentToMemberOf $SubjectContainsWords = $Request.Body.SubjectContainsWords $SubjectMatchesPatterns = $Request.Body.SubjectMatchesPatterns $SubjectOrBodyContainsWords = $Request.Body.SubjectOrBodyContainsWords @@ -60,10 +62,21 @@ function Invoke-AddEditTransportRule { $MessageTypeMatches = $Request.Body.MessageTypeMatches $SenderDomainIs = $Request.Body.SenderDomainIs $RecipientDomainIs = $Request.Body.RecipientDomainIs + $RecipientAddressContainsWords = $Request.Body.RecipientAddressContainsWords + $RecipientAddressMatchesPatterns = $Request.Body.RecipientAddressMatchesPatterns + $AnyOfRecipientAddressContainsWords = $Request.Body.AnyOfRecipientAddressContainsWords + $AnyOfRecipientAddressMatchesPatterns = $Request.Body.AnyOfRecipientAddressMatchesPatterns + $AnyOfToHeader = $Request.Body.AnyOfToHeader + $AnyOfToHeaderMemberOf = $Request.Body.AnyOfToHeaderMemberOf + $AnyOfCcHeader = $Request.Body.AnyOfCcHeader + $AnyOfCcHeaderMemberOf = $Request.Body.AnyOfCcHeaderMemberOf + $AnyOfToCcHeader = $Request.Body.AnyOfToCcHeader + $AnyOfToCcHeaderMemberOf = $Request.Body.AnyOfToCcHeaderMemberOf $HeaderContainsWords = $Request.Body.HeaderContainsWords $HeaderContainsWordsMessageHeader = $Request.Body.HeaderContainsWordsMessageHeader $HeaderMatchesPatterns = $Request.Body.HeaderMatchesPatterns $HeaderMatchesPatternsMessageHeader = $Request.Body.HeaderMatchesPatternsMessageHeader + $SenderIpRanges = $Request.Body.SenderIpRanges # Extract action fields $DeleteMessage = $Request.Body.DeleteMessage @@ -91,8 +104,10 @@ function Invoke-AddEditTransportRule { # Extract exception fields (ExceptIf versions) $ExceptIfFrom = $Request.Body.ExceptIfFrom $ExceptIfFromScope = $Request.Body.ExceptIfFromScope + $ExceptIfFromMemberOf = $Request.Body.ExceptIfFromMemberOf $ExceptIfSentTo = $Request.Body.ExceptIfSentTo $ExceptIfSentToScope = $Request.Body.ExceptIfSentToScope + $ExceptIfSentToMemberOf = $Request.Body.ExceptIfSentToMemberOf $ExceptIfSubjectContainsWords = $Request.Body.ExceptIfSubjectContainsWords $ExceptIfSubjectMatchesPatterns = $Request.Body.ExceptIfSubjectMatchesPatterns $ExceptIfSubjectOrBodyContainsWords = $Request.Body.ExceptIfSubjectOrBodyContainsWords @@ -109,10 +124,21 @@ function Invoke-AddEditTransportRule { $ExceptIfMessageTypeMatches = $Request.Body.ExceptIfMessageTypeMatches $ExceptIfSenderDomainIs = $Request.Body.ExceptIfSenderDomainIs $ExceptIfRecipientDomainIs = $Request.Body.ExceptIfRecipientDomainIs + $ExceptIfRecipientAddressContainsWords = $Request.Body.ExceptIfRecipientAddressContainsWords + $ExceptIfRecipientAddressMatchesPatterns = $Request.Body.ExceptIfRecipientAddressMatchesPatterns + $ExceptIfAnyOfRecipientAddressContainsWords = $Request.Body.ExceptIfAnyOfRecipientAddressContainsWords + $ExceptIfAnyOfRecipientAddressMatchesPatterns = $Request.Body.ExceptIfAnyOfRecipientAddressMatchesPatterns + $ExceptIfAnyOfToHeader = $Request.Body.ExceptIfAnyOfToHeader + $ExceptIfAnyOfToHeaderMemberOf = $Request.Body.ExceptIfAnyOfToHeaderMemberOf + $ExceptIfAnyOfCcHeader = $Request.Body.ExceptIfAnyOfCcHeader + $ExceptIfAnyOfCcHeaderMemberOf = $Request.Body.ExceptIfAnyOfCcHeaderMemberOf + $ExceptIfAnyOfToCcHeader = $Request.Body.ExceptIfAnyOfToCcHeader + $ExceptIfAnyOfToCcHeaderMemberOf = $Request.Body.ExceptIfAnyOfToCcHeaderMemberOf $ExceptIfHeaderContainsWords = $Request.Body.ExceptIfHeaderContainsWords $ExceptIfHeaderContainsWordsMessageHeader = $Request.Body.ExceptIfHeaderContainsWordsMessageHeader $ExceptIfHeaderMatchesPatterns = $Request.Body.ExceptIfHeaderMatchesPatterns $ExceptIfHeaderMatchesPatternsMessageHeader = $Request.Body.ExceptIfHeaderMatchesPatternsMessageHeader + $ExceptIfSenderIpRanges = $Request.Body.ExceptIfSenderIpRanges # Helper function to process array fields function Process-ArrayField { @@ -202,13 +228,29 @@ function Invoke-AddEditTransportRule { # Process array fields for recipients/users $From = Process-ArrayField -Field $From + $FromMemberOf = Process-ArrayField -Field $FromMemberOf $SentTo = Process-ArrayField -Field $SentTo + $SentToMemberOf = Process-ArrayField -Field $SentToMemberOf + $AnyOfToHeader = Process-ArrayField -Field $AnyOfToHeader + $AnyOfToHeaderMemberOf = Process-ArrayField -Field $AnyOfToHeaderMemberOf + $AnyOfCcHeader = Process-ArrayField -Field $AnyOfCcHeader + $AnyOfCcHeaderMemberOf = Process-ArrayField -Field $AnyOfCcHeaderMemberOf + $AnyOfToCcHeader = Process-ArrayField -Field $AnyOfToCcHeader + $AnyOfToCcHeaderMemberOf = Process-ArrayField -Field $AnyOfToCcHeaderMemberOf $RedirectMessageTo = Process-ArrayField -Field $RedirectMessageTo $BlindCopyTo = Process-ArrayField -Field $BlindCopyTo $CopyTo = Process-ArrayField -Field $CopyTo $ModerateMessageByUser = Process-ArrayField -Field $ModerateMessageByUser $ExceptIfFrom = Process-ArrayField -Field $ExceptIfFrom + $ExceptIfFromMemberOf = Process-ArrayField -Field $ExceptIfFromMemberOf $ExceptIfSentTo = Process-ArrayField -Field $ExceptIfSentTo + $ExceptIfSentToMemberOf = Process-ArrayField -Field $ExceptIfSentToMemberOf + $ExceptIfAnyOfToHeader = Process-ArrayField -Field $ExceptIfAnyOfToHeader + $ExceptIfAnyOfToHeaderMemberOf = Process-ArrayField -Field $ExceptIfAnyOfToHeaderMemberOf + $ExceptIfAnyOfCcHeader = Process-ArrayField -Field $ExceptIfAnyOfCcHeader + $ExceptIfAnyOfCcHeaderMemberOf = Process-ArrayField -Field $ExceptIfAnyOfCcHeaderMemberOf + $ExceptIfAnyOfToCcHeader = Process-ArrayField -Field $ExceptIfAnyOfToCcHeader + $ExceptIfAnyOfToCcHeaderMemberOf = Process-ArrayField -Field $ExceptIfAnyOfToCcHeaderMemberOf $SenderDomainIs = Process-ArrayField -Field $SenderDomainIs $RecipientDomainIs = Process-ArrayField -Field $RecipientDomainIs $ExceptIfSenderDomainIs = Process-ArrayField -Field $ExceptIfSenderDomainIs @@ -224,6 +266,10 @@ function Invoke-AddEditTransportRule { $AttachmentContainsWords = Process-TextArrayField -Field $AttachmentContainsWords $AttachmentMatchesPatterns = Process-TextArrayField -Field $AttachmentMatchesPatterns $AttachmentExtensionMatchesWords = Process-TextArrayField -Field $AttachmentExtensionMatchesWords + $RecipientAddressContainsWords = Process-TextArrayField -Field $RecipientAddressContainsWords + $RecipientAddressMatchesPatterns = Process-TextArrayField -Field $RecipientAddressMatchesPatterns + $AnyOfRecipientAddressContainsWords = Process-TextArrayField -Field $AnyOfRecipientAddressContainsWords + $AnyOfRecipientAddressMatchesPatterns = Process-TextArrayField -Field $AnyOfRecipientAddressMatchesPatterns $HeaderContainsWords = Process-TextArrayField -Field $HeaderContainsWords $HeaderMatchesPatterns = Process-TextArrayField -Field $HeaderMatchesPatterns @@ -237,9 +283,17 @@ function Invoke-AddEditTransportRule { $ExceptIfAttachmentContainsWords = Process-TextArrayField -Field $ExceptIfAttachmentContainsWords $ExceptIfAttachmentMatchesPatterns = Process-TextArrayField -Field $ExceptIfAttachmentMatchesPatterns $ExceptIfAttachmentExtensionMatchesWords = Process-TextArrayField -Field $ExceptIfAttachmentExtensionMatchesWords + $ExceptIfRecipientAddressContainsWords = Process-TextArrayField -Field $ExceptIfRecipientAddressContainsWords + $ExceptIfRecipientAddressMatchesPatterns = Process-TextArrayField -Field $ExceptIfRecipientAddressMatchesPatterns + $ExceptIfAnyOfRecipientAddressContainsWords = Process-TextArrayField -Field $ExceptIfAnyOfRecipientAddressContainsWords + $ExceptIfAnyOfRecipientAddressMatchesPatterns = Process-TextArrayField -Field $ExceptIfAnyOfRecipientAddressMatchesPatterns $ExceptIfHeaderContainsWords = Process-TextArrayField -Field $ExceptIfHeaderContainsWords $ExceptIfHeaderMatchesPatterns = Process-TextArrayField -Field $ExceptIfHeaderMatchesPatterns + # Process IP range fields + $SenderIpRanges = Process-TextArrayField -Field $SenderIpRanges + $ExceptIfSenderIpRanges = Process-TextArrayField -Field $ExceptIfSenderIpRanges + try { # Build command parameters for transport rule $ruleParams = @{ @@ -256,22 +310,37 @@ function Invoke-AddEditTransportRule { if (($null -ne $State) -and (!$Identity)) { $ruleParams.Add('Enabled', $State) } if ($null -ne $Priority) { $ruleParams.Add('Priority', $Priority) } if ($null -ne $Comments) { $ruleParams.Add('Comments', $Comments) } - if ($null -ne $Mode -and $null -ne $Mode.value) { $ruleParams.Add('Mode', $Mode.value) } - if ($null -ne $SetAuditSeverity -and $null -ne $SetAuditSeverity.value -and $SetAuditSeverity.value -ne '') { - $ruleParams.Add('SetAuditSeverity', $SetAuditSeverity.value) + if ($null -ne $Mode) { + $modeValue = if ($Mode.value) { $Mode.value } else { $Mode } + $ruleParams.Add('Mode', $modeValue) + } + if ($null -ne $SetAuditSeverity) { + $severityValue = if ($SetAuditSeverity.value) { $SetAuditSeverity.value } else { $SetAuditSeverity } + if ($severityValue -ne '') { + $ruleParams.Add('SetAuditSeverity', $severityValue) + } } if ($null -ne $StopRuleProcessing) { $ruleParams.Add('StopRuleProcessing', $StopRuleProcessing) } - if ($null -ne $SenderAddressLocation -and $null -ne $SenderAddressLocation.value) { - $ruleParams.Add('SenderAddressLocation', $SenderAddressLocation.value) + if ($null -ne $SenderAddressLocation) { + $locationValue = if ($SenderAddressLocation.value) { $SenderAddressLocation.value } else { $SenderAddressLocation } + $ruleParams.Add('SenderAddressLocation', $locationValue) } if ($null -ne $ActivationDate -and $ActivationDate -ne '') { $ruleParams.Add('ActivationDate', $ActivationDate) } if ($null -ne $ExpiryDate -and $ExpiryDate -ne '') { $ruleParams.Add('ExpiryDate', $ExpiryDate) } # Condition parameters if ($null -ne $From -and $From.Count -gt 0) { $ruleParams.Add('From', $From) } - if ($null -ne $FromScope -and $null -ne $FromScope.value) { $ruleParams.Add('FromScope', $FromScope.value) } + if ($null -ne $FromScope) { + $fromScopeValue = if ($FromScope.value) { $FromScope.value } else { $FromScope } + $ruleParams.Add('FromScope', $fromScopeValue) + } + if ($null -ne $FromMemberOf -and $FromMemberOf.Count -gt 0) { $ruleParams.Add('FromMemberOf', $FromMemberOf) } if ($null -ne $SentTo -and $SentTo.Count -gt 0) { $ruleParams.Add('SentTo', $SentTo) } - if ($null -ne $SentToScope -and $null -ne $SentToScope.value) { $ruleParams.Add('SentToScope', $SentToScope.value) } + if ($null -ne $SentToScope) { + $sentToScopeValue = if ($SentToScope.value) { $SentToScope.value } else { $SentToScope } + $ruleParams.Add('SentToScope', $sentToScopeValue) + } + if ($null -ne $SentToMemberOf -and $SentToMemberOf.Count -gt 0) { $ruleParams.Add('SentToMemberOf', $SentToMemberOf) } if ($null -ne $SubjectContainsWords -and $SubjectContainsWords.Count -gt 0) { $ruleParams.Add('SubjectContainsWords', $SubjectContainsWords) } @@ -301,12 +370,17 @@ function Invoke-AddEditTransportRule { } if ($null -ne $AttachmentSizeOver) { $ruleParams.Add('AttachmentSizeOver', $AttachmentSizeOver) } if ($null -ne $MessageSizeOver) { $ruleParams.Add('MessageSizeOver', $MessageSizeOver) } - if ($null -ne $SCLOver -and $null -ne $SCLOver.value) { $ruleParams.Add('SCLOver', $SCLOver.value) } - if ($null -ne $WithImportance -and $null -ne $WithImportance.value) { - $ruleParams.Add('WithImportance', $WithImportance.value) + if ($null -ne $SCLOver) { + $sclValue = if ($SCLOver.value) { $SCLOver.value } else { $SCLOver } + $ruleParams.Add('SCLOver', $sclValue) } - if ($null -ne $MessageTypeMatches -and $null -ne $MessageTypeMatches.value) { - $ruleParams.Add('MessageTypeMatches', $MessageTypeMatches.value) + if ($null -ne $WithImportance) { + $importanceValue = if ($WithImportance.value) { $WithImportance.value } else { $WithImportance } + $ruleParams.Add('WithImportance', $importanceValue) + } + if ($null -ne $MessageTypeMatches) { + $messageTypeValue = if ($MessageTypeMatches.value) { $MessageTypeMatches.value } else { $MessageTypeMatches } + $ruleParams.Add('MessageTypeMatches', $messageTypeValue) } if ($null -ne $SenderDomainIs -and $SenderDomainIs.Count -gt 0) { $ruleParams.Add('SenderDomainIs', $SenderDomainIs) @@ -314,6 +388,36 @@ function Invoke-AddEditTransportRule { if ($null -ne $RecipientDomainIs -and $RecipientDomainIs.Count -gt 0) { $ruleParams.Add('RecipientDomainIs', $RecipientDomainIs) } + if ($null -ne $RecipientAddressContainsWords -and $RecipientAddressContainsWords.Count -gt 0) { + $ruleParams.Add('RecipientAddressContainsWords', $RecipientAddressContainsWords) + } + if ($null -ne $RecipientAddressMatchesPatterns -and $RecipientAddressMatchesPatterns.Count -gt 0) { + $ruleParams.Add('RecipientAddressMatchesPatterns', $RecipientAddressMatchesPatterns) + } + if ($null -ne $AnyOfRecipientAddressContainsWords -and $AnyOfRecipientAddressContainsWords.Count -gt 0) { + $ruleParams.Add('AnyOfRecipientAddressContainsWords', $AnyOfRecipientAddressContainsWords) + } + if ($null -ne $AnyOfRecipientAddressMatchesPatterns -and $AnyOfRecipientAddressMatchesPatterns.Count -gt 0) { + $ruleParams.Add('AnyOfRecipientAddressMatchesPatterns', $AnyOfRecipientAddressMatchesPatterns) + } + if ($null -ne $AnyOfToHeader -and $AnyOfToHeader.Count -gt 0) { + $ruleParams.Add('AnyOfToHeader', $AnyOfToHeader) + } + if ($null -ne $AnyOfToHeaderMemberOf -and $AnyOfToHeaderMemberOf.Count -gt 0) { + $ruleParams.Add('AnyOfToHeaderMemberOf', $AnyOfToHeaderMemberOf) + } + if ($null -ne $AnyOfCcHeader -and $AnyOfCcHeader.Count -gt 0) { + $ruleParams.Add('AnyOfCcHeader', $AnyOfCcHeader) + } + if ($null -ne $AnyOfCcHeaderMemberOf -and $AnyOfCcHeaderMemberOf.Count -gt 0) { + $ruleParams.Add('AnyOfCcHeaderMemberOf', $AnyOfCcHeaderMemberOf) + } + if ($null -ne $AnyOfToCcHeader -and $AnyOfToCcHeader.Count -gt 0) { + $ruleParams.Add('AnyOfToCcHeader', $AnyOfToCcHeader) + } + if ($null -ne $AnyOfToCcHeaderMemberOf -and $AnyOfToCcHeaderMemberOf.Count -gt 0) { + $ruleParams.Add('AnyOfToCcHeaderMemberOf', $AnyOfToCcHeaderMemberOf) + } if ($null -ne $HeaderContainsWords -and $HeaderContainsWords.Count -gt 0 -and $null -ne $HeaderContainsWordsMessageHeader) { $ruleParams.Add('HeaderContainsMessageHeader', $HeaderContainsWordsMessageHeader) $ruleParams.Add('HeaderContainsWords', $HeaderContainsWords) @@ -322,6 +426,9 @@ function Invoke-AddEditTransportRule { $ruleParams.Add('HeaderMatchesMessageHeader', $HeaderMatchesPatternsMessageHeader) $ruleParams.Add('HeaderMatchesPatterns', $HeaderMatchesPatterns) } + if ($null -ne $SenderIpRanges -and $SenderIpRanges.Count -gt 0) { + $ruleParams.Add('SenderIpRanges', $SenderIpRanges) + } # Action parameters if ($null -ne $DeleteMessage) { $ruleParams.Add('DeleteMessage', $DeleteMessage) } @@ -342,7 +449,10 @@ function Invoke-AddEditTransportRule { $ruleParams.Add('RejectMessageEnhancedStatusCode', $RejectMessageEnhancedStatusCode) } if ($null -ne $PrependSubject -and $PrependSubject -ne '') { $ruleParams.Add('PrependSubject', $PrependSubject) } - if ($null -ne $SetSCL -and $null -ne $SetSCL.value) { $ruleParams.Add('SetSCL', $SetSCL.value) } + if ($null -ne $SetSCL) { + $setSclValue = if ($SetSCL.value) { $SetSCL.value } else { $SetSCL } + $ruleParams.Add('SetSCL', $setSclValue) + } if ($null -ne $SetHeaderName -and $SetHeaderName -ne '' -and $null -ne $SetHeaderValue) { $ruleParams.Add('SetHeaderName', $SetHeaderName) $ruleParams.Add('SetHeaderValue', $SetHeaderValue) @@ -353,11 +463,13 @@ function Invoke-AddEditTransportRule { } if ($null -ne $ApplyHtmlDisclaimerText -and $ApplyHtmlDisclaimerText -ne '') { $ruleParams.Add('ApplyHtmlDisclaimerText', $ApplyHtmlDisclaimerText) - if ($null -ne $ApplyHtmlDisclaimerLocation -and $null -ne $ApplyHtmlDisclaimerLocation.value) { - $ruleParams.Add('ApplyHtmlDisclaimerLocation', $ApplyHtmlDisclaimerLocation.value) + if ($null -ne $ApplyHtmlDisclaimerLocation) { + $disclaimerLocationValue = if ($ApplyHtmlDisclaimerLocation.value) { $ApplyHtmlDisclaimerLocation.value } else { $ApplyHtmlDisclaimerLocation } + $ruleParams.Add('ApplyHtmlDisclaimerLocation', $disclaimerLocationValue) } - if ($null -ne $ApplyHtmlDisclaimerFallbackAction -and $null -ne $ApplyHtmlDisclaimerFallbackAction.value) { - $ruleParams.Add('ApplyHtmlDisclaimerFallbackAction', $ApplyHtmlDisclaimerFallbackAction.value) + if ($null -ne $ApplyHtmlDisclaimerFallbackAction) { + $disclaimerFallbackValue = if ($ApplyHtmlDisclaimerFallbackAction.value) { $ApplyHtmlDisclaimerFallbackAction.value } else { $ApplyHtmlDisclaimerFallbackAction } + $ruleParams.Add('ApplyHtmlDisclaimerFallbackAction', $disclaimerFallbackValue) } } if ($null -ne $GenerateIncidentReport -and $GenerateIncidentReport.Count -gt 0) { @@ -370,13 +482,17 @@ function Invoke-AddEditTransportRule { # Exception parameters (ExceptIf versions) if ($null -ne $ExceptIfFrom -and $ExceptIfFrom.Count -gt 0) { $ruleParams.Add('ExceptIfFrom', $ExceptIfFrom) } - if ($null -ne $ExceptIfFromScope -and $null -ne $ExceptIfFromScope.value) { - $ruleParams.Add('ExceptIfFromScope', $ExceptIfFromScope.value) + if ($null -ne $ExceptIfFromScope) { + $exceptFromScopeValue = if ($ExceptIfFromScope.value) { $ExceptIfFromScope.value } else { $ExceptIfFromScope } + $ruleParams.Add('ExceptIfFromScope', $exceptFromScopeValue) } + if ($null -ne $ExceptIfFromMemberOf -and $ExceptIfFromMemberOf.Count -gt 0) { $ruleParams.Add('ExceptIfFromMemberOf', $ExceptIfFromMemberOf) } if ($null -ne $ExceptIfSentTo -and $ExceptIfSentTo.Count -gt 0) { $ruleParams.Add('ExceptIfSentTo', $ExceptIfSentTo) } - if ($null -ne $ExceptIfSentToScope -and $null -ne $ExceptIfSentToScope.value) { - $ruleParams.Add('ExceptIfSentToScope', $ExceptIfSentToScope.value) + if ($null -ne $ExceptIfSentToScope) { + $exceptSentToScopeValue = if ($ExceptIfSentToScope.value) { $ExceptIfSentToScope.value } else { $ExceptIfSentToScope } + $ruleParams.Add('ExceptIfSentToScope', $exceptSentToScopeValue) } + if ($null -ne $ExceptIfSentToMemberOf -and $ExceptIfSentToMemberOf.Count -gt 0) { $ruleParams.Add('ExceptIfSentToMemberOf', $ExceptIfSentToMemberOf) } if ($null -ne $ExceptIfSubjectContainsWords -and $ExceptIfSubjectContainsWords.Count -gt 0) { $ruleParams.Add('ExceptIfSubjectContainsWords', $ExceptIfSubjectContainsWords) } @@ -408,14 +524,17 @@ function Invoke-AddEditTransportRule { $ruleParams.Add('ExceptIfAttachmentSizeOver', $ExceptIfAttachmentSizeOver) } if ($null -ne $ExceptIfMessageSizeOver) { $ruleParams.Add('ExceptIfMessageSizeOver', $ExceptIfMessageSizeOver) } - if ($null -ne $ExceptIfSCLOver -and $null -ne $ExceptIfSCLOver.value) { - $ruleParams.Add('ExceptIfSCLOver', $ExceptIfSCLOver.value) + if ($null -ne $ExceptIfSCLOver) { + $exceptSclValue = if ($ExceptIfSCLOver.value) { $ExceptIfSCLOver.value } else { $ExceptIfSCLOver } + $ruleParams.Add('ExceptIfSCLOver', $exceptSclValue) } - if ($null -ne $ExceptIfWithImportance -and $null -ne $ExceptIfWithImportance.value) { - $ruleParams.Add('ExceptIfWithImportance', $ExceptIfWithImportance.value) + if ($null -ne $ExceptIfWithImportance) { + $exceptImportanceValue = if ($ExceptIfWithImportance.value) { $ExceptIfWithImportance.value } else { $ExceptIfWithImportance } + $ruleParams.Add('ExceptIfWithImportance', $exceptImportanceValue) } - if ($null -ne $ExceptIfMessageTypeMatches -and $null -ne $ExceptIfMessageTypeMatches.value) { - $ruleParams.Add('ExceptIfMessageTypeMatches', $ExceptIfMessageTypeMatches.value) + if ($null -ne $ExceptIfMessageTypeMatches) { + $exceptMessageTypeValue = if ($ExceptIfMessageTypeMatches.value) { $ExceptIfMessageTypeMatches.value } else { $ExceptIfMessageTypeMatches } + $ruleParams.Add('ExceptIfMessageTypeMatches', $exceptMessageTypeValue) } if ($null -ne $ExceptIfSenderDomainIs -and $ExceptIfSenderDomainIs.Count -gt 0) { $ruleParams.Add('ExceptIfSenderDomainIs', $ExceptIfSenderDomainIs) @@ -423,6 +542,36 @@ function Invoke-AddEditTransportRule { if ($null -ne $ExceptIfRecipientDomainIs -and $ExceptIfRecipientDomainIs.Count -gt 0) { $ruleParams.Add('ExceptIfRecipientDomainIs', $ExceptIfRecipientDomainIs) } + if ($null -ne $ExceptIfRecipientAddressContainsWords -and $ExceptIfRecipientAddressContainsWords.Count -gt 0) { + $ruleParams.Add('ExceptIfRecipientAddressContainsWords', $ExceptIfRecipientAddressContainsWords) + } + if ($null -ne $ExceptIfRecipientAddressMatchesPatterns -and $ExceptIfRecipientAddressMatchesPatterns.Count -gt 0) { + $ruleParams.Add('ExceptIfRecipientAddressMatchesPatterns', $ExceptIfRecipientAddressMatchesPatterns) + } + if ($null -ne $ExceptIfAnyOfRecipientAddressContainsWords -and $ExceptIfAnyOfRecipientAddressContainsWords.Count -gt 0) { + $ruleParams.Add('ExceptIfAnyOfRecipientAddressContainsWords', $ExceptIfAnyOfRecipientAddressContainsWords) + } + if ($null -ne $ExceptIfAnyOfRecipientAddressMatchesPatterns -and $ExceptIfAnyOfRecipientAddressMatchesPatterns.Count -gt 0) { + $ruleParams.Add('ExceptIfAnyOfRecipientAddressMatchesPatterns', $ExceptIfAnyOfRecipientAddressMatchesPatterns) + } + if ($null -ne $ExceptIfAnyOfToHeader -and $ExceptIfAnyOfToHeader.Count -gt 0) { + $ruleParams.Add('ExceptIfAnyOfToHeader', $ExceptIfAnyOfToHeader) + } + if ($null -ne $ExceptIfAnyOfToHeaderMemberOf -and $ExceptIfAnyOfToHeaderMemberOf.Count -gt 0) { + $ruleParams.Add('ExceptIfAnyOfToHeaderMemberOf', $ExceptIfAnyOfToHeaderMemberOf) + } + if ($null -ne $ExceptIfAnyOfCcHeader -and $ExceptIfAnyOfCcHeader.Count -gt 0) { + $ruleParams.Add('ExceptIfAnyOfCcHeader', $ExceptIfAnyOfCcHeader) + } + if ($null -ne $ExceptIfAnyOfCcHeaderMemberOf -and $ExceptIfAnyOfCcHeaderMemberOf.Count -gt 0) { + $ruleParams.Add('ExceptIfAnyOfCcHeaderMemberOf', $ExceptIfAnyOfCcHeaderMemberOf) + } + if ($null -ne $ExceptIfAnyOfToCcHeader -and $ExceptIfAnyOfToCcHeader.Count -gt 0) { + $ruleParams.Add('ExceptIfAnyOfToCcHeader', $ExceptIfAnyOfToCcHeader) + } + if ($null -ne $ExceptIfAnyOfToCcHeaderMemberOf -and $ExceptIfAnyOfToCcHeaderMemberOf.Count -gt 0) { + $ruleParams.Add('ExceptIfAnyOfToCcHeaderMemberOf', $ExceptIfAnyOfToCcHeaderMemberOf) + } if ($null -ne $ExceptIfHeaderContainsWords -and $ExceptIfHeaderContainsWords.Count -gt 0 -and $null -ne $ExceptIfHeaderContainsWordsMessageHeader) { $ruleParams.Add('ExceptIfHeaderContainsMessageHeader', $ExceptIfHeaderContainsWordsMessageHeader) $ruleParams.Add('ExceptIfHeaderContainsWords', $ExceptIfHeaderContainsWords) @@ -431,6 +580,9 @@ function Invoke-AddEditTransportRule { $ruleParams.Add('ExceptIfHeaderMatchesMessageHeader', $ExceptIfHeaderMatchesPatternsMessageHeader) $ruleParams.Add('ExceptIfHeaderMatchesPatterns', $ExceptIfHeaderMatchesPatterns) } + if ($null -ne $ExceptIfSenderIpRanges -and $ExceptIfSenderIpRanges.Count -gt 0) { + $ruleParams.Add('ExceptIfSenderIpRanges', $ExceptIfSenderIpRanges) + } if (!$Identity) { $ExoRequestParam = @{ 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 6df90b2a1a65..202377450790 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 @@ -11,7 +11,7 @@ function Invoke-ExecCreateAppTemplate { param($Request, $TriggerMetadata) $APIName = $TriggerMetadata.FunctionName - Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message 'Accessed this API' -Sev 'Debug' + Write-LogMessage -headers $Request.headers -API $APINAME -message 'Accessed this API' -Sev 'Debug' try { $TenantFilter = $Request.Body.TenantFilter @@ -47,7 +47,7 @@ function Invoke-ExecCreateAppTemplate { $RequiredResourceAccess = @() } } catch { - Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message "Could not retrieve app registration for $AppId - will extract from service principal" -Sev 'Warning' + Write-LogMessage -headers $Request.headers -API $APINAME -message "Could not retrieve app registration for $AppId - will extract from service principal" -Sev 'Warning' $RequiredResourceAccess = @() } @@ -56,16 +56,91 @@ function Invoke-ExecCreateAppTemplate { $Permissions = $RequiredResourceAccess } else { # No permissions found - warn the user - Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message "No permissions found for $AppId. The app registration may not have configured API permissions." -Sev 'Warning' + Write-LogMessage -headers $Request.headers -API $APINAME -message "No permissions found for $AppId. The app registration may not have configured API permissions." -Sev 'Warning' $Permissions = @() } } else { # For app registrations (applications) - $AppDetails = New-GraphGetRequest -uri "https://graph.microsoft.com/beta/applications?`$filter=appId eq '$AppId'&`$select=id,appId,displayName,requiredResourceAccess" -tenantid $TenantFilter - if (-not $AppDetails -or $AppDetails.Count -eq 0) { - throw "Application not found for AppId: $AppId" + $App = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/applications(appId='$AppId')" -tenantid $TenantFilter + if (-not $App -or $App.Count -eq 0) { + throw "App registration not found for AppId: $AppId" } - $App = $AppDetails[0] + + $Tenant = Get-Tenants -TenantFilter $TenantFilter + if ($Tenant.customerId -ne $env:TenantID) { + $ExistingApp = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/applications?`$filter=displayName eq '$DisplayName'" -tenantid $env:TenantID -NoAuthCheck $true -AsApp $true + + if ($ExistingApp) { + Write-Information "App Registration $AppId already exists in partner tenant" + $AppId = $ExistingApp.appId + $App = $ExistingApp + Write-LogMessage -headers $Request.headers -API $APINAME -message "App Registration $($AppDetails.displayName) already exists in partner tenant" -Sev 'Info' + } else { + Write-Information "Copying App Registration $AppId from customer tenant $TenantFilter to partner tenant" + $PropertiesToRemove = @( + 'appId' + 'id' + 'createdDateTime' + 'deletedDateTime' + 'publisherDomain' + 'servicePrincipalLockConfiguration' + 'identifierUris' + 'applicationIdUris' + 'keyCredentials' + 'passwordCredentials' + 'isDisabled' + ) + $AppCopyBody = $App | Select-Object -Property * -ExcludeProperty $PropertiesToRemove + # Remove any null properties + $NullProperties = [System.Collections.Generic.List[string]]::new() + foreach ($Property in $AppCopyBody.PSObject.Properties.Name) { + if ($null -eq $AppCopyBody.$Property -or $AppCopyBody.$Property -eq '' -or !$AppCopyBody.$Property) { + Write-Information "Removing null property $Property from app copy body" + $NullProperties.Add($Property) + } + } + $AppCopyBody = $AppCopyBody | Select-Object -Property * -ExcludeProperty $NullProperties + if ($AppCopyBody.signInAudience -eq 'AzureADMyOrg') { + # Enterprise apps cannot be copied to another tenant + $AppCopyBody.signInAudience = 'AzureADMultipleOrgs' + } + if ($AppCopyBody.web -and $AppCopyBody.web.redirectUris) { + # Remove redirect URI settings if property exists + $AppCopyBody.web.PSObject.Properties.Remove('redirectUriSettings') + } + if ($AppCopyBody.api.oauth2PermissionScopes) { + $AppCopyBody.api.oauth2PermissionScopes = @(foreach ($Scope in $AppCopyBody.api.oauth2PermissionScopes) { + $Scope | Select-Object * -ExcludeProperty 'isPrivate' + }) + } + if ($AppCopyBody.appRoles) { + $AppCopyBody.appRoles = @(foreach ($Role in $AppCopyBody.api.appRoles) { + $Role | Select-Object * -ExcludeProperty 'isPreAuthorizationRequired', 'isPrivate' + }) + } + if ($AppCopyBody.api -and $AppCopyBody.api.tokenEncryptionSetting) { + # Remove token encryption settings if property exists + $AppCopyBody.api.PSObject.Properties.Remove('tokenEncryptionSetting') + } + + $NewApp = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/v1.0/applications' -tenantid $env:TenantID -NoAuthCheck $true -AsApp $true -type POST -body ($AppCopyBody | ConvertTo-Json -Depth 10) + + if (-not $NewApp) { + throw 'Failed to copy app registration to partner tenant' + } + + Write-Information "App Registration copied. New AppId: $($NewApp.appId)" + $App = $NewApp + $AppId = $NewApp.appId + Write-Information "Creating service principal for AppId: $AppId in partner tenant" + $Body = @{ + appId = $AppId + } + $NewSP = New-GraphPOSTRequest -uri 'https://graph.microsoft.com/v1.0/servicePrincipals' -tenantid $env:TenantID -NoAuthCheck $true -AsApp $true -type POST -body ($Body | ConvertTo-Json -Depth 10) + Write-LogMessage -headers $Request.headers -API $APINAME -message "App Registration $($AppDetails.displayName) copied to partner tenant" -Sev 'Info' + } + } + $Permissions = if ($App.requiredResourceAccess) { $App.requiredResourceAccess } else { @() } } @@ -114,7 +189,7 @@ function Invoke-ExecCreateAppTemplate { } Add-CIPPAzDataTableEntity @PermissionsTable -Entity $PermissionEntity -Force - Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message "Permission set created with ID: $PermissionSetId for $($Permissions.Count) resource(s)" -Sev 'Info' + Write-LogMessage -headers $Request.headers -API $APINAME -message "Permission set created with ID: $PermissionSetId for $($Permissions.Count) resource(s)" -Sev 'Info' } # Create the template @@ -156,24 +231,33 @@ function Invoke-ExecCreateAppTemplate { } $Message = "Template created: $DisplayName with $PermissionCount permission(s)" - Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message $Message -Sev 'Info' + Write-LogMessage -headers $Request.headers -API $APINAME -message $Message -Sev 'Info' $Body = @{ - Results = $Message - TemplateId = $TemplateId + Results = @{'resultText' = $Message; 'state' = 'success' } + Metadata = @{ + TemplateId = $TemplateId + SourceTenant = $TenantFilter + } } $StatusCode = [HttpStatusCode]::OK } catch { $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message - Write-LogMessage -user $Request.headers.'x-ms-client-principal' -API $APINAME -message "Failed to create template: $ErrorMessage" -Sev 'Error' + Write-LogMessage -headers $Request.headers -API $APINAME -message "Failed to create template: $ErrorMessage" -Sev 'Error' -LogData (Get-CippException -Exception $_) + Write-Warning "Failed to create template: $ErrorMessage" + Write-Information $_.InvocationInfo.PositionMessage $Body = @{ - Results = "Failed to create template: $ErrorMessage" + Results = @(@{ + resultText = "Failed to create template: $ErrorMessage" + state = 'error' + details = Get-CippException -Exception $_ + }) } $StatusCode = [HttpStatusCode]::BadRequest } - Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + return ([HttpResponseContext]@{ StatusCode = $StatusCode Body = ($Body | ConvertTo-Json -Depth 10) }) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 index 7922fa3841e5..92682df3bf50 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 @@ -86,6 +86,7 @@ function Invoke-ListLogs { $TenantFilter = $Request.Query.Tenant $ApiFilter = $Request.Query.API $StandardFilter = $Request.Query.StandardTemplateId + $ScheduledTaskFilter = $Request.Query.ScheduledTaskId $StartDate = $Request.Query.StartDate ?? $Request.Query.DateFilter $EndDate = $Request.Query.EndDate ?? $Request.Query.DateFilter @@ -115,9 +116,10 @@ function Invoke-ListLogs { $Rows = Get-AzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Severity -in $LogLevel -and $_.Username -like $username -and - ($TenantFilter -eq $null -or $TenantFilter -eq 'AllTenants' -or $_.Tenant -like "*$TenantFilter*" -or $_.TenantID -eq $TenantFilter) -and - ($ApiFilter -eq $null -or $_.API -match "$ApiFilter") -and - ($StandardFilter -eq $null -or $_.StandardTemplateId -eq $StandardFilter) + ([string]::IsNullOrEmpty($TenantFilter) -or $TenantFilter -eq 'AllTenants' -or $_.Tenant -like "*$TenantFilter*" -or $_.TenantID -eq $TenantFilter) -and + ([string]::IsNullOrEmpty($ApiFilter) -or $_.API -match "$ApiFilter") -and + ([string]::IsNullOrEmpty($StandardFilter) -or $_.StandardTemplateId -eq $StandardFilter) -and + ([string]::IsNullOrEmpty($ScheduledTaskFilter) -or $_.ScheduledTaskId -eq $ScheduledTaskFilter) } if ($AllowedTenants -notcontains 'AllTenants') { @@ -126,7 +128,7 @@ function Invoke-ListLogs { foreach ($Row in $Rows) { if ($AllowedTenants -contains 'AllTenants' -or ($AllowedTenants -notcontains 'AllTenants' -and ($TenantList.defaultDomainName -contains $Row.Tenant -or $Row.Tenant -eq 'CIPP' -or $TenantList.customerId -contains $Row.TenantId)) ) { - if ($Row.StandardTemplateId) { + if ($StandardTaskFilter -and $Row.StandardTemplateId) { $Standard = ($Templates | Where-Object { $_.RowKey -eq $Row.StandardTemplateId }).JSON | ConvertFrom-Json $StandardInfo = @{ diff --git a/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 b/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 index 5cff84ab5762..ebcabfa12702 100644 --- a/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/New-GraphPOSTRequest.ps1 @@ -1,9 +1,25 @@ -function New-GraphPOSTRequest ($uri, $tenantid, $body, $type, $scope, $AsApp, $NoAuthCheck, $skipTokenCache, $AddedHeaders, $contentType, $IgnoreErrors = $false, $returnHeaders = $false) { +function New-GraphPOSTRequest { <# .FUNCTIONALITY Internal #> + param( + $uri, + $tenantid, + $body, + $type = 'POST', + $scope, + $AsApp, + $NoAuthCheck, + $skipTokenCache, + $AddedHeaders, + $contentType, + $IgnoreErrors = $false, + $returnHeaders = $false, + $maxRetries = 1 + ) + if ($NoAuthCheck -or (Get-AuthorisedRequest -Uri $uri -TenantID $tenantid)) { $headers = Get-GraphToken -tenantid $tenantid -scope $scope -AsApp $asapp -SkipCache $skipTokenCache if ($AddedHeaders) { @@ -12,27 +28,35 @@ function New-GraphPOSTRequest ($uri, $tenantid, $body, $type, $scope, $AsApp, $N } } - if (!$type) { - $type = 'POST' - } - - Write-Information "$($type.ToUpper()) [ $uri ] | tenant: $tenantid" - if (!$contentType) { $contentType = 'application/json; charset=utf-8' } - try { - $body = Get-CIPPTextReplacement -TenantFilter $tenantid -Text $body -EscapeForJson - $ReturnedData = (Invoke-RestMethod -Uri $($uri) -Method $TYPE -Body $body -Headers $headers -ContentType $contentType -SkipHttpErrorCheck:$IgnoreErrors -ResponseHeadersVariable responseHeaders) - } catch { - $Message = if ($_.ErrorDetails.Message) { - Get-NormalizedError -Message $_.ErrorDetails.Message - } else { - $_.Exception.message + + $body = Get-CIPPTextReplacement -TenantFilter $tenantid -Text $body -EscapeForJson + + $x = 0 + do { + try { + Write-Information "$($type.ToUpper()) [ $uri ] | tenant: $tenantid | attempt: $($x + 1) of $maxRetries" + $success = $false + $ReturnedData = (Invoke-RestMethod -Uri $($uri) -Method $TYPE -Body $body -Headers $headers -ContentType $contentType -SkipHttpErrorCheck:$IgnoreErrors -ResponseHeadersVariable responseHeaders) + $success = $true + } catch { + + $Message = if ($_.ErrorDetails.Message) { + Get-NormalizedError -Message $_.ErrorDetails.Message + } else { + $_.Exception.message + } + $x++ + Start-Sleep -Seconds (2 * $x) } + } while (($x -lt $maxRetries) -and ($success -eq $false)) + if ($success -eq $false) { throw $Message } + if ($returnHeaders) { return $responseHeaders } else { diff --git a/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 b/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 index 833b4d6f38eb..52127cc88471 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 @@ -76,6 +76,9 @@ function Write-LogMessage { $TableRow.ConditionalAccessTemplateId = [string]$script:StandardInfo.ConditionalAccessTemplateId } } + if ($script:ScheduledTaskId) { + $TableRow.ScheduledTaskId = [string]$script:ScheduledTaskId + } $Table.Entity = $TableRow Add-CIPPAzDataTableEntity @Table | Out-Null diff --git a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 index cf947d6d8f82..3eee2aff1ed1 100644 --- a/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 +++ b/Modules/CIPPCore/Public/Send-CIPPAlert.ps1 @@ -18,6 +18,11 @@ function Send-CIPPAlert { $Table = Get-CIPPTable -TableName SchedulerConfig $Filter = "RowKey eq 'CippNotifications' and PartitionKey eq 'CippNotifications'" $Config = [pscustomobject](Get-CIPPAzDataTableEntity @Table -Filter $Filter) + + if ($HTMLContent) { + $HTMLContent = Get-CIPPTextReplacement -TenantFilter $TenantFilter -Text $HTMLContent + } + if ($Type -eq 'email') { Write-Information 'Trying to send email' try { @@ -39,6 +44,7 @@ function Send-CIPPAlert { } } } + $PowerShellBody = [PSCustomObject]@{ message = @{ subject = $Title @@ -52,6 +58,7 @@ function Send-CIPPAlert { } $JSONBody = ConvertTo-Json -Compress -Depth 10 -InputObject $PowerShellBody + if ($PSCmdlet.ShouldProcess($($Recipients.EmailAddress.Address -join ', '), 'Sending email')) { $null = New-GraphPostRequest -uri 'https://graph.microsoft.com/v1.0/me/sendMail' -tenantid $env:TenantID -NoAuthCheck $true -type POST -body ($JSONBody) } @@ -93,7 +100,7 @@ function Send-CIPPAlert { if ($Type -eq 'webhook') { Write-Information 'Trying to send webhook' - + $JSONBody = Get-CIPPTextReplacement -TenantFilter $TenantFilter -Text $JSONContent -EscapeForJson try { if (![string]::IsNullOrWhiteSpace($Config.webhook) -or ![string]::IsNullOrWhiteSpace($AltWebhook)) { if ($PSCmdlet.ShouldProcess($Config.webhook, 'Sending webhook')) { diff --git a/Modules/CIPPCore/Public/Set-CIPPMessageCopy.ps1 b/Modules/CIPPCore/Public/Set-CIPPMessageCopy.ps1 index 512d56a75257..08e15977157e 100644 --- a/Modules/CIPPCore/Public/Set-CIPPMessageCopy.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPMessageCopy.ps1 @@ -1,20 +1,27 @@ function Set-CIPPMessageCopy { [CmdletBinding()] param ( - $userid, + $UserId, [bool]$MessageCopyForSentAsEnabled, + [bool]$MessageCopyForSendOnBehalfEnabled, $TenantFilter, - $APIName = 'Manage OneDrive Access', + $APIName = 'Set message copy for sent', $Headers ) - Try { - $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams @{Identity = $userid; MessageCopyForSentAsEnabled = $MessageCopyForSentAsEnabled } - $Result = "Successfully set MessageCopyForSentAsEnabled as $MessageCopyForSentAsEnabled on $($userid)." + try { + $cmdParams = @{ + Identity = $UserId + MessageCopyForSentAsEnabled = $MessageCopyForSentAsEnabled + MessageCopyForSendOnBehalfEnabled = $MessageCopyForSendOnBehalfEnabled + + } + $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Set-Mailbox' -cmdParams $cmdParams + $Result = "Successfully set message copy for 'Send as' as $MessageCopyForSentAsEnabled and 'Sent on behalf' as $MessageCopyForSendOnBehalfEnabled on $($UserId)." Write-LogMessage -headers $Headers -API $APIName -tenant $($TenantFilter) -message $Result -Sev 'Info' return $Result } catch { $ErrorMessage = Get-CippException -Exception $_ - $Result = "Failed to set MessageCopyForSentAsEnabled to $MessageCopyForSentAsEnabled - $($ErrorMessage.NormalizedError)" + $Result = "Failed to set message copy for 'Send as' as $MessageCopyForSentAsEnabled and 'Sent on behalf' as $MessageCopyForSendOnBehalfEnabled - $($ErrorMessage.NormalizedError)" Write-LogMessage -headers $Headers -API $APIName -tenant $($TenantFilter) -message $Result -Sev 'Error' -LogData $ErrorMessage throw $Result } diff --git a/Modules/CIPPCore/Public/TenantGroups/Update-CIPPDynamicTenantGroups.ps1 b/Modules/CIPPCore/Public/TenantGroups/Update-CIPPDynamicTenantGroups.ps1 index 41ec19b11af1..8ea1a508d4c6 100644 --- a/Modules/CIPPCore/Public/TenantGroups/Update-CIPPDynamicTenantGroups.ps1 +++ b/Modules/CIPPCore/Public/TenantGroups/Update-CIPPDynamicTenantGroups.ps1 @@ -173,11 +173,17 @@ function Update-CIPPDynamicTenantGroups { $TenantVariables = Get-CIPPTenantVariables -TenantFilter $_.customerId -IncludeGlobal } catch { Write-Information "Error fetching custom variables for tenant $($_.defaultDomainName): $($_.Exception.Message)" + Write-LogMessage -API 'TenantGroups' -message 'Error getting tenant variables' -Tenant $_.defaultDomainName -sev Warning -LogData (Get-CippException -Exception $_) } } - $SKUId = $LicenseInfo.SKUId ?? @() - $ServicePlans = (Get-CIPPTenantCapabilities -TenantFilter $_.defaultDomainName).psobject.properties.name + try { + $SKUId = $LicenseInfo.SKUId ?? @() + $ServicePlans = (Get-CIPPTenantCapabilities -TenantFilter $_.defaultDomainName).psobject.properties.name + } catch { + Write-Information "Error fetching capabilities for tenant $($_.defaultDomainName): $($_.Exception.Message)" + Write-LogMessage -API 'TenantGroups' -message 'Error getting tenant capabilities' -Tenant $_.defaultDomainName -sev Warning -LogData (Get-CippException -Exception $_) + } [pscustomobject]@{ customerId = $_.customerId defaultDomainName = $_.defaultDomainName @@ -192,6 +198,7 @@ function Update-CIPPDynamicTenantGroups { $LogicOperator = if ($Group.RuleLogic -eq 'or') { ' -or ' } else { ' -and ' } $WhereString = $WhereConditions -join $LogicOperator Write-Information "Evaluating tenants with condition: $WhereString" + Write-LogMessage -API 'TenantGroups' -message "Evaluating tenants for group '$($Group.Name)' with condition: $WhereString" -sev Info $ScriptBlock = [ScriptBlock]::Create($WhereString) $MatchingTenants = $TenantObj | Where-Object $ScriptBlock diff --git a/host.json b/host.json index cb92d98a0fcc..2cf91f7b1f33 100644 --- a/host.json +++ b/host.json @@ -5,7 +5,7 @@ }, "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", - "version": "[4.*, 5.0.0)" + "version": "[4.26.0, 5.0.0)" }, "functionTimeout": "00:10:00", "extensions": { @@ -15,7 +15,10 @@ "tracing": { "distributedTracingEnabled": false, "version": "None" - } + }, + "defaultVersion": "8.7.1", + "versionMatchStrategy": "Strict", + "versionFailureStrategy": "Fail" } } } diff --git a/profile.ps1 b/profile.ps1 index e8a94d1cea5e..97c133727559 100644 --- a/profile.ps1 +++ b/profile.ps1 @@ -58,6 +58,10 @@ if (!$LastStartup -or $CurrentVersion -ne $LastStartup.Version) { } catch { Write-LogMessage -message 'Failed to clear durables after update' -LogData (Get-CippException -Exception $_) -Sev 'Error' } + + $ReleaseTable = Get-CippTable -tablename 'cacheGitHubReleaseNotes' + Remove-AzDataTableEntity @ReleaseTable -Entity @{ PartitionKey = 'GitHubReleaseNotes'; RowKey = 'GitHubReleaseNotes' } -ErrorAction SilentlyContinue + Write-Host 'Cleared GitHub release notes cache to force refresh on version update.' } # Uncomment the next line to enable legacy AzureRm alias in Azure PowerShell. # Enable-AzureRmAlias diff --git a/version_latest.txt b/version_latest.txt index df5119ec64e6..d139a75408e9 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -8.7.0 +8.7.1