Windows
banshee/windows-collection/windows/ssh/
eventlog
The errors and critical events written to the System log of a Windows since the previous run, by SSH and PowerShell
by banshee1 installation2 versions
v2Latest
Published on October 28, 2026. One naming convention across collections; documentation completed.
// The errors and the critical events written to the System log of a Windows since the previous run, by SSH.
// The errors are not watched by default: on most servers a few errors a day are routine, and only the
// administrator knows which level is not. A critical event is rare and grave (Kernel-Power 41, a
// restart without a clean shutdown): it is watched.
// Runs PowerShell commands that only read the log, by Get-WinEvent. Each event has a record number,
// EventRecordID, which only grows: the collector keeps in the cache of the probe the highest it has
// counted, and counts at the next run the errors (Level 2) and critical events (Level 1) above it. An event
// written during the reading has a higher number, and is counted at the next run: none is counted twice,
// none is lost. The first run only notes the number where counting starts.
need('protocol:ssh');
output('errors', 'number', array('label' => 'Errors since the previous run'));
output('critical', 'number', array('label' => 'Critical events since the previous run'));
watch.above('errors', 'Errors in the System log', 'errors', array('warning' => 0, 'enabled' => false));
watch.above('critical', 'Critical events in the System log', 'critical', array('critical' => 0));
// The number kept lasts a week: a probe stopped longer starts again as at its first run.
if (!cache.has('last-record')) {
$read = ssh.run("powershell -NoProfile -NonInteractive -Command \""
. "(Get-WinEvent -LogName System -MaxEvents 1).RecordId\"");
$newest = text.trim($read['output']);
if (!text.is_number($newest)) {
fail('misconfigured', 'PowerShell did not return the last record of the System log', $newest . $read['errors']);
}
// Kept as a number, to be compared with the numbers of the next run.
cache.set('last-record', $newest + 0, 604800);
skip('First reading: errors are counted from the next run');
}
$last = cache.get('last-record');
// newest: the record number of the latest event of the log, of any level; last: the highest record
// number among the errors read, 0 when there is none. Get-WinEvent reports "no event found" as an error,
// silenced on the reading of the errors; with $ErrorActionPreference set to Stop, any other failure, an
// access to the log refused among them, ends the command on the reading of the newest event, with no
// answer, rather than an answer of zero errors.
$read = ssh.run("powershell -NoProfile -NonInteractive -Command \""
. "$ErrorActionPreference = 'Stop'; "
. "$events = @(Get-WinEvent -LogName System -ErrorAction SilentlyContinue"
. " -FilterXPath '*[System[(Level=1 or Level=2) and EventRecordID>" . $last . "]]'); "
. "ConvertTo-Json -Compress -InputObject @{"
. "newest = [long](Get-WinEvent -LogName System -MaxEvents 1).RecordId; "
. "last = [long]($events | Measure-Object RecordId -Maximum).Maximum; "
. "critical = @($events | Where-Object Level -eq 1).Count; "
. "errors = @($events | Where-Object Level -eq 2).Count}\"");
$answer = text.trim($read['output']);
if (list.count(text.match($answer, '^\{')) == 0) {
fail('misconfigured', 'PowerShell did not return the errors of the System log', $answer . $read['errors']);
}
$log = json.read($answer);
// A log that was cleared numbers its events from 1 again: counting starts again from the start of the log.
if ($log['newest'] < $last) {
cache.set('last-record', 0, 604800);
skip('The System log was cleared: errors are counted again from the next run');
}
if ($log['last'] > $last) {
cache.set('last-record', $log['last'], 604800);
} else {
cache.set('last-record', $last, 604800);
}
value('errors', $log['errors']);
value('critical', $log['critical']);