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 2bfd9a5ed156..dc988dae26b5 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 @@ -1,6 +1,6 @@ using namespace System.Net -Function Invoke-ListTenants { +function Invoke-ListTenants { <# .FUNCTIONALITY Entrypoint,AnyTenant @@ -95,15 +95,15 @@ Function Invoke-ListTenants { } if ($Request.Query.Mode -eq 'TenantList') { # add portal link properties - $Body = $Body | Select-Object *, @{Name = 'portal_m365'; Expression = { "https://admin.microsoft.com/Partner/BeginClientSession.aspx?CTID=$($_.customerId)&CSDEST=o365admincenter" } }, - @{Name = 'portal_exchange'; Expression = { "https://admin.exchange.microsoft.com/?landingpage=homepage&form=mac_sidebar&delegatedOrg=$($_.defaultDomainName)" } }, + $Body = $Body | Select-Object *, @{Name = 'portal_m365'; Expression = { "https://admin.cloud.microsoft/?delegatedOrg=$($_.initialDomainName)" } }, + @{Name = 'portal_exchange'; Expression = { "https://admin.cloud.microsoft/exchange/?delegatedOrg=$($_.initialDomainName)" } }, @{Name = 'portal_entra'; Expression = { "https://entra.microsoft.com/$($_.defaultDomainName)" } }, - @{Name = 'portal_teams'; Expression = { "https://admin.teams.microsoft.com/?delegatedOrg=$($_.defaultDomainName)" } }, + @{Name = 'portal_teams'; Expression = { "https://admin.teams.microsoft.com/?delegatedOrg=$($_.initialDomainName)" } }, @{Name = 'portal_azure'; Expression = { "https://portal.azure.com/$($_.defaultDomainName)" } }, @{Name = 'portal_intune'; Expression = { "https://intune.microsoft.com/$($_.defaultDomainName)" } }, @{Name = 'portal_security'; Expression = { "https://security.microsoft.com/?tid=$($_.customerId)" } }, @{Name = 'portal_compliance'; Expression = { "https://purview.microsoft.com/?tid=$($_.customerId)" } }, - @{Name = 'portal_sharepoint'; Expression = { "https://admin.microsoft.com/Partner/beginclientsession.aspx?CTID=$($_.customerId)&CSDEST=SharePoint" } } + @{Name = 'portal_sharepoint'; Expression = { "/api/ListSharePointAdminUrl?tenantFilter=$($_.defaultDomainName)" } } } } else { diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogProcessingOrchestrator.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogProcessingOrchestrator.ps1 index e4eb7b779ddf..17318704ebe9 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogProcessingOrchestrator.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-AuditLogProcessingOrchestrator.ps1 @@ -7,36 +7,52 @@ function Start-AuditLogProcessingOrchestrator { param() Write-Information 'Starting audit log processing in batches of 1000, per tenant' $WebhookCacheTable = Get-CippTable -TableName 'CacheWebhooks' - $WebhookCache = Get-CIPPAzDataTableEntity @WebhookCacheTable - $TenantGroups = $WebhookCache | Group-Object -Property PartitionKey - if ($TenantGroups) { - Write-Information "Processing webhook cache for $($TenantGroups.Count) tenants" - #Write-Warning "AuditLogJobs are: $($TenantGroups.Count) tenants. Tenants: $($TenantGroups.name | ConvertTo-Json -Compress) " - #Write-Warning "Here are the groups: $($TenantGroups | ConvertTo-Json -Compress)" - $ProcessQueue = New-CippQueueEntry -Name 'Audit Logs Process' -Reference 'AuditLogsProcess' -TotalTasks ($TenantGroups | Measure-Object -Property Count -Sum).Sum - $ProcessBatch = foreach ($TenantGroup in $TenantGroups) { - $TenantFilter = $TenantGroup.Name - $RowIds = @($TenantGroup.Group.RowKey) - for ($i = 0; $i -lt $RowIds.Count; $i += 1000) { - Write-Host "Processing $TenantFilter with $($RowIds.Count) row IDs. We're processing id $($RowIds[$i]) to $($RowIds[[Math]::Min($i + 999, $RowIds.Count - 1)])" - $BatchRowIds = $RowIds[$i..([Math]::Min($i + 999, $RowIds.Count - 1))] - [PSCustomObject]@{ - TenantFilter = $TenantFilter - RowIds = $BatchRowIds - QueueId = $ProcessQueue.RowKey - FunctionName = 'AuditLogTenantProcess' + $DataTableQuery = @{ + First = 20000 + Skip = 0 + } + + do { + $WebhookCache = Get-CIPPAzDataTableEntity @WebhookCacheTable @DataTableQuery + $TenantGroups = $WebhookCache | Group-Object -Property PartitionKey + + if ($TenantGroups) { + Write-Information "Processing webhook cache for $($TenantGroups.Count) tenants" + #Write-Warning "AuditLogJobs are: $($TenantGroups.Count) tenants. Tenants: $($TenantGroups.name | ConvertTo-Json -Compress) " + #Write-Warning "Here are the groups: $($TenantGroups | ConvertTo-Json -Compress)" + $ProcessQueue = New-CippQueueEntry -Name 'Audit Logs Process' -Reference 'AuditLogsProcess' -TotalTasks ($TenantGroups | Measure-Object -Property Count -Sum).Sum + $ProcessBatch = foreach ($TenantGroup in $TenantGroups) { + $TenantFilter = $TenantGroup.Name + $RowIds = @($TenantGroup.Group.RowKey) + for ($i = 0; $i -lt $RowIds.Count; $i += 1000) { + Write-Host "Processing $TenantFilter with $($RowIds.Count) row IDs. We're processing id $($RowIds[$i]) to $($RowIds[[Math]::Min($i + 999, $RowIds.Count - 1)])" + $BatchRowIds = $RowIds[$i..([Math]::Min($i + 999, $RowIds.Count - 1))] + [PSCustomObject]@{ + TenantFilter = $TenantFilter + RowIds = $BatchRowIds + QueueId = $ProcessQueue.RowKey + FunctionName = 'AuditLogTenantProcess' + } } } - } - if ($ProcessBatch) { - $ProcessInputObject = [PSCustomObject]@{ - OrchestratorName = 'AuditLogTenantProcess' - Batch = @($ProcessBatch) - SkipLog = $true + if ($ProcessBatch) { + $ProcessInputObject = [PSCustomObject]@{ + OrchestratorName = 'AuditLogTenantProcess' + Batch = @($ProcessBatch) + SkipLog = $true + } + Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($ProcessInputObject | ConvertTo-Json -Depth 5 -Compress) + Write-Information "Started audit log processing orchestration with $($ProcessBatch.Count) batches" } - Start-NewOrchestration -FunctionName 'CIPPOrchestrator' -InputObject ($ProcessInputObject | ConvertTo-Json -Depth 5 -Compress) - Write-Information "Started audit log processing orchestration with $($ProcessBatch.Count) batches" } - } + + if ($WebhookCache.Count -lt 20000) { + Write-Information 'No more rows to process' + break + } + Write-Information "Processed $($WebhookCache.Count) rows" + $DataTableQuery.Skip += 20000 + Write-Information "Getting next batch of $($DataTableQuery.First) rows" + } while ($WebhookCache.Count -eq 20000) } diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-DurableCleanup.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-DurableCleanup.ps1 index c10f4ad91212..aaca4e5c6baa 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-DurableCleanup.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-DurableCleanup.ps1 @@ -15,7 +15,7 @@ function Start-DurableCleanup { [CmdletBinding(SupportsShouldProcess = $true)] param( - [int]$MaxDuration = 3600 + [int]$MaxDuration = 86400 ) $WarningPreference = 'SilentlyContinue' @@ -49,6 +49,11 @@ function Start-DurableCleanup { if ($PSCmdlet.ShouldProcess($_.PartitionKey, 'Terminate Orchestrator')) { $Orchestrator = Get-CIPPAzDataTableEntity @Table -Filter "PartitionKey eq '$($Orchestrator.PartitionKey)'" $Orchestrator.RuntimeStatus = 'Failed' + if ($Orchestrator.PSObject.Properties.Name -contains 'CustomStatus') { + $Orchestrator.CustomStatus = "Terminated by Durable Cleanup - Exceeded max duration of $MaxDuration seconds" + } else { + $Orchestrator | Add-Member -MemberType NoteProperty -Name CustomStatus -Value "Terminated by Durable Cleanup - Exceeded max duration of $MaxDuration seconds" + } Update-AzDataTableEntity @Table -Entity $Orchestrator $CleanupCount++ } diff --git a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 index ad0bd8ba0fb2..a40c6cb07463 100644 --- a/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 +++ b/Modules/CIPPCore/Public/Standards/Get-CIPPStandards.ps1 @@ -20,16 +20,16 @@ function Get-CIPPStandards { $Table = Get-CippTable -tablename 'templates' $Filter = "PartitionKey eq 'StandardsTemplateV2'" $Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter | Sort-Object TimeStamp).JSON | - ForEach-Object { - try { - # Fix old "Action" => "action" - $JSON = $_ -replace '"Action":', '"action":' -replace '"permissionlevel":', '"permissionLevel":' - ConvertFrom-Json -InputObject $JSON -ErrorAction SilentlyContinue - } catch {} - } | - Where-Object { - $_.GUID -like $TemplateId -and $_.runManually -eq $runManually - } + ForEach-Object { + try { + # Fix old "Action" => "action" + $JSON = $_ -replace '"Action":', '"action":' -replace '"permissionlevel":', '"permissionLevel":' + ConvertFrom-Json -InputObject $JSON -ErrorAction SilentlyContinue + } catch {} + } | + Where-Object { + $_.GUID -like $TemplateId -and $_.runManually -eq $runManually + } # 2. Get tenant list, filter if needed $AllTenantsList = Get-Tenants @@ -138,7 +138,15 @@ function Get-CIPPStandards { if ($template.excludedTenants) { if ($template.excludedTenants -is [System.Collections.IEnumerable] -and -not ($template.excludedTenants -is [string])) { - $excludedTenantValues = $template.excludedTenants | ForEach-Object { $_.value } + $excludedTenantValues = $template.excludedTenants | ForEach-Object { + $FilterValue = $_.value + if ($_.type -eq 'Group') { + ($TenantGroups | Where-Object { + $_.Id -eq $FilterValue + }).Members.defaultDomainName + } else { + $FilterValue + } } } else { $excludedTenantValues = @($template.excludedTenants) } diff --git a/Modules/CippExtensions/Public/Hudu/Get-HuduFieldMapping.ps1 b/Modules/CippExtensions/Public/Hudu/Get-HuduFieldMapping.ps1 index 3a74f9ce2b3f..a08834a7cbbe 100644 --- a/Modules/CippExtensions/Public/Hudu/Get-HuduFieldMapping.ps1 +++ b/Modules/CippExtensions/Public/Hudu/Get-HuduFieldMapping.ps1 @@ -68,7 +68,7 @@ function Get-HuduFieldMapping { CIPPFields = $CIPPFields CIPPFieldHeaders = $CIPPFieldHeaders IntegrationFields = @($Unset) + @($AssetLayouts) - Mappings = $Mappings + Mappings = @($Mappings) } return $MappingObj diff --git a/Modules/CippExtensions/Public/NinjaOne/Get-NinjaOneFieldMapping.ps1 b/Modules/CippExtensions/Public/NinjaOne/Get-NinjaOneFieldMapping.ps1 index d3de5486cab7..6e61d59f7e3a 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Get-NinjaOneFieldMapping.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Get-NinjaOneFieldMapping.ps1 @@ -109,7 +109,7 @@ function Get-NinjaOneFieldMapping { CIPPFields = $CIPPFields CIPPFieldHeaders = $CIPPFieldHeaders IntegrationFields = @($Unset) + @($NinjaCustomFieldsOrg) + @($NinjaCustomFieldsNode) - Mappings = $Mappings + Mappings = @($Mappings) } return $MappingObj diff --git a/version_latest.txt b/version_latest.txt index 3488e2954e25..017f8006642e 100644 --- a/version_latest.txt +++ b/version_latest.txt @@ -1 +1 @@ -7.5.2 +7.5.3