Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/100-General/10-Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic

* [#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
* [#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
* [#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

### Enhancements

* [#732](https://github.com/Icinga/icinga-powershell-framework/pull/732) Adds support for TLS 1.3 and improves startup response
* [#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

## 1.12.3 (2024-04-24)

Expand Down
1 change: 1 addition & 0 deletions lib/icinga/exception/Icinga_IcingaExceptionEnums.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
[hashtable]$Configuration = @{
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.';
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.';
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.';
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;';
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.';
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.';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ function Get-IcingaProviderDataValuesEventlog()

$EventLogData.Metrics | Add-Member -MemberType NoteProperty -Name 'List' -Value $FilterObject.EventLog.Query.List;
$EventLogData.Metrics | Add-Member -MemberType NoteProperty -Name 'Events' -Value $FilterObject.EventLog.Query.Events;
$EventLogData.Metrics | Add-Member -MemberType NoteProperty -Name 'Problems' -Value $FilterObject.EventLog.Query.Problems;
$EventLogData.Metrics | Add-Member -MemberType NoteProperty -Name 'HasEvents' -Value $FilterObject.EventLog.Query.HasEvents;

$FilterObject = $null;
Expand Down
171 changes: 129 additions & 42 deletions lib/provider/logging/New-IcingaProviderFilterDataEventlog.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,32 @@
function New-IcingaProviderFilterDataEventlog()
{
param(
[string]$LogName = '',
[array]$IncludeEventId = @(),
[array]$ExcludeEventId = @(),
[array]$IncludeUsername = @(),
[array]$ExcludeUsername = @(),
[array]$IncludeEntryType = @(),
[array]$ExcludeEntryType = @(),
[array]$IncludeMessage = @(),
[array]$ExcludeMessage = @(),
[array]$IncludeSource = @(),
[array]$ExcludeSource = @(),
[string]$EventsAfter = $null,
[string]$EventsBefore = $null,
[int]$MaxEntries = 40000,
[switch]$DisableTimeCache = $FALSE
[string]$LogName = '',
[array]$IncludeEventId = @(),
[array]$ExcludeEventId = @(),
[array]$IncludeUsername = @(),
[array]$ExcludeUsername = @(),
[array]$IncludeEntryType = @(),
[array]$ExcludeEntryType = @(),
[array]$IncludeMessage = @(),
[array]$ExcludeMessage = @(),
[array]$IncludeSource = @(),
[array]$ExcludeSource = @(),
[array]$ProblemId = @(),
[array]$AcknowledgeId = @(),
[string]$EventsAfter = $null,
[string]$EventsBefore = $null,
[int]$MaxEntries = 40000,
[switch]$DisableTimeCache = $FALSE
);

if ($ProblemId.Count -ne $AcknowledgeId.Count) {
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Configuration.PluginArgumentAsymmetry -ExceptionList $IcingaPluginExceptions -CustomMessage ([string]::Format('ProblemId count: {0}, AcknowledgeId count: {1}', $ProblemId.Count, $AcknowledgeId.Count)) -Force;
}

[string]$EventLogFilter = '';
$EventIdFilter = New-Object -TypeName 'System.Text.StringBuilder';
$EventIdInternalFilter = New-Object -TypeName 'System.Text.StringBuilder';
$EntryTypeFilter = New-Object -TypeName 'System.Text.StringBuilder';
$SourceFilter = New-Object -TypeName 'System.Text.StringBuilder';
$UserFilter = New-Object -TypeName 'System.Text.StringBuilder';
Expand All @@ -33,7 +40,31 @@ function New-IcingaProviderFilterDataEventlog()
$EventBeforeFilter = $null;
$EventsAfter = (Convert-IcingaPluginThresholds -Threshold $EventsAfter).Value;
$EventsBefore = (Convert-IcingaPluginThresholds -Threshold $EventsBefore).Value;
[string]$CheckHash = (Get-StringSha1 ($LogName + $IncludeEventId + $ExcludeEventId + $IncludeUsername + $ExcludeUsername + $IncludeEntryType + $ExcludeEntryType + $IncludeMessage + $ExcludeMessage)) + '.lastcheck';
[string]$CheckHash = (Get-StringSha1 ($LogName + $IncludeEventId + $ExcludeEventId + $IncludeUsername + $ExcludeUsername + $IncludeEntryType + $ExcludeEntryType + $IncludeMessage + $ExcludeMessage + $ProblemId + $AcknowledgeId)) + '.lastcheck';
[hashtable]$ProblemList = @{ };
[hashtable]$ResolveList = @{ };
[int]$IndexOfEntries = 0;

foreach ($entry in $ProblemId) {
Add-IcingaHashtableItem -Hashtable $ProblemList -Key ([string]$entry) -Value @{
'NewestEntry' = '';
'Message' = '';
'Count' = 0;
'ResolvedId' = $AcknowledgeId[$IndexOfEntries];
'IsProblem' = $TRUE;
} | Out-Null;
}

# Reset the Id's
[int]$IndexOfEntries = 0;

foreach ($entry in $AcknowledgeId) {
Add-IcingaHashtableItem -Hashtable $ResolveList -Key ([string]$entry) -Value @{
'NewestEntry' = '';
'Count' = 0;
'ProblemId' = $ProblemId[$IndexOfEntries];
} | Out-Null;
}

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

foreach ($entry in $IncludeEventId) {
if ($EventIdFilter.Length -ne 0) {
$EventIdFilter.Append(
([string]::Format(' and EventID={0}', $entry))
) | Out-Null;
} else {
$EventIdFilter.Append(
([string]::Format('EventID={0}', $entry))
) | Out-Null;
# The filter string can be used to query Event Log entries based on the specified Event IDs, to filter correctly
# between included and excluded Event IDs to ensure that includes are separated with OR while excludes
# are added with AND to ensure that the filter string is correctly constructed.
if ($IncludeEventId.Count -ne 0 -Or $ExcludeEventId.Count -ne 0) {
$EventIdInternalFilter.Append('(') | Out-Null;

foreach ($entry in $IncludeEventId) {
if ($EventIdFilter.Length -ne 0) {
$EventIdFilter.Append(
([string]::Format(' or EventID={0}', $entry))
) | Out-Null;
} else {
$EventIdFilter.Append(
([string]::Format('( EventID={0}', $entry))
) | Out-Null;
}
}
}

foreach ($entry in $ExcludeEventId) {
if ($EventIdFilter.Length -ne 0) {
$EventIdFilter.Append(
([string]::Format(' and EventID!={0}', $entry))
) | Out-Null;
} else {
$EventIdFilter.Append(
([string]::Format('EventID!={0}', $entry))
) | Out-Null;
$EventIdFilter.Append(' )');
}

foreach ($entry in $ExcludeEventId) {
if ($EventIdFilter.Length -ne 0) {
$EventIdFilter.Append(
([string]::Format(' and EventID!={0}', $entry))
) | Out-Null;
} else {
$EventIdFilter.Append(
([string]::Format('EventID!={0}', $entry))
) | Out-Null;
}
}

$EventIdInternalFilter.Append($EventIdFilter.ToString()) | Out-Null;
$EventIdInternalFilter.Append(')') | Out-Null;
}

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

[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $EventIdFilter;
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $EventIdInternalFilter;
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $EntryTypeFilter;
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $SourceFilter;
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $UserFilter;
Expand All @@ -198,6 +243,7 @@ function New-IcingaProviderFilterDataEventlog()
$EventLogQueryData = New-Object PSCustomObject;
$EventLogQueryData | Add-Member -MemberType NoteProperty -Name 'List' -Value (New-Object PSCustomObject);
$EventLogQueryData | Add-Member -MemberType NoteProperty -Name 'Events' -Value (New-Object PSCustomObject);
$EventLogQueryData | Add-Member -MemberType NoteProperty -Name 'Problems' -Value (New-Object PSCustomObject);
$EventLogQueryData | Add-Member -MemberType NoteProperty -Name 'HasEvents' -Value $FALSE;

foreach ($event in $EventLogEntries) {
Expand All @@ -206,6 +252,19 @@ function New-IcingaProviderFilterDataEventlog()
continue;
}

if ($ProblemList.ContainsKey([string]$event.Id)) {
if ([string]::IsNullOrEmpty($ProblemList[([string]$event.Id)].NewestEntry)) {
$ProblemList[([string]$event.Id)].NewestEntry = ([string]($event.TimeCreated));
$ProblemList[([string]$event.Id)].Message = [string]($event.Message);
}
$ProblemList[([string]$event.Id)].Count += 1;
}
if ($ResolveList.ContainsKey([string]$event.Id)) {
if ([string]::IsNullOrEmpty($ResolveList[([string]$event.Id)].NewestEntry)) {
$ResolveList[([string]$event.Id)].NewestEntry = ([string]($event.TimeCreated));
}
}

$EventLogQueryData.HasEvents = $TRUE;

[string]$EventIdentifier = [string]::Format('{0}-{1}',
Expand Down Expand Up @@ -242,17 +301,45 @@ function New-IcingaProviderFilterDataEventlog()
}
}

if ($ProblemId.Count -ne 0) {
foreach ($problem in $ProblemList.Keys) {
[string]$ressolvedId = $ProblemList[$problem].ResolvedId;
$LastProblem = $null;
$LastResolved = $null;

if ([string]::IsNullOrEmpty($ProblemList[$problem].NewestEntry) -eq $FALSE) {
$LastProblem = [DateTime]$ProblemList[$problem].NewestEntry;
}
if ([string]::IsNullOrEmpty($ResolveList[$ressolvedId].NewestEntry) -eq $FALSE) {
$LastResolved = [DateTime]$ResolveList[$ressolvedId].NewestEntry;
}

if ($ResolveList.ContainsKey($ressolvedId)) {
if ($null -ne $LastProblem -And $null -ne $LastResolved -And $LastProblem -le $LastResolved) {
$ProblemList[$problem].$IsProblem = $FALSE;
} else {
$EventLogQueryData.Problems | Add-Member -MemberType NoteProperty -Name $problem -Value (New-Object PSCustomObject);
$EventLogQueryData.Problems.$problem | Add-Member -MemberType NoteProperty -Name 'EventId' -Value $problem;
$EventLogQueryData.Problems.$problem | Add-Member -MemberType NoteProperty -Name 'Count' -Value $ProblemList[$problem].Count;
$EventLogQueryData.Problems.$problem | Add-Member -MemberType NoteProperty -Name 'Message' -Value $ProblemList[$problem].Message;
$EventLogQueryData.Problems.$problem | Add-Member -MemberType NoteProperty -Name 'NewestEntry' -Value $ProblemList[$problem].NewestEntry;
}
}
}
}

if ($null -ne $EventLogEntries) {
$EventLogEntries.Dispose();
}

$EventLogEntries = $null;
$EventLogFilter = $null;
$EventIdFilter = $null;
$EntryTypeFilter = $null;
$SourceFilter = $null;
$UserFilter = $null;
$TimeFilter = $null;
$EventLogEntries = $null;
$EventLogFilter = $null;
$EventIdFilter = $null;
$EventIdInternalFilter = $null;
$EntryTypeFilter = $null;
$SourceFilter = $null;
$UserFilter = $null;
$TimeFilter = $null;

return $EventLogQueryData;
}