From 256d9eaa3575911ec7e086611c7c2904371c3bcc Mon Sep 17 00:00:00 2001 From: John Duprey Date: Tue, 8 Oct 2024 16:16:26 -0400 Subject: [PATCH 01/10] Optimize tenant refresh in onboarding --- .../Activity Triggers/Push-ExecOnboardTenantQueue.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecOnboardTenantQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecOnboardTenantQueue.ps1 index bf9b17bb9dc9..5c18cbe54d21 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecOnboardTenantQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Activity Triggers/Push-ExecOnboardTenantQueue.ps1 @@ -275,7 +275,7 @@ Function Push-ExecOnboardTenantQueue { $Logs.Add([PSCustomObject]@{ Date = Get-Date -UFormat $DateFormat; Log = 'Clearing tenant cache' }) $y = 0 do { - $Tenant = Get-Tenants -TriggerRefresh -IncludeAll | Where-Object { $_.customerId -eq $Relationship.customer.tenantId } | Select-Object -First 1 + $Tenant = Get-Tenants -TriggerRefresh -TenantFilter $Relationship.customer.tenantId | Select-Object -First 1 $y++ Start-Sleep -Seconds 20 } while (!$Tenant -and $y -le 10) From 62fc28b8e757b61999bcaad1c8211b676a2c1819 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 9 Oct 2024 14:10:21 -0400 Subject: [PATCH 02/10] Ninja webhook error handling --- .../NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 index 9213a7015b1a..0404a44aa618 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 @@ -24,23 +24,36 @@ function Invoke-NinjaOneDeviceWebhook { $Device = Get-CIPPAzDataTableEntity @DeviceMapTable -Filter $DeviceFilter if (($Device | Measure-Object).count -eq 1) { - $Token = Get-NinjaOneToken -configuration $Configuration + try { + $Token = Get-NinjaOneToken -configuration $Configuration - if ($DeviceM365.isCompliant -eq $True) { - $Compliant = 'Compliant' - } else { - $Compliant = 'Non-Compliant' - } - - $ComplianceBody = @{ - "$($MappedFields.DeviceCompliance)" = $Compliant - } | ConvertTo-Json + if (!$Token.access_token) { + Write-LogMessage -API 'NinjaOneSync' -tenant $tenantfilter -user 'CIPP' -message 'Failed to get NinjaOne Token for Device Compliance Update' -Sev 'Error' + return + } - $Null = Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/device/$($Device.NinjaOneID)/custom-fields" -Method PATCH -Body $ComplianceBody -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' + if ($DeviceM365.isCompliant -eq $True) { + $Compliant = 'Compliant' + } else { + $Compliant = 'Non-Compliant' + } - Write-Host 'Updated NinjaOne Device Compliance' + $ComplianceBody = @{ + "$($MappedFields.DeviceCompliance)" = $Compliant + } | ConvertTo-Json + $Null = Invoke-WebRequest -Uri "https://$($Configuration.Instance)/api/v2/device/$($Device.NinjaOneID)/custom-fields" -Method PATCH -Body $ComplianceBody -Headers @{Authorization = "Bearer $($token.access_token)" } -ContentType 'application/json' + Write-Host 'Updated NinjaOne Device Compliance' + } catch { + $Message = if ($_.ErrorDetails.Message) { + Get-NormalizedError -Message $_.ErrorDetails.Message + } else { + $_.Exception.message + } + Write-Error "Failed NinjaOne Device Webhook for: $($Data | ConvertTo-Json -Depth 100) Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $Message" + Write-LogMessage -API 'NinjaOneSync' -user 'CIPP' -message "Failed NinjaOne Device Webhook Linenumber: $($_.InvocationInfo.ScriptLineNumber) Error: $Message" -Sev 'Error' + } } else { Write-LogMessage -API 'NinjaOneSync' -user 'CIPP' -message "$($DeviceM365.displayName) ($($M365DeviceID)) was not matched in Ninja for $($tenantfilter)" -Sev 'Info' } @@ -59,4 +72,4 @@ function Invoke-NinjaOneDeviceWebhook { -} \ No newline at end of file +} From 3f6e628649779cf0f51c1c4d66054ab2a1dbc76b Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 9 Oct 2024 14:48:07 -0400 Subject: [PATCH 03/10] Adjust logging webhooks for ninja --- .../Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 index 0404a44aa618..67e54991324e 100644 --- a/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 +++ b/Modules/CippExtensions/Public/NinjaOne/Invoke-NinjaOneDeviceWebhook.ps1 @@ -5,7 +5,6 @@ function Invoke-NinjaOneDeviceWebhook { $Configuration ) try { - Write-LogMessage -user $ExecutingUser -API $APIName -message "Webhook Recieved - Updating NinjaOne Device compliance for $($Data.resourceData.id) in $($Data.tenantId)" -Sev 'Info' -tenant $TenantFilter $MappedFields = [pscustomobject]@{} $CIPPMapping = Get-CIPPTable -TableName CippMapping $Filter = "PartitionKey eq 'NinjaOneFieldMapping'" @@ -14,6 +13,7 @@ function Invoke-NinjaOneDeviceWebhook { } if ($MappedFields.DeviceCompliance) { + Write-LogMessage -user $ExecutingUser -API $APIName -message "Webhook Recieved - Updating NinjaOne Device compliance for $($Data.resourceData.id) in $($Data.tenantId)" -Sev 'Info' -tenant $TenantFilter $tenantfilter = $Data.tenantId $M365DeviceID = $Data.resourceData.id From 16b087cc1b07891144144e2a5d7c63b3f0f42ac9 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 9 Oct 2024 14:48:20 -0400 Subject: [PATCH 04/10] Add function node to log messages --- Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 b/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 index 5828884a19d1..c73b97f205a5 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 @@ -37,6 +37,7 @@ function Write-LogMessage { 'SentAsAlert' = $false 'PartitionKey' = $PartitionKey 'RowKey' = ([guid]::NewGuid()).ToString() + 'FunctionNode' = $env:WEBSITE_SITE_NAME 'LogData' = [string]$LogData } From f0e19e04f212847c8442f69275de0adc6eb1352c Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 9 Oct 2024 14:48:30 -0400 Subject: [PATCH 05/10] Fix issue with ProcessorQueue functions --- .../Timer Functions/Start-CIPPProcessorQueue.ps1 | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 index ed6e09bebf62..ab29f115a55a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 @@ -12,7 +12,16 @@ function Start-CIPPProcessorQueue { foreach ($QueueItem in $QueueItems) { if ($PSCmdlet.ShouldProcess("Processing function $($QueueItem.ProcessorFunction)")) { Remove-AzDataTableEntity @QueueTable -Entity $QueueItem - $Parameters = $QueueItem.Parameters | ConvertFrom-Json -AsHashtable + + if ($QueueItem.Parameters) { + try { + $Parameters = $QueueItem.Parameters | ConvertFrom-Json -AsHashtable + } catch { + $Parameters = @{} + } + } else { + $Parameters = @{} + } if (Get-Command -Name $QueueItem.FunctionName -Module CIPPCore -ErrorAction SilentlyContinue) { & $QueueItem.FunctionName @Parameters } else { From eb174ac78ffe7d309b4350e2abc6b593f0250cdc Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 9 Oct 2024 16:50:08 -0400 Subject: [PATCH 06/10] Add missing timer --- CIPPTimers.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CIPPTimers.json b/CIPPTimers.json index e8763e7cf3d9..e527285dd78f 100644 --- a/CIPPTimers.json +++ b/CIPPTimers.json @@ -23,6 +23,13 @@ "PreferredProcessor": "auditlog", "IsSystem": true }, + { + "Command": "Start-ApplicationOrchestrator", + "Description": "Orchestrator to process application uploads", + "Cron": "0 0 */12 * * *", + "Priority": 2, + "RunOnProcessor": true + }, { "Command": "Start-WebhookOrchestrator", "Description": "Orchestrator to process webhooks", From 66d1a690d54b1d1e284df2470f31f794905fa730 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 9 Oct 2024 17:09:52 -0400 Subject: [PATCH 07/10] app upload tweaks --- .../Endpoint/Applications/Invoke-ExecAppUpload.ps1 | 1 - .../Start-ApplicationOrchestrator.ps1 | 2 +- .../Timer Functions/Start-CIPPProcessorQueue.ps1 | 4 ++-- Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 | 6 +++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAppUpload.ps1 b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAppUpload.ps1 index 2202e7f58ccd..824722a5e6de 100644 --- a/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAppUpload.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/HTTP Functions/Endpoint/Applications/Invoke-ExecAppUpload.ps1 @@ -31,7 +31,6 @@ function Invoke-ExecAppUpload { } } - $Results = [pscustomobject]@{'Results' = 'Started application queue' } Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{ StatusCode = [HttpStatusCode]::OK Body = $Results diff --git a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-ApplicationOrchestrator.ps1 b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-ApplicationOrchestrator.ps1 index c564d6a70d60..eb4d4386aeac 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-ApplicationOrchestrator.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Orchestrator Functions/Start-ApplicationOrchestrator.ps1 @@ -7,7 +7,7 @@ function Start-ApplicationOrchestrator { Param() Write-LogMessage -API 'IntuneApps' -message 'Started uploading applications to tenants' -sev Info - + Write-Information 'Started uploading applications to tenants' $InputObject = [PSCustomObject]@{ OrchestratorName = 'ApplicationOrchestrator' SkipLog = $true diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 index ab29f115a55a..c32f1ef8cf1d 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 @@ -11,8 +11,7 @@ function Start-CIPPProcessorQueue { foreach ($QueueItem in $QueueItems) { if ($PSCmdlet.ShouldProcess("Processing function $($QueueItem.ProcessorFunction)")) { - Remove-AzDataTableEntity @QueueTable -Entity $QueueItem - + Write-Information "Running queued function $($QueueItem.ProcessorFunction)" if ($QueueItem.Parameters) { try { $Parameters = $QueueItem.Parameters | ConvertFrom-Json -AsHashtable @@ -27,6 +26,7 @@ function Start-CIPPProcessorQueue { } else { Write-Warning "Function $($QueueItem.FunctionName) not found" } + Remove-AzDataTableEntity @QueueTable -Entity $QueueItem } } } diff --git a/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 b/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 index c73b97f205a5..27560afaa984 100644 --- a/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 +++ b/Modules/CIPPCore/Public/GraphHelper/Write-LogMessage.ps1 @@ -35,9 +35,9 @@ function Write-LogMessage { 'Username' = [string]$username 'Severity' = [string]$sev 'SentAsAlert' = $false - 'PartitionKey' = $PartitionKey - 'RowKey' = ([guid]::NewGuid()).ToString() - 'FunctionNode' = $env:WEBSITE_SITE_NAME + 'PartitionKey' = [string]$PartitionKey + 'RowKey' = [string]([guid]::NewGuid()).ToString() + 'FunctionNode' = [string]$env:WEBSITE_SITE_NAME 'LogData' = [string]$LogData } From 0b255894dbc6deaa9358bc243ec41ea57bb371e7 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 9 Oct 2024 17:18:22 -0400 Subject: [PATCH 08/10] Update Start-CIPPProcessorQueue.ps1 --- .../Timer Functions/Start-CIPPProcessorQueue.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 index c32f1ef8cf1d..5ba435f87a2b 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 @@ -22,7 +22,11 @@ function Start-CIPPProcessorQueue { $Parameters = @{} } if (Get-Command -Name $QueueItem.FunctionName -Module CIPPCore -ErrorAction SilentlyContinue) { - & $QueueItem.FunctionName @Parameters + try { + Invoke-Command -ScriptBlock { & $QueueItem.FunctionName @Parameters } + } catch { + Write-Warning "Failed to run function $($QueueItem.FunctionName). Error: $($_.Exception.Message)" + } } else { Write-Warning "Function $($QueueItem.FunctionName) not found" } From 2aa948bd3b0049163e0295fc734623104ce5bf68 Mon Sep 17 00:00:00 2001 From: John Duprey Date: Wed, 9 Oct 2024 17:33:28 -0400 Subject: [PATCH 09/10] Update Start-CIPPProcessorQueue.ps1 --- .../Timer Functions/Start-CIPPProcessorQueue.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 index 5ba435f87a2b..a0d340bb6c8a 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Timer Functions/Start-CIPPProcessorQueue.ps1 @@ -21,14 +21,14 @@ function Start-CIPPProcessorQueue { } else { $Parameters = @{} } - if (Get-Command -Name $QueueItem.FunctionName -Module CIPPCore -ErrorAction SilentlyContinue) { + if (Get-Command -Name $QueueItem.ProcessorFunction -Module CIPPCore -ErrorAction SilentlyContinue) { try { - Invoke-Command -ScriptBlock { & $QueueItem.FunctionName @Parameters } + Invoke-Command -ScriptBlock { & $QueueItem.ProcessorFunction @Parameters } } catch { - Write-Warning "Failed to run function $($QueueItem.FunctionName). Error: $($_.Exception.Message)" + Write-Warning "Failed to run function $($QueueItem.ProcessorFunction). Error: $($_.Exception.Message)" } } else { - Write-Warning "Function $($QueueItem.FunctionName) not found" + Write-Warning "Function $($QueueItem.ProcessorFunction) not found" } Remove-AzDataTableEntity @QueueTable -Entity $QueueItem } From 67c266a149698d0b570b90e5caa302144cbf294e Mon Sep 17 00:00:00 2001 From: John Duprey Date: Thu, 10 Oct 2024 10:59:26 -0400 Subject: [PATCH 10/10] cleanup generic graph request --- .../Public/Entrypoints/Invoke-ListGraphRequest.ps1 | 8 +++++--- .../Public/GraphRequests/Get-GraphRequestList.ps1 | 5 ----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphRequest.ps1 b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphRequest.ps1 index dbb63b088425..f656bd541400 100644 --- a/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphRequest.ps1 +++ b/Modules/CIPPCore/Public/Entrypoints/Invoke-ListGraphRequest.ps1 @@ -116,13 +116,15 @@ function Invoke-ListGraphRequest { $GraphRequestParams.AsApp = $true } - Write-Host ($GraphRequestParams | ConvertTo-Json) - $Metadata = $GraphRequestParams try { $Results = Get-GraphRequestList @GraphRequestParams - + if ($Results.nextLink -and $Request.Query.NoPagination) { + $Metadata['nextLink'] = $Results.nextLink | Select-Object -Last 1 + #Results is an array of objects, so we need to remove the last object before returning + $Results = $Results | Select-Object -First ($Results.Count - 1) + } if ($Request.Query.ListProperties) { $Columns = ($Results | Select-Object -First 1).PSObject.Properties.Name $Results = $Columns | Where-Object { @('Tenant', 'CippStatus') -notcontains $_ } diff --git a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 index 769796f02504..e5687be6900d 100644 --- a/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 +++ b/Modules/CIPPCore/Public/GraphRequests/Get-GraphRequestList.ps1 @@ -295,11 +295,6 @@ function Get-GraphRequestList { if ($nextLink) { $GraphRequest.uri = $nextLink } $GraphRequestResults = New-GraphGetRequest @GraphRequest -Caller 'Get-GraphRequestList' -ErrorAction Stop - if ($GraphRequestResults.nextLink) { - #$Metadata['nextLink'] = $GraphRequestResults.nextLink | Select-Object -Last 1 - #GraphRequestResults is an array of objects, so we need to remove the last object before returning - $GraphRequestResults = $GraphRequestResults | Select-Object -First ($GraphRequestResults.Count - 1) - } $GraphRequestResults = $GraphRequestResults | Select-Object *, @{n = 'Tenant'; e = { $TenantFilter } }, @{n = 'CippStatus'; e = { 'Good' } } if ($ReverseTenantLookup -and $GraphRequestResults) {