mirror of
https://github.com/Icinga/icinga-powershell-framework.git
synced 2025-12-21 07:10:15 -05:00
Remove remaining legacy code of module
This commit is contained in:
parent
8e62cdb836
commit
6ffd3ac0ec
46 changed files with 0 additions and 4758 deletions
142
core/config.ps1
142
core/config.ps1
|
|
@ -1,142 +0,0 @@
|
|||
param(
|
||||
[string]$AddKey = '',
|
||||
[Object]$AddValue = '',
|
||||
[string]$GetConfig = '',
|
||||
[string]$RemoveConfig = '',
|
||||
[boolean]$ListConfig = $FALSE,
|
||||
[boolean]$Reload = $FALSE
|
||||
);
|
||||
|
||||
function ClassConfig()
|
||||
{
|
||||
param(
|
||||
[string]$AddKey = '',
|
||||
[Object]$AddValue = '',
|
||||
[string]$GetConfig = '',
|
||||
[string]$RemoveConfig = '',
|
||||
[boolean]$ListConfig = $FALSE,
|
||||
[boolean]$Reload = $FALSE
|
||||
);
|
||||
|
||||
$instance = New-Object -TypeName PSObject;
|
||||
|
||||
$instance | Add-Member -membertype NoteProperty -name 'ConfigDirectory' -value (Join-Path $Icinga2.App.RootPath -ChildPath 'agent\config');
|
||||
$instance | Add-Member -membertype NoteProperty -name 'ConfigFile' -value (Join-Path $instance.ConfigDirectory -ChildPath 'config.conf');
|
||||
|
||||
$instance | Add-Member -membertype ScriptMethod -name 'Init' -value {
|
||||
if ($ListConfig) {
|
||||
return $this.DumpConfig();
|
||||
}
|
||||
|
||||
if ($Reload) {
|
||||
return $this.ReloadConfig();
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($GetConfig) -eq $FALSE) {
|
||||
return $this.GetAttribute();
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($AddKey) -eq $FALSE) {
|
||||
return $this.SetAttribute();
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($RemoveConfig) -eq $FALSE) {
|
||||
return $this.RemoveAttribute();
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'{ Invalid or insufficient arguments specified. }'
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
$instance | Add-Member -membertype ScriptMethod -name 'ReloadConfig' -value {
|
||||
$Icinga2.Config = & (Join-Path $Icinga2.App.RootPath -ChildPath '\core\include\Config.ps1');
|
||||
}
|
||||
|
||||
$instance | Add-Member -membertype ScriptMethod -name 'WriteConfig' -value {
|
||||
If ((Test-Path ($this.ConfigDirectory)) -eq $FALSE) {
|
||||
$Icinga2.Log.WriteConsole(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
'Config Directory is not present. Please run "Icinga-Setup" for the base installation'
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
$config = ConvertTo-Json $Icinga2.Config -Depth 100;
|
||||
[System.IO.File]::WriteAllText($this.ConfigFile, $config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
$instance | Add-Member -membertype ScriptMethod -name 'DumpConfig' -value {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
([string]::Format('Config location: {0}', $this.ConfigFile))
|
||||
);
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
$Icinga2.Config
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
$instance | Add-Member -membertype ScriptMethod -name 'GetAttribute' -value {
|
||||
return $Icinga2.Config.$GetConfig;
|
||||
}
|
||||
|
||||
$instance | Add-Member -membertype ScriptMethod -name 'SetAttribute' -value {
|
||||
$value = $AddValue;
|
||||
|
||||
if ([string]::IsNullOrEmpty($AddValue)) {
|
||||
$value = $null;
|
||||
}
|
||||
|
||||
if ([bool]($Icinga2.Config.PSobject.Properties.Name -eq $AddKey) -eq $FALSE) {
|
||||
$Icinga2.Config | Add-Member -membertype NoteProperty -name $AddKey -value $value;
|
||||
} else {
|
||||
$Icinga2.Config.$AddKey = $value;
|
||||
}
|
||||
|
||||
if ($this.WriteConfig() -eq 0) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
([string]::Format('{0} Set config attribute "{1}" to "{2}. {3}', '{', $AddKey, $value, '}'))
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Error,
|
||||
([string]::Format('{0} Unable to write config file to disk. Failed to update attribute "{1}" to "{2}. {3}', '{', $AddKey, $value, '}'))
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
$instance | Add-Member -membertype ScriptMethod -name 'RemoveAttribute' -value {
|
||||
if ([bool]($Icinga2.Config.PSobject.Properties.Name -eq $RemoveConfig) -eq $TRUE) {
|
||||
$Icinga2.Config.PSobject.Members.Remove($RemoveConfig);
|
||||
if ($this.WriteConfig() -eq 0) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
([string]::Format('{0} Successfully removed config attribute "{1}" {2}', '{', $RemoveConfig, '}'))
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Error,
|
||||
([string]::Format('{0} Config attribute "{1}" was removed, but storing the new config file failed. {2}', '{', $RemoveConfig, '}'))
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
([string]::Format('{0} Unable to remove attribute "{1}". Attribute not found {2}', '{', $RemoveConfig, '}'))
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return $instance.Init();
|
||||
}
|
||||
|
||||
return ClassConfig -AddKey $AddKey -AddValue $AddValue -GetConfig $GetConfig -RemoveConfig $RemoveConfig -ListConfig $ListConfig -Reload $Reload;
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
$APIResponse = New-Object -TypeName PSObject;
|
||||
|
||||
$APIResponse | Add-Member -membertype NoteProperty -name 'static' -value $FALSE;
|
||||
$APIResponse | Add-Member -membertype NoteProperty -name 'statuscode' -value 200;
|
||||
$APIResponse | Add-Member -membertype NoteProperty -name 'message' -value '';
|
||||
$APIResponse | Add-Member -membertype NoteProperty -name 'content' -value $null;
|
||||
$APIResponse | Add-Member -membertype NoteProperty -name 'authheader' -value '';
|
||||
|
||||
$APIResponse | Add-Member -membertype ScriptMethod -name 'setContent' -value {
|
||||
param([object]$content);
|
||||
|
||||
$this.content = $content;
|
||||
}
|
||||
|
||||
$APIResponse | Add-Member -membertype ScriptMethod -name 'CustomBadRequest' -value {
|
||||
param([string]$message);
|
||||
|
||||
$this.statuscode = 400;
|
||||
$this.message = $message;
|
||||
}
|
||||
|
||||
$APIResponse | Add-Member -membertype ScriptMethod -name 'InternalServerError' -value {
|
||||
$this.statuscode = 500;
|
||||
$this.message = 'An internal server error occured while parsing your request.';
|
||||
}
|
||||
|
||||
$APIResponse | Add-Member -membertype ScriptMethod -name 'HTTPSRequired' -value {
|
||||
$this.statuscode = 403;
|
||||
$this.message = 'This API only supports connections over HTTPS.';
|
||||
}
|
||||
|
||||
$APIResponse | Add-Member -membertype ScriptMethod -name 'AuthenticationRequired' -value {
|
||||
$this.statuscode = 401;
|
||||
$this.message = 'You require to login in order to access this ressource.';
|
||||
$this.authheader = [string]::Format(
|
||||
'WWW-Authenticate: Basic realm="Icinga Windows Daemon"{0}',
|
||||
"`r`n"
|
||||
);
|
||||
}
|
||||
|
||||
$APIResponse | Add-Member -membertype ScriptMethod -name 'CompileMessage' -value {
|
||||
# If our message is empty, do nothing
|
||||
if ([string]::IsNullOrEmpty($this.message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
# In case we assigned custom content, do not override this content
|
||||
if ($this.content -ne $null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this.content = @{
|
||||
response = $this.statuscode;
|
||||
message = $this.message;
|
||||
};
|
||||
}
|
||||
|
||||
$APIResponse | Add-Member -membertype ScriptMethod -name 'Compile' -value {
|
||||
|
||||
$this.CompileMessage();
|
||||
|
||||
[string]$ContentLength = '';
|
||||
[string]$HTMLContent = '';
|
||||
if ($this.content -ne $null) {
|
||||
$json = ConvertTo-Json $this.content -Depth 100 -Compress;
|
||||
$bytes = [System.Text.Encoding]::UTF8.GetBytes($json);
|
||||
$HTMLContent = [System.Text.Encoding]::UTF8.GetString($bytes);
|
||||
if ($bytes.Length -gt 0) {
|
||||
$ContentLength = [string]::Format(
|
||||
'Content-Length: {0}{1}',
|
||||
$bytes.Length,
|
||||
"`r`n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return -Join(
|
||||
[string]::Format(
|
||||
'HTTP/1.1 {0} {1}{2}',
|
||||
$this.statuscode,
|
||||
$Icinga2.Enums.HttpStatusCodes.$this.statuscode,
|
||||
"`r`n"
|
||||
),
|
||||
[string]::Format(
|
||||
'Server: {0}{1}',
|
||||
(Get-WmiObject Win32_ComputerSystem).Name,
|
||||
"`r`n"
|
||||
),
|
||||
[string]::Format(
|
||||
'Content-Type: application/json{0}',
|
||||
"`r`n"
|
||||
),
|
||||
$this.authheader,
|
||||
$ContentLength,
|
||||
"`r`n",
|
||||
$HTMLContent
|
||||
);
|
||||
}
|
||||
|
||||
return $APIResponse;
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
# App configuration
|
||||
$App = @{
|
||||
LogSeverity = [PSCustomObject]@{
|
||||
PSTypeName = "LogSeverity"
|
||||
Info = 0
|
||||
Warning = 1
|
||||
Error = 2
|
||||
Exception = 3
|
||||
Debug = 4
|
||||
};
|
||||
RootPath = $_InternalTempVariables.RootPath;
|
||||
ModuleName = $_InternalTempVariables.ModuleName;
|
||||
}
|
||||
|
||||
return $App;
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
$Checker = New-Object -TypeName PSObject;
|
||||
|
||||
$Checker | Add-Member -membertype NoteProperty -name 'os' -value '';
|
||||
$Checker | Add-Member -membertype NoteProperty -name 'version' -value '';
|
||||
$Checker | Add-Member -membertype NoteProperty -name 'fqdn' -value '';
|
||||
$Checker | Add-Member -membertype NoteProperty -name 'bind' -value 'wdt';
|
||||
$Checker | Add-Member -membertype NoteProperty -name 'time_offset' -value 0;
|
||||
|
||||
$Checker | Add-Member -membertype ScriptMethod -name 'Start' -value {
|
||||
|
||||
$Icinga2.PidManager.StopProcessByBind($this.bind);
|
||||
|
||||
Start-Sleep 1;
|
||||
|
||||
$Icinga2.PidManager.CreatePidFile($this.bind);
|
||||
|
||||
$WindowsInformations = Get-CimInstance Win32_OperatingSystem;
|
||||
$this.version = $WindowsInformations.CimInstanceProperties['Version'].Value;
|
||||
$this.os = $WindowsInformations.CimInstanceProperties['Caption'].Value;
|
||||
$this.fqdn = [System.Net.Dns]::GetHostEntry('localhost').HostName;
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'Starting checker component of module.'
|
||||
);
|
||||
|
||||
$Icinga2.ClientProtocol.setFQDN($this.fqdn);
|
||||
$Icinga2.Cache.Checker.ModuleScheduler = @{ };
|
||||
|
||||
while($true) {
|
||||
|
||||
$StopWatchHandler = [System.Diagnostics.StopWatch]::StartNew()
|
||||
$this.ScheduleWindowsHello($FALSE);
|
||||
$this.UpdateModuleTimer();
|
||||
$Icinga2.ClientJobs.ParseJobResults();
|
||||
|
||||
# This part will help us to keep the gap between module execution as low as possible
|
||||
# We will check how many seconds have been passed while the modules were executed
|
||||
# This value will then be added to our module timings, ensuring that in general
|
||||
# they will become executed right on time
|
||||
$StopWatchHandler.Stop();
|
||||
$this.time_offset = [math]::Round($StopWatchHandler.Elapsed.TotalSeconds, 0);
|
||||
$Icinga2.ClientJobs.AddTicks($this.time_offset);
|
||||
|
||||
Start-Sleep -Seconds 1;
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'Stopping checker component of module.'
|
||||
);
|
||||
}
|
||||
|
||||
$Checker | Add-Member -membertype ScriptMethod -name 'UpdateModuleTimer' -value {
|
||||
if ($Icinga2.Cache.Checker.ModuleConfig -eq $null) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($module in $Icinga2.Cache.Checker.ModuleConfig.Keys) {
|
||||
if ($Icinga2.Cache.Checker.ModuleScheduler.ContainsKey($module) -eq $FALSE) {
|
||||
$Icinga2.Cache.Checker.ModuleScheduler.Add($module, 0);
|
||||
} else {
|
||||
$Icinga2.Cache.Checker.ModuleScheduler[$module] += (1 + $this.time_offset);
|
||||
|
||||
if ($Icinga2.Cache.Checker.ModuleScheduler[$module] -ge $Icinga2.Cache.Checker.ModuleConfig[$module]) {
|
||||
$Icinga2.Cache.Checker.ModuleScheduler[$module] = 0;
|
||||
$this.ScheduleModuleJob($module);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this.time_offset = 0;
|
||||
}
|
||||
|
||||
$Checker | Add-Member -membertype ScriptMethod -name 'ScheduleModuleJob' -value {
|
||||
param([string]$module);
|
||||
|
||||
$Icinga2.ClientJobs.ScheduleJob($module);
|
||||
}
|
||||
|
||||
$Checker | Add-Member -membertype ScriptMethod -name 'ScheduleWindowsHello' -value {
|
||||
param([bool]$force);
|
||||
$this.WriteLogOutput($Icinga2.ClientJobs.WindowsHello(
|
||||
$this.os,
|
||||
$this.fqdn,
|
||||
$this.version,
|
||||
$force
|
||||
));
|
||||
}
|
||||
|
||||
$Checker | Add-Member -membertype ScriptMethod -name 'WriteLogOutput' -value {
|
||||
param($response);
|
||||
|
||||
if ($response -ne $null) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
$response
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$Checker | Add-Member -membertype ScriptMethod -name 'Stop' -value {
|
||||
$Icinga2.PidManager.StopProcessByBind($this.bind);
|
||||
}
|
||||
|
||||
return $Checker;
|
||||
|
|
@ -1,292 +0,0 @@
|
|||
$ClientJobs = New-Object -TypeName PSObject;
|
||||
|
||||
$ClientJobs | Add-Member -membertype NoteProperty -name 'hello_counter' -value 0;
|
||||
$ClientJobs | Add-Member -membertype NoteProperty -name 'module_scheduler' -value @( );
|
||||
$ClientJobs | Add-Member -membertype NoteProperty -name 'module_output' -value $null;
|
||||
|
||||
$ClientJobs | Add-Member -membertype ScriptMethod -name 'AddTicks' -value {
|
||||
param([int]$ticks);
|
||||
|
||||
$this.hello_counter += $ticks;
|
||||
}
|
||||
|
||||
$ClientJobs | Add-Member -membertype ScriptMethod -name 'WindowsHello' -value {
|
||||
param([string]$os, [string]$fqdn, [string]$version, [bool]$force);
|
||||
|
||||
if ($this.hello_counter -ge 30) {
|
||||
$this.hello_counter = 0;
|
||||
}
|
||||
|
||||
if ($this.hello_counter -eq 0 -Or $force -eq $TRUE) {
|
||||
[hashtable]$hello = @{
|
||||
'os' = $os;
|
||||
'fqdn' = $fqdn;
|
||||
'version' = $version;
|
||||
'port' = $Icinga2.Config.'tcp.socket.port';
|
||||
};
|
||||
|
||||
[string]$token = $this.getAuthToken();
|
||||
if ([string]::isNullOrEmpty($token) -eq $FALSE) {
|
||||
$hello.Add(
|
||||
'modules',
|
||||
(New-Icinga-Monitoring -ListModules)
|
||||
)
|
||||
}
|
||||
|
||||
$response = $Icinga2.ClientProtocol.NewRequest(
|
||||
@('X-Windows-Hello: 1'),
|
||||
($hello | ConvertTo-Json -Depth 2 -Compress),
|
||||
$Icinga2.Config.'checker.server.host',
|
||||
$token
|
||||
);
|
||||
|
||||
$this.hello_counter += 1;
|
||||
|
||||
if ($response -eq $null) {
|
||||
return $null;
|
||||
}
|
||||
|
||||
try {
|
||||
$json = $response | ConvertFrom-Json;
|
||||
$Icinga2.Cache.Checker.Authenticated = $TRUE;
|
||||
$Icinga2.ClientProtocol.parseWindowsHelloResponse($json);
|
||||
return $null;
|
||||
} catch {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
$_.Exception.Message
|
||||
);
|
||||
}
|
||||
|
||||
$Icinga2.Cache.Checker.Authenticated = $FALSE;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$this.hello_counter += 1;
|
||||
|
||||
return $null;
|
||||
}
|
||||
|
||||
$ClientJobs | Add-Member -membertype ScriptMethod -name 'getAuthToken' -value {
|
||||
[string]$token = '';
|
||||
if ($Icinga2.Cache.Checker.Authenticated -eq $TRUE -And $Icinga2.Cache.Checker.AuthToken -ne $null) {
|
||||
$token = [string]::Format('?token={0}', $Icinga2.Cache.Checker.AuthToken);
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
$ClientJobs | Add-Member -membertype ScriptMethod -name 'ScheduleJob' -value {
|
||||
param([string]$module);
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format(
|
||||
'Scheduling execution check for module: {0}',
|
||||
$module
|
||||
)
|
||||
);
|
||||
|
||||
$this.module_scheduler += $module;
|
||||
return;
|
||||
|
||||
# This would be the best, but will cause too much overhead and system load
|
||||
Start-Job -Name $module -ScriptBlock {
|
||||
return New-Icinga-Monitoring -include $args[0];
|
||||
} -ArgumentList $module;
|
||||
}
|
||||
|
||||
$ClientJobs | Add-Member -membertype ScriptMethod -name 'ParseJobResults' -value {
|
||||
|
||||
if ($this.module_scheduler.Count -eq 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$moduleOutput = New-Icinga-Monitoring -Include ($this.module_scheduler) -Config $Icinga2.Cache.Checker.ModuleArguments;
|
||||
|
||||
[string]$token = $this.getAuthToken();
|
||||
|
||||
[string]$modules = $this.module_scheduler -Join ","
|
||||
|
||||
if ([string]::isNullOrEmpty($token) -eq $TRUE) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
'Unable to send job results to server. No auth token is specified'
|
||||
);
|
||||
$this.FlushModuleCache($TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Icinga2.ClientProtocol.GetConnectionState($Icinga2.Config.'checker.server.host') -eq $FALSE) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
[string]::Format(
|
||||
'Module results for "{0}" will not be send to {1}. A previous connection failed. Re-Trying in some seconds...',
|
||||
$modules,
|
||||
$Icinga2.Config.'checker.server.host'
|
||||
)
|
||||
);
|
||||
$this.FlushModuleCache($TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
$this.module_output = ($moduleOutput | ConvertTo-Json -Depth 100 -Compress);
|
||||
|
||||
$response = $Icinga2.ClientProtocol.NewRequest(
|
||||
@('X-Windows-Result: 1'),
|
||||
$this.module_output,
|
||||
$Icinga2.Config.'checker.server.host',
|
||||
[string]::Format(
|
||||
'{0}&results=1',
|
||||
$token
|
||||
)
|
||||
);
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format(
|
||||
'Send modules {0} results to server. Received result: {1}',
|
||||
$modules,
|
||||
$response
|
||||
)
|
||||
);
|
||||
|
||||
$this.ParseResponse($response);
|
||||
return;
|
||||
|
||||
# This would be the best, but will cause too much overhead and system load
|
||||
[hashtable]$moduleOutput = @{ };
|
||||
|
||||
Get-Job -State Completed | Where-Object {
|
||||
$moduleOutput.Add(
|
||||
$_.Name,
|
||||
(Receive-Job -Id $_.Id)
|
||||
);
|
||||
Remove-Job -Id $_.Id;
|
||||
};
|
||||
|
||||
[string]$token = $this.getAuthToken();
|
||||
|
||||
if ([string]::isNullOrEmpty($token) -eq $TRUE) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
'Unable to send job results to server. No auth token is specified'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Icinga2.ClientProtocol.GetConnectionState($Icinga2.Config.'checker.server.host') -eq $FALSE) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
[string]::Format(
|
||||
'Module results for "{0}" will not be send to {1}. A previous connection failed. Re-Trying in some seconds...',
|
||||
$modules,
|
||||
$Icinga2.Config.'checker.server.host'
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$response = $Icinga2.ClientProtocol.NewRequest(
|
||||
@('X-Windows-Result: 1'),
|
||||
($moduleOutput | ConvertTo-Json -Depth 100 -Compress),
|
||||
$Icinga2.Config.'checker.server.host',
|
||||
[string]::Format(
|
||||
'{0}&results=1',
|
||||
$token
|
||||
)
|
||||
);
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format(
|
||||
'Send modules {0} results to server. Received result: {1}',
|
||||
($moduleOutput | Out-String),
|
||||
$response
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$ClientJobs | Add-Member -membertype ScriptMethod -name 'FlushModuleCache' -value {
|
||||
param([bool]$flush);
|
||||
|
||||
if ($flush -eq $TRUE) {
|
||||
foreach($module in $this.module_scheduler) {
|
||||
$Icinga2.Utils.Modules.FlushModuleCache($module);
|
||||
}
|
||||
}
|
||||
|
||||
$this.module_scheduler = @();
|
||||
}
|
||||
|
||||
$ClientJobs | Add-Member -membertype ScriptMethod -name 'ParseResponse' -value {
|
||||
param([string]$response);
|
||||
|
||||
if ([string]::IsNullOrEmpty($response) -eq $TRUE) {
|
||||
$this.FlushModuleCache($TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
# Re-Try to send the informations once in case we are not authorized
|
||||
if ($response -eq '401') {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
'Received Unauthorized (401) response. Trying to re-send results after requesting permission.'
|
||||
);
|
||||
$Icinga2.Checker.ScheduleWindowsHello($TRUE);
|
||||
[string]$token = $this.getAuthToken();
|
||||
$response = $Icinga2.ClientProtocol.NewRequest(
|
||||
@('X-Windows-Result: 1'),
|
||||
$this.module_output,
|
||||
$Icinga2.Config.'checker.server.host',
|
||||
[string]::Format(
|
||||
'{0}&results=1',
|
||||
$token
|
||||
)
|
||||
);
|
||||
|
||||
if ([string]::IsNullOrEmpty($response) -eq $TRUE) {
|
||||
$this.FlushModuleCache($TRUE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$json = ConvertFrom-Json $response -ErrorAction Stop -WarningAction Stop;
|
||||
} catch {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Error,
|
||||
[string]::Format(
|
||||
'Received invalid JSON response from request: {0}',
|
||||
$response
|
||||
)
|
||||
);
|
||||
$this.FlushModuleCache($TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if ($json.response -ne $null) {
|
||||
if ($json.response -ne 200) {
|
||||
$this.FlushModuleCache($TRUE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Error,
|
||||
[string]::Format(
|
||||
'Failed to properly parse JSON response: {0} . Exception Message: {1}',
|
||||
$response,
|
||||
$_.Exception.Message
|
||||
)
|
||||
);
|
||||
$this.FlushModuleCache($TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
$this.FlushModuleCache($FALSE);
|
||||
}
|
||||
|
||||
return $ClientJobs;
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
$ClientProtocol = New-Object -TypeName PSObject;
|
||||
|
||||
$ClientProtocol | Add-Member -membertype NoteProperty -name 'fqdn' -value '';
|
||||
|
||||
$ClientProtocol | Add-Member -membertype ScriptMethod -name 'setFQDN' -value {
|
||||
param([string]$fqdn);
|
||||
|
||||
$this.fqdn = $fqdn;
|
||||
}
|
||||
|
||||
$ClientProtocol | Add-Member -membertype ScriptMethod -name 'SetConnectionState' -value {
|
||||
param([string]$remoteAddress, [bool]$reachable);
|
||||
|
||||
if ($Icinga2.Cache.Checker.RemoteServices -eq $null) {
|
||||
$Icinga2.Cache.Checker.RemoteServices = @{ };
|
||||
}
|
||||
|
||||
if ($Icinga2.Cache.Checker.RemoteServices.ContainsKey($remoteAddress) -eq $FALSE) {
|
||||
$Icinga2.Cache.Checker.RemoteServices.Add($remoteAddress, $reachable);
|
||||
return;
|
||||
}
|
||||
|
||||
$Icinga2.Cache.Checker.RemoteServices[$remoteAddress] = $reachable;
|
||||
}
|
||||
|
||||
$ClientProtocol | Add-Member -membertype ScriptMethod -name 'GetConnectionState' -value {
|
||||
param([string]$remoteAddress);
|
||||
|
||||
if ($Icinga2.Cache.Checker.RemoteServices.ContainsKey($remoteAddress) -eq $FALSE) {
|
||||
return $TRUE;
|
||||
}
|
||||
|
||||
return $Icinga2.Cache.Checker.RemoteServices[$remoteAddress];
|
||||
}
|
||||
|
||||
$ClientProtocol | Add-Member -membertype ScriptMethod -name 'NewRequest' -value {
|
||||
param([array]$headers, [string]$content, [string]$remoteAddress, [string]$url);
|
||||
|
||||
$url = [string]::Format(
|
||||
'{0}{1}',
|
||||
$remoteAddress,
|
||||
$url
|
||||
);
|
||||
|
||||
$httpRequest = [System.Net.HttpWebRequest]::Create(
|
||||
$url
|
||||
);
|
||||
$httpRequest.Method = 'POST';
|
||||
$httpRequest.Accept = 'application/json';
|
||||
$httpRequest.ContentType = 'application/json';
|
||||
$httpRequest.Headers.Add(
|
||||
[string]::Format(
|
||||
'X-Windows-CheckResult: {0}',
|
||||
$this.fqdn
|
||||
)
|
||||
);
|
||||
|
||||
# Add possible custom header
|
||||
foreach ($header in $headers) {
|
||||
$httpRequest.Headers.Add($header);
|
||||
}
|
||||
$httpRequest.TimeOut = 60000;
|
||||
|
||||
# If we are using self-signed certificates for example, the HTTP request will
|
||||
# fail caused by the SSL certificate. With this we can allow even faulty
|
||||
# certificates. This should be used with caution
|
||||
if (-Not $Icinga2.Config.'checker.ssl.verify') {
|
||||
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
|
||||
}
|
||||
|
||||
try {
|
||||
# Only send data in case we want to send some data
|
||||
if ($content -ne '') {
|
||||
$transmitBytes = [System.Text.Encoding]::UTF8.GetBytes($content);
|
||||
$httpRequest.ContentLength = $transmitBytes.Length;
|
||||
[System.IO.Stream]$httpOutput = [System.IO.Stream]$httpRequest.GetRequestStream()
|
||||
$httpOutput.Write($transmitBytes, 0, $transmitBytes.Length)
|
||||
$httpOutput.Close()
|
||||
}
|
||||
} catch [System.Net.WebException] {
|
||||
$this.SetConnectionState($remoteAddress, $FALSE);
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
[string]::Format('Exception while trying to connect to "{0}". Possible a connection error. Message: {1}',
|
||||
$url,
|
||||
$_.Exception.Message
|
||||
)
|
||||
);
|
||||
return $null;
|
||||
} catch {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
$_.Exception.Message
|
||||
);
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
$_.Exception.StackTrace
|
||||
);
|
||||
return $null;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
$this.SetConnectionState($remoteAddress, $TRUE);
|
||||
return $this.readResponseStream($httpRequest.GetResponse());
|
||||
|
||||
} catch [System.Net.WebException] {
|
||||
# Print an exception message and the possible body in case we received one
|
||||
# to make troubleshooting easier
|
||||
[string]$errorResponse = $this.readResponseStream($_.Exception.Response);
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
$_.Exception.Message
|
||||
);
|
||||
if ($errorResponse -ne '') {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
$errorResponse
|
||||
);
|
||||
}
|
||||
|
||||
$exceptionMessage = $_.Exception.Response;
|
||||
if ($exceptionMessage.StatusCode) {
|
||||
return [int][System.Net.HttpStatusCode]$exceptionMessage.StatusCode;
|
||||
} else {
|
||||
return 900;
|
||||
}
|
||||
}
|
||||
|
||||
return $null;
|
||||
}
|
||||
|
||||
$ClientProtocol | Add-Member -membertype ScriptMethod -name 'readResponseStream' -value {
|
||||
param([System.Object]$response);
|
||||
|
||||
try {
|
||||
if ($response) {
|
||||
$responseStream = $response.getResponseStream();
|
||||
$streamReader = New-Object IO.StreamReader($responseStream);
|
||||
$result = $streamReader.ReadToEnd();
|
||||
$response.close()
|
||||
$streamReader.close()
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
'The received response from the remote server is NULL. This might be caused by SSL errors or wrong Webserver configuration.'
|
||||
);
|
||||
} catch {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
$_.Exception.Message
|
||||
);
|
||||
}
|
||||
|
||||
return $null;
|
||||
}
|
||||
|
||||
$ClientProtocol | Add-Member -membertype ScriptMethod -name 'parseWindowsHelloResponse' -value {
|
||||
param($json);
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format(
|
||||
'Remote Server Output: {0}',
|
||||
$json
|
||||
)
|
||||
);
|
||||
|
||||
$Icinga2.Cache.Checker.AuthToken = $json.token;
|
||||
if ($Icinga2.Cache.Checker.ModuleConfig -eq $null) {
|
||||
$Icinga2.Cache.Checker.ModuleConfig = @{};
|
||||
}
|
||||
|
||||
$Icinga2.Cache.Checker.ModuleArguments = $json.module_arguments;
|
||||
|
||||
[hashtable]$activeModules = @{};
|
||||
|
||||
foreach ($module in $json.modules) {
|
||||
if ($Icinga2.Cache.Checker.ModuleConfig.ContainsKey($module.name)) {
|
||||
$Icinga2.Cache.Checker.ModuleConfig[$module.name] = $module.check_interval;
|
||||
} else {
|
||||
$Icinga2.Cache.Checker.ModuleConfig.Add($module.name, $module.check_interval);
|
||||
}
|
||||
$activeModules.Add($module.name, $TRUE);
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format(
|
||||
'Adding module {0} with check intervall {1}',
|
||||
$module.name,
|
||||
$module.check_interval
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
# We might have disabled some modules. Lets handle this by setting the
|
||||
# execution timer to -1
|
||||
foreach ($module in $Icinga2.Cache.Checker.ModuleConfig.Keys) {
|
||||
if ($activeModules.ContainsKey($module) -eq $FALSE) {
|
||||
$activeModules.Add($module, $FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
# We require a second loop to ensure we won't crash because of a changed hashtable
|
||||
foreach($module in $activeModules.Keys) {
|
||||
if ($activeModules[$module] -eq $FALSE) {
|
||||
if ($Icinga2.Cache.Checker.ModuleConfig.ContainsKey($module)) {
|
||||
$Icinga2.Cache.Checker.ModuleConfig.Remove($module);
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format(
|
||||
'Disabling module {0}',
|
||||
$module
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ClientProtocol;
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
# Inetrnal variable to store the root directory path
|
||||
[string]$RootDirectory = '';
|
||||
|
||||
# In case we load the module for the first time, this variable contains the root path
|
||||
# of our module
|
||||
if ($_InternalTempVariables -ne $null) {
|
||||
$RootDirectory = $_InternalTempVariables.RootPath;
|
||||
} else {
|
||||
# In case we want to reload the configuration, we simply can access the namespace
|
||||
# variable we already loaded
|
||||
$RootDirectory = $Icinga2.App.RootPath;
|
||||
}
|
||||
|
||||
# Build the Config directory and file path
|
||||
[string]$ConfigDirectory = (Join-Path $RootDirectory -ChildPath 'agent\config');
|
||||
[string]$ConfigFile = (Join-Path $ConfigDirectory -ChildPath 'config.conf');
|
||||
|
||||
# In case the config file does not exist, return an empty hashtable
|
||||
if ((Test-Path ($ConfigFile)) -eq $FALSE) {
|
||||
return ('{ }' | ConvertFrom-Json);
|
||||
}
|
||||
|
||||
# Return the content of the file as objects (config is stored as JSON)
|
||||
return ([System.IO.File]::ReadAllText($ConfigFile) | ConvertFrom-Json);
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
<#
|
||||
# This script will provide 'Enums' we can use within our module to
|
||||
# easier access constants and to maintain a better overview of the
|
||||
# entire components
|
||||
#>
|
||||
|
||||
[hashtable]$LogState = @{
|
||||
Info = 0;
|
||||
Warning = 1;
|
||||
Error = 2;
|
||||
Exception = 3;
|
||||
Debug = 4;
|
||||
};
|
||||
|
||||
[hashtable]$LogSeverity = @{
|
||||
0 = 'Info';
|
||||
1 = 'Warning';
|
||||
2 = 'Error';
|
||||
3 = 'Exception';
|
||||
4 = 'Debug';
|
||||
};
|
||||
|
||||
[hashtable]$EventLogType = @{
|
||||
0 = 'Information';
|
||||
1 = 'Warning';
|
||||
2 = 'Error';
|
||||
3 = 'Error';
|
||||
4 = 'Information';
|
||||
};
|
||||
|
||||
[hashtable]$LogColor = @{
|
||||
0 = 'DarkGreen';
|
||||
1 = 'Yellow';
|
||||
2 = 'Red';
|
||||
3 = 'DarkRed';
|
||||
4 = 'Magenta';
|
||||
};
|
||||
|
||||
[hashtable]$ServiceStatus = @{
|
||||
'NotInstalled' = 'The Icinga service for this module is not installed. Please run Install-Icinga to install the service.';
|
||||
'Running' = 'The Icinga service is running.';
|
||||
'Stopped' = 'The Icinga service is not running.';
|
||||
'Starting' = 'The Icinga service is about to start.';
|
||||
'Stopping' = 'The Icinga service is shutting down.';
|
||||
}
|
||||
|
||||
[hashtable]$SCErrorCodes = @{
|
||||
5 = 'Failed to execute Icinga 2 Service operation: Permission denied.';
|
||||
1053 = 'Failed to start the Icinga 2 Service: The Service did not respond in time to the start or operation request.';
|
||||
1056 = 'Failed to start the Icinga 2 Service: The Service is already running.';
|
||||
1060 = 'Failed to apply action for Icinga 2 Service: The Service is not installed.';
|
||||
1062 = 'Failed to stop the Icinga 2 Service: The Service is not running.';
|
||||
1072 = 'Failed to uninstall the Icinga 2 Service: The Service is already marked for deletion.';
|
||||
1073 = 'Failed to install the Icinga 2 Service: The Service is already installed.';
|
||||
};
|
||||
|
||||
[hashtable]$HttpStatusCodes = @{
|
||||
200 = 'Ok';
|
||||
400 = 'Bad Request';
|
||||
401 = 'Unauthorized';
|
||||
403 = 'Forbidden';
|
||||
404 = 'Not Found'
|
||||
500 = 'Internal Server Error';
|
||||
};
|
||||
|
||||
<#
|
||||
# Once we defined a new enum hashtable above, simply add it to this list
|
||||
# to make it available within the entire module.
|
||||
#
|
||||
# Example usage:
|
||||
# $Icinga2.Enums.LogState.Info
|
||||
#>
|
||||
[hashtable]$Enums = @{
|
||||
LogSeverity = $LogSeverity;
|
||||
EventLogType = $EventLogType;
|
||||
LogColor = $LogColor;
|
||||
LogState = $LogState;
|
||||
ServiceStatus = $ServiceStatus;
|
||||
SCErrorCodes = $SCErrorCodes;
|
||||
HttpStatusCodes = $HttpStatusCodes;
|
||||
}
|
||||
|
||||
return $Enums;
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
<#
|
||||
# Handle the entire logging process of the module by sending the events
|
||||
# to console, the event log and if configured into an own log file.
|
||||
# This entire script will return a 'function' handler, dealing with
|
||||
# all events.
|
||||
# To create log events, simply use the following example:
|
||||
#
|
||||
# $Icinga2.Log.Write($Icinga2.Enums.LogState.Info, 'This is a info message');
|
||||
#>
|
||||
|
||||
$IcingaLogger = New-Object -TypeName PSObject;
|
||||
|
||||
$IcingaLogger | Add-Member -membertype NoteProperty -name 'noconsole' -value $FALSE;
|
||||
|
||||
$IcingaLogger | Add-Member -membertype ScriptMethod -name 'DisableConsole' -value {
|
||||
$this.noconsole = $TRUE;
|
||||
}
|
||||
|
||||
$IcingaLogger | Add-Member -membertype ScriptMethod -name 'Write' -value {
|
||||
param($Severity, [string]$Message);
|
||||
|
||||
# Only write debug output if enabled
|
||||
if ($Severity -eq $Icinga2.Enums.LogState.Debug -And $Icinga2.Config.'logger.debug' -eq $FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
[string]$SeverityToString = $this.GetSeverityAsString($Severity);
|
||||
|
||||
# Format a timestamp to get to know the exact date and time. Example: 2017-13-07 22:09:13.263.263
|
||||
$timestamp = Get-Date -Format "yyyy-dd-MM HH:mm:ss.fff";
|
||||
[string]$LogMessage = [string]::Format('{0} [{1}]: {2}', $timestamp, $SeverityToString, $Message);
|
||||
|
||||
$this.WriteConsole($Severity, $LogMessage);
|
||||
$this.WriteEventLog($Severity, $Message);
|
||||
$this.WriteLogFile($Severity, $LogMessage);
|
||||
}
|
||||
|
||||
$IcingaLogger | Add-Member -membertype ScriptMethod -name 'GetConsoleColorFromSeverity' -value {
|
||||
param([int]$Severity);
|
||||
|
||||
if ($Icinga2.Enums.LogColor.ContainsKey($Severity) -eq $FALSE) {
|
||||
return 'White';
|
||||
}
|
||||
|
||||
return $Icinga2.Enums.LogColor[$Severity];
|
||||
}
|
||||
|
||||
$IcingaLogger | Add-Member -membertype ScriptMethod -name 'GetSeverityAsString' -value {
|
||||
param([int]$Severity);
|
||||
|
||||
if ($Icinga2.Enums.LogSeverity.ContainsKey($Severity) -eq $FALSE) {
|
||||
return 'Undefined';
|
||||
}
|
||||
|
||||
return $Icinga2.Enums.LogSeverity[$Severity];
|
||||
}
|
||||
|
||||
$IcingaLogger | Add-Member -membertype ScriptMethod -name 'WriteLogFile' -value {
|
||||
param([int]$Severity, [string]$Message);
|
||||
|
||||
[string]$LogDirectory = $Icinga2.Config.'logger.directory';
|
||||
|
||||
if ([string]::IsNullOrEmpty($LogDirectory)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (-Not (Test-Path $LogDirectory)) {
|
||||
New-Item $LogDirectory -ItemType Directory | Out-Null;
|
||||
|
||||
# Something went wrong while trying to create the directory
|
||||
if (-Not (Test-Path $LogDirectory)) {
|
||||
$this.WriteConsole($Icinga2.Enums.LogState.Error,
|
||||
[string]::Format('Failed to create logfile directory at location "{0}"', $LogDirectory)
|
||||
)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[string]$LogFile = Join-Path $LogDirectory -ChildPath 'icinga2.log';
|
||||
|
||||
try {
|
||||
$LogStream = New-Object System.IO.FileStream(
|
||||
$LogFile,
|
||||
[System.IO.FileMode]::Append,
|
||||
[System.IO.FileAccess]::Write,
|
||||
[IO.FileShare]::Read
|
||||
);
|
||||
$LogWriter = New-Object System.IO.StreamWriter($LogStream);
|
||||
$LogWriter.writeLine($Message);
|
||||
} catch {
|
||||
$this.WriteConsole($Icinga2.Enums.LogState.Error,
|
||||
[string]::Format('Failed to write into logfile: "{0}"', $_.Exception.Message)
|
||||
)
|
||||
} finally {
|
||||
$LogWriter.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
$IcingaLogger | Add-Member -membertype ScriptMethod -name 'WriteEventLog' -value {
|
||||
param([int]$Severity, [string]$Message);
|
||||
|
||||
try {
|
||||
Write-EventLog -LogName "Application" `
|
||||
-Source $Icinga2.Service.servicedisplayname `
|
||||
-EventID (1000 + $Severity) `
|
||||
-EntryType $Icinga2.Enums.EventLogType.$Severity `
|
||||
-Message $Message `
|
||||
-Category $Severity `
|
||||
-ErrorAction Stop;
|
||||
} catch {
|
||||
$this.WriteLogFile(
|
||||
$Icinga2.Enums.LogState.Error,
|
||||
$_.Exception.Message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$IcingaLogger | Add-Member -membertype ScriptMethod -name 'WriteConsole' -value {
|
||||
param([int]$Severity, [string]$Message);
|
||||
|
||||
if ($this.noconsole) {
|
||||
return;
|
||||
}
|
||||
|
||||
Write-Host $Message -ForegroundColor ($this.GetConsoleColorFromSeverity($Severity))
|
||||
}
|
||||
|
||||
return $IcingaLogger;
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
$NetworkProtocol = New-Object -TypeName PSObject;
|
||||
|
||||
$NetworkProtocol | Add-Member -membertype NoteProperty -name 'static' -value $FALSE;
|
||||
$NetworkProtocol | Add-Member -membertype NoteProperty -name 'sslstream' -value $null;
|
||||
$NetworkProtocol | Add-Member -membertype NoteProperty -name 'networkstream' -value $null;
|
||||
$NetworkProtocol | Add-Member -membertype NoteProperty -name 'encrypted' -value $null;
|
||||
|
||||
$NetworkProtocol | Add-Member -membertype ScriptMethod -name 'Create' -value {
|
||||
param($Stream);
|
||||
|
||||
$this.networkstream = $Stream;
|
||||
$this.sslstream = $this.CreateSSLStream($Stream);
|
||||
}
|
||||
|
||||
$NetworkProtocol | Add-Member -membertype ScriptMethod -name 'CreateSSLStream' -value {
|
||||
param($Stream);
|
||||
|
||||
try {
|
||||
$sslStream = New-Object System.Net.Security.SslStream(
|
||||
$Stream,
|
||||
$false
|
||||
)
|
||||
$sslStream.AuthenticateAsServer(
|
||||
$Icinga2.Cache.Certificates.Server,
|
||||
0,
|
||||
[System.Security.Authentication.SslProtocols]::Tls,
|
||||
1
|
||||
);
|
||||
$sslStream.ReadTimeout = 2000;
|
||||
$this.encrypted = $TRUE;
|
||||
|
||||
return $sslStream;
|
||||
} catch [System.IO.IOException] {
|
||||
# Exceptions which occure when connecting from HTTP to this API, as we force HTTPS
|
||||
# Use the client's non-ssl stream to inform the user about our forced
|
||||
# HTTPS handling and set an internal variable to not send any data
|
||||
# to our client over HTTP
|
||||
$this.encrypted = $FALSE;
|
||||
$Stream.ReadTimeout = 2000;
|
||||
$Stream.WriteTimeout = 2000;
|
||||
return $Stream;
|
||||
} catch [System.NotSupportedException] {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
'The used SSL certificate is not providing a linked private key and cannot be used as Server certificate'
|
||||
);
|
||||
} catch {
|
||||
# Handle every other error here
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
$_.Exception.Message
|
||||
);
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
$_.Exception
|
||||
);
|
||||
}
|
||||
|
||||
return $null;
|
||||
}
|
||||
|
||||
$NetworkProtocol | Add-Member -membertype ScriptMethod -name 'ReadMessage' -value {
|
||||
param([int]$BytesToRead)
|
||||
|
||||
# If we have no bytes to read, do nothing
|
||||
if ($BytesToRead -eq 0) {
|
||||
return $null;
|
||||
}
|
||||
|
||||
[string]$content = '';
|
||||
[SecureString]$SecureContent = $null;
|
||||
[int]$TotalMessageSize = 0;
|
||||
# Define our buffer size to ensure we read a certain
|
||||
# amount of bytes each read attempt only
|
||||
[int]$BufferSize = 1024;
|
||||
# If we read the message and don't know if there is a content available
|
||||
# we have to read until we reach EOF. In case we have the exact size
|
||||
# of the content, we can read the possible rest
|
||||
[bool]$IsSizeKnown = $FALSE;
|
||||
|
||||
# This will allow us to read a fixed amount of data from our
|
||||
# stream and terminate the operation afterwards
|
||||
if ($BytesToRead -gt 0) {
|
||||
$BufferSize = $BytesToRead;
|
||||
$IsSizeKnown = $TRUE;
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
'Reading new message from TCP NetworkStream of Client'
|
||||
);
|
||||
|
||||
# Handle errors while reading the SSL Stream
|
||||
try {
|
||||
# Read the stream as long as we receive data from it
|
||||
while ($true) {
|
||||
|
||||
# Create a new byte array with a fixed buffer size
|
||||
[byte[]]$bytes = New-Object byte[] $BufferSize;
|
||||
|
||||
# Read the actual data from the stream
|
||||
$bytesRead = $this.sslstream.Read($bytes, 0, $bytes.Length);
|
||||
$TotalMessageSize += $bytesRead;
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format(
|
||||
'Reading {0} bytes from TCP connection',
|
||||
$bytesRead
|
||||
)
|
||||
);
|
||||
|
||||
# Build a output message from our received as string and perform
|
||||
# possible required cleanup in addition
|
||||
if ($bytesRead -ne 0) {
|
||||
[string]$message = [System.Text.Encoding]::UTF8.GetString($bytes);
|
||||
|
||||
# In case we receive a larger message, append the message content
|
||||
# to our string value
|
||||
$content = -Join(
|
||||
$content,
|
||||
$message
|
||||
);
|
||||
|
||||
# Ensure our output string is always matching the correct length
|
||||
# but only apply this in case we are unsure about the real length
|
||||
if ($IsSizeKnown -eq $FALSE) {
|
||||
$content = $content.Substring(
|
||||
0,
|
||||
$TotalMessageSize
|
||||
);
|
||||
}
|
||||
|
||||
# EOF reached or the amount of bytes to read was known
|
||||
# and we should abort here
|
||||
if ($content.Contains("`r`n`r`n") -Or $IsSizeKnown) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
# Might be good too remove this, as errors will occure very likely in case the SSLStream
|
||||
# timed out after 2 seconds because no new data have been received.
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
[string]::Format(
|
||||
'Failed to read Message from stream: {0}',
|
||||
$_.Exception.Message
|
||||
)
|
||||
);
|
||||
|
||||
return $null;
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format(
|
||||
'Finished reading {0} bytes from current NetworkMessage',
|
||||
$TotalMessageSize
|
||||
)
|
||||
);
|
||||
|
||||
# In case we read no message from the stream, we should do nothing
|
||||
if ($TotalMessageSize -eq 0) {
|
||||
return $null;
|
||||
}
|
||||
|
||||
$SecureContent = $Icinga2.Utils.SecureString.ConvertTo($content);
|
||||
$content = $null;
|
||||
|
||||
return $SecureContent;
|
||||
}
|
||||
|
||||
$NetworkProtocol | Add-Member -membertype ScriptMethod -name 'WriteMessage' -value {
|
||||
param($message);
|
||||
|
||||
try {
|
||||
$bytes = [System.Text.Encoding]::UTF8.GetBytes($message);
|
||||
$Client.SendBufferSize = $bytes.Length;
|
||||
$this.sslstream.Write($bytes, 0, $bytes.Length);
|
||||
$this.sslstream.Flush();
|
||||
} catch {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
'Failed to write message into data stream'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $NetworkProtocol;
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
$PidManager = New-Object -TypeName PSObject;
|
||||
|
||||
$PidManager | Add-Member -membertype ScriptMethod -name 'PidExists' -value {
|
||||
param([string]$bind);
|
||||
|
||||
[string]$PidFile = $this.PidFileName($bind);
|
||||
|
||||
return (Test-Path ($this.FullPidPath($PidFile)));
|
||||
}
|
||||
|
||||
$PidManager | Add-Member -membertype ScriptMethod -name 'CreatePidFile' -value {
|
||||
param([string]$bind);
|
||||
|
||||
[string]$PidFile = $this.PidFileName($bind);
|
||||
|
||||
Add-Content -Path ($this.FullPidPath($PidFile)) -Value $pid;
|
||||
}
|
||||
|
||||
$PidManager | Add-Member -membertype ScriptMethod -name 'PidFileName' -value {
|
||||
param([string]$bind);
|
||||
|
||||
return [string]::Format(
|
||||
'icingabind{0}.pid',
|
||||
$bind
|
||||
);
|
||||
}
|
||||
|
||||
$PidManager | Add-Member -membertype ScriptMethod -name 'FullPidPath' -value {
|
||||
param([string]$PidFile);
|
||||
|
||||
return (Join-Path $Icinga2.App.RootPath -ChildPath (
|
||||
[string]::Format(
|
||||
'\agent\state\{0}',
|
||||
$PidFile
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
$PidManager | Add-Member -membertype ScriptMethod -name 'ProcessID' -value {
|
||||
param([string]$FullPidFile);
|
||||
|
||||
if ((Test-Path $FullPidFile) -eq $FALSE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Get-Content -Path $FullPidFile;
|
||||
}
|
||||
|
||||
$PidManager | Add-Member -membertype ScriptMethod -name 'GetPIDByBind' -value {
|
||||
param([string]$bind);
|
||||
|
||||
return $this.ProcessID(
|
||||
$this.FullPidPath(
|
||||
$this.PidFileName(
|
||||
$bind
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$PidManager | Add-Member -membertype ScriptMethod -name 'GetPIDPathByBind' -value {
|
||||
param([string]$bind);
|
||||
|
||||
return $this.FullPidPath(
|
||||
$this.PidFileName(
|
||||
$bind
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$PidManager | Add-Member -membertype ScriptMethod -name 'RemovePidFile' -value {
|
||||
param([string]$FullPidPath, [string]$bind);
|
||||
|
||||
[string]$PidFile = $this.PidFileName($bind);
|
||||
|
||||
if (Test-Path $FullPidPath) {
|
||||
Remove-Item $FullPidPath | Out-Null;
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
[string]::Format(
|
||||
'Removing PID-File "{0}" for bind "{1}"',
|
||||
$PidFile,
|
||||
$bind
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
[string]::Format(
|
||||
'PID File "{0}" for bind "{1}" does not exist and could therefor not be removed',
|
||||
$PidFile,
|
||||
$bind
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$PidManager | Add-Member -membertype ScriptMethod -name 'PidProcess' -value {
|
||||
param([int]$ProcessID);
|
||||
|
||||
if ($ProcessID -eq 0) {
|
||||
return $null;
|
||||
}
|
||||
|
||||
# Look for the Process over WMI, as we might run as Service User and require
|
||||
# to fetch the entire scope of running processes
|
||||
$ProcessList = Get-WmiObject Win32_Process | Select-Object ProcessName, ProcessId -ErrorAction Stop;
|
||||
|
||||
foreach ($process in $ProcessList) {
|
||||
if ($process.ProcessId -eq $ProcessID) {
|
||||
if ($process.ProcessName -eq 'powershell.exe') {
|
||||
return $process;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $null;
|
||||
}
|
||||
|
||||
$PidManager | Add-Member -membertype ScriptMethod -name 'StopProcessByBind' -value {
|
||||
param([string]$bind);
|
||||
|
||||
if ($this.PidExists($bind)) {
|
||||
$ProcessId = $this.GetPIDByBind($bind);
|
||||
$this.ShutdownProcess($ProcessId);
|
||||
$this.RemovePidFile(
|
||||
$this.GetPIDPathByBind($bind),
|
||||
$bind
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$PidManager | Add-Member -membertype ScriptMethod -name 'ShutdownProcess' -value {
|
||||
param($ProcessID);
|
||||
|
||||
# Close possible PowerShell instances
|
||||
if ($Icinga2.PidManager.PidProcess($ProcessID) -ne $null) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
[string]::Format(
|
||||
'Trying to terminate process with PID "{0}"',
|
||||
$ProcessID
|
||||
)
|
||||
);
|
||||
Stop-Process -Id $ProcessID -Force;
|
||||
}
|
||||
}
|
||||
|
||||
return $PidManager;
|
||||
|
|
@ -1,223 +0,0 @@
|
|||
$ServerProtocoll = New-Object -TypeName PSObject;
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype NoteProperty -name 'static' -value $FALSE;
|
||||
$ServerProtocoll | Add-Member -membertype NoteProperty -name 'Client' -value $Null;
|
||||
$ServerProtocoll | Add-Member -membertype NoteProperty -name 'Network' -value (Get-Icinga-Lib -Include 'NetworkProtocol');
|
||||
$ServerProtocoll | Add-Member -membertype NoteProperty -name 'Response' -value (Get-Icinga-Lib -Include 'APIResponse');
|
||||
$ServerProtocoll | Add-Member -membertype NoteProperty -name 'Timer' -value $Null;
|
||||
$ServerProtocoll | Add-Member -membertype NoteProperty -name 'Message' -value $Null;
|
||||
$ServerProtocoll | Add-Member -membertype NoteProperty -name 'Commands' -value @{};
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'Create' -value {
|
||||
param([System.Net.Sockets.TcpClient]$Client);
|
||||
|
||||
$this.Client = $Client;
|
||||
$this.Client.SendTimeout = 2000
|
||||
$this.Client.NoDelay = $TRUE;
|
||||
|
||||
$this.Timer = [System.Diagnostics.Stopwatch]::StartNew();
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
'New incoming TCP Client connection'
|
||||
);
|
||||
|
||||
$this.Network.Create($Client.GetStream());
|
||||
|
||||
# Just in case we received connections over HTTP, send a short answer message
|
||||
# back and close the client request
|
||||
if ($this.Network.encrypted -eq $FALSE) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
'Received client connection over HTTP. Rejecting client request.'
|
||||
);
|
||||
$this.Response.HTTPSRequired();
|
||||
$this.Network.WriteMessage(
|
||||
$this.Response.Compile()
|
||||
);
|
||||
$this.Close();
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
return $TRUE;
|
||||
}
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'ParseRequest' -value {
|
||||
# Tell our network protocol to read all messages until
|
||||
# EOF is reached
|
||||
[SecureString]$message = $this.Network.ReadMessage(-1);
|
||||
|
||||
if ($message -eq $null) {
|
||||
return;
|
||||
}
|
||||
|
||||
[hashtable]$ApiMessage = $Icinga2.Utils.WebHelper.ParseApiMessage($message);
|
||||
|
||||
if ($ApiMessage -eq $null -Or $ApiMessage.Count -eq 0) {
|
||||
$this.SendInternalServerError();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Icinga2.Config.'authentication.enabled') {
|
||||
[int]$Authenticated = $Icinga2.Utils.AuthHelper.Login(
|
||||
$ApiMessage.credentials.user,
|
||||
$ApiMessage.credentials.password,
|
||||
$ApiMessage.credentials.domain
|
||||
);
|
||||
if ($Authenticated -eq 0) {
|
||||
$this.SendAuthenticationRequired();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($ApiMessage.headers.ContainsKey('content-length')) {
|
||||
[int]$ContentLength = ($ApiMessage.headers['content-length'] - $ApiMessage.content.Length);
|
||||
$ApiMessage.content += $Icinga2.Utils.SecureString.ConvertFrom(
|
||||
$this.Network.ReadMessage(
|
||||
$ContentLength
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this.Message = $ApiMessage;
|
||||
$this.ParseQuery();
|
||||
$this.ExecuteQuery();
|
||||
}
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'ParseQuery' -value {
|
||||
[string]$QueryString = $this.Message.base.query;
|
||||
if ($QueryString[0] -eq '?') {
|
||||
$QueryString = $QueryString.Substring(
|
||||
1,
|
||||
$QueryString.Length - 1
|
||||
);
|
||||
}
|
||||
|
||||
[array]$SplitCommand = $QueryString.Split('&');
|
||||
foreach ($command in $SplitCommand) {
|
||||
[hashtable]$data = $Icinga2.Utils.WebHelper.ParseUrlCommand($command);
|
||||
if ($this.Commands.ContainsKey(($data.GetEnumerator() | Select-Object -First 1).Key) -eq $FALSE) {
|
||||
$this.Commands += $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'ExecuteQuery' -value {
|
||||
switch($this.IsUrlPathValid(0)) {
|
||||
'' {
|
||||
switch($this.IsUrlPathValid(1)) {
|
||||
'v1' {
|
||||
switch($this.IsUrlPathValid(2)) {
|
||||
'data' {
|
||||
$this.ParseDataV1();
|
||||
};
|
||||
'modules' {
|
||||
$this.ParseModulesV1();
|
||||
};
|
||||
default {
|
||||
$this.SendBadRequest(
|
||||
'Unsupported Cmdlets specified. The following Cmdlets are supported: data, modules'
|
||||
);
|
||||
};
|
||||
}
|
||||
};
|
||||
default {
|
||||
$this.SendBadRequest(
|
||||
'Unsupported API version specified. The following versions are supported: v1'
|
||||
);
|
||||
};
|
||||
}
|
||||
};
|
||||
default {
|
||||
$this.SendInternalServerError();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'GetExecutionTime' -value {
|
||||
return $this.Timer.Elapsed.TotalSeconds;
|
||||
}
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'ParseDataV1' -value {
|
||||
[hashtable]$data =
|
||||
@{
|
||||
data = New-Icinga-Monitoring -Include $this.Commands.include -Exclude $this.Commands.exclude;
|
||||
execution = $this.GetExecutionTime();
|
||||
};
|
||||
|
||||
$this.Response.setContent($data);
|
||||
$this.SendOkResponse();
|
||||
}
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'ParseModulesV1' -value {
|
||||
[hashtable]$modules =
|
||||
@{
|
||||
modules = New-Icinga-Monitoring -ListModules $TRUE;
|
||||
execution = $this.GetExecutionTime();
|
||||
};
|
||||
|
||||
$this.Response.setContent($modules);
|
||||
$this.SendOkResponse();
|
||||
}
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'IsUrlPathValid' -value {
|
||||
param([int]$Index);
|
||||
|
||||
[string]$path = $this.Message.base.segments[$Index];
|
||||
|
||||
if ([string]::IsNullOrEmpty($path) -eq $TRUE) {
|
||||
return 'default';
|
||||
}
|
||||
|
||||
return $path.Replace('/', '');
|
||||
}
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'SendOkResponse' -value {
|
||||
$this.Network.WriteMessage(
|
||||
$this.Response.Compile()
|
||||
);
|
||||
$this.Close();
|
||||
}
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'SendInternalServerError' -value {
|
||||
$this.Response.InternalServerError();
|
||||
$this.Network.WriteMessage(
|
||||
$this.Response.Compile()
|
||||
);
|
||||
$this.Close();
|
||||
}
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'SendAuthenticationRequired' -value {
|
||||
$this.Response.AuthenticationRequired();
|
||||
$this.Network.WriteMessage(
|
||||
$this.Response.Compile()
|
||||
);
|
||||
$this.Close();
|
||||
}
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'SendBadRequest' -value {
|
||||
param([string]$message);
|
||||
|
||||
$this.Response.CustomBadRequest($message);
|
||||
$this.Network.WriteMessage(
|
||||
$this.Response.Compile()
|
||||
);
|
||||
$this.Close();
|
||||
}
|
||||
|
||||
$ServerProtocoll | Add-Member -membertype ScriptMethod -name 'Close' -value {
|
||||
try {
|
||||
$this.Timer.Stop();
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
'Closing TCP Client connection'
|
||||
)
|
||||
$this.Client.Close();
|
||||
$this.Client.Dispose()
|
||||
$this.Client = $Null;
|
||||
} catch {
|
||||
# Nothing to handle. If the connection is closed already, ignore it.
|
||||
}
|
||||
}
|
||||
|
||||
return $ServerProtocoll;
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
$Service = New-Object -TypeName PSObject;
|
||||
|
||||
$Service | Add-Member -membertype NoteProperty -name 'servicename' -value 'IcingaWindowsModule';
|
||||
$Service | Add-Member -membertype NoteProperty -name 'servicedisplayname' -value 'Icinga Windows Service';
|
||||
|
||||
$Service | Add-Member -membertype ScriptMethod -name 'Install' -value {
|
||||
param([string]$ServiceBinaryPath);
|
||||
|
||||
if ([string]::IsNullOrEmpty($ServiceBinaryPath) -eq $TRUE) {
|
||||
return 'Please specify a valid service binary path.';
|
||||
}
|
||||
|
||||
# Test if our binary does exist
|
||||
if (-Not (Test-Path $ServiceBinaryPath)) {
|
||||
return ([string]::Format(
|
||||
'Failed to install the Icinga service. The service binary specified at "{0}" does not exist.',
|
||||
$ServiceBinaryPath
|
||||
));
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'Trying to install Icinga 2 Service...'
|
||||
);
|
||||
|
||||
# Now add the script root which we require to include to the service
|
||||
$ServiceBinaryPath = [string]::Format(
|
||||
'{0} \"{1}\"',
|
||||
$ServiceBinaryPath,
|
||||
(Join-Path -Path $Icinga2.App.RootPath -ChildPath $Icinga2.App.ModuleName)
|
||||
);
|
||||
|
||||
$result = & sc.exe create $this.servicename binPath= "$ServiceBinaryPath" DisplayName= $this.servicedisplayname start= auto;
|
||||
|
||||
if ($this.HandleServiceError($LASTEXITCODE) -eq $TRUE) {
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'Successfully installed the Icinga 2 Windows Service.'
|
||||
);
|
||||
|
||||
return $TRUE;
|
||||
}
|
||||
|
||||
$Service | Add-Member -membertype ScriptMethod -name 'Uninstall' -value {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'Trying to uninstall Icinga Service...'
|
||||
);
|
||||
|
||||
# Stop the service before uninstalling it
|
||||
$this.Stop();
|
||||
|
||||
$result = & sc.exe delete $this.servicename;
|
||||
|
||||
if ($this.HandleServiceError($LASTEXITCODE) -eq $TRUE) {
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'Successfully uninstalled the Icinga 2 Windows Service.'
|
||||
);
|
||||
|
||||
return $TRUE;
|
||||
}
|
||||
|
||||
$Service | Add-Member -membertype ScriptMethod -name 'Start' -value {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'Trying to start Icinga 2 Service...'
|
||||
);
|
||||
|
||||
$result = & sc.exe start $this.servicename;
|
||||
|
||||
if ($this.HandleServiceError($LASTEXITCODE) -eq $TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'Successfully started the Icinga 2 Service.'
|
||||
);
|
||||
|
||||
$this.QueryStatus();
|
||||
}
|
||||
|
||||
$Service | Add-Member -membertype ScriptMethod -name 'Stop' -value {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'Trying to stop Icinga 2 Service...'
|
||||
);
|
||||
|
||||
$result = & sc.exe stop ($this.servicename);
|
||||
|
||||
if ($this.HandleServiceError($LASTEXITCODE) -eq $TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'Successfully stopped the Icinga 2 Service.'
|
||||
);
|
||||
|
||||
$this.QueryStatus();
|
||||
}
|
||||
|
||||
$Service | Add-Member -membertype ScriptMethod -name 'Restart' -value {
|
||||
$this.Stop();
|
||||
# Wait two seconds before starting the service again
|
||||
Start-Sleep -Seconds 2;
|
||||
$this.Start();
|
||||
}
|
||||
|
||||
$Service | Add-Member -membertype ScriptMethod -name 'QueryStatus' -value {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'Waiting to query the proper Icinga 2 Service status...'
|
||||
);
|
||||
Start-Sleep -Seconds 1;
|
||||
|
||||
$this.Status();
|
||||
}
|
||||
|
||||
$Service | Add-Member -membertype ScriptMethod -name 'Status' -value {
|
||||
$ServiceStatus = (Get-WMIObject win32_service -Filter (
|
||||
[string]::Format(
|
||||
"Name='{0}'",
|
||||
($this.servicename)
|
||||
)
|
||||
)).State;
|
||||
|
||||
if ([string]::IsNullOrEmpty($ServiceStatus) -eq $TRUE) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
$Icinga2.Enums.ServiceStatus.NotInstalled
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Icinga2.Enums.ServiceStatus.ContainsKey($ServiceStatus)) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
$Icinga2.Enums.ServiceStatus.$ServiceStatus
|
||||
);
|
||||
} else {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
[string]::Format(
|
||||
'The Icinga service status is {0}',
|
||||
$ServiceStatus
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$Service | Add-Member -membertype ScriptMethod -name 'HandleServiceError' -value {
|
||||
param([int]$ErrorCode);
|
||||
|
||||
# Nothing to do as no error occured
|
||||
if ($ErrorCode -eq 0) {
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
if ($Icinga2.Enums.SCErrorCodes.ContainsKey($ErrorCode)) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Error,
|
||||
$Icinga2.Enums.SCErrorCodes.$ErrorCode
|
||||
);
|
||||
} else {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Error,
|
||||
([string]::Format('Failed to execute operation for Icinga 2 Service: {0}', $result))
|
||||
);
|
||||
}
|
||||
|
||||
return $TRUE;
|
||||
}
|
||||
|
||||
return $Service;
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
$SystemCPU = Get-CimInstance -ClassName 'Win32_Processor';
|
||||
|
||||
[int]$NumberOfCPUCores = 0;
|
||||
[int]$NumberOfCPUThreads = 0;
|
||||
|
||||
if (($SystemCPU.NumberOfCores).GetType() -is [Object]) {
|
||||
$SystemCPU.NumberOfCores | Foreach { $NumberOfCPUCores += $_; };
|
||||
} else {
|
||||
$NumberOfCPUCores = $SystemCPU.NumberOfCores;
|
||||
}
|
||||
|
||||
if (($SystemCPU.NumberOfLogicalProcessors).GetType() -is [Object]) {
|
||||
$SystemCPU.NumberOfLogicalProcessors | Foreach { $NumberOfCPUThreads += $_; };
|
||||
} else {
|
||||
$NumberOfCPUThreads = $SystemCPU.NumberOfCores;
|
||||
}
|
||||
|
||||
[hashtable]$Overview = @{
|
||||
'NumberOfCPUCores' = $NumberOfCPUCores;
|
||||
'NumberOfCPUThreads' = $NumberOfCPUThreads;
|
||||
};
|
||||
|
||||
return $Overview;
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
$TCPDaemon = New-Object -TypeName PSObject;
|
||||
|
||||
$TCPDaemon | Add-Member -membertype ScriptMethod -name 'Start' -value {
|
||||
|
||||
[int]$Port = $Icinga2.Config.'tcp.socket.port';
|
||||
|
||||
if (-Not $Icinga2.Cache.Certificates.Server) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Error,
|
||||
[string]::Format(
|
||||
'Unable to start TCP socket daemon for port {0}. No valid SSL certificate was loaded.',
|
||||
$Port
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Icinga2.TCPSocket.IsSocketOpenAndValid($Port) -eq $TRUE) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
[string]::Format(
|
||||
'A PowerShell instance for socket on port "{0}" is already running with PID "{1}"',
|
||||
$Port,
|
||||
$Icinga2.PidManager.GetPIDByBind($port)
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
$TCPSocket = $Icinga2.TCPSocket.CreateTCPSocket($Port);
|
||||
|
||||
if ($TCPSocket -eq $null) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Error,
|
||||
[string]::Format(
|
||||
'Failed to start TCP socket on port "{0}"',
|
||||
$Port
|
||||
)
|
||||
)
|
||||
return;
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
[string]::Format(
|
||||
'Starting new API listener on port "{0}"',
|
||||
$Port
|
||||
)
|
||||
);
|
||||
|
||||
while($true) {
|
||||
[System.Net.Sockets.TcpClient]$client = $TCPSocket.AcceptTcpClient();
|
||||
|
||||
$ServerProtocol = Get-Icinga-Lib -Include 'ServerProtocol';
|
||||
if ($ServerProtocol.Create($Client) -eq $FALSE) {
|
||||
continue;
|
||||
}
|
||||
$ServerProtocol.ParseRequest();
|
||||
}
|
||||
|
||||
$Icinga2.TCPSocket.CloseTCPSocket($Port);
|
||||
}
|
||||
|
||||
$TCPDaemon | Add-Member -membertype ScriptMethod -name 'Stop' -value {
|
||||
if ($Icinga2.Utils.AdminShell.IsAdminShell() -eq $FALSE) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Error,
|
||||
'Please run this shell as Administrator in order to stop daemon processes'
|
||||
);
|
||||
return;
|
||||
}
|
||||
[int]$Port = $Icinga2.Config.'tcp.socket.port';
|
||||
$Icinga2.TCPSocket.CloseTCPSocket($Port);
|
||||
|
||||
}
|
||||
|
||||
return $TCPDaemon;
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
$TCPSocket = New-Object -TypeName PSObject;
|
||||
|
||||
$TCPSocket | Add-Member -membertype ScriptMethod -name 'CreateTCPSocket' -value {
|
||||
param([int]$port);
|
||||
|
||||
[string]$PidFile = $Icinga2.PidManager.PidFileName($port);
|
||||
|
||||
try {
|
||||
$TCPSocket = [System.Net.Sockets.TcpListener]$port;
|
||||
$TCPSocket.Start();
|
||||
$Icinga2.Cache.Sockets.Add($PidFile, $TCPSocket);
|
||||
$Icinga2.PidManager.CreatePidFile($port);
|
||||
|
||||
return $TCPSocket;
|
||||
} catch {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
[string]::Format(
|
||||
'Failed to create TCP socket on port "{0}": {1}',
|
||||
$port,
|
||||
$_.Exception.Message
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $null;
|
||||
}
|
||||
|
||||
# Properly close sockets, flush PID Files or terminate PowerShell instances as owner of sockets
|
||||
$TCPSocket | Add-Member -membertype ScriptMethod -name 'CloseTCPSocket' -value {
|
||||
param([int]$port);
|
||||
|
||||
[string]$PidFile = $Icinga2.PidManager.PidFileName($port);
|
||||
[bool]$IsExternalSocket = $FALSE;
|
||||
|
||||
# Clear our Socket cache
|
||||
# In case the socket does not exist, create a new socket
|
||||
if ($Icinga2.Cache.Sockets.ContainsKey($PidFile) -eq $FALSE) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
[string]::Format(
|
||||
'The socket of port "{0}" is not part of this PowerShell instance',
|
||||
$port
|
||||
)
|
||||
);
|
||||
$IsExternalSocket = $TRUE;
|
||||
} else {
|
||||
try {
|
||||
$TCPSocket = $Icinga2.Cache.Sockets.$PidFile;
|
||||
$TCPSocket.Stop();
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
[string]::Format(
|
||||
'Closing TCP socket on port "{0}"',
|
||||
$port
|
||||
)
|
||||
);
|
||||
} catch {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
[string]::Format(
|
||||
'Failed to close TCP socket on port "{0}": {1}',
|
||||
$port,
|
||||
$_.Exception.Message
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$Icinga2.Cache.Sockets.Remove($PidFile);
|
||||
}
|
||||
|
||||
# Delete the PID file from disk in case it exists
|
||||
[string]$FullPidPath = $Icinga2.PidManager.FullPidPath($PidFile);
|
||||
[int]$ProcessID = $Icinga2.PidManager.ProcessID($FullPidPath);
|
||||
|
||||
$Icinga2.PidManager.RemovePidFile($FullPidPath);
|
||||
|
||||
# Close possible PowerShell instances
|
||||
if ($Icinga2.PidManager.PidProcess($ProcessID) -ne $null) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
[string]::Format(
|
||||
'Trying to terminate process with PID "{0}"',
|
||||
$ProcessID
|
||||
)
|
||||
);
|
||||
Stop-Process -Id $ProcessID -Force;
|
||||
}
|
||||
}
|
||||
|
||||
$TCPSocket | Add-Member -membertype ScriptMethod -name 'IsSocketOpenAndValid' -value {
|
||||
param([int]$port);
|
||||
|
||||
[string]$PidFile = $Icinga2.PidManager.PidFileName($port);
|
||||
|
||||
[string]$FullPidPath = $Icinga2.PidManager.FullPidPath($PidFile);
|
||||
|
||||
if ((Test-Path $FullPidPath) -eq $FALSE) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
[string]::Format(
|
||||
'No PID-File found for TCP socket on port "{0}". Trying to close socket...',
|
||||
$port
|
||||
)
|
||||
);
|
||||
|
||||
# Even when the PID-File does not exist, try to gracefull shutdown the socket
|
||||
$this.CloseTCPSocket($port);
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
[int]$ProcessID = $Icinga2.PidManager.ProcessID($FullPidPath);
|
||||
|
||||
if ([string]::IsNullOrEmpty($ProcessID) -eq $TRUE) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
[string]::Format(
|
||||
'No process ID found for socket on port "{0}". Trying to close socket anyway...',
|
||||
$port
|
||||
)
|
||||
);
|
||||
|
||||
# Even when the PID-File does not exist, try to gracefull shutdown the socket
|
||||
$this.CloseTCPSocket($port);
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
try {
|
||||
# Look for the Process over WMI, as we might run as Service User and require
|
||||
# to fetch the entire scope of running processes
|
||||
if ($Icinga2.PidManager.PidProcess($ProcessID) -ne $null) {
|
||||
return $TRUE;
|
||||
}
|
||||
|
||||
# Socket does not exist or is not valid. Perform a cleanup and return false
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
[string]::Format(
|
||||
'The socket configuration for port "{0}" is not valid. Performing cleanup...',
|
||||
$port
|
||||
)
|
||||
);
|
||||
|
||||
$this.CloseTCPSocket($port);
|
||||
return $FALSE;
|
||||
} catch [System.Exception] {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
[string]::Format(
|
||||
'Exception while trying to lookup the process for socket port "{0}": {1}...',
|
||||
$port,
|
||||
$_.Exception.Message
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this.CloseTCPSocket($port);
|
||||
return $FALSE;
|
||||
}
|
||||
|
||||
return $TCPSocket;
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# Provide a collection of utility functions for the module
|
||||
[hashtable]$Utils = @{};
|
||||
|
||||
Get-ChildItem (Join-Path -Path $PSScriptRoot -ChildPath '\utils\') -Filter *.ps1 |
|
||||
Foreach-Object {
|
||||
$path = $_.FullName;
|
||||
$name = $_.Name.Replace('.ps1', '');
|
||||
|
||||
$Utils.Add($name, (& $path));
|
||||
}
|
||||
|
||||
return $Utils;
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
$AdminShell = New-Object -TypeName PSObject;
|
||||
$AdminShell | Add-Member -membertype ScriptMethod -name 'IsAdminShell' -value {
|
||||
$CurrentIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent();
|
||||
$WindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($CurrentIdentity);
|
||||
|
||||
if (-Not $WindowsPrincipal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
return $FALSE;
|
||||
}
|
||||
return $TRUE;
|
||||
}
|
||||
|
||||
return $AdminShell;
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
Add-Type -AssemblyName System.DirectoryServices.AccountManagement;
|
||||
|
||||
$AuthHelper = New-Object -TypeName PSObject;
|
||||
|
||||
<#
|
||||
# This function will allow us to authenticate against either a
|
||||
# Domain Controller or the local machine the module runs on.
|
||||
# For security reasons, Username and Password have to be
|
||||
# stored within a SecureString. If no Domain is specified,
|
||||
# a login will always be attempted to the local machine
|
||||
#>
|
||||
$AuthHelper | Add-Member -membertype ScriptMethod -name 'Login' -value {
|
||||
param([SecureString]$UserName, [SecureString]$Password, [String]$Domain);
|
||||
|
||||
# Base handling: We try to authenticate against a local user on the machine
|
||||
[string]$AuthMethod = [System.DirectoryServices.AccountManagement.ContextType]::Machine;
|
||||
[string]$AuthDomain = $env:COMPUTERNAME;
|
||||
|
||||
# If we specify a domain, we should authenticate against our Domain
|
||||
if ([string]::IsNullOrEmpty($Domain) -eq $FALSE) {
|
||||
$AuthMethod = [System.DirectoryServices.AccountManagement.ContextType]::Domain;
|
||||
$AuthDomain = $Domain;
|
||||
}
|
||||
|
||||
try {
|
||||
# Create an Account Management object based on the above determined settings
|
||||
$AccountService = New-Object System.DirectoryServices.AccountManagement.PrincipalContext(
|
||||
$AuthMethod,
|
||||
$AuthDomain
|
||||
);
|
||||
} catch {
|
||||
# Regardless of the error, print the message and return false to prevent further execution
|
||||
$Icinga2.Log.Write($Icinga2.Enums.LogState.Exception, $_.Exception.Message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
# In case we couldn't setup the Account Service, always return false
|
||||
if ($AccountService -eq $null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
# Try to authenticate and either return true or false as integer
|
||||
[int]$AuthResult = [int]($AccountService.ValidateCredentials(
|
||||
$Icinga2.Utils.SecureString.ConvertFrom($UserName),
|
||||
$Icinga2.Utils.SecureString.ConvertFrom($Password)
|
||||
));
|
||||
|
||||
return $AuthResult;
|
||||
} catch {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format(
|
||||
'Failed to authenticate with the provided user credentials. Error: {0}',
|
||||
$_.Exception.Message
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $AuthHelper;
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
<#
|
||||
# Helper class allowing to read INI files basicly
|
||||
# and return the content as Hashtable
|
||||
#>
|
||||
|
||||
$IniParser = New-Object -TypeName PSObject;
|
||||
|
||||
$IniParser | Add-Member -membertype ScriptMethod -name 'LoadFromArray' -value {
|
||||
param([array]$content, [bool]$CutLastSpace);
|
||||
|
||||
[hashtable]$IniContent = @{};
|
||||
[string]$IniKey = '';
|
||||
[string]$SubIniKey = '';
|
||||
|
||||
# First, loop all lines of our NTP config
|
||||
foreach ($item in $content) {
|
||||
# At first we require to parse the section argument for the config
|
||||
if ($item.Contains('[')) {
|
||||
$IniKey = $item.Replace('[', '').Replace(']', '');
|
||||
$IniContent.Add($IniKey, @{ });
|
||||
continue;
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($item) -eq $TRUE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
# In case our entry does not contain ':', we are not loading a config entry
|
||||
if ($item.Contains(':') -eq $FALSE) {
|
||||
$SubIniKey = $item;
|
||||
$IniContent[$IniKey].Add($SubIniKey, @{ });
|
||||
continue;
|
||||
}
|
||||
|
||||
# Now as we found an config entry point, split the result at first to get
|
||||
# the key of our config. Afterwards we load the value by removing all
|
||||
# spaces before the actual value
|
||||
[array]$ConfigData = $item.Split(':');
|
||||
[string]$ConfigKey = $ConfigData[0];
|
||||
[string]$ConfigValue = $item.Substring($item.IndexOf(':') + 1, $item.Length - $item.IndexOf(':') - 1);
|
||||
|
||||
# Some INI files (like NTP) add additional details behind the values if they
|
||||
# are configured by Local or Remote for example. With this we can cut these
|
||||
# informations out, idependently from our configured OS language
|
||||
if ($CutLastSpace -eq $TRUE) {
|
||||
$ConfigValue = $ConfigValue.Substring(0, $ConfigValue.LastIndexOf(' '));
|
||||
}
|
||||
|
||||
while ($ConfigValue[0] -eq ' ') {
|
||||
$ConfigValue = $ConfigValue.Substring(1, $ConfigValue.Length - 1);
|
||||
}
|
||||
|
||||
# It could happen that within a section keys are being overwritten again
|
||||
# We should take care of this and update a possible added key with the
|
||||
# next configured values to receive only the correct configuration as result
|
||||
# as it is interpreted by the time service
|
||||
if ([string]::IsNullOrEmpty($SubIniKey) -eq $TRUE) {
|
||||
if ($IniContent[$IniKey].ContainsKey($ConfigKey) -eq $FALSE) {
|
||||
$IniContent[$IniKey].Add($ConfigKey, $ConfigValue);
|
||||
} else {
|
||||
$IniContent[$IniKey][$ConfigKey] = $ConfigValue;
|
||||
}
|
||||
} else {
|
||||
if ($IniContent[$IniKey][$SubIniKey].ContainsKey($ConfigKey) -eq $FALSE) {
|
||||
$IniContent[$IniKey][$SubIniKey].Add($ConfigKey, $ConfigValue);
|
||||
} else {
|
||||
$IniContent[$IniKey][$SubIniKey][$ConfigKey] = $ConfigValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $IniContent;
|
||||
}
|
||||
|
||||
return $IniParser;
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
<#
|
||||
# Helper class for accessing and handling modules in a
|
||||
# more easier and managed way
|
||||
#>
|
||||
|
||||
$Modules = New-Object -TypeName PSObject;
|
||||
|
||||
$Modules | Add-Member -membertype ScriptMethod -name 'LoadIncludes' -value {
|
||||
param([string]$modulename, $Config);
|
||||
|
||||
$modulename = $modulename.ToLower();
|
||||
$modulename = $modulename.Replace('.ps1', '');
|
||||
|
||||
[string]$ModuleDir = Join-Path `
|
||||
-Path $Icinga2.App.RootPath `
|
||||
-ChildPath (
|
||||
[string]::Format(
|
||||
'\modules\include\{0}',
|
||||
$modulename
|
||||
)
|
||||
)
|
||||
|
||||
[hashtable]$ModuleIndludes = @{};
|
||||
|
||||
if ( (Test-Path $ModuleDir) -eq $FALSE) {
|
||||
return $ModuleIndludes;
|
||||
}
|
||||
|
||||
Get-ChildItem $ModuleDir -Filter *.ps1 |
|
||||
Foreach-Object {
|
||||
[string]$name = $_.Name.ToLower().Replace(
|
||||
'.ps1',
|
||||
''
|
||||
);
|
||||
try {
|
||||
$ModuleIndludes.Add(
|
||||
$name,
|
||||
(& $_.FullName -Config $Config)
|
||||
);
|
||||
} catch {
|
||||
$ModuleIndludes.Add(
|
||||
$name,
|
||||
[string]::Format(
|
||||
'Failed to execute include "{0}" for module "{1}". Exception: {2}',
|
||||
$name,
|
||||
$modulename,
|
||||
$_.Exception.Message
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $ModuleIndludes;
|
||||
}
|
||||
|
||||
$Modules | Add-Member -membertype ScriptMethod -name 'FlushModuleCache' -value {
|
||||
param([string]$modulename);
|
||||
|
||||
if ($Icinga2.Cache.Modules.ContainsKey($modulename) -eq $FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$Icinga2.Cache.Modules[$modulename] = @{ };
|
||||
}
|
||||
|
||||
$Modules | Add-Member -membertype ScriptMethod -name 'AddCacheElement' -value {
|
||||
param([string]$modulename, [string]$cachename, $value);
|
||||
|
||||
if ($Icinga2.Cache.Modules.ContainsKey($modulename) -eq $FALSE) {
|
||||
$Icinga2.Cache.Modules.Add($modulename, @{ });
|
||||
}
|
||||
|
||||
if ($Icinga2.Cache.Modules[$modulename].ContainsKey($cachename) -eq $FALSE) {
|
||||
$Icinga2.Cache.Modules[$modulename].Add($cachename, $value);
|
||||
} else {
|
||||
$Icinga2.Cache.Modules[$modulename][$cachename] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$Modules | Add-Member -membertype ScriptMethod -name 'GetCacheElement' -value {
|
||||
param([string]$modulename, [string]$cachename);
|
||||
|
||||
if ($Icinga2.Cache.Modules.ContainsKey($modulename) -eq $FALSE) {
|
||||
return @{ };
|
||||
}
|
||||
|
||||
if ($Icinga2.Cache.Modules[$modulename].ContainsKey($cachename) -eq $FALSE) {
|
||||
return @{ };
|
||||
}
|
||||
|
||||
return $Icinga2.Cache.Modules[$modulename][$cachename];
|
||||
}
|
||||
|
||||
$Modules | Add-Member -membertype ScriptMethod -name 'GetHashtableDiff' -value {
|
||||
param([hashtable]$new, [hashtable]$cache, [array]$addkeys);
|
||||
|
||||
[hashtable]$DiffTable = @{
|
||||
FullList = @{ };
|
||||
Removed = @( );
|
||||
Added = $null;
|
||||
Modified = @{ };
|
||||
}
|
||||
|
||||
if ($cache -eq $null -or $cache.Count -eq 0) {
|
||||
$DiffTable.FullList = $new;
|
||||
} else {
|
||||
# Each additional call will only send the diffs to the server
|
||||
$int = 0;
|
||||
foreach ($cachedProcess in $cache.Keys) {
|
||||
$oldProcess = $cache[$cachedProcess];
|
||||
|
||||
# In case a service is no longer present on our system, send the process Id
|
||||
# only so we can delete it from our database
|
||||
if ($new.ContainsKey($cachedProcess) -eq $FALSE) {
|
||||
$DiffTable['Removed'] += $oldProcess.ProcessId;
|
||||
} else {
|
||||
# If we know about a process, only send the values which have been updated
|
||||
# since the last check
|
||||
$newProcess = $new[$cachedProcess];
|
||||
|
||||
foreach ($entry in $newProcess.Keys) {
|
||||
$oldValue = $oldProcess[$entry];
|
||||
$newValue = $newProcess[$entry];
|
||||
|
||||
if ($oldValue -ne $newValue) {
|
||||
if ($DiffTable['Modified'].ContainsKey($cachedProcess) -eq $FALSE) {
|
||||
$DiffTable['Modified'].Add($cachedProcess, @{ });
|
||||
}
|
||||
$DiffTable['Modified'][$cachedProcess].Add($entry, $newValue);
|
||||
}
|
||||
}
|
||||
|
||||
if ($DiffTable['Modified'].ContainsKey($cachedProcess) -eq $TRUE) {
|
||||
foreach($entry in $addkeys) {
|
||||
if ($DiffTable['Modified'][$cachedProcess].ContainsKey($entry) -eq $FALSE -and
|
||||
$newProcess.ContainsKey($entry) -eq $TRUE) {
|
||||
|
||||
$DiffTable['Modified'][$cachedProcess].Add($entry, $newProcess[$entry]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$new.Remove($cachedProcess);
|
||||
}
|
||||
}
|
||||
|
||||
# All other processes are new and should be added
|
||||
$DiffTable['Added'] = $new;
|
||||
}
|
||||
|
||||
return $DiffTable;
|
||||
}
|
||||
|
||||
return $Modules;
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
|
||||
$SSL = New-Object -TypeName PSObject;
|
||||
$SSL | Add-Member -membertype ScriptMethod -name 'LoadServerCertificate' -value {
|
||||
|
||||
if ((Get-Icinga-Setup) -eq $FALSE) {
|
||||
$Icinga2.Log.WriteConsole(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
'The module has not been configured yet. Skipping certificate loading'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$CertStore = New-Object System.Security.Cryptography.X509Certificates.X509Store(
|
||||
$Icinga2.Config.'certstore.name',
|
||||
$Icinga2.Config.'certstore.location'
|
||||
);
|
||||
$CertStore.Open("ReadOnly");
|
||||
|
||||
$ServerCertificate = $null;
|
||||
|
||||
[string]$CertName = $Icinga2.Config.'certstore.certificate.name';
|
||||
[string]$CertThumbprint = $Icinga2.Config.'certstore.certificate.thumbprint';
|
||||
|
||||
# Try to discover the certificate based on our FQDN
|
||||
if ([string]::IsNullOrEmpty($CertName) -eq $TRUE -And [string]::IsNullOrEmpty($CertThumbprint) -eq $TRUE) {
|
||||
$CertName = [System.Net.Dns]::GetHostEntry('localhost').HostName;
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format(
|
||||
'Trying to discover certificate for this host with FQDN "{0}"',
|
||||
$CertName
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($cert in $CertStore.Certificates) {
|
||||
if ([string]::IsNullOrEmpty($CertThumbprint) -eq $FALSE) {
|
||||
if ($CertThumbprint.ToLower() -eq $cert.Thumbprint.ToLower()) {
|
||||
$ServerCertificate = $cert;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($CertName) -eq $FALSE) {
|
||||
[string]$CNCertName = [string]::Format('CN={0}', $CertName.ToLower());
|
||||
if ($CNCertName.ToLower() -eq $cert.Subject.ToLower()) {
|
||||
$ServerCertificate = $cert;
|
||||
|
||||
try {
|
||||
$result = Test-Certificate -Cert $cert -ErrorAction SilentlyContinue -WarningAction SilentlyContinue;
|
||||
if ($result -eq $FALSE) {
|
||||
continue;
|
||||
}
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$certificate = $null;
|
||||
|
||||
if ($ServerCertificate -ne $null) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format(
|
||||
'Using certificate "{0}" with thumbprint "{1}"',
|
||||
$ServerCertificate.Subject,
|
||||
$ServerCertificate.Thumbprint
|
||||
)
|
||||
);
|
||||
$certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2;
|
||||
$certificate.Import($ServerCertificate.RawData)
|
||||
}
|
||||
|
||||
$CertStore.Close();
|
||||
|
||||
return $certificate;
|
||||
} catch [System.ComponentModel.Win32Exception] {
|
||||
# This error occures in case we provide a cert store and location which is not accessable
|
||||
# from our current user. We have to simply drop everything and close every possible
|
||||
# connection
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
'SSL-Error: Unable to access provided certificate from the user space this module is started with.'
|
||||
);
|
||||
} catch [System.NotSupportedException] {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
'The used SSL certificate is not providing a linked private key and cannot be used as Server certificate'
|
||||
);
|
||||
} catch {
|
||||
# Handle every other error here
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
$_.Exception.Message
|
||||
);
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
$_.Exception
|
||||
);
|
||||
}
|
||||
|
||||
return $null;
|
||||
}
|
||||
|
||||
return $SSL;
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<#
|
||||
# Helper class allowing to easily convert strings into SecureStrings
|
||||
# and vice-versa
|
||||
#>
|
||||
|
||||
$SecureString = New-Object -TypeName PSObject;
|
||||
|
||||
$SecureString | Add-Member -membertype ScriptMethod -name 'ConvertTo' -value {
|
||||
param([string]$string);
|
||||
|
||||
[SecureString]$SecureString = ConvertTo-SecureString -AsPlainText $string -Force;
|
||||
|
||||
return $SecureString;
|
||||
}
|
||||
|
||||
$SecureString | Add-Member -membertype ScriptMethod -name 'ConvertFrom' -value {
|
||||
param([SecureString]$SecureString);
|
||||
|
||||
if ($SecureString -eq $null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
[IntPtr]$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)
|
||||
[string]$String = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
|
||||
|
||||
return $String;
|
||||
}
|
||||
|
||||
return $SecureString;
|
||||
|
|
@ -1,296 +0,0 @@
|
|||
$WebHelper = New-Object -TypeName PSObject;
|
||||
|
||||
$WebHelper | Add-Member -membertype ScriptMethod -name 'ParseApiMessage' -value {
|
||||
param([SecureString]$message);
|
||||
|
||||
try {
|
||||
[hashtable]$HeaderContent = @{};
|
||||
|
||||
if ($message -eq $null) {
|
||||
return $HeaderContent;
|
||||
}
|
||||
|
||||
[string]$HTMLMessage = $Icinga2.Utils.SecureString.ConvertFrom($message);
|
||||
|
||||
[string]$HTMLContent = '';
|
||||
if ($HTMLMessage.Contains("`r`n`r`n")) {
|
||||
[int]$EOFIndex = $HTMLMessage.IndexOf("`r`n`r`n") + 4;
|
||||
$HTMLContent = $HTMLMessage.Substring(
|
||||
$EOFIndex,
|
||||
$HTMLMessage.Length - $EOFIndex
|
||||
);
|
||||
# Remove the content from our message
|
||||
if ([string]::IsNullOrEmpty($HTMLContent) -eq $FALSE) {
|
||||
$HTMLMessage = $HTMLMessage.Replace($HTMLContent, '');
|
||||
}
|
||||
}
|
||||
|
||||
[array]$SingleHeaders = $HTMLMessage.Split("`r`n");
|
||||
$HTMLMessage = $null;
|
||||
|
||||
# At first read the method, the http call and the protocol
|
||||
$HeaderContent.Add(
|
||||
'base',
|
||||
$this.ParseMethodAndUrl($SingleHeaders[0])
|
||||
);
|
||||
# Now add possible content to our hashtable
|
||||
$HeaderContent.Add(
|
||||
'content',
|
||||
$HTMLContent
|
||||
);
|
||||
# Drop the first entry of the array, as we no longer require it
|
||||
$SingleHeaders = $SingleHeaders | Select-Object -Skip 1;
|
||||
|
||||
# Read the headers from the array
|
||||
$HeaderContent.Add(
|
||||
'headers',
|
||||
$this.ParseHeaders($SingleHeaders)
|
||||
);
|
||||
# Flush the array from the memory
|
||||
$SingleHeaders = $null;
|
||||
|
||||
if ($HeaderContent.headers.ContainsKey('Authorization')) {
|
||||
$HeaderContent.Add(
|
||||
'credentials',
|
||||
$this.ParseUserCredentials(
|
||||
$HeaderContent.headers.Authorization
|
||||
)
|
||||
);
|
||||
$HeaderContent.headers.Remove('Authorization');
|
||||
}
|
||||
|
||||
return $HeaderContent;
|
||||
}
|
||||
catch {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Exception,
|
||||
[string]::Format(
|
||||
'Failed to parse HTTP content and headers. Error {0}',
|
||||
$_.Exception.Message
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $null;
|
||||
}
|
||||
|
||||
$WebHelper | Add-Member -membertype ScriptMethod -name 'ParseMethodAndUrl' -value {
|
||||
param([string]$message);
|
||||
|
||||
[array]$Content = $message.Split(' ');
|
||||
[uri]$UriData = [uri][string]::Format(
|
||||
'https://localhost{0}',
|
||||
$Content[1]
|
||||
);
|
||||
|
||||
return @{
|
||||
method = $Content[0];
|
||||
call = [System.Web.HttpUtility]::UrlDecode(
|
||||
$Content[1]
|
||||
);
|
||||
protocol = $Content[2];
|
||||
segments = $UriData.Segments;
|
||||
query = [System.Web.HttpUtility]::UrlDecode(
|
||||
$UriData.Query
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$WebHelper | Add-Member -membertype ScriptMethod -name 'ParseHeaders' -value {
|
||||
param([array]$message);
|
||||
|
||||
[hashtable]$Headers = @{};
|
||||
|
||||
foreach ($header in $message) {
|
||||
[string]$HeaderName = '';
|
||||
[string]$HeaderValue = '';
|
||||
# Skip empty array values
|
||||
if ([string]::IsNullOrEmpty($header) -eq $FALSE) {
|
||||
if ($header.Contains(':')) {
|
||||
[array]$Element = $header.Split(':');
|
||||
$HeaderName = $Element[0];
|
||||
|
||||
if ($Element.Count -gt 1) {
|
||||
for ($i = 1; $i -le ($Element.Count - 1); $i++) {
|
||||
$HeaderValue = -Join(
|
||||
$HeaderValue,
|
||||
$Element[$i],
|
||||
':'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# Remove the last added ':' at the end of the string
|
||||
if ($HeaderValue.Length -gt 1) {
|
||||
$HeaderValue = $HeaderValue.Substring(
|
||||
0,
|
||||
$HeaderValue.Length - 1
|
||||
);
|
||||
}
|
||||
|
||||
# In case the first letter of our value is a space, remove it
|
||||
while ($HeaderValue[0] -eq ' ') {
|
||||
$HeaderValue = $HeaderValue.Substring(
|
||||
1,
|
||||
$HeaderValue.Length - 1
|
||||
);
|
||||
}
|
||||
|
||||
if ($Headers.ContainsKey($HeaderName) -eq $FALSE) {
|
||||
# We have to modify the Authorization header value a little more and also
|
||||
# ensure we store it as secure string within our module
|
||||
if ($HeaderName -eq 'Authorization') {
|
||||
[array]$AuthArray = $HeaderValue.Split(' ');
|
||||
# TODO: Shall we handle each auth type differently?
|
||||
$Headers.Add(
|
||||
$HeaderName,
|
||||
$Icinga2.Utils.SecureString.ConvertTo($AuthArray[1])
|
||||
);
|
||||
$AuthArray = $null;
|
||||
} else {
|
||||
$Headers.Add($HeaderName, $HeaderValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$Headers.Add($header, $null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $Headers;
|
||||
}
|
||||
|
||||
$WebHelper | Add-Member -membertype ScriptMethod -name 'ParseUserCredentials' -value {
|
||||
param([SecureString]$Base64String);
|
||||
|
||||
[hashtable]$Credentials = @{};
|
||||
|
||||
if ($Base64String -eq $null) {
|
||||
return $Credentials;
|
||||
}
|
||||
|
||||
# Convert the Base64 Secure String back to a normal string
|
||||
[string]$PlainAuth = [System.Text.Encoding]::UTF8.GetString(
|
||||
[System.Convert]::FromBase64String(
|
||||
$Icinga2.Utils.SecureString.ConvertFrom($Base64String)
|
||||
)
|
||||
);
|
||||
$Base64String = $null;
|
||||
|
||||
# If no ':' is within the string, the credential data is not properly formated
|
||||
if ($PlainAuth.Contains(':') -eq $FALSE) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
'Received invalid formated credentials as Base64 encoded.'
|
||||
);
|
||||
$PlainAuth = $null;
|
||||
return $Credentials;
|
||||
}
|
||||
|
||||
try {
|
||||
# Build our User Data and Password from the string
|
||||
[string]$UserData = $PlainAuth.Substring(
|
||||
0,
|
||||
$PlainAuth.IndexOf(':')
|
||||
);
|
||||
$Credentials.Add(
|
||||
'password',
|
||||
$Icinga2.Utils.SecureString.ConvertTo(
|
||||
$PlainAuth.Substring(
|
||||
$PlainAuth.IndexOf(':') + 1,
|
||||
$PlainAuth.Length - $UserData.Length - 1
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$PlainAuth = $null;
|
||||
|
||||
# Extract a possible domain
|
||||
if ($UserData.Contains('\')) {
|
||||
# Split the auth string on the '\'
|
||||
[array]$AuthData = $UserData.Split('\');
|
||||
# First value of the array is the Domain, second is the Username
|
||||
$Credentials.Add('domain', $AuthData[0]);
|
||||
$Credentials.Add(
|
||||
'user',
|
||||
$Icinga2.Utils.SecureString.ConvertTo(
|
||||
$AuthData[1]
|
||||
)
|
||||
);
|
||||
$AuthData = $null;
|
||||
} else {
|
||||
$Credentials.Add('domain', $null);
|
||||
$Credentials.Add(
|
||||
'user',
|
||||
$Icinga2.Utils.SecureString.ConvertTo(
|
||||
$UserData
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$UserData = $null;
|
||||
} catch {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Error,
|
||||
'Failed to handle authentication request. An exception occured while processing the request.'
|
||||
);
|
||||
}
|
||||
|
||||
return $Credentials;
|
||||
}
|
||||
|
||||
$WebHelper | Add-Member -membertype ScriptMethod -name 'ParseUrlCommand' -value {
|
||||
param([string]$Argument);
|
||||
|
||||
[hashtable]$StructuredCommand = @{};
|
||||
# If no = is included, we don't need to handle anything special
|
||||
if ($Argument.Contains('=') -eq $FALSE) {
|
||||
$StructuredCommand.Add($Argument, $null);
|
||||
return $StructuredCommand;
|
||||
}
|
||||
|
||||
[int]$SeperatorIndex = $Argument.IndexOf('=');
|
||||
[string]$Command = $Argument.Substring(
|
||||
0,
|
||||
$SeperatorIndex
|
||||
);
|
||||
$Command = $Command.Replace(' ', '').ToLower();
|
||||
|
||||
[array]$Values = @();
|
||||
[string]$Value = $Argument.Substring(
|
||||
$SeperatorIndex + 1,
|
||||
$Argument.Length - $SeperatorIndex - 1
|
||||
);
|
||||
|
||||
if ($Value.Contains(',') -eq $TRUE) {
|
||||
[array]$Entries = $Value.Split(',');
|
||||
foreach ($entry in $Entries) {
|
||||
[string]$ParsedValue = $entry;
|
||||
# Cut spaces before names of inputs
|
||||
while ($ParsedValue[0] -eq ' ') {
|
||||
$ParsedValue = $ParsedValue.Substring(
|
||||
1,
|
||||
$ParsedValue.Length - 1
|
||||
);
|
||||
}
|
||||
|
||||
# Cut spaces after names of inputs
|
||||
while ($ParsedValue[$ParsedValue.Length - 1] -eq ' ') {
|
||||
$ParsedValue = $ParsedValue.Substring(
|
||||
0,
|
||||
$ParsedValue.Length - 1
|
||||
);
|
||||
}
|
||||
$Values += $ParsedValue.ToLower();
|
||||
}
|
||||
} else {
|
||||
$Values += $Value.Replace(' ', '').ToLower();
|
||||
}
|
||||
|
||||
# Filter out duplicate entries
|
||||
$Values = $Values | Select-Object -Unique;
|
||||
$StructuredCommand.Add($Command, $Values);
|
||||
return $StructuredCommand;
|
||||
}
|
||||
|
||||
return $WebHelper;
|
||||
100
core/init.ps1
100
core/init.ps1
|
|
@ -1,100 +0,0 @@
|
|||
# This script will initialse the entire module configuration for easier usage
|
||||
param (
|
||||
[string]$RootDirectory = '',
|
||||
[string]$ModuleName = ''
|
||||
);
|
||||
|
||||
# Create an internal 'namespace' for our environment
|
||||
Set-Variable -Name Icinga2 -Option Constant -Value @{
|
||||
Function = @(
|
||||
'Use-Icinga',
|
||||
'Import-IcingaLib',
|
||||
'Get-IcingaPluginDir',
|
||||
'Get-IcingaCustomPluginDir',
|
||||
'Get-IcingaCacheDir',
|
||||
'Get-IcingaPowerShellConfigDir',
|
||||
'Get-Icinga-Lib',
|
||||
'Get-Icinga-Object',
|
||||
'Get-Icinga-Service',
|
||||
'Start-Icinga-Service',
|
||||
'Stop-Icinga-Service',
|
||||
'Restart-Icinga-Service',
|
||||
'Install-Icinga-Service',
|
||||
'Uninstall-Icinga-Service',
|
||||
'Install-Icinga',
|
||||
'Get-Icinga-Setup',
|
||||
'Start-Icinga-Daemon',
|
||||
'Stop-Icinga-Daemon',
|
||||
'Start-Icinga-Checker',
|
||||
'Stop-Icinga-Checker',
|
||||
'Get-Icinga-Command',
|
||||
'New-Icinga-Monitoring',
|
||||
'Get-Icinga-Counter',
|
||||
'Get-Icinga-Config',
|
||||
'Set-Icinga-Config',
|
||||
'Remove-Icinga-Config',
|
||||
'New-Icinga-Config'
|
||||
);
|
||||
}
|
||||
|
||||
# Define temporary variables to store the main current root and module name
|
||||
# Note: Never use this variables within the module besides inside '\core\includes\'
|
||||
$_InternalTempVariables = @{
|
||||
RootPath = $RootDirectory;
|
||||
ModuleName = $ModuleName;
|
||||
}
|
||||
# End definition of temporary variables
|
||||
|
||||
# Load all PowerShell scripts within our '\core\include\' directory and add the content with the name
|
||||
# of the script into our namespace
|
||||
Get-ChildItem (Join-Path -Path $PSScriptRoot -ChildPath '\include\') -Filter *.ps1 |
|
||||
Foreach-Object {
|
||||
$path = $_.FullName;
|
||||
$name = $_.Name.Replace('.ps1', '');
|
||||
|
||||
# Add variables to a global namespace. Should only be used within the
|
||||
# same PowerShell instance
|
||||
try {
|
||||
$include = (& $path);
|
||||
} catch {
|
||||
Write-Host (
|
||||
[string]::Format(
|
||||
'Failed to execute core module "{0}". Exception: {1}',
|
||||
$name,
|
||||
$_.Exception.Message
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ([bool]($include.PSobject.Properties.Name -eq 'static') -eq $FALSE -Or $include.static -eq $TRUE) {
|
||||
$Icinga2.Add($name, $include);
|
||||
}
|
||||
}
|
||||
|
||||
# Flush the internal temp variable cache
|
||||
$_InternalTempVariables = $null;
|
||||
|
||||
# Load our System.Web helper class
|
||||
[Reflection.Assembly]::LoadWithPartialName("System.Web") | Out-Null;
|
||||
|
||||
$Icinga2.Add(
|
||||
'Cache',
|
||||
@{
|
||||
# This will allow us to dynamicly initialise Performance Counters during
|
||||
# startup to speed up actual checks later on. Of course counters will be
|
||||
# cached anyway once they are executed, but will speed up first check
|
||||
# executions for CPU Performance Counters for example
|
||||
PerformanceCounter = @{ };
|
||||
# Pre-Load the Server SSL Certificate
|
||||
Certificates = @{ Server = $Icinga2.Utils.SSL.LoadServerCertificate() };
|
||||
# Create a instance for storing TCP Sockets (in case we later want to listen in multi-sockets)
|
||||
Sockets = @{ };
|
||||
# Store our checker configuration we receive from the remote endpoint
|
||||
Checker = @{ };
|
||||
# This cache can be used for storing informations of modules to compare send informations
|
||||
# as well as required data for a later execution of the same module again
|
||||
Modules = @{ };
|
||||
}
|
||||
);
|
||||
|
||||
return $Icinga2;
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
param(
|
||||
[array]$Include = @(),
|
||||
[array]$Exclude = @(),
|
||||
[boolean]$ListModules = $FALSE,
|
||||
$Config = $null,
|
||||
[string]$AgentRoot = ''
|
||||
)
|
||||
|
||||
function ClassMonitoring()
|
||||
{
|
||||
param(
|
||||
[array]$Include = @(),
|
||||
[array]$Exclude = @(),
|
||||
[boolean]$ListModules = $FALSE,
|
||||
$Config = $null,
|
||||
[string]$AgentRoot = ''
|
||||
)
|
||||
|
||||
[string]$ModuleDirectory = Join-Path $AgentRoot -ChildPath 'modules';
|
||||
[hashtable]$ModuleList = @{};
|
||||
[array]$AvailableModules = @();
|
||||
$ResultList = New-Object psobject -prop @{};
|
||||
|
||||
# Let's do a small fix here: We have defined 'include' within the URL, but
|
||||
# we haven't specified any values. So lets assume we want to load all
|
||||
# modules
|
||||
if ($Include.Count -eq 1 -And [string]::IsNullOrEmpty($Include[0])) {
|
||||
$Include[0] = '*';
|
||||
}
|
||||
|
||||
# In case no includes are specified, lets include everything
|
||||
if ($Include.Count -eq 0) {
|
||||
$Include += '*';
|
||||
}
|
||||
|
||||
<#
|
||||
# In case no filter is specified, we asume we want to collect everything.
|
||||
# Lets fetch all PowerShell Scripts within our module Directory
|
||||
# Will also be used to return a list of installed modules
|
||||
#>
|
||||
if (($Include.Count -eq 1 -And $Include[0] -eq '*') -Or $ListModules) {
|
||||
Get-ChildItem $ModuleDirectory -Filter *.ps1 |
|
||||
Foreach-Object {
|
||||
$path = $_.FullName
|
||||
$name = $_.Name.Replace('.ps1', '').ToLower();
|
||||
|
||||
$ModuleList.Add($name, $path);
|
||||
$AvailableModules += $name;
|
||||
}
|
||||
|
||||
if ($ListModules) {
|
||||
return $AvailableModules;
|
||||
}
|
||||
} else {
|
||||
# In case we provided a filter, try to locate these modules
|
||||
foreach ($module in $Include) {
|
||||
# Just to ensure we skip this argument in case it is provided
|
||||
if ($module -eq '*') {
|
||||
continue;
|
||||
}
|
||||
$module = $module.ToLower();
|
||||
[string]$file = [string]::Format('{0}.ps1', $module);
|
||||
[string]$path = Join-Path $ModuleDirectory -ChildPath $file;
|
||||
|
||||
if ($ModuleList.ContainsKey($module) -eq $FALSE) {
|
||||
$ModuleList.Add($module, $path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($module in $Exclude) {
|
||||
if ($ModuleList.ContainsKey($module)) {
|
||||
$ModuleList.Remove($module);
|
||||
}
|
||||
}
|
||||
|
||||
[System.Diagnostics.Stopwatch]$ModuleTimer = New-Object System.Diagnostics.Stopwatch;
|
||||
# Now as we have our module list available, lets execute them to fetch informations
|
||||
foreach ($module in $ModuleList.Keys) {
|
||||
$ModuleTimer.Start();
|
||||
[string]$path = $ModuleList[$module];
|
||||
[hashtable]$ModuleResult = @{};
|
||||
$moduleConfig = $null;
|
||||
|
||||
if ($Config -ne $null -AND $Config.$module -ne $null) {
|
||||
$moduleConfig = $Config.$module;
|
||||
}
|
||||
|
||||
# First test if the specified module is available
|
||||
if (Test-Path ($path)) {
|
||||
try {
|
||||
# If it is, execute the script and return the output
|
||||
$ModuleResult.Add('output', (&$path -Config $moduleConfig));
|
||||
$ModuleResult.Add('response', 200);
|
||||
$ModuleResult.Add('error', $null);
|
||||
} catch {
|
||||
# In case the script we tried to execute runs into a failure, return the exception message as result
|
||||
$ModuleResult.Add('output', $null);
|
||||
$ModuleResult.Add('response', 500);
|
||||
$ModuleResult.Add('error', [string]::Format('Failed to execute module "{0}". Exeception: {1}', $module, $_.Exception.Message));
|
||||
}
|
||||
} else {
|
||||
# Include the module to our output with a small notify message
|
||||
$ModuleResult.Add('output', $null);
|
||||
$ModuleResult.Add('response', 404);
|
||||
$ModuleResult.Add('error', 'Module not found');
|
||||
}
|
||||
|
||||
$ModuleResult.Add('execution', $ModuleTimer.Elapsed.TotalSeconds);
|
||||
$ModuleTimer.Stop();
|
||||
|
||||
$ResultList | Add-Member -Name $module -Type NoteProperty -Value $ModuleResult;
|
||||
}
|
||||
|
||||
return $ResultList;
|
||||
}
|
||||
|
||||
return ClassMonitoring -Include $Include -Exclude $Exclude -ListModules $ListModules -Config $Config -AgentRoot $AgentRoot;
|
||||
|
|
@ -1,577 +0,0 @@
|
|||
param(
|
||||
[string]$Counter = '',
|
||||
[string]$ListCounter = '',
|
||||
[array]$CounterArray = @(),
|
||||
[boolean]$ListCategories = $FALSE,
|
||||
[boolean]$SkipWait = $FALSE,
|
||||
# These arguments apply to CreateStructuredPerformanceCounterTable
|
||||
# This is the category name we want to create a structured output
|
||||
# Example: 'Network Interface'
|
||||
[string]$CreateStructuredOutputForCategory = '',
|
||||
# This is the hashtable of Performance Counters, created by
|
||||
# PerformanceCounterArray
|
||||
[hashtable]$StructuredCounterInput = @{},
|
||||
# This argument is just a helper to replace certain strings within
|
||||
# a instance name with simply nothing.
|
||||
# Example: 'HarddiskVolume1' => '1'
|
||||
[array]$StructuredCounterInstanceCleanup = @()
|
||||
);
|
||||
|
||||
# This is our internal cache for Performance Counters already loaded
|
||||
# In case the Icinga Agent is running as daemon, this hashtable is
|
||||
# already initialised at the beginning. But if we run the Agent
|
||||
# from the Powershell directly, we will require to build this cache
|
||||
# within the environment to work properly and to receive valid data
|
||||
if ($Icinga2.Cache.PerformanceCounter -eq $null) {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
'Creating new performance counter cache'
|
||||
);
|
||||
$Icinga2.Cache.PerformanceCounter = @{};
|
||||
}
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format(
|
||||
'Performance Counter Cache content {0}',
|
||||
($Icinga2.Cache.PerformanceCounter | Out-String)
|
||||
)
|
||||
);
|
||||
|
||||
<#
|
||||
# This function will provide a virtual object, containing an array
|
||||
# of Performance Counters. The object has the following members:
|
||||
# Name
|
||||
# Value
|
||||
# This will ensure we will not have to worry about looping an array
|
||||
# of mutltiple instances within a counter handler, because this
|
||||
# function will deal with everything, returning an hashtable
|
||||
# containing the parent counter name including the values and
|
||||
# samples for every single instance
|
||||
#>
|
||||
function PerformanceCounterArray()
|
||||
{
|
||||
param(
|
||||
[string]$FullName = '',
|
||||
[array]$PerformanceCounters = @()
|
||||
);
|
||||
|
||||
$pc_instance = New-Object -TypeName PSObject;
|
||||
$pc_instance | Add-Member -membertype NoteProperty -name 'FullName' -value $FullName;
|
||||
$pc_instance | Add-Member -membertype NoteProperty -name 'Counters' -value $PerformanceCounters;
|
||||
|
||||
$pc_instance | Add-Member -membertype ScriptMethod -name 'Name' -value {
|
||||
return $this.FullName;
|
||||
}
|
||||
|
||||
$pc_instance | Add-Member -membertype ScriptMethod -name 'Value' -value {
|
||||
[hashtable]$CounterResults = @{};
|
||||
|
||||
foreach ($counter in $this.Counters) {
|
||||
$CounterResults.Add($counter.Name(), $counter.Value());
|
||||
}
|
||||
|
||||
return $CounterResults;
|
||||
}
|
||||
|
||||
return $pc_instance;
|
||||
}
|
||||
|
||||
<#
|
||||
# This function will create a custom Performance Counter object with
|
||||
# already initialised counters, which can be accessed with the
|
||||
# following members:
|
||||
# Name
|
||||
# Value
|
||||
# Like the PerformanceCounterArray, this will allow to fetch the
|
||||
# current values of a single counter instance including the name
|
||||
# of the counter. Within the PerformanceCounterArray function,
|
||||
# objects created by this function are used.
|
||||
#>
|
||||
function PerformanceCounterObject()
|
||||
{
|
||||
param(
|
||||
[string]$FullName = '',
|
||||
[string]$Category = '',
|
||||
[string]$Instance = '',
|
||||
[string]$Counter = '',
|
||||
[boolean]$SkipWait = $FALSE
|
||||
);
|
||||
|
||||
$pc_instance = New-Object -TypeName PSObject;
|
||||
$pc_instance | Add-Member -membertype NoteProperty -name 'FullName' -value $FullName;
|
||||
$pc_instance | Add-Member -membertype NoteProperty -name 'Category' -value $Category;
|
||||
$pc_instance | Add-Member -membertype NoteProperty -name 'Instance' -value $Instance;
|
||||
$pc_instance | Add-Member -membertype NoteProperty -name 'Counter' -value $Counter;
|
||||
$pc_instance | Add-Member -membertype NoteProperty -name 'PerfCounter' -value $Counter;
|
||||
$pc_instance | Add-Member -membertype NoteProperty -name 'SkipWait' -value $SkipWait;
|
||||
|
||||
$pc_instance | Add-Member -membertype ScriptMethod -name 'Init' -value {
|
||||
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Debug,
|
||||
[string]::Format('Creating new Counter for Category {0} with Instance {1} and Counter {2}. Full Name "{3}"',
|
||||
$this.Category,
|
||||
$this.Instance,
|
||||
$this.Counter,
|
||||
$this.FullName
|
||||
)
|
||||
);
|
||||
|
||||
# Create the Performance Counter object we want to access
|
||||
$this.PerfCounter = New-Object System.Diagnostics.PerformanceCounter;
|
||||
$this.PerfCounter.CategoryName = $this.Category;
|
||||
$this.PerfCounter.CounterName = $this.Counter;
|
||||
|
||||
# Only add an instance in case it is defined
|
||||
if ([string]::IsNullOrEmpty($this.Instance) -eq $FALSE) {
|
||||
$this.PerfCounter.InstanceName = $this.Instance
|
||||
}
|
||||
|
||||
# Initialise the counter
|
||||
try {
|
||||
$this.PerfCounter.NextValue() | Out-Null;
|
||||
} catch {
|
||||
# Nothing to do here, will be handled later
|
||||
}
|
||||
|
||||
<#
|
||||
# For some counters we require to wait a small amount of time to receive proper data
|
||||
# Other counters do not need these informations and we do also not require to wait
|
||||
# for every counter we use, once the counter is initialised within our environment.
|
||||
# This will allow us to skip the sleep to speed up loading counters
|
||||
#>
|
||||
if ($this.SkipWait -eq $FALSE) {
|
||||
Start-Sleep -Milliseconds 500;
|
||||
}
|
||||
}
|
||||
|
||||
# Return the name of the counter as string
|
||||
$pc_instance | Add-Member -membertype ScriptMethod -name 'Name' -value {
|
||||
return $this.FullName;
|
||||
}
|
||||
|
||||
<#
|
||||
# Return a hashtable containting the counter value including the
|
||||
# Sample values for the counter itself. In case we run into an error,
|
||||
# keep the counter construct but add an error message in addition.
|
||||
#>
|
||||
$pc_instance | Add-Member -membertype ScriptMethod -name 'Value' -value {
|
||||
[hashtable]$CounterData = @{};
|
||||
|
||||
try {
|
||||
[string]$CounterType = $this.PerfCounter.CounterType;
|
||||
$CounterData.Add('value', $this.PerfCounter.NextValue());
|
||||
$CounterData.Add('sample', $this.PerfCounter.NextSample());
|
||||
$CounterData.Add('help', $this.PerfCounter.CounterHelp);
|
||||
$CounterData.Add('type', $CounterType);
|
||||
$CounterData.Add('error', $null);
|
||||
} catch {
|
||||
$CounterData = @{};
|
||||
$CounterData.Add('value', $null);
|
||||
$CounterData.Add('sample', $null);
|
||||
$CounterData.Add('help', $null);
|
||||
$CounterData.Add('type', $null);
|
||||
$CounterData.Add('error', $_.Exception.Message);
|
||||
}
|
||||
|
||||
return $CounterData;
|
||||
}
|
||||
|
||||
# Initialiste the entire counter and internal handlers
|
||||
$pc_instance.Init();
|
||||
|
||||
# Return this custom object
|
||||
return $pc_instance;
|
||||
}
|
||||
|
||||
<#
|
||||
# If some informations are missing, it could happen that
|
||||
# we are unable to create a Performance Counter.
|
||||
# In this case we will use this Null Object, containing
|
||||
# the same member functions but allowing us to maintain
|
||||
# stability without unwanted exceptions
|
||||
#>
|
||||
function PerformanceCounterNullObject()
|
||||
{
|
||||
param(
|
||||
[string]$FullName = '',
|
||||
[string]$ErrorMessage = ''
|
||||
);
|
||||
|
||||
$pc_instance = New-Object -TypeName PSObject;
|
||||
$pc_instance | Add-Member -membertype NoteProperty -name 'FullName' -value $FullName;
|
||||
$pc_instance | Add-Member -membertype NoteProperty -name 'ErrorMessage' -value $ErrorMessage;
|
||||
|
||||
$pc_instance | Add-Member -membertype ScriptMethod -name 'Name' -value {
|
||||
return $this.FullName;
|
||||
}
|
||||
|
||||
$pc_instance | Add-Member -membertype ScriptMethod -name 'Value' -value {
|
||||
[hashtable]$ErrorMessage = @{};
|
||||
|
||||
$ErrorMessage.Add('value', $null);
|
||||
$ErrorMessage.Add('sample', $null);
|
||||
$ErrorMessage.Add('help', $null);
|
||||
$ErrorMessage.Add('type', $null);
|
||||
$ErrorMessage.Add('error', $this.ErrorMessage);
|
||||
|
||||
return $ErrorMessage;
|
||||
}
|
||||
|
||||
return $pc_instance;
|
||||
}
|
||||
|
||||
<#
|
||||
# This function will make monitoring an entire list of
|
||||
# Performance counters even more easier. We simply provide
|
||||
# an array of Performance Counters to this module
|
||||
# and we will receive a construct-save result of an
|
||||
# hashtable with all performance counters including
|
||||
# the corresponding values. In that case the code
|
||||
# size decreases for larger modules.
|
||||
# Example:
|
||||
$counter = Get-Icinga-Counter -CounterArray @(
|
||||
'\Memory\Available Bytes',
|
||||
'\Memory\% Committed Bytes In Use'
|
||||
);
|
||||
#>
|
||||
function CreatePerformanceCounterResult()
|
||||
{
|
||||
param(
|
||||
[array]$CounterArray = @()
|
||||
)
|
||||
|
||||
[hashtable]$CounterResult = @{};
|
||||
[bool]$RequireSleep = $FALSE;
|
||||
foreach ($counter in $CounterArray) {
|
||||
# We want to speed up things with loading, so we will check if a specified
|
||||
# Counter is already cached within our hashtable. If it is not, we sleep
|
||||
# at the end of the function the required 500ms and don't have to wait
|
||||
# NumOfCounters * 500 milliseconds for the first runs. This will speed
|
||||
# up the general loading of counters and will not require some fancy
|
||||
# pre-caching / configuration handler
|
||||
if ($Icinga2.Cache.PerformanceCounter -ne $null) {
|
||||
if ($Icinga2.Cache.PerformanceCounter.ContainsKey($counter) -eq $FALSE) {
|
||||
$RequireSleep = $TRUE;
|
||||
}
|
||||
}
|
||||
$obj = CreatePerformanceCounter -Counter $counter -SkipWait $TRUE;
|
||||
if ($CounterResult.ContainsKey($obj.Name()) -eq $FALSE) {
|
||||
$CounterResult.Add($obj.Name(), $obj.Value());
|
||||
}
|
||||
}
|
||||
|
||||
# Above we initialse ever single counter and we only require a sleep once
|
||||
# in case a new, yet unknown counter was added
|
||||
if ($RequireSleep) {
|
||||
Start-Sleep -Milliseconds 500;
|
||||
|
||||
# Agreed, this is some sort of code duplication but it wouldn't make
|
||||
# any sense to create a own function for this. Why are we doing
|
||||
# this anway?
|
||||
# Simple: In case we found counters which have yet not been initialised
|
||||
# we did this above. Now we have waited 500 ms to receive proper
|
||||
# values from these counters. As the previous generated result
|
||||
# might have contained counters with 0 results, we will now
|
||||
# check all counters again to receive the proper values.
|
||||
# Agreed, might sound like a overhead, but the impact only
|
||||
# applies to the first call of the module with the counters.
|
||||
# This 'duplication' however decreased the execution from
|
||||
# certain modules from 25s to 1s on the first run. Every
|
||||
# additional run is then beeing executed within 0.x s
|
||||
# which sounds like a very good performance and solution
|
||||
$CounterResult = @{};
|
||||
foreach ($counter in $CounterArray) {
|
||||
$obj = CreatePerformanceCounter -Counter $counter -SkipWait $TRUE;
|
||||
if ($CounterResult.ContainsKey($obj.Name()) -eq $FALSE) {
|
||||
$CounterResult.Add($obj.Name(), $obj.Value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $CounterResult;
|
||||
}
|
||||
|
||||
<#
|
||||
# This is the main function which is called from this script, constructing our counters
|
||||
# and loading possible sub-instances from our Performance Counter.
|
||||
# It will return either an PerformanceCounterObject or PerformanceCounterArray
|
||||
# which both contain the same members, allowing us to dynamicly use the objects
|
||||
# without having to worry about exception.
|
||||
#>
|
||||
function CreatePerformanceCounter()
|
||||
{
|
||||
param(
|
||||
[string]$Counter = '',
|
||||
[boolean]$SkipWait = $FALSE
|
||||
);
|
||||
|
||||
# Simply use the counter name, like
|
||||
# \Paging File(_total)\% Usage
|
||||
if ([string]::IsNullOrEmpty($Counter) -eq $TRUE) {
|
||||
return (PerformanceCounterNullObject -FullName $Counter -ErrorMessage 'Failed to initialise counter, as no counter was specified.');
|
||||
}
|
||||
|
||||
[array]$CounterArray = $Counter.Split('\');
|
||||
[string]$UseCounterCategory = '';
|
||||
[string]$UseCounterName = '';
|
||||
[string]$UseCounterInstance = '';
|
||||
|
||||
# If we add the counter as it should be
|
||||
# \Paging File(_total)\% Usage
|
||||
# the first array element will be an empty string we can skip
|
||||
# Otherwise the name was wrong and we should not continue
|
||||
if (-Not [string]::IsNullOrEmpty($CounterArray[0])) {
|
||||
return (PerformanceCounterNullObject -FullName $Counter -ErrorMessage ([string]::Format('Failed to deserialize counter "{0}". It seems the leading "\" is missing.', $Counter)));
|
||||
}
|
||||
|
||||
# In case our Performance Counter is containing instances, we should split
|
||||
# The content and read the instance and counter category out
|
||||
if ($CounterArray[1].Contains('(')) {
|
||||
[array]$TmpCounter = $CounterArray[1].Split('(');
|
||||
$UseCounterCategory = $TmpCounter[0];
|
||||
$UseCounterInstance = $TmpCounter[1].Replace(')', '');
|
||||
} else {
|
||||
# Otherwise we only require the category
|
||||
$UseCounterCategory = $CounterArray[1];
|
||||
}
|
||||
|
||||
# At last get the actual counter containing our values
|
||||
$UseCounterName = $CounterArray[2];
|
||||
|
||||
# Now as we know how the counter path is constructed and has been splitted into
|
||||
# the different values, we need to know how to handle the instances of the counter
|
||||
|
||||
# If we specify a instance with (*) we want the module to automaticly fetch all
|
||||
# instances for this counter. This will result in an PerformanceCounterArray
|
||||
# which contains the parent name including counters for all instances that
|
||||
# have been found
|
||||
if ($UseCounterInstance -eq '*') {
|
||||
# In case we already loaded the counters once, return the finished array
|
||||
if ($Icinga2.Cache.PerformanceCounter.ContainsKey($Counter) -eq $TRUE) {
|
||||
return (PerformanceCounterArray -FullName $Counter -PerformanceCounters $Icinga2.Cache.PerformanceCounter[$Counter]);
|
||||
}
|
||||
|
||||
# If we need to build the array, load all instances from the counters and
|
||||
# create single performance counters and add them to a custom array and
|
||||
# later to a custom object
|
||||
try {
|
||||
[array]$AllCountersIntances = @();
|
||||
$CounterInstances = New-Object System.Diagnostics.PerformanceCounterCategory($UseCounterCategory);
|
||||
foreach ($instance in $CounterInstances.GetInstanceNames()) {
|
||||
[string]$NewCounterName = $Counter.Replace('*', $instance);
|
||||
$NewCounter = PerformanceCounterObject -FullName $NewCounterName -Category $UseCounterCategory -Counter $UseCounterName -Instance $instance -SkipWait $SkipWait;
|
||||
$AllCountersIntances += $NewCounter;
|
||||
}
|
||||
} catch {
|
||||
return (PerformanceCounterNullObject -FullName $Counter -ErrorMessage ([string]::Format('Failed to deserialize instances for counter "{0}". Exception: "{1}".', $Counter, $_.Exception.Message)));
|
||||
}
|
||||
|
||||
# Add the parent counter including the array of Performance Counters to our
|
||||
# caching mechanism and return the PerformanceCounterArray object for usage
|
||||
# within the monitoring modules
|
||||
$Icinga2.Cache.PerformanceCounter.Add($Counter, $AllCountersIntances);
|
||||
return (PerformanceCounterArray -FullName $Counter -PerformanceCounters $AllCountersIntances);
|
||||
} else {
|
||||
# This part will handle the counters without any instances as well as
|
||||
# specificly assigned instances, like (_Total) CPU usage.
|
||||
|
||||
# In case we already have the counter within our cache, return the
|
||||
# cached informations
|
||||
if ($Icinga2.Cache.PerformanceCounter.ContainsKey($Counter) -eq $TRUE) {
|
||||
return $Icinga2.Cache.PerformanceCounter[$Counter];
|
||||
}
|
||||
|
||||
# If the cache is not present yet, create the Performance Counter object,
|
||||
# and add it to our cache
|
||||
$NewCounter = PerformanceCounterObject -FullName $Counter -Category $UseCounterCategory -Counter $UseCounterName -Instance $UseCounterInstance -SkipWait $SkipWait;
|
||||
$Icinga2.Cache.PerformanceCounter.Add($Counter, $NewCounter);
|
||||
}
|
||||
|
||||
# This function will always return non-instance counters or
|
||||
# specificly defined instance counters. Performance Counter Arrays
|
||||
# are returned within their function. This is just to ensure that the
|
||||
# function looks finished from developer point of view
|
||||
return $Icinga2.Cache.PerformanceCounter[$Counter];
|
||||
}
|
||||
|
||||
#
|
||||
# This function will get handy in case we want to fetch Counters
|
||||
# which have instances which might be helpful to group by their
|
||||
# instances name. This will apply to Disk and Network Interface
|
||||
# outputs for example, as it would be helpful to combine all
|
||||
# counter results for a specific disk / interface in one
|
||||
# result for easier working with these informations
|
||||
#
|
||||
function CreateStructuredPerformanceCounterTable
|
||||
{
|
||||
param(
|
||||
[string]$CounterCategory = '',
|
||||
[hashtable]$PerformanceCounterHash = @{},
|
||||
[array]$InstanceNameCleanupArray = @()
|
||||
)
|
||||
|
||||
# The storage variables we require to store our data
|
||||
[array]$AvailableInstances = @();
|
||||
[hashtable]$StructuredCounterData = @{};
|
||||
|
||||
# With this little trick we can fetch all instances we have and get their unique name
|
||||
$CounterInstances = New-Object System.Diagnostics.PerformanceCounterCategory($CounterCategory);
|
||||
foreach ($instance in $CounterInstances.GetInstanceNames()) {
|
||||
# For some counters we require to apply a 'cleanup' for the instance name
|
||||
# Example Disks: Some disks are stored with the name
|
||||
# 'HarddiskVolume1'
|
||||
# To be able to map the volume correctly to disks, we require to remove
|
||||
# 'HarddiskVolume' so only '1' will remain, which allows us to map the
|
||||
# volume correctly afterwards
|
||||
[string]$CleanInstanceName = $instance;
|
||||
foreach ($cleanup in $InstanceNameCleanupArray) {
|
||||
$CleanInstanceName = $CleanInstanceName.Replace($cleanup, '');
|
||||
}
|
||||
$AvailableInstances += $CleanInstanceName;
|
||||
}
|
||||
|
||||
# Now let the real magic begin.
|
||||
|
||||
# At first we will loop all instances of our Performance Counters, which means all
|
||||
# instances we have found above. We build a new hashtable then to list the instances
|
||||
# by their individual name and all corresponding counters as children
|
||||
# This allows us a structured output with all data for each instance
|
||||
foreach ($instance in $AvailableInstances) {
|
||||
|
||||
# First build a hashtable for each instance to add data to later
|
||||
$StructuredCounterData.Add($instance, @{});
|
||||
|
||||
# Now we need to loop all return values from our Performance Counters
|
||||
foreach ($InterfaceCounter in $PerformanceCounterHash.Keys) {
|
||||
# As we just looped the parent counter (Instance *), we now need to
|
||||
# loop the actual counters for each instance
|
||||
foreach ($interface in $PerformanceCounterHash[$InterfaceCounter]) {
|
||||
# Finally let's loop through all the results which contain the values
|
||||
# to build our new, structured hashtable
|
||||
foreach ($entry in $interface.Keys) {
|
||||
# Match the counters based on our current parent index
|
||||
# (the instance name we want to add the values as children).
|
||||
if ($entry.Contains('(' + $instance + ')')) {
|
||||
# To ensure we don't transmit the entire counter name,
|
||||
# we only want to include the name of the actual counter.
|
||||
# There is no need to return
|
||||
# \Network Interface(Desktopadapter Intel[R] Gigabit CT)\Bytes Received/sec
|
||||
# the naming
|
||||
# Bytes Received/sec
|
||||
# is enough
|
||||
[array]$TmpOutput = $entry.Split('\');
|
||||
[string]$OutputName = $TmpOutput[$TmpOutput.Count - 1];
|
||||
|
||||
# Now add the actual value to our parent instance with the
|
||||
# improved value name, including the sample and counter value data
|
||||
$StructuredCounterData[$instance].Add($OutputName, $interface[$entry]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $StructuredCounterData;
|
||||
}
|
||||
|
||||
#
|
||||
# This function will load all available Categories of Performance Counters
|
||||
# from the registry and outputs them. This will ensure we can fetch the real
|
||||
# english names instead of the localiced ones
|
||||
#
|
||||
function ListCounterCategories()
|
||||
{
|
||||
$RegistryData = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009' `
|
||||
-Name 'counter' | Select-Object -ExpandProperty Counter;
|
||||
[array]$Counters = @();
|
||||
|
||||
# Now lets loop our registry data and fetch only for counter categories
|
||||
# Ignore everything else and drop the information
|
||||
foreach ($counter in $RegistryData) {
|
||||
# First filter out the ID's of the performance counter
|
||||
if (-Not ($counter -match "^[\d\.]+$") -And [string]::IsNullOrEmpty($counter) -eq $FALSE) {
|
||||
# Now check if the value we got is a counter category
|
||||
if ([System.Diagnostics.PerformanceCounterCategory]::Exists($counter) -eq $TRUE) {
|
||||
$Counters += $counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $Counters;
|
||||
}
|
||||
|
||||
#
|
||||
# Provide the name of a category to fetch all available counters and
|
||||
# if there are any instances assigned to it
|
||||
#
|
||||
function ListCountersFromCategory()
|
||||
{
|
||||
param ([string]$CounterCategory);
|
||||
|
||||
[hashtable]$counters = @{};
|
||||
try {
|
||||
# At first create our Performance Counter object for the category we specified
|
||||
$Category = New-Object System.Diagnostics.PerformanceCounterCategory($CounterCategory);
|
||||
|
||||
# Now loop through all keys to find the name of available counters
|
||||
foreach ($counter in $Category.ReadCategory().Keys) {
|
||||
[string]$CounterInstanceAddition = '';
|
||||
|
||||
# As counters might also have instances (like interfaces, disks, paging file), we should
|
||||
# try to load them as well
|
||||
foreach ($instance in $Category.ReadCategory()[$counter].Keys) {
|
||||
# If we do not match this magic string, we have multiple instances we can access
|
||||
# to get informations for different disks, volumes and interfaces for example
|
||||
if ($instance -ne 'systemdiagnosticsperfcounterlibsingleinstance') {
|
||||
# Re-Write the name we return of the counter to something we can use directly
|
||||
# within our modules to load data from. A returned counter will look like this
|
||||
# for example:
|
||||
# \PhysicalDisk(*)\avg. disk bytes/read
|
||||
[string]$UsableCounterName = [string]::Format('\{0}(*)\{1}', $CounterCategory, $counter);
|
||||
if ($counters.ContainsKey($UsableCounterName) -eq $TRUE) {
|
||||
$counters[$UsableCounterName] += $Category.ReadCategory()[$counter][$instance];
|
||||
} else {
|
||||
$counters.Add($UsableCounterName, @( $Category.ReadCategory()[$counter][$instance] ));
|
||||
}
|
||||
} else {
|
||||
# For counters with no instances, we still require to return a re-build Performance Counter
|
||||
# output, to make later usage in our modules very easy. This can look like this:
|
||||
# \System\system up time
|
||||
[string]$UsableCounterName = [string]::Format('\{0}\{1}', $CounterCategory, $counter);
|
||||
$counters.Add($UsableCounterName, $null);
|
||||
}
|
||||
}
|
||||
};
|
||||
} catch {
|
||||
# In case we run into an error, return an error message
|
||||
$counters.Add('error', $_.Exception.Message);
|
||||
}
|
||||
|
||||
return $counters;
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($CreateStructuredOutputForCategory) -eq $FALSE) {
|
||||
return (CreateStructuredPerformanceCounterTable `
|
||||
-CounterCategory $CreateStructuredOutputForCategory `
|
||||
-PerformanceCounterHash $StructuredCounterInput `
|
||||
-InstanceNameCleanupArray $StructuredCounterInstanceCleanup
|
||||
)
|
||||
}
|
||||
|
||||
if ($ListCategories -eq $TRUE) {
|
||||
return ListCounterCategories;
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrEmpty($ListCounter) -eq $FALSE) {
|
||||
return ListCountersFromCategory -CounterCategory $ListCounter;
|
||||
}
|
||||
|
||||
# Make things easier by simply proividing an array of Performance Counter
|
||||
# Names we wish to monitor
|
||||
if ($CounterArray.Count -ne 0) {
|
||||
return (CreatePerformanceCounterResult -CounterArray $CounterArray);
|
||||
}
|
||||
|
||||
return CreatePerformanceCounter -Counter $Counter -SkipWait $SkipWait;
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
param(
|
||||
[bool]$IsAgentIntalled = $FALSE
|
||||
)
|
||||
|
||||
function ClassSetup()
|
||||
{
|
||||
param(
|
||||
[bool]$IsAgentIntalled = $FALSE
|
||||
);
|
||||
|
||||
$instance = New-Object -TypeName PSObject;
|
||||
|
||||
$instance | Add-Member -membertype NoteProperty -name 'BaseDirectory' -value (Join-Path $Icinga2.App.RootPath -ChildPath 'agent');
|
||||
|
||||
$instance | Add-Member -membertype ScriptMethod -name 'Init' -value {
|
||||
$IsInstalled = Get-Icinga-Config -Key 'setup.installed';
|
||||
|
||||
if ($IsAgentIntalled) {
|
||||
if ($IsInstalled -eq $FALSE -Or $IsInstalled -eq $null) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
$this.CreateDirectories('config');
|
||||
$this.CreateDirectories('state');
|
||||
|
||||
if ($IsInstalled -eq $FALSE -Or $IsInstalled -eq $null) {
|
||||
$this.InstallEventLog();
|
||||
$this.CreateConfig();
|
||||
}
|
||||
|
||||
# At this point for this module, we require to return 1 as 'true'
|
||||
return 1;
|
||||
}
|
||||
|
||||
$instance | Add-Member -membertype ScriptMethod -name 'CreateDirectories' -value {
|
||||
param([string]$directory);
|
||||
|
||||
[string]$path = Join-Path $this.BaseDirectory -ChildPath $directory;
|
||||
if (-Not (Test-Path $path)) {
|
||||
New-Item $path -ItemType Directory | Out-Null;
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
([string]::Format('Creating new directory "{0}"', $path))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$instance | Add-Member -membertype ScriptMethod -name 'InstallEventLog' -value {
|
||||
try {
|
||||
New-EventLog -LogName Application -Source ($Icinga2.Service.servicedisplayname) -ErrorAction Stop;
|
||||
$Icinga2.Log.WriteConsole(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
[string]::Format(
|
||||
'Successfully installed EventLog "{0}" for this module',
|
||||
$Icinga2.Service.servicedisplayname
|
||||
)
|
||||
);
|
||||
} catch {
|
||||
$Icinga2.Log.WriteConsole(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
[string]::Format(
|
||||
'EventLog for "{0}" is already installed.',
|
||||
$Icinga2.Service.servicedisplayname
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$instance | Add-Member -membertype ScriptMethod -name 'CreateConfig' -value {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Info,
|
||||
'### Installing default configuration values ###'
|
||||
);
|
||||
|
||||
Set-Icinga-Config -Key 'checker.server.host' -Value 'https://localhost/icingaweb2/windows/checkresult' | Out-Null;
|
||||
Set-Icinga-Config -Key 'checker.ssl.verify' -Value $TRUE | Out-Null;
|
||||
Set-Icinga-Config -Key 'tcp.socket.host' -Value 'localhost' | Out-Null;
|
||||
Set-Icinga-Config -Key 'tcp.socket.port' -Value '5891' | Out-Null;
|
||||
Set-Icinga-Config -Key 'service.name' -Value 'icinga2winservice' | Out-Null;
|
||||
Set-Icinga-Config -Key 'service.displayname' -Value 'Icinga 2 Windows Service' | Out-Null;
|
||||
Set-Icinga-Config -Key 'setup.installed' -Value $TRUE | Out-Null;
|
||||
Set-Icinga-Config -Key 'certstore.name' -Value 'My' | Out-Null;
|
||||
Set-Icinga-Config -Key 'certstore.location' -Value 'LocalMachine' | Out-Null;
|
||||
Set-Icinga-Config -Key 'certstore.certificate.name' -Value '' | Out-Null;
|
||||
Set-Icinga-Config -Key 'certstore.certificate.thumbprint' -Value '' | Out-Null;
|
||||
Set-Icinga-Config -Key 'logger.directory' -Value '' | Out-Null;
|
||||
Set-Icinga-Config -Key 'logger.debug' -Value $FALSE | Out-Null;
|
||||
Set-Icinga-Config -Key 'authentication.enabled' -Value $FALSE | Out-Null;
|
||||
Set-Icinga-Config -Key 'authentication.user' -Value '' | Out-Null;
|
||||
Set-Icinga-Config -Key 'authentication.domain' -Value '' | Out-Null;
|
||||
}
|
||||
|
||||
return $instance.Init();
|
||||
}
|
||||
|
||||
return ClassSetup -IsAgentIntalled $IsAgentIntalled;
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
|
||||
|
||||
function ClassBIOS
|
||||
{
|
||||
# Lets load some bios informations
|
||||
$BIOSInformation = Get-CimInstance Win32_BIOS;
|
||||
[hashtable]$BIOSData = @{};
|
||||
|
||||
foreach ($bios_properties in $BIOSInformation) {
|
||||
#$bios_datails = @{};
|
||||
foreach($bios in $bios_properties.CimInstanceProperties) {
|
||||
#$bios_datails.Add($bios.Name, $bios.Value);
|
||||
$BIOSData.Add($bios.Name, $bios.Value);
|
||||
}
|
||||
#$BIOSData.Add($bios_datails.DeviceID, $bios_datails);
|
||||
}
|
||||
|
||||
return $BIOSData;
|
||||
}
|
||||
|
||||
return ClassBIOS;
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
function ClassCertificates()
|
||||
{
|
||||
param($Config = $null);
|
||||
|
||||
[hashtable]$CertStore = @{};
|
||||
[hashtable]$CertLocation = @{};
|
||||
[hashtable]$CertCounters = @{};
|
||||
|
||||
Set-Location 'cert:' | Out-Null;
|
||||
$certs = Get-ChildItem -Recurse;
|
||||
|
||||
foreach ($cert in $certs) {
|
||||
if ($cert.LocationName) {
|
||||
if ($CertStore.ContainsKey($cert.LocationName) -eq $FALSE) {
|
||||
$CertStore.Add($cert.LocationName, @{});
|
||||
}
|
||||
}
|
||||
|
||||
if ($cert.IssuerName) {
|
||||
[hashtable]$Certificate = @{};
|
||||
$Certificate.Add('Archived', $cert.Archived);
|
||||
$Certificate.Add('HasPrivateKey', $cert.HasPrivateKey);
|
||||
$Certificate.Add('IssuerName.Name', $cert.IssuerName.Name);
|
||||
$Certificate.Add('IssuerName.Oid', $cert.IssuerName.Oid);
|
||||
$Certificate.Add('NotAfter', $cert.NotAfter);
|
||||
$Certificate.Add('NotBefore', $cert.NotBefore);
|
||||
$Certificate.Add('SerialNumber', $cert.SerialNumber);
|
||||
$Certificate.Add('SubjectName.Name', $cert.SubjectName.Name);
|
||||
$Certificate.Add('SubjectOid.Oid', $cert.SubjectName.Oid);
|
||||
$Certificate.Add('SignatureAlgorithm.Value', $cert.SignatureAlgorithm.Value);
|
||||
$Certificate.Add('SignatureAlgorithm.FriendlyName', $cert.SignatureAlgorithm.FriendlyName);
|
||||
$Certificate.Add('Thumbprint', $cert.Thumbprint);
|
||||
$Certificate.Add('Version', $cert.Version);
|
||||
$Certificate.Add('Issuer', $cert.Issuer);
|
||||
$Certificate.Add('Subject', $cert.Subject);
|
||||
$Certificate.Add('PSParentPath', $cert.PSParentPath);
|
||||
$Certificate.Add('PSChildName', $cert.PSChildName);
|
||||
$Certificate.Add('DnsNameList', $cert.DnsNameList);
|
||||
|
||||
[string]$cert_store = (GetCertStore -CertPath $cert.PSPath);
|
||||
[string]$cert_location = (GetCertLocation -CertPath $cert.PSPath);
|
||||
|
||||
$Certificate.Add('CertStore', $cert_store);
|
||||
$Certificate.Add('CertLocation', $cert_location);
|
||||
|
||||
if ($CertLocation.ContainsKey($cert_location)) {
|
||||
$CertLocation[$cert_location] += $Certificate;
|
||||
} else {
|
||||
$CertLocation.Add($cert_location, @( $Certificate ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($cert_arr in $CertLocation.Keys) {
|
||||
foreach ($cert in $CertLocation[$cert_arr]) {
|
||||
[string]$CertFullPathCache = [string]::Format(
|
||||
'{0}\{1}\{2}',
|
||||
$cert.CertStore,
|
||||
$cert.CertLocation,
|
||||
$cert.Thumbprint
|
||||
);
|
||||
if ($CertCounters.ContainsKey($CertFullPathCache) -eq $FALSE) {
|
||||
$CertCounters.Add($CertFullPathCache, 1);
|
||||
} else {
|
||||
$CertCounters[$CertFullPathCache] += 1;
|
||||
}
|
||||
if ($CertStore[$cert.CertStore].ContainsKey($cert.CertLocation)) {
|
||||
[string]$CertThumbprintKey = $cert.Thumbprint;
|
||||
if ($CertCounters[$CertFullPathCache] -gt 1) {
|
||||
$CertThumbprintKey = [string]::Format(
|
||||
'{0} ({1})',
|
||||
$CertThumbprintKey,
|
||||
$CertCounters[$CertFullPathCache]
|
||||
);
|
||||
}
|
||||
$CertStore[$cert.CertStore][$cert.CertLocation].Add($CertThumbprintKey, $cert);
|
||||
} else {
|
||||
$CertStore[$cert.CertStore].Add($cert.CertLocation, @{ $cert.Thumbprint = $cert });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $CertStore
|
||||
}
|
||||
|
||||
function GetCertStore()
|
||||
{
|
||||
param([string]$CertPath);
|
||||
|
||||
$CertPath = $CertPath.Replace('Microsoft.PowerShell.Security\', '');
|
||||
$CertPath = $CertPath.Replace('Certificate::', '');
|
||||
|
||||
[array]$path = $CertPath.Split('\');
|
||||
|
||||
return $path[0];
|
||||
}
|
||||
|
||||
function GetCertLocation()
|
||||
{
|
||||
param([string]$CertPath);
|
||||
|
||||
$CertPath = $CertPath.Replace('Microsoft.PowerShell.Security\', '');
|
||||
$CertPath = $CertPath.Replace('Certificate::', '');
|
||||
|
||||
[array]$path = $CertPath.Split('\');
|
||||
|
||||
return $path[1];
|
||||
}
|
||||
|
||||
return ClassCertificates -Config $Config;
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
function ClassCPU
|
||||
{
|
||||
param($Config = $null);
|
||||
|
||||
# This will return a hashtable with every single counter
|
||||
# We specify within the array
|
||||
$counter = Get-Icinga-Counter -CounterArray @(
|
||||
'\Processor(*)\% Processor Time',
|
||||
'\System\Processor Queue Length',
|
||||
'\System\Threads'
|
||||
);
|
||||
|
||||
return $counter;
|
||||
}
|
||||
|
||||
return ClassCPU -Config $Config;
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
function ClassDisk()
|
||||
{
|
||||
param($Config = $null);
|
||||
# The storage variables we require to store our data
|
||||
[hashtable]$StructuredDiskData = @{};
|
||||
|
||||
# This will return a hashtable with every single counter
|
||||
# we specify within the array. Instead of returning all
|
||||
# the values in the returned hashtable, we will rebuild
|
||||
# the result a little to have a improved output which
|
||||
# is more user friendly and allows us to check for
|
||||
# certain disks / volumes in details with a simpler
|
||||
# accessing possibility
|
||||
$counter = Get-Icinga-Counter -CounterArray @(
|
||||
'\PhysicalDisk(*)\% Disk Read Time',
|
||||
'\PhysicalDisk(*)\Current Disk Queue Length',
|
||||
'\PhysicalDisk(*)\Avg. Disk Bytes/Transfer',
|
||||
'\PhysicalDisk(*)\Split IO/sec',
|
||||
'\PhysicalDisk(*)\Disk Reads/sec',
|
||||
'\PhysicalDisk(*)\Disk Writes/sec',
|
||||
'\PhysicalDisk(*)\Disk Bytes/sec',
|
||||
'\PhysicalDisk(*)\Avg. Disk Read Queue Length',
|
||||
'\PhysicalDisk(*)\Avg. Disk sec/Write',
|
||||
'\PhysicalDisk(*)\% Disk Time',
|
||||
'\PhysicalDisk(*)\Avg. Disk sec/Transfer',
|
||||
'\PhysicalDisk(*)\Avg. Disk Bytes/Write',
|
||||
'\PhysicalDisk(*)\% Disk Write Time',
|
||||
'\PhysicalDisk(*)\Avg. Disk Queue Length',
|
||||
'\PhysicalDisk(*)\Disk Write Bytes/sec',
|
||||
'\PhysicalDisk(*)\Avg. Disk sec/Read',
|
||||
'\PhysicalDisk(*)\Disk Read Bytes/sec',
|
||||
'\PhysicalDisk(*)\Disk Transfers/sec',
|
||||
'\PhysicalDisk(*)\% Idle Time',
|
||||
'\PhysicalDisk(*)\Avg. Disk Write Queue Length',
|
||||
'\PhysicalDisk(*)\Avg. Disk Bytes/Read'
|
||||
);
|
||||
|
||||
$logicalCounter = Get-Icinga-Counter -CounterArray @(
|
||||
'\LogicalDisk(*)\Free Megabytes',
|
||||
'\LogicalDisk(*)\% Free Space'
|
||||
);
|
||||
|
||||
# This function will help us to build a structured output based on
|
||||
# volumes / disks found within the instances. We will use our
|
||||
# LogicalDisk as 'index' to assign our performance Counters to.
|
||||
# In addition we then provide the hashtable of counters we fetched
|
||||
# above. Last but not least we cleanup the instances name to replace
|
||||
# 'HarddiskVolume1' for '1' for example, to ensure the mapping of disk
|
||||
# informations is working as intended
|
||||
[hashtable]$DiskData = Get-Icinga-Counter `
|
||||
-CreateStructuredOutputForCategory 'PhysicalDisk' `
|
||||
-StructuredCounterInput $counter;
|
||||
|
||||
foreach ($counters in $logicalCounter.Keys) {
|
||||
foreach ($counter in $logicalCounter[$counters].Keys) {
|
||||
[string]$instance = $counter;
|
||||
if ($instance.Contains('(') -And $instance.Contains(')')) {
|
||||
[int]$bracketStart = $instance.IndexOf('(') + 1;
|
||||
[int]$bracketEnd = $instance.IndexOf(')');
|
||||
$instance = $instance.Substring($bracketStart, $bracketEnd - $bracketStart);
|
||||
$instanceArray = $counter.Split('\');
|
||||
$counterName = $instanceArray[$instanceArray.Length - 1];
|
||||
foreach ($disk in $DiskData.Keys) {
|
||||
if ($disk.Contains($instance)) {
|
||||
$DiskData[$disk].Add(
|
||||
$counterName,
|
||||
$logicalCounter[$counters][$counter]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Rewrite our output a little to make it more user friendly
|
||||
# This is unique for disks, as we want to remove the ':' from
|
||||
# Drive Letters and add back the HarddiskVolume label to volumes
|
||||
# to prevent having only a numeric table keys. Example:
|
||||
# '1' => 'HarddiskVolume1'
|
||||
foreach ($disk in $DiskData.Keys) {
|
||||
$NewKey = $disk.Replace(':', '');
|
||||
if ($NewKey -match "^[\d\.]+$") {
|
||||
$NewKey = [string]::Format('HarddiskVolume{0}', $NewKey);
|
||||
}
|
||||
if ($NewKey[0] -match "^[\d\.]+$") {
|
||||
$NewKey = $NewKey.Substring(2, $NewKey.Length - 2);
|
||||
}
|
||||
$StructuredDiskData.Add($NewKey, $DiskData[$disk]);
|
||||
}
|
||||
|
||||
return $StructuredDiskData;
|
||||
}
|
||||
|
||||
return ClassDisk -Config $Config;
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
return $Icinga2.Utils.Modules.LoadIncludes(
|
||||
$MyInvocation.MyCommand.Name,
|
||||
$Config
|
||||
);
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
param($Config = $null);
|
||||
#
|
||||
# Fetch the CPU Hardware informations
|
||||
#
|
||||
|
||||
# Lets load some additional CPU informations, besides current performance counters
|
||||
# It might be useful to get more details about the hardware itself
|
||||
$CPUInformations = Get-CimInstance Win32_Processor;
|
||||
[hashtable]$PhysicalCPUData = @{};
|
||||
|
||||
foreach ($cpu_properties in $CPUInformations) {
|
||||
$cpu_datails = @{};
|
||||
foreach($cpu_core in $cpu_properties.CimInstanceProperties) {
|
||||
$cpu_datails.Add($cpu_core.Name, $cpu_core.Value);
|
||||
}
|
||||
$PhysicalCPUData.Add($cpu_datails.DeviceID, $cpu_datails);
|
||||
}
|
||||
|
||||
return $PhysicalCPUData;
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
param($Config = $null);
|
||||
#
|
||||
# Fetch the Disk Hardware informations
|
||||
#
|
||||
|
||||
# Lets load some additional disk informations, besides current data
|
||||
# It might be useful to get more details about the hardware itself
|
||||
$DisksInformations = Get-CimInstance Win32_DiskDrive;
|
||||
|
||||
[hashtable]$PhysicalDiskData = @{};
|
||||
|
||||
foreach ($disk_properties in $DisksInformations) {
|
||||
$disk_datails = @{};
|
||||
foreach($disk in $disk_properties.CimInstanceProperties) {
|
||||
$disk_datails.Add($disk.Name, $disk.Value);
|
||||
}
|
||||
$disk_datails.Add('DriveReference', @());
|
||||
$PhysicalDiskData.Add($disk_datails.DeviceID, $disk_datails);
|
||||
}
|
||||
|
||||
$DiskPartitionInfo = Get-WmiObject Win32_DiskDriveToDiskPartition;
|
||||
|
||||
[hashtable]$MapDiskPartitionToLogicalDisk = @{};
|
||||
|
||||
foreach ($item in $DiskPartitionInfo) {
|
||||
[string]$diskPartition = $item.Dependent.SubString(
|
||||
$item.Dependent.LastIndexOf('=') + 1,
|
||||
$item.Dependent.Length - $item.Dependent.LastIndexOf('=') - 1
|
||||
);
|
||||
$diskPartition = $diskPartition.Replace('"', '');
|
||||
|
||||
[string]$physicalDrive = $item.Antecedent.SubString(
|
||||
$item.Antecedent.LastIndexOf('\') + 1,
|
||||
$item.Antecedent.Length - $item.Antecedent.LastIndexOf('\') - 1
|
||||
)
|
||||
$physicalDrive = $physicalDrive.Replace('"', '');
|
||||
|
||||
$MapDiskPartitionToLogicalDisk.Add($diskPartition, $physicalDrive);
|
||||
}
|
||||
|
||||
$LogicalDiskInfo = Get-WmiObject Win32_LogicalDiskToPartition;
|
||||
|
||||
foreach ($item in $LogicalDiskInfo) {
|
||||
[string]$driveLetter = $item.Dependent.SubString(
|
||||
$item.Dependent.LastIndexOf('=') + 1,
|
||||
$item.Dependent.Length - $item.Dependent.LastIndexOf('=') - 1
|
||||
);
|
||||
$driveLetter = $driveLetter.Replace('"', '');
|
||||
|
||||
[string]$diskPartition = $item.Antecedent.SubString(
|
||||
$item.Antecedent.LastIndexOf('=') + 1,
|
||||
$item.Antecedent.Length - $item.Antecedent.LastIndexOf('=') - 1
|
||||
)
|
||||
$diskPartition = $diskPartition.Replace('"', '');
|
||||
|
||||
if ($MapDiskPartitionToLogicalDisk.ContainsKey($diskPartition)) {
|
||||
foreach ($disk in $PhysicalDiskData.Keys) {
|
||||
[string]$DiskId = $disk.SubString(
|
||||
$disk.LastIndexOf('\') + 1,
|
||||
$disk.Length - $disk.LastIndexOf('\') - 1
|
||||
);
|
||||
|
||||
if ($DiskId.ToLower() -eq $MapDiskPartitionToLogicalDisk[$diskPartition].ToLower()) {
|
||||
$PhysicalDiskData[$disk]['DriveReference'] += $driveLetter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $PhysicalDiskData;
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
param($Config = $null);
|
||||
#
|
||||
# Fetch the Memory Hardware informations
|
||||
#
|
||||
|
||||
# Lets load some additional memory informations, besides current performance counters
|
||||
# It might be useful to get more details about the hardware itself
|
||||
$MemoryInformations = Get-CimInstance Win32_PhysicalMemory;
|
||||
$capacity = $MemoryInformations | Measure-Object -Property capacity -Sum;
|
||||
|
||||
# Lets load the details from our RAM modules
|
||||
[hashtable]$PhysicalMemoryData = @{};
|
||||
|
||||
$PhysicalMemoryData.Add('Modules', $capacity.Count);
|
||||
|
||||
foreach($memory_object in $MemoryInformations) {
|
||||
$memory_datails = @{};
|
||||
$memory_datails.Add('caption', $memory_object.Caption);
|
||||
$memory_datails.Add('desc', $memory_object.Description);
|
||||
$memory_datails.Add('name', $memory_object.Name);
|
||||
$memory_datails.Add('install_date', $memory_object.InstallDate);
|
||||
$memory_datails.Add('status', $memory_object.Status);
|
||||
$memory_datails.Add('creation_class_name', $memory_object.CreationClassName);
|
||||
$memory_datails.Add('manufacturer', $memory_object.Manufacturer);
|
||||
$memory_datails.Add('model', $memory_object.Model);
|
||||
$memory_datails.Add('other_identifiying_info', $memory_object.OtherIdentifyingInfo);
|
||||
$memory_datails.Add('part_number', $memory_object.PartNumber);
|
||||
$memory_datails.Add('powered_on', $memory_object.PoweredOn);
|
||||
$memory_datails.Add('serial_number', $memory_object.SerialNumber);
|
||||
$memory_datails.Add('sku', $memory_object.SKU);
|
||||
$memory_datails.Add('tag', $memory_object.Tag);
|
||||
$memory_datails.Add('version', $memory_object.Version);
|
||||
$memory_datails.Add('hot_swappable', $memory_object.HotSwappable);
|
||||
$memory_datails.Add('removable', $memory_object.Removable);
|
||||
$memory_datails.Add('replaceable', $memory_object.Replaceable);
|
||||
$memory_datails.Add('form_factor', $memory_object.FormFactor);
|
||||
$memory_datails.Add('bank_label', $memory_object.BankLabel);
|
||||
$memory_datails.Add('capacity', $memory_object.Capacity);
|
||||
$memory_datails.Add('data_width', $memory_object.DataWidth);
|
||||
$memory_datails.Add('interleave_position', $memory_object.InterleavePosition);
|
||||
$memory_datails.Add('memory_type', $memory_object.MemoryType);
|
||||
$memory_datails.Add('position_in_row', $memory_object.PositionInRow);
|
||||
$memory_datails.Add('speed', $memory_object.Speed);
|
||||
$memory_datails.Add('total_width', $memory_object.TotalWidth);
|
||||
$memory_datails.Add('attributes', $memory_object.Attributes);
|
||||
$memory_datails.Add('configured_clock_speed', $memory_object.ConfiguredClockSpeed);
|
||||
$memory_datails.Add('configured_voltage', $memory_object.ConfiguredVoltage);
|
||||
$memory_datails.Add('device_locator', $memory_object.DeviceLocator);
|
||||
$memory_datails.Add('interleave_data_depth', $memory_object.InterleaveDataDepth);
|
||||
$memory_datails.Add('max_voltage', $memory_object.MaxVoltage);
|
||||
$memory_datails.Add('min_voltage', $memory_object.MinVoltage);
|
||||
$memory_datails.Add('smbios_memory_type', $memory_object.SMBIOSMemoryType);
|
||||
$memory_datails.Add('type_detail', $memory_object.TypeDetail);
|
||||
$memory_datails.Add('ps_computer_name', $memory_object.PSComputerName);
|
||||
|
||||
$PhysicalMemoryData.Add($memory_object.Tag, $memory_datails);
|
||||
}
|
||||
|
||||
return $PhysicalMemoryData;
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
[hashtable]$HotfixInfo = @{};
|
||||
[hashtable]$HotfixNameCache = @{};
|
||||
|
||||
# First fetch all of our hotfixes
|
||||
$Hotfixes = Get-Hotfix;
|
||||
|
||||
foreach ($property in $Hotfixes) {
|
||||
[hashtable]$HotfixData = @{};
|
||||
foreach ($hotfix in $property.Properties) {
|
||||
$HotfixData.Add($hotfix.Name, $hotfix.Value);
|
||||
}
|
||||
|
||||
[string]$name = [string]::Format('{0} [{1}]', $HotfixData.HotFixID, $HotfixData.InstalledOn);
|
||||
|
||||
if ($HotfixNameCache.ContainsKey($name) -eq $FALSE) {
|
||||
$HotfixNameCache.Add($name, 1);
|
||||
} else {
|
||||
$HotfixNameCache[$name] += 1;
|
||||
$name = [string]::Format('{0} ({1})', $name, $HotfixNameCache[$name]);
|
||||
}
|
||||
|
||||
$HotfixInfo.Add($name, $HotfixData);
|
||||
}
|
||||
|
||||
return $HotfixInfo;
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
[hashtable]$PendingUpdates = @{};
|
||||
[hashtable]$PendingUpdateNameCache = @{};
|
||||
# Fetch all informations about installed updates and add them
|
||||
$WindowsUpdates = New-Object -ComObject "Microsoft.Update.Session";
|
||||
$SearchIndex = $WindowsUpdates.CreateUpdateSearcher();
|
||||
|
||||
try {
|
||||
# Get a list of current pending updates which are not yet installed on the system
|
||||
$Pending = $SearchIndex.Search("IsInstalled=0");
|
||||
$PendingUpdates.Add('count', $Pending.Updates.Count);
|
||||
|
||||
foreach ($update in $Pending.Updates) {
|
||||
[hashtable]$PendingUpdateDetails = @{};
|
||||
$PendingUpdateDetails.Add('Title', $update.Title);
|
||||
$PendingUpdateDetails.Add('Deadline', $update.Deadline);
|
||||
$PendingUpdateDetails.Add('Description', $update.Description);
|
||||
$PendingUpdateDetails.Add('IsBeta', $update.IsBeta);
|
||||
$PendingUpdateDetails.Add('IsDownloaded', $update.IsDownloaded);
|
||||
$PendingUpdateDetails.Add('IsHidden', $update.IsHidden);
|
||||
$PendingUpdateDetails.Add('IsInstalled', $update.IsInstalled);
|
||||
$PendingUpdateDetails.Add('IsMandatory', $update.IsMandatory);
|
||||
$PendingUpdateDetails.Add('IsUninstallable', $update.IsUninstallable);
|
||||
$PendingUpdateDetails.Add('Languages', $update.Languages);
|
||||
$PendingUpdateDetails.Add('LastDeploymentChangeTime', $update.LastDeploymentChangeTime);
|
||||
$PendingUpdateDetails.Add('MaxDownloadSize', $update.MaxDownloadSize);
|
||||
$PendingUpdateDetails.Add('MinDownloadSize', $update.MinDownloadSize);
|
||||
$PendingUpdateDetails.Add('MoreInfoUrls', $update.MoreInfoUrls);
|
||||
$PendingUpdateDetails.Add('MsrcSeverity', $update.MsrcSeverity);
|
||||
$PendingUpdateDetails.Add('RecommendedCpuSpeed', $update.RecommendedCpuSpeed);
|
||||
$PendingUpdateDetails.Add('RecommendedHardDiskSpace', $update.RecommendedHardDiskSpace);
|
||||
$PendingUpdateDetails.Add('RecommendedMemory', $update.RecommendedMemory);
|
||||
$PendingUpdateDetails.Add('ReleaseNotes', $update.ReleaseNotes);
|
||||
$PendingUpdateDetails.Add('SecurityBulletinIDs', $update.SecurityBulletinIDs);
|
||||
$PendingUpdateDetails.Add('SupersededUpdateIDs', $update.SupersededUpdateIDs);
|
||||
$PendingUpdateDetails.Add('SupportUrl', $update.SupportUrl);
|
||||
$PendingUpdateDetails.Add('Type', $update.Type);
|
||||
$PendingUpdateDetails.Add('UninstallationNotes', $update.UninstallationNotes);
|
||||
$PendingUpdateDetails.Add('UninstallationBehavior', $update.UninstallationBehavior);
|
||||
$PendingUpdateDetails.Add('UninstallationSteps', $update.UninstallationSteps);
|
||||
$PendingUpdateDetails.Add('KBArticleIDs', $update.KBArticleIDs);
|
||||
$PendingUpdateDetails.Add('DeploymentAction', $update.DeploymentAction);
|
||||
$PendingUpdateDetails.Add('DownloadPriority', $update.DownloadPriority);
|
||||
$PendingUpdateDetails.Add('RebootRequired', $update.RebootRequired);
|
||||
$PendingUpdateDetails.Add('IsPresent', $update.IsPresent);
|
||||
$PendingUpdateDetails.Add('CveIDs', $update.CveIDs);
|
||||
$PendingUpdateDetails.Add('BrowseOnly', $update.BrowseOnly);
|
||||
$PendingUpdateDetails.Add('PerUser', $update.PerUser);
|
||||
$PendingUpdateDetails.Add('AutoSelection', $update.AutoSelection);
|
||||
$PendingUpdateDetails.Add('AutoDownload', $update.AutoDownload);
|
||||
|
||||
[string]$name = [string]::Format('{0} [{1}]', $update.Title, $update.LastDeploymentChangeTime);
|
||||
|
||||
if ($PendingUpdateNameCache.ContainsKey($name) -eq $FALSE) {
|
||||
$PendingUpdateNameCache.Add($name, 1);
|
||||
} else {
|
||||
$PendingUpdateNameCache[$name] += 1;
|
||||
$name = [string]::Format('{0} ({1})', $name, $PendingUpdateNameCache[$name]);
|
||||
}
|
||||
|
||||
$PendingUpdates.Add($name, $PendingUpdateDetails);
|
||||
}
|
||||
} catch {
|
||||
if ($PendingUpdates.ContainsKey('Count') -eq $FALSE) {
|
||||
$PendingUpdates.Add('count', 0);
|
||||
} else {
|
||||
$PendingUpdates['count'] = 0;
|
||||
}
|
||||
$PendingUpdates.Add('error', [string]::Format(
|
||||
'Failed to query Windows Update server: {0}',
|
||||
$_.Exception.Message
|
||||
));
|
||||
}
|
||||
|
||||
return $PendingUpdates;
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
# Fetch all informations about installed updates and add them
|
||||
$WindowsUpdates = New-Object -ComObject "Microsoft.Update.Session";
|
||||
$SearchIndex = $WindowsUpdates.CreateUpdateSearcher();
|
||||
[hashtable]$UpdateList = @{};
|
||||
[hashtable]$UpdateInstalled = @{};
|
||||
[hashtable]$UpdateUninstalled = @{};
|
||||
[hashtable]$UpdateOther = @{};
|
||||
|
||||
# Operation ID's
|
||||
# 1: Installed
|
||||
# 2: Uninstalled
|
||||
# 3: Other
|
||||
|
||||
# At first get a list of our Windows Update history
|
||||
$Updates = $SearchIndex.QueryHistory(0, $SearchIndex.GetTotalHistoryCount()) |
|
||||
Select-Object Operation, ResultCode, HResult, Date, Title, Description, ServiceID, SupportUrl;
|
||||
|
||||
foreach ($update in $Updates) {
|
||||
[string]$UpdateKey = [string]::Format('{0} [{1}|{2}]', $update.Title, $update.Date, $update.HResult);
|
||||
switch ($update.Operation) {
|
||||
1 {
|
||||
if ($UpdateInstalled.ContainsKey($UpdateKey) -eq $FALSE) {
|
||||
$UpdateInstalled.Add($UpdateKey, $update);
|
||||
} else {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
[string]::Format(
|
||||
'Unable to add update "{0}" to update list. The key with content "{1}" is already present',
|
||||
$UpdateKey,
|
||||
$update
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
2 {
|
||||
if ($UpdateUninstalled.ContainsKey($UpdateKey) -eq $FALSE) {
|
||||
$UpdateUninstalled.Add($UpdateKey, $update);
|
||||
} else {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
[string]::Format(
|
||||
'Unable to add update "{0}" to update list. The key with content "{1}" is already present',
|
||||
$UpdateKey,
|
||||
$update
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
default {
|
||||
if ($UpdateOther.ContainsKey($UpdateKey) -eq $FALSE) {
|
||||
$UpdateOther.Add($UpdateKey, $update);
|
||||
} else {
|
||||
$Icinga2.Log.Write(
|
||||
$Icinga2.Enums.LogState.Warning,
|
||||
[string]::Format(
|
||||
'Unable to add update "{0}" to update list. The key with content "{1}" is already present',
|
||||
$UpdateKey,
|
||||
$update
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
$UpdateList.Add('installed', $UpdateInstalled);
|
||||
$UpdateList.Add('uninstalled', $UpdateUninstalled);
|
||||
$UpdateList.Add('other', $UpdateOther);
|
||||
|
||||
return $UpdateList;
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
|
||||
|
||||
param($Config = $null);
|
||||
|
||||
function ClassMemory
|
||||
{
|
||||
param($Config = $null);
|
||||
# This will return a hashtable with every single counter
|
||||
# We specify within the array
|
||||
$counter = Get-Icinga-Counter -CounterArray @(
|
||||
'\Memory\Available Bytes',
|
||||
'\Memory\% Committed Bytes In Use',
|
||||
'\Memory\Committed Bytes',
|
||||
'\Memory\Cache Bytes',
|
||||
'\Memory\Pool Nonpaged Bytes',
|
||||
'\Memory\Pages/sec',
|
||||
'\Memory\Page Reads/sec',
|
||||
'\Memory\Page Writes/sec',
|
||||
'\Memory\Pages Input/sec',
|
||||
'\Memory\Pages Output/sec',
|
||||
'\Paging File(*)\% Usage',
|
||||
'\Paging File(*)\% Usage Peak'
|
||||
);
|
||||
|
||||
# Lets load some additional memory informations, besides current performance counters
|
||||
$ComputerInformation = Get-CimInstance Win32_ComputerSystem;
|
||||
$counter.Add('\Memory\Physical Memory Total Bytes', @{ 'value' = $ComputerInformation.TotalPhysicalMemory; 'sample' = @{ }; });
|
||||
|
||||
return $counter;
|
||||
}
|
||||
|
||||
return ClassMemory -Config $Config;
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
function ClassNetwork
|
||||
{
|
||||
param($Config = $null);
|
||||
# The storage variables we require to store our data
|
||||
[hashtable]$NetworkData = @{};
|
||||
[hashtable]$StructuredInterfaceData = @{};
|
||||
|
||||
$CachedNetwork = $Icinga2.Utils.Modules.GetCacheElement(
|
||||
$MyInvocation.MyCommand.Name,
|
||||
'NetworkData'
|
||||
);
|
||||
|
||||
# This will return a hashtable with every single counter
|
||||
# we specify within the array. Instead of returning all
|
||||
# the values in the returned hashtable, we will rebuild
|
||||
# the result a little to have a improved output which
|
||||
# is more user friendly and allows us to check for
|
||||
# certain interfaces in detail with a simpler
|
||||
# accessing possibility
|
||||
$counter = Get-Icinga-Counter -CounterArray @(
|
||||
'\Network Interface(*)\Bytes Received/sec',
|
||||
'\Network Interface(*)\Bytes Sent/sec',
|
||||
'\Network Interface(*)\Packets Received Unicast/sec',
|
||||
'\Network Interface(*)\Packets Sent Unicast/sec',
|
||||
'\Network Interface(*)\Packets Received Non-Unicast/sec',
|
||||
'\Network Interface(*)\Packets Sent Non-Unicast/sec',
|
||||
'\Network Interface(*)\Packets Outbound Errors',
|
||||
'\Network Interface(*)\Packets Sent/sec',
|
||||
'\Network Interface(*)\TCP RSC Exceptions/sec',
|
||||
'\Network Interface(*)\Packets Outbound Discarded',
|
||||
'\Network Interface(*)\TCP RSC Coalesced Packets/sec',
|
||||
'\Network Interface(*)\Bytes Total/sec',
|
||||
'\Network Interface(*)\Current Bandwidth',
|
||||
'\Network Interface(*)\Packets Received Unknown',
|
||||
'\Network Interface(*)\TCP Active RSC Connections',
|
||||
'\Network Interface(*)\Offloaded Connections',
|
||||
'\Network Interface(*)\Packets/sec',
|
||||
'\Network Interface(*)\Packets Received Errors',
|
||||
'\Network Interface(*)\Packets Received/sec',
|
||||
'\Network Interface(*)\Packets Received Discarded',
|
||||
'\Network Interface(*)\Output Queue Length',
|
||||
'\Network Interface(*)\TCP RSC Average Packet Size'
|
||||
);
|
||||
|
||||
# This function will help us to build a structured output based on
|
||||
# interfaces found within the instances. We will use our
|
||||
# Network Interface as 'index' to assign our performance Counters to.
|
||||
# In addition we then provide the hashtable of counters we fetched
|
||||
# above.
|
||||
$StructuredInterfaceData = Get-Icinga-Counter `
|
||||
-CreateStructuredOutputForCategory 'Network Interface' `
|
||||
-StructuredCounterInput $counter;
|
||||
|
||||
$NetworkData.Add('interfaces', $StructuredInterfaceData);
|
||||
|
||||
# Add additional details to our interfaces, like MAC Address, Interface Index and current connection status
|
||||
$NetworkAdapter = Get-WMIObject Win32_NetworkAdapter;
|
||||
|
||||
[hashtable]$DuplicateIDCache = @{};
|
||||
|
||||
foreach ($adapter in $NetworkAdapter) {
|
||||
# The Performance Counter return values in brackets with [], while WMI returns ()
|
||||
# In addition, WMI uses / within Interface names, while Perf Counter uses _
|
||||
# We need to take care about this here
|
||||
[string]$AdapterName = $adapter.Name.Replace('(', '[').Replace(')', ']');
|
||||
[string]$AdapterName = $AdapterName.Replace('/', '_');
|
||||
[string]$AdapterName = $AdapterName.Replace('#', '_');
|
||||
|
||||
# To ensure duplicate interface names will not cause this module
|
||||
# to crash, we will have to build up a cache and add numeric
|
||||
# additions.
|
||||
if ($DuplicateIDCache.ContainsKey($AdapterName) -eq $FALSE) {
|
||||
$DuplicateIDCache.Add($AdapterName, 0);
|
||||
}
|
||||
|
||||
# In case we add adapters we have no performance counters for,
|
||||
# create a new hashtable object for the name
|
||||
if ($StructuredInterfaceData.ContainsKey($AdapterName) -eq $FALSE) {
|
||||
$StructuredInterfaceData.Add($AdapterName, @{});
|
||||
} else {
|
||||
# In case the interface does already exist, check if we require
|
||||
# to rename the interface with a index ID in addition. As we
|
||||
# have to ensure Performance Counters are added to Physical Adapters
|
||||
# only, we will focus in these indexes. All other instances will
|
||||
# receive a follow-up ID.
|
||||
[int]$ID = $DuplicateIDCache[$AdapterName] + 1;
|
||||
if ($adapter.PhysicalAdapter -eq $FALSE) {
|
||||
$ID += 1;
|
||||
$DuplicateIDCache[$AdapterName] = $ID;
|
||||
} else {
|
||||
# Physical Adapters always have unique names, therefor we should
|
||||
# always use index 1 for these to ensure Performance Counter data
|
||||
# is added to the correct interfaces
|
||||
$ID = 1;
|
||||
}
|
||||
|
||||
# Only add index ID's to interfaces in case we are not equal 1
|
||||
if ($ID -ne 1) {
|
||||
$AdapterName = [string]::Format('{0} ({1})',
|
||||
$AdapterName,
|
||||
$ID
|
||||
);
|
||||
$StructuredInterfaceData.Add($AdapterName, @{});
|
||||
}
|
||||
}
|
||||
|
||||
# Add the WMI informations to this interface
|
||||
$StructuredInterfaceData[$AdapterName].Add('NetConnectionID', $adapter.NetConnectionID);
|
||||
$StructuredInterfaceData[$AdapterName].Add('InterfaceIndex', $adapter.InterfaceIndex);
|
||||
$StructuredInterfaceData[$AdapterName].Add('NetConnectionStatus', $adapter.NetConnectionStatus);
|
||||
$StructuredInterfaceData[$AdapterName].Add('DeviceID', $adapter.DeviceID);
|
||||
$StructuredInterfaceData[$AdapterName].Add('MACAddress', $adapter.MACAddress);
|
||||
$StructuredInterfaceData[$AdapterName].Add('ServiceName', $adapter.ServiceName);
|
||||
$StructuredInterfaceData[$AdapterName].Add('Speed', $adapter.Speed);
|
||||
$StructuredInterfaceData[$AdapterName].Add('AdapterType', $adapter.AdapterType);
|
||||
$StructuredInterfaceData[$AdapterName].Add('NetworkAddresses', $adapter.NetworkAddresses);
|
||||
$StructuredInterfaceData[$AdapterName].Add('Manufacturer', $adapter.Manufacturer);
|
||||
$StructuredInterfaceData[$AdapterName].Add('PNPDeviceID', $adapter.PNPDeviceID);
|
||||
$StructuredInterfaceData[$AdapterName].Add('PhysicalAdapter', $adapter.PhysicalAdapter);
|
||||
}
|
||||
|
||||
# In addition to our general network interface data, it might also
|
||||
# be helpful to have a look on the configured routing table
|
||||
$RoutingTable = Get-CimInstance -ClassName Win32_IP4RouteTable
|
||||
[array]$RoutingData = @();
|
||||
|
||||
foreach ($tables in $RoutingTable) {
|
||||
$routes = @{};
|
||||
foreach($route in $tables.CimInstanceProperties) {
|
||||
$routes.Add($route.Name, $route.Value);
|
||||
}
|
||||
$RoutingData += $routes;
|
||||
}
|
||||
|
||||
$NetworkData.Add('routes', $RoutingData);
|
||||
|
||||
$Icinga2.Utils.Modules.AddCacheElement(
|
||||
$MyInvocation.MyCommand.Name,
|
||||
'NetworkData',
|
||||
$NetworkData
|
||||
);
|
||||
|
||||
return $Icinga2.Utils.Modules.GetHashtableDiff(
|
||||
$NetworkData.Clone(),
|
||||
$CachedNetwork.Clone()
|
||||
);
|
||||
|
||||
# At the end simply return the entire hashtable
|
||||
return $NetworkData;
|
||||
}
|
||||
|
||||
return ClassNetwork -Config $Config;
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
function ClassNTP
|
||||
{
|
||||
param($Config = $null);
|
||||
[hashtable]$NTPInformations = @{};
|
||||
# This will return a hashtable with every single counter
|
||||
# we specify within the array
|
||||
$counter = Get-Icinga-Counter -CounterArray @(
|
||||
'\Windows Time service\clock frequency adjustment',
|
||||
'\Windows Time service\ntp client time source count',
|
||||
'\Windows Time service\ntp server outgoing responses',
|
||||
'\Windows Time service\computed time offset',
|
||||
'\Windows Time service\ntp roundtrip delay',
|
||||
'\Windows Time service\ntp server incoming requests'
|
||||
);
|
||||
$NTPInformations.Add('counter', $counter);
|
||||
|
||||
# Load the source from which we receive our NTP config
|
||||
$NTPInformations.Add('source', (&W32tm /query /source));
|
||||
|
||||
# Load the NTP config and parse it properly
|
||||
$NTPInformations.Add(
|
||||
'config',
|
||||
$Icinga2.Utils.IniParser.LoadFromArray(
|
||||
(&W32tm /query /configuration),
|
||||
$TRUE
|
||||
)
|
||||
);
|
||||
|
||||
return $NTPInformations;
|
||||
}
|
||||
|
||||
return ClassNTP -Config $Config;
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
$CachedProcessList = $Icinga2.Utils.Modules.GetCacheElement(
|
||||
$MyInvocation.MyCommand.Name,
|
||||
'ProcessList'
|
||||
);
|
||||
|
||||
$ProcessList = Get-WmiObject Win32_Process;
|
||||
$ProcessPerfList = Get-WmiObject Win32_PerfFormattedData_PerfProc_Process;
|
||||
|
||||
$NumberOfCPUThreads = $Icinga2.System.NumberOfCPUThreads;
|
||||
|
||||
[hashtable]$ProcessReference = @{};
|
||||
[hashtable]$Processes = @{};
|
||||
[hashtable]$ProcessValues = @{
|
||||
FullList = @{ };
|
||||
Removed = @( );
|
||||
Added = $null;
|
||||
Modified = @{ };
|
||||
}
|
||||
|
||||
foreach ($process in $ProcessList) {
|
||||
[string]$ProcessKey = [string]::Format(
|
||||
'{0} [{1}]',
|
||||
$process.ProcessName,
|
||||
$process.ProcessId
|
||||
);
|
||||
|
||||
[hashtable]$ProcessInfo = @{};
|
||||
|
||||
$ProcessInfo.Add('Name', $process.Name);
|
||||
$ProcessInfo.Add('ProcessId', $process.ProcessId);
|
||||
$ProcessInfo.Add('Priority', $process.Priority);
|
||||
$ProcessInfo.Add('PageFileUsage', $process.PageFileUsage);
|
||||
$ProcessInfo.Add('ThreadCount', $process.ThreadCount);
|
||||
$ProcessInfo.Add('KernelModeTime', $process.KernelModeTime);
|
||||
$ProcessInfo.Add('UserModeTime', $process.UserModeTime);
|
||||
$ProcessInfo.Add('WorkingSetSize', $process.WorkingSetSize);
|
||||
$ProcessInfo.Add('CommandLine', $process.CommandLine);
|
||||
<#
|
||||
# These are not required by now
|
||||
$ProcessInfo.Add('Caption', $process.Caption);
|
||||
$ProcessInfo.Add('CreationClassName', $process.CreationClassName);
|
||||
$ProcessInfo.Add('CreationDate', $process.CreationDate);
|
||||
$ProcessInfo.Add('CSCreationClassName', $process.CSCreationClassName);
|
||||
$ProcessInfo.Add('CSName', $process.CSName);
|
||||
$ProcessInfo.Add('Description', $process.Description);
|
||||
$ProcessInfo.Add('ExecutablePath', $process.ExecutablePath);
|
||||
$ProcessInfo.Add('ExecutionState', $process.ExecutionState);
|
||||
$ProcessInfo.Add('Handle', $process.Handle);
|
||||
$ProcessInfo.Add('HandleCount', $process.HandleCount);
|
||||
$ProcessInfo.Add('InstallDate', $process.InstallDate);
|
||||
$ProcessInfo.Add('MaximumWorkingSetSize', $process.MaximumWorkingSetSize);
|
||||
$ProcessInfo.Add('MinimumWorkingSetSize', $process.MinimumWorkingSetSize);
|
||||
$ProcessInfo.Add('OSCreationClassName', $process.OSCreationClassName);
|
||||
$ProcessInfo.Add('OSName', $process.OSName);
|
||||
$ProcessInfo.Add('OtherOperationCount', $process.OtherOperationCount);
|
||||
$ProcessInfo.Add('OtherTransferCount', $process.OtherTransferCount);
|
||||
$ProcessInfo.Add('PageFaults', $process.PageFaults);
|
||||
$ProcessInfo.Add('ParentProcessId', $process.ParentProcessId);
|
||||
$ProcessInfo.Add('PeakPageFileUsage', $process.PeakPageFileUsage);
|
||||
$ProcessInfo.Add('PeakVirtualSize', $process.PeakVirtualSize);
|
||||
$ProcessInfo.Add('PeakWorkingSetSize', $process.PeakWorkingSetSize);
|
||||
$ProcessInfo.Add('PrivatePageCount', $process.PrivatePageCount);
|
||||
$ProcessInfo.Add('QuotaNonPagedPoolUsage', $process.QuotaNonPagedPoolUsage);
|
||||
$ProcessInfo.Add('QuotaPagedPoolUsage', $process.QuotaPagedPoolUsage);
|
||||
$ProcessInfo.Add('QuotaPeakNonPagedPoolUsage', $process.QuotaPeakNonPagedPoolUsage);
|
||||
$ProcessInfo.Add('QuotaPeakPagedPoolUsage', $process.QuotaPeakPagedPoolUsage);
|
||||
$ProcessInfo.Add('ReadOperationCount', $process.ReadOperationCount);
|
||||
$ProcessInfo.Add('ReadTransferCount', $process.ReadTransferCount);
|
||||
$ProcessInfo.Add('SessionId', $process.SessionId);
|
||||
$ProcessInfo.Add('Status', $process.Status);
|
||||
$ProcessInfo.Add('TerminationDate', $process.TerminationDate);
|
||||
$ProcessInfo.Add('VirtualSize', $process.VirtualSize);
|
||||
$ProcessInfo.Add('WindowsVersion', $process.WindowsVersion);
|
||||
$ProcessInfo.Add('WriteOperationCount', $process.WriteOperationCount);
|
||||
$ProcessInfo.Add('WriteTransferCount', $process.WriteTransferCount);
|
||||
#>
|
||||
$ProcessReference.Add($process.ProcessId, $ProcessKey);
|
||||
$Processes.Add($ProcessKey, $ProcessInfo);
|
||||
}
|
||||
|
||||
foreach ($perfdata in $ProcessPerfList) {
|
||||
if ($perfdata.Name -eq '_Total') {
|
||||
continue;
|
||||
}
|
||||
if ($ProcessReference.ContainsKey($perfdata.IDProcess)) {
|
||||
$Processes[$ProcessReference[$perfdata.IDProcess]].Add(
|
||||
'WorkingSetPrivate',
|
||||
$perfdata.WorkingSetPrivate
|
||||
);
|
||||
# Note: In order to get the correct CPU time in % we have to divide the
|
||||
# Processor Time with the amount of threads installed on our CPU
|
||||
$Processes[$ProcessReference[$perfdata.IDProcess]].Add(
|
||||
'PercentProcessorTime',
|
||||
[math]::Round(($perfdata.PercentProcessorTime / $NumberOfCPUThreads), 2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$Processes.Add('count', $Processes.count);
|
||||
|
||||
$Icinga2.Utils.Modules.AddCacheElement(
|
||||
$MyInvocation.MyCommand.Name,
|
||||
'ProcessList',
|
||||
$Processes
|
||||
);
|
||||
|
||||
return $Icinga2.Utils.Modules.GetHashtableDiff(
|
||||
$Processes.Clone(),
|
||||
$CachedProcessList.Clone(),
|
||||
@('ProcessId')
|
||||
);
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
function ClassService()
|
||||
{
|
||||
param($Config = $null);
|
||||
$services = Get-Service;
|
||||
|
||||
[hashtable]$ServiceData = @{};
|
||||
|
||||
$CachedServiceData = $Icinga2.Utils.Modules.GetCacheElement(
|
||||
$MyInvocation.MyCommand.Name,
|
||||
'ServiceData'
|
||||
);
|
||||
|
||||
foreach ($service in $services) {
|
||||
[hashtable]$ServiceInfo = @{};
|
||||
|
||||
$ServiceInfo.Add('display_name', $service.DisplayName);
|
||||
$ServiceInfo.Add('service_name', $service.ServiceName);
|
||||
$ServiceInfo.Add('can_pause_and_continue', $service.CanPauseAndContinue);
|
||||
$ServiceInfo.Add('can_shutdown', $service.CanShutdown);
|
||||
$ServiceInfo.Add('can_stop', $service.CanStop);
|
||||
$ServiceInfo.Add('service_handle', $service.ServiceHandle);
|
||||
$ServiceInfo.Add('status', $service.Status);
|
||||
$ServiceInfo.Add('service_type', $service.ServiceType);
|
||||
$ServiceInfo.Add('start_type', $service.StartType);
|
||||
$ServiceInfo.Add('site', $service.Site);
|
||||
$ServiceInfo.Add('container', $service.Container);
|
||||
|
||||
[array]$DependentServices = $null;
|
||||
foreach ($dependency in $service.DependentServices) {
|
||||
if ($DependentServices -eq $null) { $DependentServices = @(); }
|
||||
$DependentServices += $dependency.Name;
|
||||
}
|
||||
$ServiceInfo.Add('dependent_services', $DependentServices);
|
||||
|
||||
[array]$DependentServices = $null;
|
||||
foreach ($dependency in $service.ServicesDependedOn) {
|
||||
if ($DependentServices -eq $null) { $DependentServices = @(); }
|
||||
$DependentServices += $dependency.Name;
|
||||
}
|
||||
$ServiceInfo.Add('depends_on', $DependentServices);
|
||||
|
||||
$ServiceData.Add($service.Name, $ServiceInfo);
|
||||
}
|
||||
|
||||
$Icinga2.Utils.Modules.AddCacheElement(
|
||||
$MyInvocation.MyCommand.Name,
|
||||
'ServiceData',
|
||||
$ServiceData
|
||||
);
|
||||
|
||||
return $Icinga2.Utils.Modules.GetHashtableDiff(
|
||||
$ServiceData.Clone(),
|
||||
$CachedServiceData.Clone(),
|
||||
@('service_name')
|
||||
);
|
||||
|
||||
return $ServiceData;
|
||||
}
|
||||
|
||||
return ClassService -Config $Config;
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
return $Icinga2.Utils.Modules.LoadIncludes(
|
||||
$MyInvocation.MyCommand.Name,
|
||||
$Config
|
||||
);
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
param($Config = $null);
|
||||
|
||||
function ClassWindows
|
||||
{
|
||||
param($Config = $null);
|
||||
$WindowsInformations = Get-CimInstance Win32_OperatingSystem;
|
||||
|
||||
$windows_datails = @{};
|
||||
foreach($cpu_core in $WindowsInformations.CimInstanceProperties) {
|
||||
$windows_datails.Add($cpu_core.Name, $cpu_core.Value);
|
||||
}
|
||||
|
||||
return $windows_datails;
|
||||
}
|
||||
|
||||
return ClassWindows -Config $Config;
|
||||
Loading…
Reference in a new issue