Skip to content

Commit 307a57a

Browse files
committed
Adds feature to check Eventlog for problem and acknowleding events
1 parent 15b464f commit 307a57a

File tree

4 files changed

+133
-42
lines changed

4 files changed

+133
-42
lines changed

doc/100-General/10-Changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic
1515

1616
* [#729](https://github.com/Icinga/icinga-powershell-framework/issues/729) Fixes `Update-Icinga` to print an error in case a component is not installed, instead of silently continue
1717
* [#734](https://github.com/Icinga/icinga-powershell-framework/issues/734) Fixes a scenario on which a JEA service could become orphaned while manually stopping the Icinga for Windows service, without gracefully shutting down JEA
18+
* [#735](https://github.com/Icinga/icinga-powershell-framework/pull/735) Fixes an issue with filter for EventLog events, which did not properly handle multiple event id includes, causing empty results
1819

1920
### Enhancements
2021

2122
* [#732](https://github.com/Icinga/icinga-powershell-framework/pull/732) Adds support for TLS 1.3 and improves startup response
23+
* [#735](https://github.com/Icinga/icinga-powershell-framework/pull/735) Adds support to provide occuring problem event id's for the Eventlog and corresponding acknowledgement id's, providing an indicator if certain issues are resolved or still present
2224

2325
## 1.12.3 (2024-04-24)
2426

lib/icinga/exception/Icinga_IcingaExceptionEnums.psm1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
[hashtable]$Configuration = @{
3838
PluginArgumentConflict = 'Your plugin argument configuration is causing a conflict. Mostly this error is caused by mismatching configurations by enabling multiple switch arguments which are resulting in a conflicting configuration for the plugin.';
3939
PluginArgumentMissing = 'Your plugin argument configuration is missing mandatory arguments. This error is caused when mandatory or required arguments are missing from a plugin call and the operation is unable to process without them.';
40+
PluginArgumentAsymmetry = 'Your plugin argument configuration is causing an asymmetry. This error is caused by an uneven amount of arguments in your plugin call. Please ensure that your plugin call is properly configured and all arguments are set correctly.';
4041
PluginNotInstalled = 'The plugin assigned to this service check seems not to be installed on this machine. Please review your service check configuration for spelling errors and check if the plugin is installed and executable on this machine by PowerShell. You can ensure modules are available by manually importing them by their name with the following commands: Import-Module -Name "module name" -Force; Import-Module -Name "module name" -Global -Force;';
4142
PluginNotAssigned = 'Your check for this service could not be processed because it seems like no valid Cmdlet was assigned to the check command. Please review your check command to ensure that a valid Cmdlet is assigned and executed by a PowerShell call.';
4243
EventLogNotInstalled = 'Your Icinga PowerShell Framework has been executed by an unprivileged user before it was properly installed. The Windows EventLog application could not be registered because the current user has insufficient permissions. Please log into the machine and run "Use-Icinga" once from an administrative shell to complete the setup process. Once done this error should vanish.';

lib/provider/logging/Get-IcingaProviderDataValuesEventlog.psm1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ function Get-IcingaProviderDataValuesEventlog()
1212

1313
$EventLogData.Metrics | Add-Member -MemberType NoteProperty -Name 'List' -Value $FilterObject.EventLog.Query.List;
1414
$EventLogData.Metrics | Add-Member -MemberType NoteProperty -Name 'Events' -Value $FilterObject.EventLog.Query.Events;
15+
$EventLogData.Metrics | Add-Member -MemberType NoteProperty -Name 'Problems' -Value $FilterObject.EventLog.Query.Problems;
1516
$EventLogData.Metrics | Add-Member -MemberType NoteProperty -Name 'HasEvents' -Value $FilterObject.EventLog.Query.HasEvents;
1617

1718
$FilterObject = $null;

lib/provider/logging/New-IcingaProviderFilterDataEventlog.psm1

Lines changed: 129 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,32 @@
66
function New-IcingaProviderFilterDataEventlog()
77
{
88
param(
9-
[string]$LogName = '',
10-
[array]$IncludeEventId = @(),
11-
[array]$ExcludeEventId = @(),
12-
[array]$IncludeUsername = @(),
13-
[array]$ExcludeUsername = @(),
14-
[array]$IncludeEntryType = @(),
15-
[array]$ExcludeEntryType = @(),
16-
[array]$IncludeMessage = @(),
17-
[array]$ExcludeMessage = @(),
18-
[array]$IncludeSource = @(),
19-
[array]$ExcludeSource = @(),
20-
[string]$EventsAfter = $null,
21-
[string]$EventsBefore = $null,
22-
[int]$MaxEntries = 40000,
23-
[switch]$DisableTimeCache = $FALSE
9+
[string]$LogName = '',
10+
[array]$IncludeEventId = @(),
11+
[array]$ExcludeEventId = @(),
12+
[array]$IncludeUsername = @(),
13+
[array]$ExcludeUsername = @(),
14+
[array]$IncludeEntryType = @(),
15+
[array]$ExcludeEntryType = @(),
16+
[array]$IncludeMessage = @(),
17+
[array]$ExcludeMessage = @(),
18+
[array]$IncludeSource = @(),
19+
[array]$ExcludeSource = @(),
20+
[array]$ProblemId = @(),
21+
[array]$AcknowledgeId = @(),
22+
[string]$EventsAfter = $null,
23+
[string]$EventsBefore = $null,
24+
[int]$MaxEntries = 40000,
25+
[switch]$DisableTimeCache = $FALSE
2426
);
2527

28+
if ($ProblemId.Count -ne $AcknowledgeId.Count) {
29+
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Configuration.PluginArgumentAsymmetry -ExceptionList $IcingaPluginExceptions -CustomMessage ([string]::Format('ProblemId count: {0}, AcknowledgeId count: {1}', $ProblemId.Count, $AcknowledgeId.Count)) -Force;
30+
}
31+
2632
[string]$EventLogFilter = '';
2733
$EventIdFilter = New-Object -TypeName 'System.Text.StringBuilder';
34+
$EventIdInternalFilter = New-Object -TypeName 'System.Text.StringBuilder';
2835
$EntryTypeFilter = New-Object -TypeName 'System.Text.StringBuilder';
2936
$SourceFilter = New-Object -TypeName 'System.Text.StringBuilder';
3037
$UserFilter = New-Object -TypeName 'System.Text.StringBuilder';
@@ -33,7 +40,31 @@ function New-IcingaProviderFilterDataEventlog()
3340
$EventBeforeFilter = $null;
3441
$EventsAfter = (Convert-IcingaPluginThresholds -Threshold $EventsAfter).Value;
3542
$EventsBefore = (Convert-IcingaPluginThresholds -Threshold $EventsBefore).Value;
36-
[string]$CheckHash = (Get-StringSha1 ($LogName + $IncludeEventId + $ExcludeEventId + $IncludeUsername + $ExcludeUsername + $IncludeEntryType + $ExcludeEntryType + $IncludeMessage + $ExcludeMessage)) + '.lastcheck';
43+
[string]$CheckHash = (Get-StringSha1 ($LogName + $IncludeEventId + $ExcludeEventId + $IncludeUsername + $ExcludeUsername + $IncludeEntryType + $ExcludeEntryType + $IncludeMessage + $ExcludeMessage + $ProblemId + $AcknowledgeId)) + '.lastcheck';
44+
[hashtable]$ProblemList = @{ };
45+
[hashtable]$ResolveList = @{ };
46+
[int]$IndexOfEntries = 0;
47+
48+
foreach ($entry in $ProblemId) {
49+
Add-IcingaHashtableItem -Hashtable $ProblemList -Key ([string]$entry) -Value @{
50+
'NewestEntry' = '';
51+
'Message' = '';
52+
'Count' = 0;
53+
'ResolvedId' = $AcknowledgeId[$IndexOfEntries];
54+
'IsProblem' = $TRUE;
55+
} | Out-Null;
56+
}
57+
58+
# Reset the Id's
59+
[int]$IndexOfEntries = 0;
60+
61+
foreach ($entry in $AcknowledgeId) {
62+
Add-IcingaHashtableItem -Hashtable $ResolveList -Key ([string]$entry) -Value @{
63+
'NewestEntry' = '';
64+
'Count' = 0;
65+
'ProblemId' = $ProblemId[$IndexOfEntries];
66+
} | Out-Null;
67+
}
3768

3869
if ([string]::IsNullOrEmpty($EventsAfter) -and $DisableTimeCache -eq $FALSE) {
3970
$time = Get-IcingaCacheData -Space 'provider' -CacheStore 'eventlog' -KeyName $CheckHash;
@@ -67,28 +98,42 @@ function New-IcingaProviderFilterDataEventlog()
6798
[string]$EventBeforeFilter = ([datetime]::FromFileTime(((Get-Date).ToFileTime()))).ToString("yyyy-MM-dd HH:mm:ss");
6899
}
69100

70-
foreach ($entry in $IncludeEventId) {
71-
if ($EventIdFilter.Length -ne 0) {
72-
$EventIdFilter.Append(
73-
([string]::Format(' and EventID={0}', $entry))
74-
) | Out-Null;
75-
} else {
76-
$EventIdFilter.Append(
77-
([string]::Format('EventID={0}', $entry))
78-
) | Out-Null;
101+
# The filter string can be used to query Event Log entries based on the specified Event IDs, to filter correctly
102+
# between included and excluded Event IDs to ensure that includes are separated with OR while excludes
103+
# are added with AND to ensure that the filter string is correctly constructed.
104+
if ($IncludeEventId.Count -ne 0 -Or $ExcludeEventId.Count -ne 0) {
105+
$EventIdInternalFilter.Append('(') | Out-Null;
106+
107+
foreach ($entry in $IncludeEventId) {
108+
if ($EventIdFilter.Length -ne 0) {
109+
$EventIdFilter.Append(
110+
([string]::Format(' or EventID={0}', $entry))
111+
) | Out-Null;
112+
} else {
113+
$EventIdFilter.Append(
114+
([string]::Format('( EventID={0}', $entry))
115+
) | Out-Null;
116+
}
79117
}
80-
}
81118

82-
foreach ($entry in $ExcludeEventId) {
83119
if ($EventIdFilter.Length -ne 0) {
84-
$EventIdFilter.Append(
85-
([string]::Format(' and EventID!={0}', $entry))
86-
) | Out-Null;
87-
} else {
88-
$EventIdFilter.Append(
89-
([string]::Format('EventID!={0}', $entry))
90-
) | Out-Null;
120+
$EventIdFilter.Append(' )');
121+
}
122+
123+
foreach ($entry in $ExcludeEventId) {
124+
if ($EventIdFilter.Length -ne 0) {
125+
$EventIdFilter.Append(
126+
([string]::Format(' and EventID!={0}', $entry))
127+
) | Out-Null;
128+
} else {
129+
$EventIdFilter.Append(
130+
([string]::Format('EventID!={0}', $entry))
131+
) | Out-Null;
132+
}
91133
}
134+
135+
$EventIdInternalFilter.Append($EventIdFilter.ToString()) | Out-Null;
136+
$EventIdInternalFilter.Append(')') | Out-Null;
92137
}
93138

94139
foreach ($entry in $IncludeEntryType) {
@@ -175,7 +220,7 @@ function New-IcingaProviderFilterDataEventlog()
175220
([string]::Format(' and TimeCreated[@SystemTime<="{0}"]', (Get-Date $EventBeforeFilter).ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ssZ")))
176221
) | Out-Null;
177222

178-
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $EventIdFilter;
223+
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $EventIdInternalFilter;
179224
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $EntryTypeFilter;
180225
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $SourceFilter;
181226
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $UserFilter;
@@ -198,6 +243,7 @@ function New-IcingaProviderFilterDataEventlog()
198243
$EventLogQueryData = New-Object PSCustomObject;
199244
$EventLogQueryData | Add-Member -MemberType NoteProperty -Name 'List' -Value (New-Object PSCustomObject);
200245
$EventLogQueryData | Add-Member -MemberType NoteProperty -Name 'Events' -Value (New-Object PSCustomObject);
246+
$EventLogQueryData | Add-Member -MemberType NoteProperty -Name 'Problems' -Value (New-Object PSCustomObject);
201247
$EventLogQueryData | Add-Member -MemberType NoteProperty -Name 'HasEvents' -Value $FALSE;
202248

203249
foreach ($event in $EventLogEntries) {
@@ -206,6 +252,19 @@ function New-IcingaProviderFilterDataEventlog()
206252
continue;
207253
}
208254

255+
if ($ProblemList.ContainsKey([string]$event.Id)) {
256+
if ([string]::IsNullOrEmpty($ProblemList[([string]$event.Id)].NewestEntry)) {
257+
$ProblemList[([string]$event.Id)].NewestEntry = ([string]($event.TimeCreated));
258+
$ProblemList[([string]$event.Id)].Message = [string]($event.Message);
259+
}
260+
$ProblemList[([string]$event.Id)].Count += 1;
261+
}
262+
if ($ResolveList.ContainsKey([string]$event.Id)) {
263+
if ([string]::IsNullOrEmpty($ResolveList[([string]$event.Id)].NewestEntry)) {
264+
$ResolveList[([string]$event.Id)].NewestEntry = ([string]($event.TimeCreated));
265+
}
266+
}
267+
209268
$EventLogQueryData.HasEvents = $TRUE;
210269

211270
[string]$EventIdentifier = [string]::Format('{0}-{1}',
@@ -242,17 +301,45 @@ function New-IcingaProviderFilterDataEventlog()
242301
}
243302
}
244303

304+
if ($ProblemId.Count -ne 0) {
305+
foreach ($problem in $ProblemList.Keys) {
306+
[string]$ressolvedId = $ProblemList[$problem].ResolvedId;
307+
$LastProblem = $null;
308+
$LastResolved = $null;
309+
310+
if ([string]::IsNullOrEmpty($ProblemList[$problem].NewestEntry) -eq $FALSE) {
311+
$LastProblem = [DateTime]$ProblemList[$problem].NewestEntry;
312+
}
313+
if ([string]::IsNullOrEmpty($ResolveList[$ressolvedId].NewestEntry) -eq $FALSE) {
314+
$LastResolved = [DateTime]$ResolveList[$ressolvedId].NewestEntry;
315+
}
316+
317+
if ($ResolveList.ContainsKey($ressolvedId)) {
318+
if ($null -ne $LastProblem -And $null -ne $LastResolved -And $LastProblem -le $LastResolved) {
319+
$ProblemList[$problem].$IsProblem = $FALSE;
320+
} else {
321+
$EventLogQueryData.Problems | Add-Member -MemberType NoteProperty -Name $problem -Value (New-Object PSCustomObject);
322+
$EventLogQueryData.Problems.$problem | Add-Member -MemberType NoteProperty -Name 'EventId' -Value $problem;
323+
$EventLogQueryData.Problems.$problem | Add-Member -MemberType NoteProperty -Name 'Count' -Value $ProblemList[$problem].Count;
324+
$EventLogQueryData.Problems.$problem | Add-Member -MemberType NoteProperty -Name 'Message' -Value $ProblemList[$problem].Message;
325+
$EventLogQueryData.Problems.$problem | Add-Member -MemberType NoteProperty -Name 'NewestEntry' -Value $ProblemList[$problem].NewestEntry;
326+
}
327+
}
328+
}
329+
}
330+
245331
if ($null -ne $EventLogEntries) {
246332
$EventLogEntries.Dispose();
247333
}
248334

249-
$EventLogEntries = $null;
250-
$EventLogFilter = $null;
251-
$EventIdFilter = $null;
252-
$EntryTypeFilter = $null;
253-
$SourceFilter = $null;
254-
$UserFilter = $null;
255-
$TimeFilter = $null;
335+
$EventLogEntries = $null;
336+
$EventLogFilter = $null;
337+
$EventIdFilter = $null;
338+
$EventIdInternalFilter = $null;
339+
$EntryTypeFilter = $null;
340+
$SourceFilter = $null;
341+
$UserFilter = $null;
342+
$TimeFilter = $null;
256343

257344
return $EventLogQueryData;
258345
}

0 commit comments

Comments
 (0)