Moves IfW EventLog out of Application log

This commit is contained in:
Lord Hepipud 2022-01-14 19:57:43 +01:00
parent 1316ddbb3a
commit 8244c2d440
19 changed files with 248 additions and 34 deletions

View file

@ -4,6 +4,22 @@ Upgrading Icinga PowerShell Framework is usually quite straightforward.
Specific version upgrades are described below. Please note that version updates are incremental. Specific version upgrades are described below. Please note that version updates are incremental.
## Upgrading to v1.8.0 (2022-02-08)
### Service Binary
With Icinga for Windows v1.8.0 we changed on where the application will write EventLog data to. If you are using the `Icinga for Windows Service`, it is **mandatory** to upgrade to version `v1.2.0` of the service binary, **before** upgrading to Icinga for Windows v1.8.0.
Otherwise the service will not start and crash! You can either download the service binary manually from [icinga-powershell-service](https://github.com/Icinga/icinga-powershell-service/releases) or use the Icinga repository for updating:
```powershell
Update-Icinga -Name 'service';
```
After upgrading to Icinga for Windows v1.8.0, you will require to open a new Icinga shell by calling `icinga` or by using `Use-Icinga` once, to run the new migration process.
**NOTE:** In some cases the changes for the EventLog will only apply, **after** the system has been rebooted. Afterwards every Icinga for Windows EventLog entry is written in a newly created `Icinga for Windows` log.
## Upgrading to v1.7.0 (2021-11-09) ## Upgrading to v1.7.0 (2021-11-09)
### REST-Api and Api-Checks ### REST-Api and Api-Checks

View file

@ -29,7 +29,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic
* [#388](https://github.com/Icinga/icinga-powershell-framework/issues/388) Improves performance for testing if `Add-Type` functions have been added, by adding an internal test for newly introduced environment variables within a PowerShell session * [#388](https://github.com/Icinga/icinga-powershell-framework/issues/388) Improves performance for testing if `Add-Type` functions have been added, by adding an internal test for newly introduced environment variables within a PowerShell session
* [#417](https://github.com/Icinga/icinga-powershell-framework/issues/417) Adds support to allow the force creation of Icinga Agent certificates, even when they are already present on the system over Icinga Management Console installation * [#417](https://github.com/Icinga/icinga-powershell-framework/issues/417) Adds support to allow the force creation of Icinga Agent certificates, even when they are already present on the system over Icinga Management Console installation
* [#426](https://github.com/Icinga/icinga-powershell-framework/pull/426) Adds a new feature to EventLog writer, allowing to parse an exception report to identity the exact root cause and location, on where the error occurred in first place. * [#427](https://github.com/Icinga/icinga-powershell-framework/issues/427) Moves Icinga for Windows EventLog from `Application` to a custom log `Icinga for Windows`, allowing better separation
## 1.7.1 (2021-11-11) ## 1.7.1 (2021-11-11)

View file

@ -25,6 +25,11 @@ function Use-Icinga()
Import-Module (Join-Path -Path (Get-IcingaForWindowsRootPath) -ChildPath 'icinga-powershell-framework') -Global -Force; Import-Module (Join-Path -Path (Get-IcingaForWindowsRootPath) -ChildPath 'icinga-powershell-framework') -Global -Force;
} }
# Only apply migrations if we directly call "Use-Icinga" without any other argument
if ($LibOnly -eq $FALSE -And $Daemon -eq $FALSE -and $Minimal -eq $FALSE) {
Invoke-IcingaForWindowsMigration;
}
Disable-IcingaProgressPreference; Disable-IcingaProgressPreference;
if ($Minimal) { if ($Minimal) {
@ -86,6 +91,9 @@ function Use-Icinga()
$EventLogMessages = Invoke-IcingaNamespaceCmdlets -Command 'Register-IcingaEventLogMessages*'; $EventLogMessages = Invoke-IcingaNamespaceCmdlets -Command 'Register-IcingaEventLogMessages*';
foreach ($entry in $EventLogMessages.Values) { foreach ($entry in $EventLogMessages.Values) {
foreach ($event in $entry.Keys) { foreach ($event in $entry.Keys) {
if ($LibOnly -eq $FALSE) {
Register-IcingaEventLog -LogName $event;
}
Add-IcingaHashtableItem -Hashtable $global:IcingaEventLogEnums ` Add-IcingaHashtableItem -Hashtable $global:IcingaEventLogEnums `
-Key $event ` -Key $event `
-Value $entry[$event] | Out-Null; -Value $entry[$event] | Out-Null;

View file

@ -104,7 +104,7 @@ function Install-IcingaFrameworkUpdate()
Import-Module -Name $ModuleDirectory -Force; Import-Module -Name $ModuleDirectory -Force;
# Apply migration tasks # Apply migration tasks
Invoke-IcingaForWindowsMigration; Use-Icinga;
if ([string]::IsNullOrEmpty((Get-IcingaJEAContext)) -eq $FALSE) { if ([string]::IsNullOrEmpty((Get-IcingaJEAContext)) -eq $FALSE) {
Remove-IcingaFrameworkDependencyFile; Remove-IcingaFrameworkDependencyFile;

View file

@ -1,8 +1,13 @@
function Invoke-IcingaForWindowsMigration() function Invoke-IcingaForWindowsMigration()
{ {
# Upgrade to v1.8.0 # Upgrade to v1.8.0
if ((Get-Module -ListAvailable -Name icinga-powershell-framework).Version -ge (New-IcingaVersionObject -Version '1.8.0')) { if (Test-IcingaForWindowsMigration -MigrationVersion (New-IcingaVersionObject -Version '1.8.0')) {
$ServiceStatus = (Get-Service 'icingapowershell' -ErrorAction SilentlyContinue).Status;
Write-IcingaConsoleNotice 'Applying pending migrations required for Icinga for Windows v1.8.0'; Write-IcingaConsoleNotice 'Applying pending migrations required for Icinga for Windows v1.8.0';
if ($ServiceStatus -eq 'Running') {
Stop-IcingaWindowsService;
}
$ApiChecks = Get-IcingaPowerShellConfig -Path 'Framework.Experimental.UseApiChecks'; $ApiChecks = Get-IcingaPowerShellConfig -Path 'Framework.Experimental.UseApiChecks';
@ -10,5 +15,17 @@ function Invoke-IcingaForWindowsMigration()
Remove-IcingaPowerShellConfig -Path 'Framework.Experimental.UseApiChecks' | Out-Null; Remove-IcingaPowerShellConfig -Path 'Framework.Experimental.UseApiChecks' | Out-Null;
Set-IcingaPowerShellConfig -Path 'Framework.ApiChecks' -Value $ApiChecks; Set-IcingaPowerShellConfig -Path 'Framework.ApiChecks' -Value $ApiChecks;
} }
# Remove all prior EventLog handler
Unregister-IcingaEventLog;
# Add new Icinga for Windows EventLog
Register-IcingaEventLog;
Set-IcingaForWindowsMigration -MigrationVersion (New-IcingaVersionObject -Version '1.8.0');
# For upgrading to v1.8.0 it is required to restart the Icinga for Windows service
if ($ServiceStatus -eq 'Running') {
Restart-IcingaService -Service 'icingapowershell';
}
} }
} }

View file

@ -1,4 +1,8 @@
function Read-IcingaForWindowsLog() function Read-IcingaForWindowsLog()
{ {
Read-IcingaWindowsEventLog -LogName 'Application' -Source 'Icinga for Windows' -MaxEntries 500; param (
[array]$Source = @()
);
Read-IcingaWindowsEventLog -LogName 'Icinga for Windows' -Source $Source -MaxEntries 500;
} }

View file

@ -0,0 +1,14 @@
function Set-IcingaForWindowsMigration()
{
param (
[Version]$MigrationVersion = $null
);
if ($null -eq $MigrationVersion) {
return;
}
[string]$MigrationConfigPath = [string]::Format('Framework.Migrations.{0}', $MigrationVersion.ToString().Replace('.', ''));
Set-IcingaPowerShellConfig -Path $MigrationConfigPath -Value $TRUE | Out-Null
}

View file

@ -0,0 +1,25 @@
function Test-IcingaForWindowsMigration()
{
param (
[Version]$MigrationVersion = $null
);
if ($null -eq $MigrationVersion) {
return $FALSE;
}
[Version]$CurrentFrameworkVersion = (Get-Module -ListAvailable -Name icinga-powershell-framework).Version;
[string]$MigrationConfigPath = [string]::Format('Framework.Migrations.{0}', $MigrationVersion.ToString().Replace('.', ''));
$VersionMigrationApplied = Get-IcingaPowerShellConfig -Path $MigrationConfigPath;
# Migration for this version is already applied
if ($VersionMigrationApplied) {
return $FALSE;
}
if ($CurrentFrameworkVersion -ge $MigrationVersion) {
return $TRUE;
}
return $FALSE;
}

View file

@ -53,6 +53,8 @@ function Uninstall-IcingaForWindows()
Uninstall-IcingaSecurity -IcingaUser $IcingaUser; Uninstall-IcingaSecurity -IcingaUser $IcingaUser;
Write-IcingaConsoleNotice 'Uninstalling Icinga Agent'; Write-IcingaConsoleNotice 'Uninstalling Icinga Agent';
Uninstall-IcingaAgent -RemoveDataFolder | Out-Null; Uninstall-IcingaAgent -RemoveDataFolder | Out-Null;
Write-IcingaConsoleNotice 'Uninstalling Icinga for Windows EventLog';
Unregister-IcingaEventLog;
Write-IcingaConsoleNotice 'Uninstalling Icinga for Windows service'; Write-IcingaConsoleNotice 'Uninstalling Icinga for Windows service';
Uninstall-IcingaForWindowsService | Out-Null; Uninstall-IcingaForWindowsService | Out-Null;

View file

@ -0,0 +1,21 @@
<#
# This script will provide 'Enums' we can use for proper
# error handling and to provide more detailed descriptions
#
# Example usage:
# $IcingaEventLogEnums[2000]
#>
if ($null -eq $IcingaEventLogEnums -Or $IcingaEventLogEnums.ContainsKey('Debug') -eq $FALSE) {
[hashtable]$IcingaEventLogEnums += @{
'Debug' = @{
1000 = @{
'EntryType' = 'Information';
'Message' = 'Generic debug message issued by the Framework or its components';
'Details' = 'The Framework or is components can issue generic debug message in case the debug log is enabled. Please ensure to disable it, if not used. You can do so with the command "Disable-IcingaFrameworkDebugMode"';
'EventId' = 1000;
};
}
};
}
Export-ModuleMember -Variable @( 'IcingaEventLogEnums' );

View file

@ -8,12 +8,6 @@
if ($null -eq $IcingaEventLogEnums -Or $IcingaEventLogEnums.ContainsKey('Framework') -eq $FALSE) { if ($null -eq $IcingaEventLogEnums -Or $IcingaEventLogEnums.ContainsKey('Framework') -eq $FALSE) {
[hashtable]$IcingaEventLogEnums += @{ [hashtable]$IcingaEventLogEnums += @{
'Framework' = @{ 'Framework' = @{
1000 = @{
'EntryType' = 'Information';
'Message' = 'Generic debug message issued by the Framework or its components';
'Details' = 'The Framework or is components can issue generic debug message in case the debug log is enabled. Please ensure to disable it, if not used. You can do so with the command "Disable-IcingaFrameworkDebugMode"';
'EventId' = 1000;
};
1001 = @{ 1001 = @{
'EntryType' = 'Warning'; 'EntryType' = 'Warning';
'Message' = 'Icinga for Windows deprecation warning'; 'Message' = 'Icinga for Windows deprecation warning';

View file

@ -1,20 +1,16 @@
function Register-IcingaEventLog() function Register-IcingaEventLog()
{ {
try { param (
# Run this in a Try-Catch-Block, as we will run into an exception if it is not [string]$LogName = $null
# present in the Application where it should be once we try to load the
# Security log. If it is not found in the "public" Event-Log data, the
# App is not registered
$Registered = [System.Diagnostics.EventLog]::SourceExists(
'Icinga for Windows'
); );
if ($Registered) { if ([string]::IsNullOrEmpty($LogName)) {
return; New-EventLog -LogName 'Icinga for Windows' -Source 'IfW::Framework' -ErrorAction SilentlyContinue;
} New-EventLog -LogName 'Icinga for Windows' -Source 'IfW::Service' -ErrorAction SilentlyContinue;
New-EventLog -LogName 'Icinga for Windows' -Source 'IfW::Debug' -ErrorAction SilentlyContinue;
} else {
$LogName = [string]::Format('IfW::{0}', $LogName);
New-EventLog -LogName Application -Source 'Icinga for Windows'; New-EventLog -LogName 'Icinga for Windows' -Source $LogName -ErrorAction SilentlyContinue;
} catch {
Exit-IcingaThrowException -ExceptionType 'Configuration' -ExceptionThrown $IcingaExceptions.Configuration.EventLogNotInstalled -Force;
} }
} }

View file

@ -0,0 +1,104 @@
<#
This code is broken and does not work. The idea is, that we create
a log entry within the Windows EventLog with a folder structure
Icinga
|_ Icinga for Windows
|_ Admin
|_ Debug
|_ Icinga Agent
|_ Admin
|_ Debug
But it doesn't work. Ideas welcome. The entries are created, but the structure
is not represented
#>
<#
function Register-IcingaForWindowsEventLogFolder()
{
param (
[string]$RootFolder = 'Icinga',
[string]$Application = 'Icinga for Windows',
[string]$Folder = ''
);
if ([string]::IsNullOrEmpty($Folder)) {
Write-IcingaConsoleError -Message 'You have to specify a folder name';
return;
}
# Base config
[string]$IcingaGUID = '{d59d4eba-fc0e-413e-b245-c53d259428c7}'
[string]$LogRoot = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WINEVT';
[string]$ApplicationLog = 'HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Application';
[string]$LogChannel = [string]::Format('{0}\Channels', $LogRoot);
[string]$LogPublisher = [string]::Format('{0}\Publishers\{1}', $LogRoot, $IcingaGUID);
[string]$FolderPath = [string]::Format('{0}-{1}', $RootFolder, $Application);
[string]$LogFolderName = [string]::Format('{0}/{1}', $FolderPath, $Folder);
[string]$ChannelReference = [string]::Format('{0}\ChannelReference', $LogPublisher);
[string]$ChannelEntry = [string]::Format('{0}\{1}', $LogChannel, $LogFolderName);
[string]$ApplicationEntry = [string]::Format('{0}\{1}', $ApplicationLog, $FolderPath);
[string]$LogFile = [string]::Format('{0}\System32\Winevt\Logs\{1}%4{2}.evtx', $Env:SystemRoot, $FolderPath, $Folder);
[int]$FolderCount = 1;
if (Test-Path $ChannelEntry) {
Write-Host 'This log does already exist';
return;
}
# Create the file to log into and the registry key for pointing to our GUID
if ((Test-Path $ApplicationEntry) -eq $FALSE) {
New-Item -Path $ApplicationEntry | Out-Null;
New-ItemProperty -Path $ApplicationEntry -Name 'ProviderGuid' -PropertyType 'String' -Value $IcingaGUID | Out-Null;
New-ItemProperty -Path $ApplicationEntry -Name 'File' -PropertyType 'ExpandString' -Value $LogFile | Out-Null;
}
# Create the channel data
# HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WINEVT\Channels
$HKLMRoot = Get-Item -Path 'HKLM:\';
$HKLMRoot = $HKLMRoot.OpenSubKey('SOFTWARE\Microsoft\Windows\CurrentVersion\WINEVT\Channels', $TRUE);
$HKLMRoot.CreateSubKey($LogFolderName) | Out-Null;
$HKLMRoot.Close();
New-ItemProperty -Path $ChannelEntry -Name 'OwningPublisher' -PropertyType 'String' -Value $IcingaGUID | Out-Null;
New-ItemProperty -Path $ChannelEntry -Name 'Enabled' -PropertyType 'DWord' -Value 1 | Out-Null;
New-ItemProperty -Path $ChannelEntry -Name 'Type' -PropertyType 'DWord' -Value 0 | Out-Null;
New-ItemProperty -Path $ChannelEntry -Name 'Isolation' -PropertyType 'DWord' -Value 0 | Out-Null;
# Create the publisher data
if ((Test-Path $LogPublisher) -eq $FALSE) {
# HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WINEVT\Publishers\{d59d4eba-fc0e-413e-b245-c53d259428c7}
New-Item -Path $LogPublisher -Value $FolderPath | Out-Null;
New-ItemProperty -Path $LogPublisher -Name 'Enabled' -PropertyType 'DWord' -Value 1 | Out-Null;
# HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WINEVT\Publishers\{d59d4eba-fc0e-413e-b245-c53d259428c7}\ChannelReference
New-Item -Path $ChannelReference | Out-Null;
# Add Count
New-ItemProperty -Path $ChannelReference -Name 'Count' -PropertyType 'DWord' -Value $FolderCount | Out-Null;
} else {
[int]$FolderCount = (Get-ItemProperty -Path $ChannelReference -Name 'Count').Count + 1;
}
# At first, get all elements from the folder
$RegisteredFolders = Get-ChildItem $ChannelReference;
foreach ($knownFolder in $RegisteredFolders) {
# Full path to our registry sub folder
$FolderProperty = Get-ItemProperty -Path $knownFolder.PSPath;
if ($FolderProperty.'(default)' -eq $LogFolderName) {
Write-IcingaConsoleWarning -Message 'The EventLog folder "{0}" does already exist' -Objects $LogFolderName;
return;
}
}
[string]$NewFolderLocation = [string]::Format('{0}\{1}', $ChannelReference, ($FolderCount - 1));
New-Item -Path $NewFolderLocation -Value $LogFolderName | Out-Null;
New-ItemProperty -Path $NewFolderLocation -Name 'Flags' -PropertyType 'DWord' -Value 0 | Out-Null;
New-ItemProperty -Path $NewFolderLocation -Name 'Id' -PropertyType 'DWord' -Value 16 | Out-Null;
# Update Count
Set-ItemProperty -Path $ChannelReference -Name 'Count' -Value $FolderCount | Out-Null;
}
#>

View file

@ -0,0 +1,11 @@
function Unregister-IcingaEventLog()
{
# Icinga for Windows v1.8.0 or later
Remove-EventLog -LogName 'Icinga for Windows' -ErrorAction SilentlyContinue;
# Older versions
Remove-EventLog -Source 'Icinga for Windows' -ErrorAction SilentlyContinue;
# Icinga for Windows v1.8.0 or later - required a second time to ensure
# everything is removed for legacy versions
Remove-EventLog -LogName 'Icinga for Windows' -ErrorAction SilentlyContinue;
}

View file

@ -17,5 +17,5 @@ function Write-IcingaDebugMessage()
[array]$DebugContent = @($Message); [array]$DebugContent = @($Message);
$DebugContent += $Objects; $DebugContent += $Objects;
Write-IcingaEventMessage -EventId 1000 -Namespace 'Framework' -ExceptionObject $ExceptionObject -Objects $DebugContent; Write-IcingaEventMessage -EventId 1000 -Namespace 'Debug' -ExceptionObject $ExceptionObject -Objects $DebugContent;
} }

View file

@ -9,5 +9,5 @@ function Write-IcingaErrorMessage()
return; return;
} }
Write-EventLog -LogName Application -Source 'Icinga for Windows' -EntryType Error -EventId $EventId -Message $Message; Write-EventLog -LogName 'Icinga for Windows' -Source 'Icinga for Windows' -EntryType Error -EventId $EventId -Message $Message;
} }

View file

@ -57,8 +57,9 @@ function Write-IcingaEventMessage()
if ($EventLogMessage.Length -ge $MaxEventLogMessageSize) { if ($EventLogMessage.Length -ge $MaxEventLogMessageSize) {
while ($EventLogMessage.Length -ge $MaxEventLogMessageSize) { while ($EventLogMessage.Length -ge $MaxEventLogMessageSize) {
$CutMessage = $EventLogMessage.Substring(0, $MaxEventLogMessageSize); $CutMessage = $EventLogMessage.Substring(0, $MaxEventLogMessageSize);
Write-EventLog -LogName Application ` Write-EventLog `
-Source 'Icinga for Windows' ` -LogName 'Icinga for Windows' `
-Source ([string]::Format('IfW::{0}', $Namespace)) `
-EntryType $EntryType ` -EntryType $EntryType `
-EventId $EventId ` -EventId $EventId `
-Message $CutMessage; -Message $CutMessage;
@ -71,8 +72,9 @@ function Write-IcingaEventMessage()
return; return;
} }
Write-EventLog -LogName Application ` Write-EventLog `
-Source 'Icinga for Windows' ` -LogName 'Icinga for Windows' `
-Source ([string]::Format('IfW::{0}', $Namespace)) `
-EntryType $EntryType ` -EntryType $EntryType `
-EventId $EventId ` -EventId $EventId `
-Message $EventLogMessage; -Message $EventLogMessage;

View file

@ -188,9 +188,10 @@ function Install-IcingaComponent()
} }
Import-Module -Name $ComponentFolder -Force; Import-Module -Name $ComponentFolder -Force;
Import-Module -Name $ComponentFolder -Force -Global;
# Apply migration tasks # Apply migration tasks
Invoke-IcingaForWindowsMigration; Use-Icinga;
if ($ServiceStatus -eq 'Running') { if ($ServiceStatus -eq 'Running') {
Write-IcingaConsoleNotice 'Starting Icinga for Windows service'; Write-IcingaConsoleNotice 'Starting Icinga for Windows service';
@ -202,6 +203,7 @@ function Install-IcingaComponent()
} }
} else { } else {
Import-Module -Name $ComponentFolder -Force; Import-Module -Name $ComponentFolder -Force;
Import-Module -Name $ComponentFolder -Force -Global;
} }
# This will ensure that Framework functions will always win over third party functions, overwriting functionality # This will ensure that Framework functions will always win over third party functions, overwriting functionality

View file

@ -5,8 +5,6 @@ function Start-IcingaPowerShellDaemon()
[switch]$JEARestart = $FALSE [switch]$JEARestart = $FALSE
); );
Use-Icinga;
$global:IcingaDaemonData.FrameworkRunningAsDaemon = $TRUE; $global:IcingaDaemonData.FrameworkRunningAsDaemon = $TRUE;
[string]$MainServicePidFile = (Join-Path -Path (Get-IcingaCacheDir) -ChildPath 'service.pid'); [string]$MainServicePidFile = (Join-Path -Path (Get-IcingaCacheDir) -ChildPath 'service.pid');
@ -36,7 +34,7 @@ function Start-IcingaPowerShellDaemon()
Write-IcingaDebugMessage -Message 'Starting Icinga for Windows service inside JEA context' -Objects $RunAsService, $JEARestart, $JeaProfile; Write-IcingaDebugMessage -Message 'Starting Icinga for Windows service inside JEA context' -Objects $RunAsService, $JEARestart, $JeaProfile;
& powershell.exe -NoProfile -NoLogo -ConfigurationName $JeaProfile -Command { & powershell.exe -NoProfile -NoLogo -ConfigurationName $JeaProfile -Command {
try { try {
Use-Icinga; Use-Icinga -Daemon;
Write-IcingaFileSecure -File ($args[1]) -Value $PID; Write-IcingaFileSecure -File ($args[1]) -Value $PID;