Skip to content

Commit f77bb86

Browse files
committed
Adds new Eventlog data provider
1 parent adec9b8 commit f77bb86

6 files changed

+370
-0
lines changed

doc/100-General/10-Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic
1414
### Enhancements
1515

1616
* [#679](https://github.com/Icinga/icinga-powershell-framework/pull/679) Adds a new data provider for fetching process information of Windows systems, while sorting all objects based on a process name and their process id
17+
* [#682](https://github.com/Icinga/icinga-powershell-framework/pull/682) Adds new data provider for fetching Eventlog information to increase performance and reduce memory impact
1718

1819
## 1.11.2 (tbd)
1920

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
function Get-IcingaProviderFilterData()
2+
{
3+
param (
4+
[string]$ProviderName = '',
5+
[hashtable]$ProviderFilter = @()
6+
);
7+
8+
[hashtable]$FilterResult = @{ };
9+
10+
foreach ($filterObject in $ProviderFilter.Keys) {
11+
if ($filterObject.ToLower() -ne $ProviderName.ToLower()) {
12+
continue;
13+
}
14+
15+
if ($FilterResult.ContainsKey($filterObject) -eq $FALSE) {
16+
$FilterResult.Add(
17+
$filterObject,
18+
(New-IcingaProviderFilterObject -ProviderName $ProviderName -HashtableFilter $ProviderFilter[$filterObject])
19+
);
20+
}
21+
}
22+
23+
return $FilterResult;
24+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
function New-IcingaProviderFilterObject()
2+
{
3+
param (
4+
[string]$ProviderName = '',
5+
[hashtable]$HashtableFilter = @{ }
6+
);
7+
8+
if ([string]::IsNullOrEmpty($ProviderName)) {
9+
return @{ };
10+
}
11+
12+
[array]$ProviderFilterCmdlet = Get-Command ([string]::Format('New-IcingaProviderFilterData{0}', $ProviderName)) -ErrorAction SilentlyContinue;
13+
14+
if ($null -eq $ProviderFilterCmdlet -Or $ProviderFilterCmdlet.Count -eq 0) {
15+
return @{ };
16+
}
17+
18+
if ((Test-IcingaForWindowsCmdletLoader -Path $ProviderFilterCmdlet[0].Module.ModuleBase) -eq $FALSE) {
19+
return @{ };
20+
}
21+
22+
$FilterResult = & $ProviderFilterCmdlet[0].Name @HashtableFilter;
23+
24+
[string]$ObjectName = $ProviderName;
25+
$CmdHelp = Get-Help ($ProviderFilterCmdlet[0].Name) -ErrorAction SilentlyContinue;
26+
27+
if ($null -ne $CmdHelp) {
28+
if ([string]::IsNullOrEmpty($CmdHelp.Role) -eq $FALSE) {
29+
[string]$ObjectName = [string]($CmdHelp.Role);
30+
}
31+
}
32+
33+
$CmdHelp = $null;
34+
$ProviderFilterCmdlet = $null;
35+
36+
return @{
37+
$ObjectName = $FilterResult;
38+
};
39+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
function Add-IcingaProviderEventlogFilterData()
2+
{
3+
param(
4+
[string]$EventFilter = '',
5+
$StringBuilderObject = $null
6+
);
7+
8+
if ($null -eq $StringBuilderObject -Or $StringBuilderObject.Length -eq 0) {
9+
return $EventFilter;
10+
}
11+
12+
[string]$NewStringEntry = $StringBuilderObject.ToString();
13+
14+
$StringBuilderObject.Clear();
15+
$StringBuilderObject = $null;
16+
17+
if ([string]::IsNullOrEmpty($NewStringEntry)) {
18+
return $EventFilter;
19+
}
20+
21+
if ([string]::IsNullOrEmpty($EventFilter)) {
22+
return $NewStringEntry;
23+
}
24+
25+
[string]$EventFilter = [string]::Format('{0} and {1}', $EventFilter, $NewStringEntry);
26+
27+
return $EventFilter;
28+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
function Get-IcingaProviderDataValuesEventlog()
2+
{
3+
param (
4+
[array]$IncludeFilter = @(),
5+
[array]$ExcludeFilter = @(),
6+
[hashtable]$ProviderFilter = @(),
7+
[switch]$IncludeDetails = $FALSE
8+
);
9+
10+
$EventlogData = New-IcingaProviderObject -Name 'Eventlog';
11+
[hashtable]$FilterObject = Get-IcingaProviderFilterData -ProviderName 'Eventlog' -ProviderFilter $ProviderFilter;
12+
13+
$EventLogData.Metrics | Add-Member -MemberType NoteProperty -Name 'List' -Value $FilterObject.EventLog.Query.List;
14+
$EventLogData.Metrics | Add-Member -MemberType NoteProperty -Name 'Events' -Value $FilterObject.EventLog.Query.Events;
15+
$EventLogData.Metrics | Add-Member -MemberType NoteProperty -Name 'HasEvents' -Value $FilterObject.EventLog.Query.HasEvents;
16+
17+
$FilterObject = $null;
18+
19+
return $EventlogData;
20+
}
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
<#
2+
.ROLE
3+
Query
4+
#>
5+
6+
function New-IcingaProviderFilterDataEventlog()
7+
{
8+
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
24+
);
25+
26+
[string]$EventLogFilter = '';
27+
$EventIdFilter = New-Object -TypeName 'System.Text.StringBuilder';
28+
$EntryTypeFilter = New-Object -TypeName 'System.Text.StringBuilder';
29+
$SourceFilter = New-Object -TypeName 'System.Text.StringBuilder';
30+
$UserFilter = New-Object -TypeName 'System.Text.StringBuilder';
31+
$TimeFilter = New-Object -TypeName 'System.Text.StringBuilder';
32+
$EventAfterFilter = $null;
33+
$EventBeforeFilter = $null;
34+
$EventsAfter = (Convert-IcingaPluginThresholds -Threshold $EventsAfter).Value;
35+
$EventsBefore = (Convert-IcingaPluginThresholds -Threshold $EventsBefore).Value;
36+
[string]$CheckHash = (Get-StringSha1 ($LogName + $IncludeEventId + $ExcludeEventId + $IncludeUsername + $ExcludeUsername + $IncludeEntryType + $ExcludeEntryType + $IncludeMessage + $ExcludeMessage)) + '.lastcheck';
37+
38+
if ([string]::IsNullOrEmpty($EventsAfter) -and $DisableTimeCache -eq $FALSE) {
39+
$time = Get-IcingaCacheData -Space 'provider' -CacheStore 'eventlog' -KeyName $CheckHash;
40+
Set-IcingaCacheData -Space 'provider' -CacheStore 'eventlog' -KeyName $CheckHash -Value ((Get-Date).ToFileTime());
41+
42+
if ($null -ne $time) {
43+
$EventAfterFilter = ([datetime]::FromFileTime($time)).ToString("yyyy-MM-dd HH:mm:ss");
44+
}
45+
}
46+
47+
# In case we are not having cached time execution and not have not overwritten the timestamp, only fetch values from 2 hours in the past
48+
if ([string]::IsNullOrEmpty($EventAfterFilter)) {
49+
if ([string]::IsNullOrEmpty($EventsAfter)) {
50+
[string]$EventAfterFilter = ([datetime]::Now.Subtract([TimeSpan]::FromHours(2))).ToString("yyyy-MM-dd HH:mm:ss");
51+
} else {
52+
if ((Test-Numeric $EventsAfter)) {
53+
[string]$EventAfterFilter = ([datetime]::Now.Subtract([TimeSpan]::FromSeconds($EventsAfter))).ToString('yyyy\/MM\/dd HH:mm:ss');
54+
} else {
55+
[string]$EventAfterFilter = $EventsAfter;
56+
}
57+
}
58+
}
59+
60+
if ([string]::IsNullOrEmpty($EventsBefore) -eq $FALSE) {
61+
if ((Test-Numeric $EventsBefore)) {
62+
[string]$EventBeforeFilter = ([datetime]::Now.Subtract([TimeSpan]::FromSeconds($EventsBefore))).ToString("yyyy-MM-dd HH:mm:ss");
63+
} else {
64+
[string]$EventBeforeFilter = $EventsBefore;
65+
}
66+
} else {
67+
[string]$EventBeforeFilter = ([datetime]::FromFileTime(((Get-Date).ToFileTime()))).ToString("yyyy-MM-dd HH:mm:ss");
68+
}
69+
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;
79+
}
80+
}
81+
82+
foreach ($entry in $ExcludeEventId) {
83+
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;
91+
}
92+
}
93+
94+
foreach ($entry in $IncludeEntryType) {
95+
[string]$EntryId = $ProviderEnums.EventLogSeverity[$entry];
96+
if ($EntryTypeFilter.Length -ne 0) {
97+
$EntryTypeFilter.Append(
98+
([string]::Format(' and Level={0}', $EntryId))
99+
) | Out-Null;
100+
} else {
101+
$EntryTypeFilter.Append(
102+
([string]::Format('Level={0}', $EntryId))
103+
) | Out-Null;
104+
}
105+
}
106+
107+
foreach ($entry in $ExcludeEntryType) {
108+
[string]$EntryId = $ProviderEnums.EventLogSeverity[$entry];
109+
if ($EntryTypeFilter.Length -ne 0) {
110+
$EntryTypeFilter.Append(
111+
([string]::Format(' and Level!={0}', $EntryId))
112+
) | Out-Null;
113+
} else {
114+
$EntryTypeFilter.Append(
115+
([string]::Format('Level!={0}', $EntryId))
116+
) | Out-Null;
117+
}
118+
}
119+
120+
foreach ($entry in $IncludeSource) {
121+
if ($SourceFilter.Length -ne 0) {
122+
$SourceFilter.Append(
123+
([string]::Format(' and Provider[@Name="{0}"]', $entry))
124+
) | Out-Null;
125+
} else {
126+
$SourceFilter.Append(
127+
([string]::Format('Provider[@Name="{0}"]', $entry))
128+
) | Out-Null;
129+
}
130+
}
131+
132+
foreach ($entry in $ExcludeSource) {
133+
if ($SourceFilter.Length -ne 0) {
134+
$SourceFilter.Append(
135+
([string]::Format(' and Provider[@Name!="{0}"]', $entry))
136+
) | Out-Null;
137+
} else {
138+
$SourceFilter.Append(
139+
([string]::Format('Provider[@Name!="{0}"]', $entry))
140+
) | Out-Null;
141+
}
142+
}
143+
144+
foreach ($entry in $IncludeUsername) {
145+
[string]$UserSID = (Get-IcingaUserSID -User $entry);
146+
if ($UserFilter.Length -ne 0) {
147+
$UserFilter.Append(
148+
([string]::Format(' and Security[@UserID="{0}', $UserSID))
149+
) | Out-Null;
150+
} else {
151+
$UserFilter.Append(
152+
([string]::Format('Security[@UserID="{0}"]', $UserSID))
153+
) | Out-Null;
154+
}
155+
}
156+
157+
foreach ($entry in $ExcludeUsername) {
158+
[string]$UserSID = (Get-IcingaUserSID -User $entry);
159+
if ($UserFilter.Length -ne 0) {
160+
$UserFilter.Append(
161+
([string]::Format(' and Security[@UserID!="{0}"]', $UserSID))
162+
) | Out-Null;
163+
} else {
164+
$UserFilter.Append(
165+
([string]::Format('Security[@UserID!="{0}"]', $UserSID))
166+
) | Out-Null;
167+
}
168+
}
169+
170+
$TimeFilter.Append(
171+
([string]::Format('TimeCreated[@SystemTime>="{0}"]', (Get-Date $EventAfterFilter).ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ssZ")))
172+
) | Out-Null;
173+
174+
$TimeFilter.Append(
175+
([string]::Format(' and TimeCreated[@SystemTime<="{0}"]', (Get-Date $EventBeforeFilter).ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ssZ")))
176+
) | Out-Null;
177+
178+
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $EventIdFilter;
179+
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $EntryTypeFilter;
180+
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $SourceFilter;
181+
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $UserFilter;
182+
[string]$EventLogFilter = Add-IcingaProviderEventlogFilterData -EventFilter $EventLogFilter -StringBuilderObject $TimeFilter;
183+
184+
while ($EventLogFilter[0] -eq ' ') {
185+
$EventLogFilter = $EventLogFilter.Substring(1, $EventLogFilter.Length - 1);
186+
}
187+
188+
[string]$EventLogFilter = [string]::Format('Event[System[{0}]]', $EventLogFilter);
189+
190+
try {
191+
$EventLogEntries = Get-WinEvent -LogName $LogName -MaxEvents $MaxEntries -FilterXPath $EventLogFilter -ErrorAction Stop;
192+
} catch {
193+
Exit-IcingaThrowException -InputString $_.FullyQualifiedErrorId -StringPattern 'ParameterArgumentValidationError' -ExceptionList $IcingaPluginExceptions -ExceptionType 'Input' -ExceptionThrown $IcingaPluginExceptions.Inputs.EventLogNegativeEntries;
194+
Exit-IcingaThrowException -InputString $_.FullyQualifiedErrorId -StringPattern 'CannotConvertArgumentNoMessage' -ExceptionList $IcingaPluginExceptions -ExceptionType 'Input' -ExceptionThrown $IcingaPluginExceptions.Inputs.EventLogNoMessageEntries;
195+
Exit-IcingaThrowException -InputString $_.FullyQualifiedErrorId -StringPattern 'NoMatchingLogsFound' -CustomMessage (-Join $LogName) -ExceptionList $IcingaPluginExceptions -ExceptionType 'Input' -ExceptionThrown $IcingaPluginExceptions.Inputs.EventLogLogName;
196+
}
197+
198+
$EventLogQueryData = New-Object PSCustomObject;
199+
$EventLogQueryData | Add-Member -MemberType NoteProperty -Name 'List' -Value (New-Object PSCustomObject);
200+
$EventLogQueryData | Add-Member -MemberType NoteProperty -Name 'Events' -Value (New-Object PSCustomObject);
201+
$EventLogQueryData | Add-Member -MemberType NoteProperty -Name 'HasEvents' -Value $FALSE;
202+
203+
foreach ($event in $EventLogEntries) {
204+
# Filter out remaining message not matching our filter
205+
if ((Test-IcingaArrayFilter -InputObject $event.Message -Include $IncludeMessage -Exclude $ExcludeMessage) -eq $FALSE) {
206+
continue;
207+
}
208+
209+
$EventLogQueryData.HasEvents = $TRUE;
210+
211+
[string]$EventIdentifier = [string]::Format('{0}-{1}',
212+
$event.Id,
213+
$event.ProviderName
214+
);
215+
216+
[string]$EventHash = Get-StringSha1 $EventIdentifier;
217+
218+
if ((Test-PSCustomObjectMember -PSObject $EventLogQueryData.List -Name $EventHash) -eq $FALSE) {
219+
[string]$EventMessage = [string]($event.Message);
220+
if ([string]::IsNullOrEmpty($EventMessage)) {
221+
$EventMessage = '';
222+
}
223+
224+
$EventLogQueryData.List | Add-Member -MemberType NoteProperty -Name $EventHash -Value (New-Object PSCustomObject);
225+
$EventLogQueryData.List.$EventHash | Add-Member -MemberType NoteProperty -Name 'NewestEntry' -Value ([string]($event.TimeCreated));
226+
$EventLogQueryData.List.$EventHash | Add-Member -MemberType NoteProperty -Name 'OldestEntry' -Value ([string]($event.TimeCreated));
227+
$EventLogQueryData.List.$EventHash | Add-Member -MemberType NoteProperty -Name 'EventId' -Value ([string]($event.Id));
228+
$EventLogQueryData.List.$EventHash | Add-Member -MemberType NoteProperty -Name 'Message' -Value $EventMessage;
229+
$EventLogQueryData.List.$EventHash | Add-Member -MemberType NoteProperty -Name 'Severity' -Value $ProviderEnums.EventLogSeverityName[$event.Level];
230+
$EventLogQueryData.List.$EventHash | Add-Member -MemberType NoteProperty -Name 'Source' -Value ([string]($event.ProviderName));
231+
$EventLogQueryData.List.$EventHash | Add-Member -MemberType NoteProperty -Name 'Count' -Value 1;
232+
233+
} else {
234+
$EventLogQueryData.List.$EventHash.OldestEntry = ([string]($event.TimeCreated));
235+
$EventLogQueryData.List.$EventHash.Count += 1;
236+
}
237+
238+
if ((Test-PSCustomObjectMember -PSObject $EventLogQueryData.Events -Name $event.Id) -eq $FALSE) {
239+
$EventLogQueryData.Events | Add-Member -MemberType NoteProperty -Name $event.Id -Value 1;
240+
} else {
241+
$EventLogQueryData.Events.($event.Id) += 1;
242+
}
243+
}
244+
245+
if ($null -ne $EventLogEntries) {
246+
$EventLogEntries.Dispose();
247+
}
248+
249+
$EventLogEntries = $null;
250+
$EventLogFilter = $null;
251+
$EventIdFilter = $null;
252+
$EntryTypeFilter = $null;
253+
$SourceFilter = $null;
254+
$UserFilter = $null;
255+
$TimeFilter = $null;
256+
257+
return $EventLogQueryData;
258+
}

0 commit comments

Comments
 (0)