diff --git a/Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1 b/Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1 index 83b4e2bfe025..d2a4f8cd19e1 100644 --- a/Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1 +++ b/Modules/CIPPCore/Public/Add-CIPPDelegatedPermission.ps1 @@ -114,6 +114,10 @@ function Add-CIPPDelegatedPermission { $OldScope = ($CurrentDelegatedScopes | Where-Object -Property Resourceid -EQ $svcPrincipalId.id) if (!$OldScope) { + if ([string]::IsNullOrEmpty($NewScope) -or $NewScope -eq ' ') { + $Results.add("No delegated permissions to add for $($svcPrincipalId.displayName)") + continue + } try { $Createbody = @{ clientId = $ourSVCPrincipal.id @@ -147,6 +151,13 @@ function Add-CIPPDelegatedPermission { $Results.add("All delegated permissions exist for $($svcPrincipalId.displayName)") continue } + + if ([string]::IsNullOrEmpty($NewScope) -or $NewScope -eq ' ') { + # No permissions to update + $Results.add("No delegated permissions to update for $($svcPrincipalId.displayName)") + continue + } + $Patchbody = @{ scope = "$NewScope" } | ConvertTo-Json -Compress 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 new file mode 100644 index 000000000000..e2eefeff06ce --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyCalPerms.ps1 @@ -0,0 +1,140 @@ +using namespace System.Net + +Function Invoke-ExecModifyCalPerms { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Calendar.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + Write-LogMessage -headers $Request.Headers -API $APINAME-message 'Accessed this API' -Sev 'Debug' + + $Username = $request.body.userID + $Tenantfilter = $request.body.tenantfilter + $Permissions = $request.body.permissions + + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Processing request for user: $Username, tenant: $Tenantfilter" -Sev 'Debug' + + if ($username -eq $null) { + Write-LogMessage -headers $Request.Headers -API $APINAME-message 'Username is null' -Sev 'Error' + $body = [pscustomobject]@{'Results' = @('Username is required') } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::BadRequest + Body = $Body + }) + return + } + + try { + $userid = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($username)" -tenantid $Tenantfilter).id + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Retrieved user ID: $userid" -Sev 'Debug' + } + catch { + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Failed to get user ID: $($_.Exception.Message)" -Sev 'Error' + $body = [pscustomobject]@{'Results' = @("Failed to get user ID: $($_.Exception.Message)") } + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::NotFound + Body = $Body + }) + return + } + + $Results = [System.Collections.ArrayList]::new() + $HasErrors = $false + + # Convert permissions to array format if it's an object with numeric keys + if ($Permissions -is [PSCustomObject]) { + if ($Permissions.PSObject.Properties.Name -match '^\d+$') { + $Permissions = $Permissions.PSObject.Properties.Value + } + else { + $Permissions = @($Permissions) + } + } + + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Processing $($Permissions.Count) permission entries" -Sev 'Debug' + + foreach ($Permission in $Permissions) { + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Processing permission: $($Permission | ConvertTo-Json)" -Sev 'Debug' + + $PermissionLevel = $Permission.PermissionLevel.value ?? $Permission.PermissionLevel + $Modification = $Permission.Modification + $CanViewPrivateItems = $Permission.CanViewPrivateItems ?? $false + + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Permission Level: $PermissionLevel, Modification: $Modification, CanViewPrivateItems: $CanViewPrivateItems" -Sev 'Debug' + + # Handle UserID as array or single value + $TargetUsers = @($Permission.UserID | ForEach-Object { $_.value ?? $_ }) + + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Target Users: $($TargetUsers -join ', ')" -Sev 'Debug' + + foreach ($TargetUser in $TargetUsers) { + try { + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Processing target user: $TargetUser" -Sev 'Debug' + + if ($Modification -eq 'Remove') { + try { + $CalPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Remove-MailboxFolderPermission' -cmdParams @{ + Identity = "$($userid):\Calendar" + User = $TargetUser + Confirm = $false + } + $null = $results.Add("Removed $($TargetUser) from $($username) Calendar permissions") + } + catch { + $null = $results.Add("No existing permissions to remove for $($TargetUser)") + } + } + else { + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Setting permissions with AccessRights: $PermissionLevel" -Sev 'Debug' + + $cmdParams = @{ + Identity = "$($userid):\Calendar" + User = $TargetUser + AccessRights = $PermissionLevel + Confirm = $false + } + + if ($CanViewPrivateItems) { + $cmdParams['SharingPermissionFlags'] = 'Delegate,CanViewPrivateItems' + } + + try { + # Try Add first + $CalPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Add-MailboxFolderPermission' -cmdParams $cmdParams + $null = $results.Add("Granted $($TargetUser) $($PermissionLevel) access to $($username) Calendar$($CanViewPrivateItems ? ' with access to private items' : '')") + } + catch { + # If Add fails, try Set + $CalPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Set-MailboxFolderPermission' -cmdParams $cmdParams + $null = $results.Add("Updated $($TargetUser) $($PermissionLevel) access to $($username) Calendar$($CanViewPrivateItems ? ' with access to private items' : '')") + } + } + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Successfully executed $($PermissionLevel) permission modification for $($TargetUser) on $($username)" -Sev 'Info' -tenant $TenantFilter + } + catch { + $HasErrors = $true + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Could not execute $($PermissionLevel) permission modification for $($TargetUser) on $($username). Error: $($_.Exception.Message)" -Sev 'Error' -tenant $TenantFilter + $null = $results.Add("Could not execute $($PermissionLevel) permission modification for $($TargetUser) on $($username). Error: $($_.Exception.Message)") + } + } + } + + if ($results.Count -eq 0) { + Write-LogMessage -headers $Request.Headers -API $APINAME-message 'No results were generated from the operation' -Sev 'Warning' + $null = $results.Add('No results were generated from the operation. Please check the logs for more details.') + $HasErrors = $true + } + + $body = [pscustomobject]@{'Results' = @($results) } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = if ($HasErrors) { [HttpStatusCode]::InternalServerError } else { [HttpStatusCode]::OK } + Body = $Body + }) +} \ No newline at end of file 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 new file mode 100644 index 000000000000..222c3561e579 --- /dev/null +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Administration/Invoke-ExecModifyMBPerms.ps1 @@ -0,0 +1,133 @@ +using namespace System.Net + +Function Invoke-ExecModifyMBPerms { + <# + .FUNCTIONALITY + Entrypoint + .ROLE + Exchange.Mailbox.ReadWrite + #> + [CmdletBinding()] + param($Request, $TriggerMetadata) + + $APIName = $Request.Params.CIPPEndpoint + Write-LogMessage -headers $Request.Headers -API $APINAME-message 'Accessed this API' -Sev 'Debug' + + $Username = $request.body.userID + $Tenantfilter = $request.body.tenantfilter + $Permissions = $request.body.permissions + + if ($username -eq $null) { exit } + + $userid = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/users/$($username)" -tenantid $Tenantfilter).id + $Results = [System.Collections.ArrayList]::new() + + # Convert permissions to array format if it's an object with numeric keys + if ($Permissions -is [PSCustomObject]) { + if ($Permissions.PSObject.Properties.Name -match '^\d+$') { + $Permissions = $Permissions.PSObject.Properties.Value + } + else { + $Permissions = @($Permissions) + } + } + + foreach ($Permission in $Permissions) { + $PermissionLevel = $Permission.PermissionLevel + $Modification = $Permission.Modification + $AutoMap = if ($Permission.PSObject.Properties.Name -contains 'AutoMap') { $Permission.AutoMap } else { $true } + + # Handle UserID as array of objects or single value + $TargetUsers = if ($Permission.UserID -is [array]) { + $Permission.UserID | ForEach-Object { $_.value } + } + else { + @($Permission.UserID) + } + + foreach ($TargetUser in $TargetUsers) { + try { + switch ($PermissionLevel) { + 'FullAccess' { + if ($Modification -eq 'Remove') { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Remove-mailboxpermission' -cmdParams @{ + Identity = $userid + user = $TargetUser + accessRights = @('FullAccess') + Confirm = $false + } + $null = $results.Add("Removed $($TargetUser) from $($username) Shared Mailbox permissions") + } + else { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Add-MailboxPermission' -cmdParams @{ + Identity = $userid + user = $TargetUser + accessRights = @('FullAccess') + automapping = $AutoMap + Confirm = $false + } + $null = $results.Add("Granted $($TargetUser) access to $($username) Mailbox with automapping set to $($AutoMap)") + } + } + 'SendAs' { + if ($Modification -eq 'Remove') { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Remove-RecipientPermission' -cmdParams @{ + Identity = $userid + Trustee = $TargetUser + accessRights = @('SendAs') + Confirm = $false + } + $null = $results.Add("Removed $($TargetUser) from $($username) with Send As permissions") + } + else { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Add-RecipientPermission' -cmdParams @{ + Identity = $userid + Trustee = $TargetUser + accessRights = @('SendAs') + Confirm = $false + } + $null = $results.Add("Granted $($TargetUser) access to $($username) with Send As permissions") + } + } + 'SendOnBehalf' { + if ($Modification -eq 'Remove') { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Set-Mailbox' -cmdParams @{ + Identity = $userid + GrantSendonBehalfTo = @{ + '@odata.type' = '#Exchange.GenericHashTable' + remove = $TargetUser + } + Confirm = $false + } + $null = $results.Add("Removed $($TargetUser) from $($username) Send on Behalf Permissions") + } + else { + $MailboxPerms = New-ExoRequest -Anchor $username -tenantid $Tenantfilter -cmdlet 'Set-Mailbox' -cmdParams @{ + Identity = $userid + GrantSendonBehalfTo = @{ + '@odata.type' = '#Exchange.GenericHashTable' + add = $TargetUser + } + Confirm = $false + } + $null = $results.Add("Granted $($TargetUser) access to $($username) with Send On Behalf Permissions") + } + } + } + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Executed $($PermissionLevel) permission modification for $($TargetUser) on $($username)" -Sev 'Info' -tenant $TenantFilter + } + catch { + Write-LogMessage -headers $Request.Headers -API $APINAME-message "Could not execute $($PermissionLevel) permission modification for $($TargetUser) on $($username)" -Sev 'Error' -tenant $TenantFilter + $null = $results.Add("Could not execute $($PermissionLevel) permission modification for $($TargetUser) on $($username). Error: $($_.Exception.Message)") + } + } + } + + $body = [pscustomobject]@{'Results' = @($results) } + + # Associate values to output bindings by calling 'Push-OutputBinding'. + Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ + StatusCode = [HttpStatusCode]::OK + Body = $Body + }) +} diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddTransportRule.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddTransportRule.ps1 index 48b8fad2336d..6224bc13ebb6 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddTransportRule.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Email-Exchange/Transport/Invoke-AddTransportRule.ps1 @@ -1,9 +1,9 @@ using namespace System.Net -Function Invoke-AddTransportRule { +function Invoke-AddTransportRule { <# .FUNCTIONALITY - Entrypoint + Entrypoint,AnyTenant .ROLE Exchange.TransportRule.ReadWrite #> @@ -17,6 +17,15 @@ Function Invoke-AddTransportRule { $RequestParams = $Request.Body.PowerShellCommand | ConvertFrom-Json | Select-Object -Property * -ExcludeProperty GUID, HasSenderOverride, ExceptIfHasSenderOverride, ExceptIfMessageContainsDataClassifications, MessageContainsDataClassifications $Tenants = ($Request.body.selectedTenants).value + + $AllowedTenants = Test-CippAccess -Request $Request -TenantList + + if ($AllowedTenants -ne 'AllTenants') { + $AllTenants = Get-Tenants -IncludeErrors + $AllowedTenantList = $AllTenants | Where-Object { $_.customerId -in $AllowedTenants } + $Tenants = $Tenants | Where-Object { $_ -in $AllowedTenantList.defaultDomainName } + } + $Result = foreach ($tenantFilter in $tenants) { $Existing = New-ExoRequest -ErrorAction SilentlyContinue -tenantid $tenantFilter -cmdlet 'Get-TransportRule' -useSystemMailbox $true | Where-Object -Property Identity -EQ $RequestParams.name try { diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsTemplate.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsTemplate.ps1 index aa5027e259f4..c41da1262f37 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsTemplate.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-AddStandardsTemplate.ps1 @@ -29,9 +29,8 @@ function Invoke-AddStandardsTemplate { RowKey = "$GUID" PartitionKey = 'StandardsTemplateV2' GUID = "$GUID" - } - Write-LogMessage -headers $Request.Headers -API $APINAME -message "Created CA Template $($Request.body.name) with GUID $GUID" -Sev 'Debug' + Write-LogMessage -headers $Request.Headers -API $APINAME -message "Standards Template $($Request.body.templateName) with GUID $GUID added/edited." -Sev 'Info' $body = [pscustomobject]@{'Results' = 'Successfully added template'; Metadata = @{id = $GUID } } # Associate values to output bindings by calling 'Push-OutputBinding'. diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListStandardsCompare.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListStandardsCompare.ps1 index 4144312551fd..130cec97dfba 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListStandardsCompare.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-ListStandardsCompare.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ListStandardsCompare { +function Invoke-ListStandardsCompare { <# .FUNCTIONALITY Entrypoint @@ -10,7 +10,13 @@ Function Invoke-ListStandardsCompare { [CmdletBinding()] param($Request, $TriggerMetadata) + $Table = Get-CIPPTable -TableName 'CippStandardsReports' + $TenantFilter = $Request.Query.tenantFilter + if ($TenantFilter) { + $Table.Filter = "RowKey eq '{0}'" -f $TenantFilter + } + $Results = Get-CIPPAzDataTableEntity @Table #in the results we have objects starting with "standards." All these have to be converted from JSON. Do not do this is its a boolean diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-listStandardTemplates.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-listStandardTemplates.ps1 index 3ebc2712adde..ba4abdb48e30 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-listStandardTemplates.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Tenant/Standards/Invoke-listStandardTemplates.ps1 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-listStandardTemplates { +function Invoke-listStandardTemplates { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -29,7 +29,16 @@ Function Invoke-listStandardTemplates { return } $Data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.GUID -Force - if ($Data.excludedTenants) { $Data.excludedTenants = @($Data.excludedTenants) } + + if (!$Data.excludedTenants) { + $Data | Add-Member -NotePropertyName 'excludedTenants' -NotePropertyValue @() -Force + } + + if ($Data.excludedTenants -and $Data.excludedTenants -ne 'excludedTenants') { + $Data.excludedTenants = @($Data.excludedTenants) + } else { + $Data.excludedTenants = @() + } $Data } | Sort-Object -Property templateName diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 index 7547f7b2f58c..6e360b25a6a0 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListLogs.ps1 @@ -3,7 +3,7 @@ using namespace System.Net function Invoke-ListLogs { <# .FUNCTIONALITY - Entrypoint + Entrypoint,AnyTenant .ROLE CIPP.Core.Read #> @@ -54,35 +54,34 @@ function Invoke-ListLogs { Write-Host "Getting logs for filter: $Filter, LogLevel: $LogLevel, Username: $username" $Rows = Get-AzDataTableEntity @Table -Filter $Filter | Where-Object { $_.Severity -in $LogLevel -and $_.Username -like $username } + + if ($AllowedTenants -notcontains 'AllTenants') { + $TenantList = Get-Tenants -IncludeErrors | Where-Object { $_.customerId -in $AllowedTenants } + } + foreach ($Row in $Rows) { - if ($AllowedTenants -notcontains 'AllTenants') { - $TenantList = Get-Tenants -IncludeErrors - if ($Row.Tenant -ne 'None' -and $Row.Tenant) { - $Tenant = $TenantList | Where-Object -Property defaultDomainName -EQ $Row.Tenant - if ($Tenant -and $Tenant.customerId -notin $AllowedTenants) { - continue + 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)) ) { + + $LogData = if ($Row.LogData -and (Test-Json -Json $Row.LogData -ErrorAction SilentlyContinue)) { + $Row.LogData | ConvertFrom-Json + } else { $Row.LogData } + [PSCustomObject]@{ + DateTime = $Row.Timestamp + Tenant = $Row.Tenant + API = $Row.API + Message = $Row.Message + User = $Row.Username + Severity = $Row.Severity + LogData = $LogData + TenantID = if ($Row.TenantID -ne $null) { + $Row.TenantID + } else { + 'None' } + AppId = $Row.AppId + IP = $Row.IP } } - $LogData = if ($Row.LogData -and (Test-Json -Json $Row.LogData -ErrorAction SilentlyContinue)) { - $Row.LogData | ConvertFrom-Json - } else { $Row.LogData } - [PSCustomObject]@{ - DateTime = $Row.Timestamp - Tenant = $Row.Tenant - API = $Row.API - Message = $Row.Message - User = $Row.Username - Severity = $Row.Severity - LogData = $LogData - TenantID = if ($Row.TenantID -ne $null) { - $Row.TenantID - } else { - 'None' - } - AppId = $Row.AppId - IP = $Row.IP - } } } diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogSearchCreation.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogSearchCreation.ps1 index a8fb469b7edb..28919fe56f95 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogSearchCreation.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogSearchCreation.ps1 @@ -7,7 +7,12 @@ function Start-AuditLogSearchCreation { param() try { $ConfigTable = Get-CippTable -TableName 'WebhookRules' - $ConfigEntries = Get-CIPPAzDataTableEntity @ConfigTable -Filter "PartitionKey eq 'Webhookv2'" + $ConfigEntries = Get-CIPPAzDataTableEntity @ConfigTable -Filter "PartitionKey eq 'Webhookv2'" | ForEach-Object { + $ConfigEntry = $_ + $ConfigEntry.excludedTenants = $ConfigEntry.excludedTenants | ConvertFrom-Json + $ConfigEntry.Tenants = $ConfigEntry.Tenants | ConvertFrom-Json + $ConfigEntry + } $TenantList = Get-Tenants -IncludeErrors # Round time down to nearest minute @@ -16,11 +21,29 @@ function Start-AuditLogSearchCreation { $EndTime = $Now.AddSeconds(-$Now.Seconds) Write-Information 'Audit Logs: Creating new searches' + foreach ($Tenant in $TenantList) { - $TenantsList = Expand-CIPPTenantGroups -TenantFilter ($ConfigEntries.Tenants | ConvertFrom-Json) - $Configuration = $ConfigEntries | Where-Object { ($_.Tenants -match $TenantFilter -or $_.Tenants -match 'AllTenants') } - if ($Configuration -and $Tenant -in $TenantsList) { - $ServiceFilters = $Configuration | Select-Object -Property type | Sort-Object -Property type -Unique | ForEach-Object { $_.type.split('.')[1] } + Write-Information "Processing tenant $($Tenant.defaultDomainName) - $($Tenant.customerId)" + $TenantInConfig = $false + $MatchingConfigs = [System.Collections.Generic.List[object]]::new() + foreach ($ConfigEntry in $ConfigEntries) { + if ($ConfigEntry.excludedTenants.value -contains $Tenant.defaultDomainName) { + continue + } + $TenantsList = Expand-CIPPTenantGroups -TenantFilter ($ConfigEntry.Tenants) + if ($TenantsList.value -contains $Tenant.defaultDomainName -or $TenantsList.value -contains 'AllTenants') { + $TenantInConfig = $true + $MatchingConfigs.Add($ConfigEntry) + } + } + + if (!$TenantInConfig) { + Write-Information "Tenant $($Tenant.defaultDomainName) has no configured audit log rules, skipping search creation." + continue + } + + if ($MatchingConfigs) { + $ServiceFilters = $MatchingConfigs | Select-Object -Property type | Sort-Object -Property type -Unique | ForEach-Object { $_.type.split('.')[1] } try { $LogSearch = @{ StartTime = $StartTime diff --git a/Modules/CIPPCore/Public/Set-CIPPCopyGroupMembers.ps1 b/Modules/CIPPCore/Public/Set-CIPPCopyGroupMembers.ps1 index 7225829106e8..9564d818f6d5 100644 --- a/Modules/CIPPCore/Public/Set-CIPPCopyGroupMembers.ps1 +++ b/Modules/CIPPCore/Public/Set-CIPPCopyGroupMembers.ps1 @@ -46,7 +46,7 @@ function Set-CIPPCopyGroupMembers { try { if ($PSCmdlet.ShouldProcess($MailGroup.displayName, "Add $UserId to group")) { if ($MailGroup.MailEnabled -and $Mailgroup.ResourceProvisioningOptions -notcontains 'Team' -and $MailGroup.groupTypes -notcontains 'Unified') { - $Params = @{ Identity = $MailGroup.mailNickname; Member = $UserId; BypassSecurityGroupManagerCheck = $true } + $Params = @{ Identity = $MailGroup.id; Member = $UserId; BypassSecurityGroupManagerCheck = $true } try { $null = New-ExoRequest -tenantid $TenantFilter -cmdlet 'Add-DistributionGroupMember' -cmdParams $params -UseSystemMailbox $true } catch { diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 index 8267956ad637..e75909d94c41 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardEXODisableAutoForwarding.ps1 @@ -38,8 +38,7 @@ function Invoke-CIPPStandardEXODisableAutoForwarding { $CurrentInfo = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-HostedOutboundSpamFilterPolicy' -cmdParams @{Identity = 'Default' } -useSystemMailbox $true $StateIsCorrect = $CurrentInfo.AutoForwardingMode -eq 'Off' - If ($Settings.remediate -eq $true) { - + if ($Settings.remediate -eq $true) { try { New-ExoRequest -tenantid $tenant -cmdlet 'Set-HostedOutboundSpamFilterPolicy' -cmdParams @{ Identity = 'Default'; AutoForwardingMode = 'Off' } -useSystemMailbox $true Write-LogMessage -API 'Standards' -tenant $tenant -message 'Disabled auto forwarding' -sev Info @@ -50,7 +49,6 @@ function Invoke-CIPPStandardEXODisableAutoForwarding { } if ($Settings.alert -eq $true) { - if ($StateIsCorrect -eq $true) { Write-LogMessage -API 'Standards' -tenant $tenant -message 'Auto forwarding is disabled.' -sev Info } else { @@ -60,9 +58,8 @@ function Invoke-CIPPStandardEXODisableAutoForwarding { } if ($Settings.report -eq $true) { - $state = $StateIsCorrect ? $true : $CurrentInfo | Select-Object autoForwardingMode + $state = $StateIsCorrect ?? ($CurrentInfo | Select-Object AutoForwardingMode) Set-CIPPStandardsCompareField -FieldName 'standards.EXODisableAutoForwarding' -FieldValue $state -TenantFilter $Tenant Add-CIPPBPAField -FieldName 'AutoForwardingDisabled' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant } - } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 index 6ca1652b5e01..bbf74d0e09a4 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardSpamFilterPolicy.ps1 @@ -241,7 +241,7 @@ function Invoke-CIPPStandardSpamFilterPolicy { if ($StateIsCorrect) { $FieldValue = $true } else { - $FieldValue = $CurrentState ? $CurrentState : @{ state = 'Spam filter policy not found' } + $FieldValue = $StateIsCorrect -eq $true ? $true : ($CurrentState ?? @{ state = 'Spam filter policy not found' }) } Set-CIPPStandardsCompareField -FieldName 'standards.SpamFilterPolicy' -FieldValue $FieldValue -Tenant $Tenant } diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsGuestAccess.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsGuestAccess.ps1 new file mode 100644 index 000000000000..715ef12c3386 --- /dev/null +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardTeamsGuestAccess.ps1 @@ -0,0 +1,77 @@ +function Invoke-CIPPStandardTeamsGuestAccess { + <# + .FUNCTIONALITY + Internal + .COMPONENT + (APIName) TeamsGuestAccess + .SYNOPSIS + (Label) Allow guest users in Teams + .DESCRIPTION + (Helptext) Allow guest users access to teams. + (DocsDescription) Allow guest users access to teams. Guest users are users who are not part of your organization but have been invited to collaborate with your organization in Teams. This setting allows you to control whether guest users can access Teams. + .NOTES + CAT + Teams Standards + TAG + ADDEDCOMPONENT + {"type":"switch","name":"standards.TeamsGuestAccess.AllowGuestUser","label":"Allow guest users"} + IMPACT + Low Impact + ADDEDDATE + 2025-06-03 + POWERSHELLEQUIVALENT + Set-CsTeamsClientConfiguration -AllowGuestUser \$true + 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) + + $CurrentState = New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Get-CsTeamsClientConfiguration' -CmdParams @{Identity = 'Global' } | Select-Object AllowGuestUser + + if ($null -eq $Settings.AllowGuestUser) { $Settings.AllowGuestUser = $false } + + $StateIsCorrect = ($CurrentState.AllowGuestUser -eq $Settings.AllowGuestUser) + + if ($Settings.remediate -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Guest Access already set.' -sev Info + } else { + $cmdParams = @{ + Identity = 'Global' + AllowGuestUser = $Settings.AllowGuestUser + } + + try { + New-TeamsRequest -TenantFilter $Tenant -Cmdlet 'Set-CsTeamsClientConfiguration' -CmdParams $cmdParams + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Updated Teams Guest Access settings' -sev Info + } catch { + $ErrorMessage = Get-NormalizedError -Message $_.Exception.Message + Write-LogMessage -API 'Standards' -tenant $Tenant -message "Failed to set Teams Guest Access settings. Error: $ErrorMessage" -sev Error + } + } + } + + if ($Settings.alert -eq $true) { + if ($StateIsCorrect -eq $true) { + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Guest Access settings is set correctly.' -sev Info + } else { + Write-StandardsAlert -message 'Teams Guest Access settings is not set correctly.' -object $CurrentState -tenant $Tenant -standardName 'TeamsGuestAccess' -standardId $Settings.standardId + Write-LogMessage -API 'Standards' -tenant $Tenant -message 'Teams Guest Access settings is not set correctly.' -sev Info + } + } + + if ($Settings.report -eq $true) { + if ($StateIsCorrect) { + $FieldValue = $true + } else { + $FieldValue = $CurrentState + } + Set-CIPPStandardsCompareField -FieldName 'standards.TeamsGuestAccess' -FieldValue $FieldValue -Tenant $Tenant + Add-CIPPBPAField -FieldName 'TeamsGuestAccess' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $Tenant + + } +} diff --git a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 index 6b3660fec34c..e1c2ee7ca8ac 100644 --- a/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 +++ b/Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardUserSubmissions.ps1 @@ -196,6 +196,8 @@ function Invoke-CIPPStandardUserSubmissions { if ($StateIsCorrect) { $FieldValue = $true } else { + $PolicyState = $PolicyState | Select-Object EnableReportToMicrosoft, ReportJunkToCustomizedAddress, ReportNotJunkToCustomizedAddress, ReportPhishToCustomizedAddress, ReportJunkAddresses, ReportNotJunkAddresses, ReportPhishAddresses + $RuleState = $RuleState | Select-Object State, SentTo $FieldValue = @{ PolicyState = $PolicyState; RuleState = $RuleState } } diff --git a/version_latest.txt b/version_latest.txt index cd1d2e94f31d..8b22a322d0fe 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -8.0.1 +8.0.2