@@ -17,84 +17,86 @@ function Push-SchedulerCIPPNotifications {
1717
1818 $severity = $Config.Severity -split ' ,'
1919 if (! $severity ) {
20- $severity = [ System.Collections.ArrayList ] @ (' Info' , ' Error' , ' Warning' , ' Critical' , ' Alert' )
20+ $severity = @ (' Info' , ' Error' , ' Warning' , ' Critical' , ' Alert' )
2121 }
2222 Write-Information " Our Severity table is: $severity "
2323
24- $Table = Get-CIPPTable
25- $PartitionKey = Get-Date - UFormat ' %Y%m%d'
26- $Filter = " PartitionKey eq '{0}'" -f $PartitionKey
27- $Currentlog = Get-CIPPAzDataTableEntity @Table - Filter $Filter | Where-Object {
28- $_.API -in $Settings -and $_.sentAsAlert -ne $true -and $_.Severity -in $severity
29- }
24+ $LogTable = Get-CIPPTable
3025 $StandardsTable = Get-CIPPTable - tablename CippStandardsAlerts
31- $CurrentStandardsLogs = Get-CIPPAzDataTableEntity @StandardsTable - Filter $Filter | Where-Object {
32- $_.sentAsAlert -ne $true
33- }
34- Write-Information " Alerts: $ ( $Currentlog.count ) found"
35- Write-Information " Standards: $ ( $CurrentStandardsLogs.count ) found"
26+ $PartitionKey = Get-Date - UFormat ' %Y%m%d'
27+
28+ # Server-side: sentAsAlert + severity (small fixed set). API is filtered client-side
29+ # because the API list is open-ended and OR-expanding it can exceed the OData filter limit.
30+ $sevOr = ($severity | ForEach-Object { " Severity eq '$ ( $_ -replace " '" , " ''" ) '" }) -join ' or '
31+ $LogFilter = " PartitionKey eq '$PartitionKey ' and sentAsAlert eq false and ($sevOr )"
32+ $StandardsFilter = " PartitionKey eq '$PartitionKey ' and sentAsAlert eq false"
33+
34+ $Currentlog = @ (Get-CIPPAzDataTableEntity @LogTable - Filter $LogFilter | Where-Object { $_.API -in $Settings })
35+ $CurrentStandardsLogs = @ (Get-CIPPAzDataTableEntity @StandardsTable - Filter $StandardsFilter )
36+
37+ Write-Information " Alerts: $ ( $Currentlog.Count ) found"
38+ Write-Information " Standards: $ ( $CurrentStandardsLogs.Count ) found"
3639
3740 # Get the CIPP URL
3841 $CippConfigTable = Get-CippTable - tablename Config
3942 $CippConfig = Get-CIPPAzDataTableEntity @CippConfigTable - Filter " PartitionKey eq 'InstanceProperties' and RowKey eq 'CIPPURL'"
4043 $CIPPURL = ' https://{0}' -f $CippConfig.Value
4144
42- # email try
45+ $LogsByTenant = @ ($Currentlog | Group-Object - Property Tenant)
46+ $StandardsByTenant = @ ($CurrentStandardsLogs | Group-Object - Property Tenant)
47+
48+ $MarkSent = {
49+ param ($Entities , $TargetTable )
50+ if (-not $Entities -or $Entities.Count -eq 0 ) { return }
51+ $batch = [System.Collections.Generic.List [object ]]::new()
52+ foreach ($e in $Entities ) {
53+ if ($e.PSObject.Properties.Name -contains ' sentAsAlert' ) {
54+ $e.sentAsAlert = $true
55+ } else {
56+ $e | Add-Member - MemberType NoteProperty - Name sentAsAlert - Value $true - Force
57+ }
58+ $batch.Add ($e )
59+ if ($batch.Count -ge 100 ) {
60+ Add-CIPPAzDataTableEntity @TargetTable - Entity $batch - Force
61+ $batch.Clear ()
62+ }
63+ }
64+ if ($batch.Count -gt 0 ) {
65+ Add-CIPPAzDataTableEntity @TargetTable - Entity $batch - Force
66+ }
67+ }
68+
4369 try {
4470 if ($Config.email -like ' *@*' ) {
45- # Normal logs
46- if ($Currentlog ) {
71+ if ($Currentlog.Count -gt 0 ) {
4772 if ($config.onePerTenant ) {
48- foreach ($tenant in ($CurrentLog.Tenant | Sort-Object - Unique)) {
49- $Data = ($CurrentLog | Select-Object Message, API, Tenant, Username, Severity | Where-Object - Property tenant -EQ $tenant )
50- $Subject = " $ ( $Tenant ) : CIPP Alert: Alerts found starting at $ ( (Get-Date ).AddMinutes(-15 )) "
73+ foreach ($g in $LogsByTenant ) {
74+ $tenant = $g.Name
75+ $Data = $g.Group | Select-Object Message, API, Tenant, Username, Severity
76+ $Subject = " $ ( $tenant ) : CIPP Alert: Alerts found starting at $ ( (Get-Date ).AddMinutes(-15 )) "
5177 $HTMLContent = New-CIPPAlertTemplate - Data $Data - Format ' html' - InputObject ' table' - CIPPURL $CIPPURL
5278 Send-CIPPAlert - Type ' email' - Title $Subject - HTMLContent $HTMLContent.htmlcontent - TenantFilter $tenant - APIName ' Alerts'
53- $UpdateLogs = $CurrentLog | ForEach-Object {
54- if ($_.PSObject.Properties.Name -contains ' sentAsAlert' ) {
55- $_.sentAsAlert = $true
56- } else {
57- $_ | Add-Member - MemberType NoteProperty - Name sentAsAlert - Value $true - Force
58- }
59- $_
60- }
61- if ($UpdateLogs ) {
62- Add-CIPPAzDataTableEntity @Table - Entity $UpdateLogs - Force
63- }
79+ & $MarkSent $g.Group $LogTable
80+ $Data = $null ; $HTMLContent = $null
6481 }
6582 } else {
66- $Data = ( $CurrentLog | Select-Object Message, API, Tenant, Username, Severity)
83+ $Data = $CurrentLog | Select-Object Message, API, Tenant, Username, Severity
6784 $Subject = " CIPP Alert: Alerts found starting at $ ( (Get-Date ).AddMinutes(-15 )) "
6885 $HTMLContent = New-CIPPAlertTemplate - Data $Data - Format ' html' - InputObject ' table' - CIPPURL $CIPPURL
6986 Send-CIPPAlert - Type ' email' - Title $Subject - HTMLContent $HTMLContent.htmlcontent - TenantFilter ' AllTenants' - APIName ' Alerts'
70- $UpdateLogs = $CurrentLog | ForEach-Object {
71- if ($_.PSObject.Properties.Name -contains ' sentAsAlert' ) {
72- $_.sentAsAlert = $true
73- } else {
74- $_ | Add-Member - MemberType NoteProperty - Name sentAsAlert - Value $true - Force
75- }
76- $_
77- }
78- if ($UpdateLogs ) {
79- Add-CIPPAzDataTableEntity @Table - Entity $UpdateLogs - Force
80- }
87+ & $MarkSent $CurrentLog $LogTable
88+ $Data = $null ; $HTMLContent = $null
8189 }
8290 }
83- if ($CurrentStandardsLogs ) {
84- foreach ($tenant in ($CurrentStandardsLogs.Tenant | Sort-Object - Unique)) {
85- $Data = ($CurrentStandardsLogs | Where-Object - Property tenant -EQ $tenant )
86- $Subject = " $ ( $Tenant ) : Standards are out of sync for $tenant "
91+ if ($CurrentStandardsLogs.Count -gt 0 ) {
92+ foreach ($g in $StandardsByTenant ) {
93+ $tenant = $g.Name
94+ $Data = $g.Group
95+ $Subject = " $ ( $tenant ) : Standards are out of sync for $tenant "
8796 $HTMLContent = New-CIPPAlertTemplate - Data $Data - Format ' html' - InputObject ' standards' - CIPPURL $CIPPURL
8897 Send-CIPPAlert - Type ' email' - Title $Subject - HTMLContent $HTMLContent.htmlcontent - TenantFilter $tenant - APIName ' Alerts'
89- $updateStandards = $CurrentStandardsLogs | ForEach-Object {
90- if ($_.PSObject.Properties.Name -contains ' sentAsAlert' ) {
91- $_.sentAsAlert = $true
92- } else {
93- $_ | Add-Member - MemberType NoteProperty - Name sentAsAlert - Value $true - Force
94- }
95- $_
96- }
97- if ($updateStandards ) { Add-CIPPAzDataTableEntity @StandardsTable - Entity $updateStandards - Force }
98+ & $MarkSent $g.Group $StandardsTable
99+ $Data = $null ; $HTMLContent = $null
98100 }
99101 }
100102 }
@@ -104,67 +106,61 @@ function Push-SchedulerCIPPNotifications {
104106 }
105107
106108 try {
107- Write-Information $ ($config | ConvertTo-Json )
108109 Write-Information $config.webhook
109110 if (! [string ]::IsNullOrEmpty($config.webhook )) {
110- if ( $Currentlog ) {
111- $JSONContent = $ Currentlog | ConvertTo-Json - Compress
111+ $ChunkSize = 500
112+ if ( $ Currentlog.Count -gt 0 ) {
112113 $Title = " Logbook Notification: Alerts found starting at $ ( (Get-Date ).AddMinutes(-15 )) "
113- Send-CIPPAlert - Type ' webhook' - Title $Title - JSONContent $JSONContent - TenantFilter ' AllTenants' - APIName ' Alerts' - SchemaSource ' Logbook Notification' - InvokingCommand ' Push-SchedulerCIPPNotifications' - UseStandardizedSchema:$ ([boolean ]$Config.UseStandardizedSchema )
114- $UpdateLogs = $CurrentLog | ForEach-Object { $_.sentAsAlert = $true ; $_ }
115- if ($UpdateLogs ) { Add-CIPPAzDataTableEntity @Table - Entity $UpdateLogs - Force }
114+ for ($i = 0 ; $i -lt $Currentlog.Count ; $i += $ChunkSize ) {
115+ $end = [math ]::Min($i + $ChunkSize - 1 , $Currentlog.Count - 1 )
116+ $chunk = $Currentlog [$i .. $end ]
117+ $JSONContent = $chunk | ConvertTo-Json - Compress
118+ Send-CIPPAlert - Type ' webhook' - Title $Title - JSONContent $JSONContent - TenantFilter ' AllTenants' - APIName ' Alerts' - SchemaSource ' Logbook Notification' - InvokingCommand ' Push-SchedulerCIPPNotifications' - UseStandardizedSchema:$ ([boolean ]$Config.UseStandardizedSchema )
119+ & $MarkSent $chunk $LogTable
120+ $JSONContent = $null ; $chunk = $null
121+ }
116122 }
117123
118- if ($CurrentStandardsLogs ) {
119- $Data = $CurrentStandardsLogs
120- $JSONContent = New-CIPPAlertTemplate - Data $Data - Format ' json' - InputObject ' table' - CIPPURL $CIPPURL
121- $CurrentStandardsLogs | ConvertTo-Json - Compress
122- $Title = " Standards Notification: Out of sync standards detected"
123- Send-CIPPAlert - Type ' webhook' - Title $Title - JSONContent $JSONContent - TenantFilter ' AllTenants' - APIName ' Alerts' - SchemaSource ' Standards Notification' - InvokingCommand ' Push-SchedulerCIPPNotifications' - UseStandardizedSchema:$ ([boolean ]$Config.UseStandardizedSchema )
124- $updateStandards = $CurrentStandardsLogs | ForEach-Object {
125- if ($_.PSObject.Properties.Name -contains ' sentAsAlert' ) {
126- $_.sentAsAlert = $true
127- } else {
128- $_ | Add-Member - MemberType NoteProperty - Name sentAsAlert - Value $true - Force
129- }
130- $_
124+ if ($CurrentStandardsLogs.Count -gt 0 ) {
125+ $Title = ' Standards Notification: Out of sync standards detected'
126+ for ($i = 0 ; $i -lt $CurrentStandardsLogs.Count ; $i += $ChunkSize ) {
127+ $end = [math ]::Min($i + $ChunkSize - 1 , $CurrentStandardsLogs.Count - 1 )
128+ $chunk = $CurrentStandardsLogs [$i .. $end ]
129+ $JSONContent = New-CIPPAlertTemplate - Data $chunk - Format ' json' - InputObject ' table' - CIPPURL $CIPPURL
130+ Send-CIPPAlert - Type ' webhook' - Title $Title - JSONContent $JSONContent - TenantFilter ' AllTenants' - APIName ' Alerts' - SchemaSource ' Standards Notification' - InvokingCommand ' Push-SchedulerCIPPNotifications' - UseStandardizedSchema:$ ([boolean ]$Config.UseStandardizedSchema )
131+ & $MarkSent $chunk $StandardsTable
132+ $JSONContent = $null ; $chunk = $null
131133 }
132134 }
133-
134135 }
135136 } catch {
136137 Write-Information " Could not send alerts to webhook $ ( $config.webhook ) : $ ( $_.Exception.message ) "
137- Write-LogMessage - API ' Alerts' - message " Could not send alerts to webhook $ ( $config.webhook ) : $ ( $_.Exception.message ) " - tenant $Tenant - sev error - LogData (Get-CippException - Exception $_ )
138+ Write-LogMessage - API ' Alerts' - message " Could not send alerts to webhook $ ( $config.webhook ) : $ ( $_.Exception.message ) " - tenant ' AllTenants ' - sev error - LogData (Get-CippException - Exception $_ )
138139 }
139140
140141 if ($config.sendtoIntegration ) {
141142 try {
142- foreach ($tenant in ($CurrentLog.Tenant | Sort-Object - Unique)) {
143- $Data = ($CurrentLog | Select-Object Message, API, Tenant, Username, Severity | Where-Object - Property tenant -EQ $tenant )
143+ foreach ($g in $LogsByTenant ) {
144+ $tenant = $g.Name
145+ $Data = $g.Group | Select-Object Message, API, Tenant, Username, Severity
144146 $HTMLContent = New-CIPPAlertTemplate - Data $Data - Format ' html' - InputObject ' table' - CIPPURL $CIPPURL
145147 $Title = " $tenant CIPP Alert: Alerts found starting at $ ( (Get-Date ).AddMinutes(-15 )) "
146148 Send-CIPPAlert - Type ' psa' - Title $Title - HTMLContent $HTMLContent.htmlcontent - TenantFilter $tenant - APIName ' Alerts'
147- $UpdateLogs = $CurrentLog | ForEach-Object { $_ .SentAsAlert = $true ; $_ }
148- if ( $UpdateLogs ) { Add-CIPPAzDataTableEntity @Table - Entity $UpdateLogs - Force }
149+ & $MarkSent $g .Group $LogTable
150+ $Data = $null ; $HTMLContent = $null
149151 }
150- foreach ($standardsTenant in ($CurrentStandardsLogs.Tenant | Sort-Object - Unique)) {
151- $Data = ($CurrentStandardsLogs | Where-Object - Property tenant -EQ $standardsTenant )
152- $Subject = " $ ( $standardsTenant ) : Standards are out of sync for $standardsTenant "
152+ foreach ($g in $StandardsByTenant ) {
153+ $tenant = $g.Name
154+ $Data = $g.Group
155+ $Subject = " $ ( $tenant ) : Standards are out of sync for $tenant "
153156 $HTMLContent = New-CIPPAlertTemplate - Data $Data - Format ' html' - InputObject ' standards' - CIPPURL $CIPPURL
154- Send-CIPPAlert - Type ' psa' - Title $Subject - HTMLContent $HTMLContent.htmlcontent - TenantFilter $standardsTenant - APIName ' Alerts'
155- $updateStandards = $CurrentStandardsLogs | ForEach-Object {
156- if ($_.PSObject.Properties.Name -contains ' sentAsAlert' ) {
157- $_.sentAsAlert = $true
158- } else {
159- $_ | Add-Member - MemberType NoteProperty - Name sentAsAlert - Value $true - Force
160- }
161- $_
162- }
157+ Send-CIPPAlert - Type ' psa' - Title $Subject - HTMLContent $HTMLContent.htmlcontent - TenantFilter $tenant - APIName ' Alerts'
158+ & $MarkSent $g.Group $StandardsTable
159+ $Data = $null ; $HTMLContent = $null
163160 }
164161 } catch {
165162 Write-Information " Could not send alerts to ticketing system: $ ( $_.Exception.message ) "
166- Write-LogMessage - API ' Alerts' - tenant $Tenant - message " Could not send alerts to ticketing system: $ ( $_.Exception.message ) " - sev Error
163+ Write-LogMessage - API ' Alerts' - tenant ' AllTenants ' - message " Could not send alerts to ticketing system: $ ( $_.Exception.message ) " - sev Error
167164 }
168165 }
169-
170166}
0 commit comments