mirror of
https://github.com/Icinga/icinga-powershell-framework.git
synced 2025-12-20 23:00:35 -05:00
22407 lines
816 KiB
PowerShell
22407 lines
816 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Will fetch the current host configuration or general configuration depending
|
|
if a host or template key is specified from the Icinga Director Self-Service API
|
|
.DESCRIPTION
|
|
Use the Self-Service API of the Icinga Director to connect to it and fetch the
|
|
configuration to apply for this host. The configuration itself is differentiated
|
|
if a template or the specific host key is used
|
|
.FUNCTIONALITY
|
|
Fetches host or general configuration form the Icinga Director Self-Service API
|
|
.EXAMPLE
|
|
PS>Get-IcingaDirectorSelfServiceConfig -DirectorUrl 'https://example.com/icingaweb2/director -ApiKey 457g6b98054v76vb5490ß276bv0457v6054b76;
|
|
.PARAMETER DirectorUrl
|
|
The URL pointing directly to the Icinga Web 2 Director module
|
|
.PARAMETER ApiKey
|
|
Either the template or host key to authenticate against the Self-Service API
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaDirectorSelfServiceConfig()
|
|
{
|
|
param(
|
|
$DirectorUrl,
|
|
$ApiKey = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($DirectorUrl)) {
|
|
throw 'Please enter a valid Url to your Icinga Director';
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ApiKey)) {
|
|
throw 'Please enter either a template or your host key. If this message persists, ensure your host is not having a template key assigned already. If so, you can try dropping it within the Icinga Director.';
|
|
}
|
|
|
|
Set-IcingaTLSVersion;
|
|
$ProgressPreference = "SilentlyContinue";
|
|
|
|
$EndpointUrl = Join-WebPath -Path $DirectorUrl -ChildPath ([string]::Format('/self-service/powershell-parameters?key={0}', $ApiKey));
|
|
|
|
$response = Invoke-IcingaWebRequest -Uri $EndpointUrl -UseBasicParsing -Headers @{ 'accept' = 'application/json'; 'X-Director-Accept' = 'application/json' } -Method 'POST';
|
|
|
|
if ($response.StatusCode -ne 200) {
|
|
throw $response.Content;
|
|
}
|
|
|
|
$JsonContent = ConvertFrom-Json -InputObject $response.Content;
|
|
|
|
if (Test-PSCustomObjectMember -PSObject $JsonContent -Name 'error') {
|
|
throw 'Icinga Director Self-Service has thrown an error: ' + $JsonContent.error;
|
|
}
|
|
|
|
$JsonContent = Add-PSCustomObjectMember -Object $JsonContent -Key 'IcingaMaster' -Value $response.BaseResponse.ResponseUri.Host;
|
|
|
|
return $JsonContent;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Will fetch the ticket for certificate signing by using the Icinga Director
|
|
Self-Service API
|
|
.DESCRIPTION
|
|
Use the Self-Service API of the Icinga Director to connect to it and fetch the
|
|
ticket to sign Icinga 2 certificate requests
|
|
.FUNCTIONALITY
|
|
Fetches the ticket for certificate signing form the Icinga Director Self-Service API
|
|
.EXAMPLE
|
|
PS>Get-IcingaDirectorSelfServiceTicket -DirectorUrl 'https://example.com/icingaweb2/director -ApiKey 457g6b98054v76vb5490ß276bv0457v6054b76;
|
|
.PARAMETER DirectorUrl
|
|
The URL pointing directly to the Icinga Web 2 Director module
|
|
.PARAMETER ApiKey
|
|
The host key to authenticate against the Self-Service API
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaDirectorSelfServiceTicket()
|
|
{
|
|
param (
|
|
$DirectorUrl,
|
|
$ApiKey = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($DirectorUrl)) {
|
|
Write-IcingaConsoleError 'Unable to fetch host ticket. No Director url has been specified';
|
|
return;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ApiKey)) {
|
|
Write-IcingaConsoleError 'Unable to fetch host ticket. No API key has been specified';
|
|
return;
|
|
}
|
|
|
|
Set-IcingaTLSVersion;
|
|
|
|
[string]$url = Join-WebPath -Path $DirectorUrl -ChildPath ([string]::Format('/self-service/ticket?key={0}', $ApiKey));
|
|
|
|
$response = Invoke-IcingaWebRequest -Uri $url -UseBasicParsing -Headers @{ 'accept' = 'application/json'; 'X-Director-Accept' = 'application/json' } -Method 'POST';
|
|
|
|
if ($response.StatusCode -ne 200) {
|
|
throw $response.Content;
|
|
}
|
|
|
|
$JsonContent = ConvertFrom-Json -InputObject $response.Content;
|
|
|
|
return $JsonContent;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Register the current host wihtin the Icinga Director by using the
|
|
Self-Service API and return the host key
|
|
.DESCRIPTION
|
|
This function will register the current host within the Icinga Director in case
|
|
it is not already registered and returns the host key for storing it on disk
|
|
to allow the host to fetch detailed configurations like zones and endppoints
|
|
.FUNCTIONALITY
|
|
Register a host within the Icinga Director by using the Self-Service API
|
|
.EXAMPLE
|
|
PS>Register-IcingaDirectorSelfServiceHost -DirectorUrl 'https://example.com/icingaweb2/director -Hostname 'examplehost' -ApiKey 457g6b98054v76vb5490ß276bv0457v6054b76 -Endpoint 'icinga.example.com';
|
|
.PARAMETER DirectorUrl
|
|
The URL pointing directly to the Icinga Web 2 Director module
|
|
.PARAMETER Hostname
|
|
The name of the current host to register within the Icinga Director
|
|
.PARAMETER ApiKey
|
|
The template key to authenticate against the Self-Service API
|
|
.PARAMETER Endpoint
|
|
The IP or FQDN to one of the parent Icinga 2 nodes this Agent will connect to
|
|
for determining which network interface shall be used by Icinga for connecting
|
|
and to apply hostalive/ping checks to
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Register-IcingaDirectorSelfServiceHost()
|
|
{
|
|
param(
|
|
$DirectorUrl,
|
|
$Hostname,
|
|
$ApiKey = $null,
|
|
[string]$Endpoint = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($DirectorUrl)) {
|
|
throw 'Please enter a valid Url to your Icinga Director';
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Hostname)) {
|
|
throw 'Please enter the hostname to use';
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ApiKey)) {
|
|
throw 'Please enter the API key of the template you wish to use';
|
|
}
|
|
|
|
Set-IcingaTLSVersion;
|
|
$ProgressPreference = "SilentlyContinue";
|
|
$DirectorConfigJson = $null;
|
|
|
|
if ([string]::IsNullOrEmpty($Endpoint)) {
|
|
if ($DirectorUrl.Contains('https://') -Or $DirectorUrl.Contains('http://')) {
|
|
$Endpoint = $DirectorUrl.Split('/')[2];
|
|
} else {
|
|
$Endpoint = $DirectorUrl.Split('/')[0];
|
|
}
|
|
}
|
|
|
|
$Interface = Get-IcingaNetworkInterface $Endpoint;
|
|
$DirectorConfigJson = [string]::Format('{0} "address":"{2}" {1}', '{', '}', $Interface);
|
|
|
|
$EndpointUrl = Join-WebPath -Path $DirectorUrl -ChildPath ([string]::Format('/self-service/register-host?name={0}&key={1}', $Hostname, $ApiKey));
|
|
|
|
$response = Invoke-IcingaWebRequest -Uri $EndpointUrl -UseBasicParsing -Headers @{ 'accept' = 'application/json'; 'X-Director-Accept' = 'application/json' } -Method 'POST' -Body $DirectorConfigJson;
|
|
|
|
if ($response.StatusCode -ne 200) {
|
|
throw $response.Content;
|
|
}
|
|
|
|
$JsonContent = ConvertFrom-Json -InputObject $response.Content;
|
|
|
|
if (Test-PSCustomObjectMember -PSObject $JsonContent -Name 'error') {
|
|
if ($JsonContent.error -like '*already been registered*') {
|
|
return $null;
|
|
}
|
|
|
|
throw 'Icinga Director Self-Service has thrown an error: ' + $JsonContent.error;
|
|
}
|
|
|
|
Set-IcingaPowerShellConfig -Path 'IcingaDirector.SelfService.ApiKey' -Value $JsonContent;
|
|
|
|
Write-IcingaConsoleNotice 'Host was successfully registered within Icinga Director';
|
|
|
|
return $JsonContent;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Returns the amount of items for a config item
|
|
.DESCRIPTION
|
|
Returns the amount of items for a config item
|
|
.FUNCTIONALITY
|
|
Returns the amount of items for a config item
|
|
.EXAMPLE
|
|
PS>Get-IcingaConfigTreeCount -Path 'framework.daemons';
|
|
.PARAMETER Path
|
|
The path to the config item to check for
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Integer
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaConfigTreeCount()
|
|
{
|
|
param(
|
|
$Path = ''
|
|
);
|
|
|
|
$Config = Read-IcingaPowerShellConfig;
|
|
$PathArray = $Path.Split('.');
|
|
$ConfigObject = $Config;
|
|
[int]$Count = 0;
|
|
|
|
foreach ($entry in $PathArray) {
|
|
if (-Not (Test-IcingaPowerShellConfigItem -ConfigObject $ConfigObject -ConfigKey $entry)) {
|
|
continue;
|
|
}
|
|
|
|
$ConfigObject = $ConfigObject.$entry;
|
|
}
|
|
|
|
foreach ($config in $ConfigObject.PSObject.Properties) {
|
|
$Count += 1;
|
|
}
|
|
|
|
return $Count;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Returns the configuration for a provided config path
|
|
.DESCRIPTION
|
|
Returns the configuration for a provided config path
|
|
.FUNCTIONALITY
|
|
Returns the configuration for a provided config path
|
|
.EXAMPLE
|
|
PS>Get-IcingaPowerShellConfig -Path 'framework.daemons';
|
|
.PARAMETER Path
|
|
The path to the config item to check for
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaPowerShellConfig()
|
|
{
|
|
param(
|
|
$Path = ''
|
|
);
|
|
|
|
$Config = Read-IcingaPowerShellConfig;
|
|
$PathArray = $Path.Split('.');
|
|
$ConfigObject = $Config;
|
|
|
|
foreach ($entry in $PathArray) {
|
|
if (-Not (Test-IcingaPowerShellConfigItem -ConfigObject $ConfigObject -ConfigKey $entry)) {
|
|
return $null;
|
|
}
|
|
|
|
$ConfigObject = $ConfigObject.$entry;
|
|
}
|
|
|
|
return $ConfigObject;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Creates a new config entry with given arguments
|
|
.DESCRIPTION
|
|
Creates a new config entry with given arguments
|
|
.FUNCTIONALITY
|
|
Creates a new config entry with given arguments
|
|
.EXAMPLE
|
|
PS>New-IcingaPowerShellConfigItem -ConfigObject $PSObject -ConfigKey 'keyname' -ConfigValue 'keyvalue';
|
|
.PARAMETER ConfigObject
|
|
The custom config object to modify
|
|
.PARAMETER ConfigKey
|
|
The key which is added to the config object
|
|
.PARAMETER ConfigValue
|
|
The value written for the ConfigKey
|
|
.INPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function New-IcingaPowerShellConfigItem()
|
|
{
|
|
param(
|
|
$ConfigObject,
|
|
[string]$ConfigKey,
|
|
$ConfigValue = $null
|
|
);
|
|
|
|
if ($null -eq $ConfigValue) {
|
|
$ConfigValue = (New-Object -TypeName PSOBject);
|
|
}
|
|
|
|
$ConfigObject | Add-Member -MemberType NoteProperty -Name $ConfigKey -Value $ConfigValue;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Reads the entire configuration and returns it as custom object
|
|
.DESCRIPTION
|
|
Reads the entire configuration and returns it as custom object
|
|
.FUNCTIONALITY
|
|
Reads the entire configuration and returns it as custom object
|
|
.EXAMPLE
|
|
PS>Read-IcingaPowerShellConfig;
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Read-IcingaPowerShellConfig()
|
|
{
|
|
$ConfigDir = Get-IcingaPowerShellConfigDir;
|
|
$ConfigFile = Join-Path -Path $ConfigDir -ChildPath 'config.json';
|
|
|
|
if ($global:IcingaDaemonData.FrameworkRunningAsDaemon) {
|
|
if ($global:IcingaDaemonData.ContainsKey('Config')) {
|
|
return $global:IcingaDaemonData.Config;
|
|
}
|
|
}
|
|
|
|
if (-Not (Test-Path $ConfigFile)) {
|
|
return (New-Object -TypeName PSObject);
|
|
}
|
|
|
|
[string]$Content = Read-IcingaFileContent -File $ConfigFile;
|
|
|
|
if ([string]::IsNullOrEmpty($Content)) {
|
|
return (New-Object -TypeName PSObject);
|
|
}
|
|
|
|
return (ConvertFrom-Json -InputObject $Content);
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Removes a config entry from a given path
|
|
.DESCRIPTION
|
|
Removes a config entry from a given path
|
|
.FUNCTIONALITY
|
|
Removes a config entry from a given path
|
|
.EXAMPLE
|
|
PS>Remove-IcingaPowerShellConfig -Path 'framework.daemons';
|
|
.PARAMETER Path
|
|
The path to the config item to remove
|
|
.INPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Remove-IcingaPowerShellConfig()
|
|
{
|
|
param(
|
|
$Path = ''
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Path)) {
|
|
throw 'Please specify a valid path to an object';
|
|
}
|
|
|
|
$Config = Read-IcingaPowerShellConfig;
|
|
$PathArray = $Path.Split('.');
|
|
$ConfigObject = $Config;
|
|
[int]$Index = $PathArray.Count;
|
|
|
|
foreach ($entry in $PathArray) {
|
|
|
|
if (-Not (Test-IcingaPowerShellConfigItem -ConfigObject $ConfigObject -ConfigKey $entry)) {
|
|
return $null;
|
|
}
|
|
|
|
if ($index -eq 1) {
|
|
$ConfigObject.PSObject.Properties.Remove($entry);
|
|
break;
|
|
}
|
|
|
|
$ConfigObject = $ConfigObject.$entry;
|
|
$Index -= 1;
|
|
}
|
|
|
|
Write-IcingaPowerShellConfig $Config;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Sets a config entry for a given path to a certain value
|
|
.DESCRIPTION
|
|
Sets a config entry for a given path to a certain value
|
|
.FUNCTIONALITY
|
|
Sets a config entry for a given path to a certain value
|
|
.EXAMPLE
|
|
PS>Set-IcingaPowerShellConfig -Path 'framework.daemons.servicecheck' -Value $DaemonConfig;
|
|
.PARAMETER Path
|
|
The path to the config item to be set
|
|
.PARAMETER Value
|
|
The value to be set for a specific config path
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Set-IcingaPowerShellConfig()
|
|
{
|
|
param(
|
|
$Path = '',
|
|
$Value = $null
|
|
);
|
|
|
|
$Config = Read-IcingaPowerShellConfig;
|
|
$PathArray = $Path.Split('.');
|
|
$ConfigObject = $Config;
|
|
[int]$Index = $PathArray.Count;
|
|
$InputValue = $null;
|
|
foreach ($entry in $PathArray) {
|
|
if ($index -eq 1) {
|
|
$InputValue = $Value;
|
|
}
|
|
if (-Not (Test-IcingaPowerShellConfigItem -ConfigObject $ConfigObject -ConfigKey $entry)) {
|
|
New-IcingaPowerShellConfigItem -ConfigObject $ConfigObject -ConfigKey $entry -ConfigValue $InputValue;
|
|
}
|
|
|
|
if ($index -eq 1) {
|
|
$ConfigObject.$entry = $Value;
|
|
break;
|
|
}
|
|
|
|
$ConfigObject = $ConfigObject.$entry;
|
|
$index -= 1;
|
|
}
|
|
|
|
Write-IcingaPowerShellConfig $Config;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Test if a config entry on an object is already present
|
|
.DESCRIPTION
|
|
Test if a config entry on an object is already present
|
|
.FUNCTIONALITY
|
|
Test if a config entry on an object is already present
|
|
.EXAMPLE
|
|
PS>Test-IcingaPowerShellConfigItem -ConfigObject $PSObject -ConfigKey 'keyname';
|
|
.PARAMETER ConfigObject
|
|
The custom config object to check for
|
|
.PARAMETER ConfigKey
|
|
The key which is checked
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Test-IcingaPowerShellConfigItem()
|
|
{
|
|
param(
|
|
$ConfigObject,
|
|
$ConfigKey
|
|
);
|
|
|
|
return ([bool]($ConfigObject.PSobject.Properties.Name -eq $ConfigKey) -eq $TRUE);
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Writes a given config object to disk
|
|
.DESCRIPTION
|
|
Writes a given config object to disk
|
|
.FUNCTIONALITY
|
|
Writes a given config object to disk
|
|
.EXAMPLE
|
|
PS>Write-IcingaPowerShellConfig -Config $PSObject;
|
|
.PARAMETER Config
|
|
A PSObject containing the entire configuration to write
|
|
.INPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Write-IcingaPowerShellConfig()
|
|
{
|
|
param(
|
|
$Config
|
|
);
|
|
|
|
$ConfigDir = Get-IcingaPowerShellConfigDir;
|
|
$ConfigFile = Join-Path -Path $ConfigDir -ChildPath 'config.json';
|
|
|
|
if (-Not (Test-Path $ConfigDir)) {
|
|
New-Item -Path $ConfigDir -ItemType Directory | Out-Null;
|
|
}
|
|
|
|
$Content = ConvertTo-Json -InputObject $Config -Depth 100;
|
|
|
|
Set-Content -Path $ConfigFile -Value $Content;
|
|
|
|
if ($global:IcingaDaemonData.FrameworkRunningAsDaemon) {
|
|
if ($global:IcingaDaemonData.ContainsKey('Config')) {
|
|
$global:IcingaDaemonData.Config = $Config;
|
|
}
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Reads data from a cache file of the Framework and returns its content
|
|
.DESCRIPTION
|
|
Allows a developer to read data from certain cache files to either speed up
|
|
loading procedures, to store content to not lose data on restarts of a daemon
|
|
or to build data tables over time
|
|
.FUNCTIONALITY
|
|
Returns cached data for specific content
|
|
.EXAMPLE
|
|
PS>Get-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult_store' -KeyName 'Invoke-IcingaCheckCPU';
|
|
.PARAMETER Space
|
|
The individual space to read from. This is targeted to a folder the cache data is written to under icinga-powershell-framework/cache/
|
|
.PARAMETER CacheStore
|
|
This is targeted to a sub-folder under icinga-powershell-framework/cache/<space>/
|
|
.PARAMETER KeyName
|
|
This is the actual cache file located under icinga-powershell-framework/cache/<space>/<CacheStore>/<KeyName>.json
|
|
Please note to only provide the name without the '.json' apendix. This is done by the module itself
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
function Get-IcingaCacheData()
|
|
{
|
|
param(
|
|
[string]$Space,
|
|
[string]$CacheStore,
|
|
[string]$KeyName
|
|
);
|
|
|
|
$CacheFile = Join-Path -Path (Join-Path -Path (Join-Path -Path (Get-IcingaCacheDir) -ChildPath $Space) -ChildPath $CacheStore) -ChildPath ([string]::Format('{0}.json', $KeyName));
|
|
[string]$Content = '';
|
|
$cacheData = @{ };
|
|
|
|
if ((Test-Path $CacheFile) -eq $FALSE) {
|
|
return $null;
|
|
}
|
|
|
|
$Content = Read-IcingaFileContent -File $CacheFile;
|
|
|
|
if ([string]::IsNullOrEmpty($Content)) {
|
|
return $null;
|
|
}
|
|
|
|
$cacheData = ConvertFrom-Json -InputObject ([string]$Content);
|
|
|
|
if ([string]::IsNullOrEmpty($KeyName)) {
|
|
return $cacheData;
|
|
} else {
|
|
return $cacheData.$KeyName;
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Writes data to a cache file for the Framework
|
|
.DESCRIPTION
|
|
Allows a developer to write data to certain cache files to either speed up
|
|
loading procedures, to store content to not lose data on restarts of a daemon
|
|
or to build data tables over time
|
|
.FUNCTIONALITY
|
|
Writes data for specific value to a cache file
|
|
.EXAMPLE
|
|
PS>Set-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult_store' -KeyName 'Invoke-IcingaCheckCPU' -Value @{ 'CachedData' = 'MyValue' };
|
|
.PARAMETER Space
|
|
The individual space to write to. This is targeted to a folder the cache data is written to under icinga-powershell-framework/cache/
|
|
.PARAMETER CacheStore
|
|
This is targeted to a sub-folder under icinga-powershell-framework/cache/<space>/
|
|
.PARAMETER KeyName
|
|
This is the actual cache file located under icinga-powershell-framework/cache/<space>/<CacheStore>/<KeyName>.json
|
|
Please note to only provide the name without the '.json' apendix. This is done by the module itself
|
|
.PARAMETER Value
|
|
The actual value to store within the cache file. This can be any kind of value, as long as it is convertable to JSON
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function Set-IcingaCacheData()
|
|
{
|
|
param (
|
|
[string]$Space,
|
|
[string]$CacheStore,
|
|
[string]$KeyName,
|
|
$Value
|
|
);
|
|
|
|
$CacheFile = Join-Path -Path (Join-Path -Path (Join-Path -Path (Get-IcingaCacheDir) -ChildPath $Space) -ChildPath $CacheStore) -ChildPath ([string]::Format('{0}.json', $KeyName));
|
|
$cacheData = @{ };
|
|
|
|
if ((Test-Path $CacheFile)) {
|
|
$cacheData = Get-IcingaCacheData -Space $Space -CacheStore $CacheStore;
|
|
} else {
|
|
try {
|
|
New-Item -ItemType File -Path $CacheFile -Force -ErrorAction Stop | Out-Null;
|
|
} catch {
|
|
Exit-IcingaThrowException -InputString $_.Exception -CustomMessage (Get-IcingaCacheDir) -StringPattern 'NewItemUnauthorizedAccessError' -ExceptionType 'Permission' -ExceptionThrown $IcingaExceptions.Permission.CacheFolder;
|
|
Exit-IcingaThrowException -CustomMessage $_.Exception -ExceptionType 'Unhandled' -Force;
|
|
}
|
|
}
|
|
|
|
if ($null -eq $cacheData -or $cacheData.Count -eq 0) {
|
|
$cacheData = @{
|
|
$KeyName = $Value
|
|
};
|
|
} else {
|
|
if ($cacheData.PSobject.Properties.Name -ne $KeyName) {
|
|
$cacheData | Add-Member -MemberType NoteProperty -Name $KeyName -Value $Value -Force;
|
|
} else {
|
|
$cacheData.$KeyName = $Value;
|
|
}
|
|
}
|
|
|
|
try {
|
|
Set-Content -Path $CacheFile -Value (ConvertTo-Json -InputObject $cacheData -Depth 100) | Out-Null;
|
|
} catch {
|
|
Exit-IcingaThrowException -InputString $_.Exception -CustomMessage (Get-IcingaCacheDir) -StringPattern 'System.UnauthorizedAccessException' -ExceptionType 'Permission' -ExceptionThrown $IcingaExceptions.Permission.CacheFolder;
|
|
Exit-IcingaThrowException -CustomMessage $_.Exception -ExceptionType 'Unhandled' -Force;
|
|
}
|
|
}
|
|
<#
|
|
.SYNOPSIS
|
|
Clear all cached values for all check commands executed by this thread.
|
|
This is mandatory as we might run into a memory leak otherwise!
|
|
.DESCRIPTION
|
|
Clear all cached values for all check commands executed by this thread.
|
|
This is mandatory as we might run into a memory leak otherwise!
|
|
.FUNCTIONALITY
|
|
Clear all cached values for all check commands executed by this thread.
|
|
This is mandatory as we might run into a memory leak otherwise!
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Clear-IcingaCheckSchedulerCheckData()
|
|
{
|
|
if ($null -eq $global:Icinga) {
|
|
return;
|
|
}
|
|
|
|
if ($global:Icinga.ContainsKey('CheckData') -eq $FALSE) {
|
|
return;
|
|
}
|
|
|
|
$global:Icinga.CheckData.Clear();
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Clears the entire check scheduler cache environment and frees memory as
|
|
well as cleaning the stack
|
|
.DESCRIPTION
|
|
Clears the entire check scheduler cache environment and frees memory as
|
|
well as cleaning the stack
|
|
.FUNCTIONALITY
|
|
Clears the entire check scheduler cache environment and frees memory as
|
|
well as cleaning the stack
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Clear-IcingaCheckSchedulerEnvironment()
|
|
{
|
|
if ($null -eq $global:Icinga) {
|
|
return;
|
|
}
|
|
|
|
Get-IcingaCheckSchedulerPluginOutput | Out-Null;
|
|
Get-IcingaCheckSchedulerPerfData | Out-Null;
|
|
Clear-IcingaCheckSchedulerCheckData;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
A more secure way to copy items from one location to another including error handling
|
|
.DESCRIPTION
|
|
Wrapper for the Copy-Item Cmdlet to more securely copy items with error
|
|
handling to prevent interuptions during actions
|
|
.FUNCTIONALITY
|
|
Copies items from a source to a destination location
|
|
.EXAMPLE
|
|
PS>Copy-ItemSecure -Path 'C:\users\public\test.txt' -Destination 'C:\users\public\text2.txt';
|
|
.EXAMPLE
|
|
PS>Copy-ItemSecure -Path 'C:\users\public\testfolder\' -Destination 'C:\users\public\testfolder2\' -Recurse;
|
|
.PARAMETER Path
|
|
The location you wish to copy from. Can either be a file or a directory
|
|
.PARAMETER Destination
|
|
The target destination to copy to. Can either be a file or a directory
|
|
.PARAMETER Recurse
|
|
Include possible sub-folders
|
|
.PARAMETER Force
|
|
Overwrite already existing files/folders
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
function Copy-ItemSecure()
|
|
{
|
|
param(
|
|
[string]$Path,
|
|
[string]$Destination,
|
|
[switch]$Recurse,
|
|
[switch]$Force
|
|
);
|
|
|
|
if ((Test-Path $Path) -eq $FALSE) {
|
|
return $FALSE;
|
|
}
|
|
|
|
try {
|
|
if ($Recurse -And $Force) {
|
|
Copy-Item -Path $Path -Destination $Destination -Recurse -Force;
|
|
} elseif ($Recurse -And -Not $Force) {
|
|
Copy-Item -Path $Path -Destination $Destination -Recurse;
|
|
} elseif (-Not $Recurse -And $Force) {
|
|
Copy-Item -Path $Path -Destination $Destination -Force;
|
|
} else {
|
|
Copy-Item -Path $Path -Destination $Destination;
|
|
}
|
|
return $TRUE;
|
|
} catch {
|
|
Write-IcingaConsoleError -Message 'Failed to copy items from path "{0}" to "{1}": {2}' -Objects $Path, $Destination, $_.Exception;
|
|
}
|
|
return $FALSE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Disables the feature to forward all executed checks to an internal
|
|
installed API to run them within a daemon
|
|
.DESCRIPTION
|
|
Disables the feature to forward all executed checks to an internal
|
|
installed API to run them within a daemon
|
|
.FUNCTIONALITY
|
|
Disables the Icinga for Windows Api checks forwarded
|
|
.EXAMPLE
|
|
PS>Disable-IcingaFrameworkApiChecks;
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Disable-IcingaFrameworkApiChecks()
|
|
{
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Experimental.UseApiChecks' -Value $FALSE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Allows to disable any console output for this PowerShell session
|
|
.DESCRIPTION
|
|
Allows to disable any console output for this PowerShell session
|
|
.FUNCTIONALITY
|
|
Allows to disable any console output for this PowerShell session
|
|
.EXAMPLE
|
|
PS>Disable-IcingaFrameworkConsoleOutput;
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Disable-IcingaFrameworkConsoleOutput()
|
|
{
|
|
if ($null -eq $global:Icinga) {
|
|
$global:Icinga = @{ };
|
|
}
|
|
|
|
if ($global:Icinga.ContainsKey('DisableConsoleOutput') -eq $FALSE) {
|
|
$global:Icinga.Add('DisableConsoleOutput', $TRUE);
|
|
} else {
|
|
$global:Icinga.DisableConsoleOutput = $TRUE;
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Disables the debug mode of the Framework
|
|
.DESCRIPTION
|
|
Disables the debug mode of the Framework
|
|
.FUNCTIONALITY
|
|
Disables the Icinga for Windows Debug-Log
|
|
.EXAMPLE
|
|
PS>Disable-IcingaFrameworkDebugMode;
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Disable-IcingaFrameworkDebugMode()
|
|
{
|
|
$global:IcingaDaemonData.DebugMode = $FALSE;
|
|
Set-IcingaPowerShellConfig -Path 'Framework.DebugMode' -Value $FALSE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Enables the feature to forward all executed checks to an internal
|
|
installed API to run them within a daemon
|
|
.DESCRIPTION
|
|
Enables the feature to forward all executed checks to an internal
|
|
installed API to run them within a daemon
|
|
.FUNCTIONALITY
|
|
Enables the Icinga for Windows Api checks forwarded
|
|
.EXAMPLE
|
|
PS>Enable-IcingaFrameworkApiChecks;
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Enable-IcingaFrameworkApiChecks()
|
|
{
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Experimental.UseApiChecks' -Value $TRUE;
|
|
|
|
Write-IcingaConsoleWarning 'Experimental Feature: Please ensure to install the packages "icinga-powershell-restapi" and "icinga-powershell-apichecks", install the Icinga for Windows background service and also register the daemon with "Register-IcingaBackgroundDaemon -Command {0}". Afterwards all services will be executed by the background daemon in case it is running.' -Objects "'Start-IcingaWindowsRESTApi'";
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Allows to enable any console output for this PowerShell session
|
|
.DESCRIPTION
|
|
Allows to enable any console output for this PowerShell session
|
|
.FUNCTIONALITY
|
|
Allows to enable any console output for this PowerShell session
|
|
.EXAMPLE
|
|
PS>Enable-IcingaFrameworkConsoleOutput;
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Enable-IcingaFrameworkConsoleOutput()
|
|
{
|
|
if ($null -eq $global:Icinga) {
|
|
$global:Icinga = @{ };
|
|
}
|
|
|
|
if ($global:Icinga.ContainsKey('DisableConsoleOutput') -eq $FALSE) {
|
|
$global:Icinga.Add('DisableConsoleOutput', $FALSE);
|
|
} else {
|
|
$global:Icinga.DisableConsoleOutput = $FALSE;
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Enables the debug mode of the Framework to print additional details into
|
|
the Windows Event Log with Id 1000
|
|
.DESCRIPTION
|
|
Enables the debug mode of the Framework to print additional details into
|
|
the Windows Event Log with Id 1000
|
|
.FUNCTIONALITY
|
|
Enables the Icinga for Windows Debug-Log
|
|
.EXAMPLE
|
|
PS>Enable-IcingaFrameworkDebugMode;
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Enable-IcingaFrameworkDebugMode()
|
|
{
|
|
$global:IcingaDaemonData.DebugMode = $TRUE;
|
|
Set-IcingaPowerShellConfig -Path 'Framework.DebugMode' -Value $TRUE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Extracts a ZIP-Archive to a certain location
|
|
.DESCRIPTION
|
|
Unzips a ZIP-Archive on to a certain location
|
|
.FUNCTIONALITY
|
|
Unzips a ZIP-Archive on to a certain location
|
|
.EXAMPLE
|
|
PS>Expand-IcingaZipArchive -Path 'C:\users\public\test.zip' -Destination 'C:\users\public\';
|
|
.PARAMETER Path
|
|
The location of your ZIP-Archive
|
|
.PARAMETER Destination
|
|
The target destination to extract the ZIP-Archive to
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Expand-IcingaZipArchive()
|
|
{
|
|
param(
|
|
$Path,
|
|
$Destination
|
|
);
|
|
|
|
if ((Test-Path $Path) -eq $FALSE -Or (Test-Path $Destination) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'The path to the zip archive or the destination path do not exist';
|
|
return $FALSE;
|
|
}
|
|
|
|
Add-Type -AssemblyName System.IO.Compression.FileSystem;
|
|
|
|
try {
|
|
[System.IO.Compression.ZipFile]::ExtractToDirectory($Path, $Destination);
|
|
return $TRUE;
|
|
} catch {
|
|
throw $_.Exception;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Fetch the raw output values for a check command for each single object
|
|
processed by New-IcingaCheck
|
|
.DESCRIPTION
|
|
Fetch the raw output values for a check command for each single object
|
|
processed by New-IcingaCheck
|
|
.FUNCTIONALITY
|
|
Fetch the raw output values for a check command for each single object
|
|
processed by New-IcingaCheck
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaCheckSchedulerCheckData()
|
|
{
|
|
if ($null -eq $global:Icinga) {
|
|
return $null;
|
|
}
|
|
|
|
if ($global:Icinga.ContainsKey('CheckData') -eq $FALSE) {
|
|
return @{ };
|
|
}
|
|
|
|
return $global:Icinga.CheckData;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Function to fetch the last executed plugin peformance data
|
|
from an internal memory cache in case the Framework is running as daemon.
|
|
.DESCRIPTION
|
|
While running the Framework as daemon, checkresults for plugins are not
|
|
printed into the console but written into an internal memory cache. Once
|
|
a plugin was executed, use this function to fetch the plugin performance data
|
|
.FUNCTIONALITY
|
|
Returns the last performance data output for executed plugins while the
|
|
Framework is running as daemon
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaCheckSchedulerPerfData()
|
|
{
|
|
if ($null -eq $global:Icinga) {
|
|
return $null;
|
|
}
|
|
|
|
$PerfData = $global:Icinga.PerfData;
|
|
$global:Icinga.PerfData = @();
|
|
|
|
return $PerfData;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Function to fetch the last executed plugin output from an internal memory
|
|
cache in case the Framework is running as daemon.
|
|
.DESCRIPTION
|
|
While running the Framework as daemon, checkresults for plugins are not
|
|
printed into the console but written into an internal memory cache. Once
|
|
a plugin was executed, use this function to fetch the plugin output
|
|
.FUNCTIONALITY
|
|
Returns the last checkresult output for executed plugins while the
|
|
Framework is running as daemon
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaCheckSchedulerPluginOutput()
|
|
{
|
|
if ($null -eq $global:Icinga) {
|
|
return $null;
|
|
}
|
|
|
|
$CheckResult = [string]::Join("`r`n", $global:Icinga.CheckResults);
|
|
$global:Icinga.CheckResults = @();
|
|
|
|
return $CheckResult;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Fetches the current enable/disable state of the feature
|
|
for executing checks of the internal REST-Api
|
|
.DESCRIPTION
|
|
Fetches the current enable/disable state of the feature
|
|
for executing checks of the internal REST-Api
|
|
.FUNCTIONALITY
|
|
Get the current API check execution configuration of the
|
|
Icinga PowerShell Framework
|
|
.EXAMPLE
|
|
PS>Get-IcingaFrameworkApiChecks;
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.OUTPUTS
|
|
System.Boolean
|
|
#>
|
|
|
|
function Get-IcingaFrameworkApiChecks()
|
|
{
|
|
$CodeCaching = Get-IcingaPowerShellConfig -Path 'Framework.Experimental.UseApiChecks';
|
|
|
|
if ($null -eq $CodeCaching) {
|
|
return $FALSE;
|
|
}
|
|
|
|
return $CodeCaching;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Get the current debug mode configuration of the Framework
|
|
.DESCRIPTION
|
|
Get the current debug mode configuration of the Framework
|
|
.FUNCTIONALITY
|
|
Get the current debug mode configuration of the Framework
|
|
.EXAMPLE
|
|
PS>Get-IcingaFrameworkDebugMode;
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.OUTPUTS
|
|
System.Boolean
|
|
#>
|
|
|
|
function Get-IcingaFrameworkDebugMode()
|
|
{
|
|
$DebugMode = Get-IcingaPowerShellConfig -Path 'Framework.DebugMode';
|
|
|
|
if ($null -eq $DebugMode) {
|
|
return $FALSE;
|
|
}
|
|
|
|
return $DebugMode;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Downloads a ZIP-Archive for the Icinga for Windows Service Binary
|
|
and installs it into a specified directory
|
|
.DESCRIPTION
|
|
Wizard function to download the Icinga for Windows Service binary from
|
|
a public ressource or from a local webstore / webshare and extract
|
|
the ZIP-Archive into a target destination
|
|
.FUNCTIONALITY
|
|
Downloads and unzips the Icinga for Windows service binary ZIP-Archive
|
|
.EXAMPLE
|
|
PS>Get-IcingaFrameworkServiceBinary -FrameworkServiceUrl 'https://github.com/Icinga/icinga-powershell-service/releases/download/v1.0.0/icinga-service-v1.0.0.zip' -ServiceDirectory 'C:\Program Files\icinga-framework-service';
|
|
.EXAMPLE
|
|
PS>Get-IcingaFrameworkServiceBinary -FrameworkServiceUrl 'C:/users/public/icinga-service-v1.0.0.zip' -ServiceDirectory 'C:\Program Files\icinga-framework-service';
|
|
.PARAMETER FrameworkServiceUrl
|
|
The URL / Source for downloading the ZIP-Archive from.
|
|
.PARAMETER Destination
|
|
The target destination to extract the ZIP-Archive to and to place the service binary
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Hashtable
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaFrameworkServiceBinary()
|
|
{
|
|
param(
|
|
[string]$FrameworkServiceUrl,
|
|
[string]$ServiceDirectory,
|
|
[switch]$Release = $FALSE
|
|
);
|
|
|
|
Set-IcingaTLSVersion;
|
|
$ProgressPreference = "SilentlyContinue";
|
|
|
|
if ([string]::IsNullOrEmpty($FrameworkServiceUrl) -Or $Release) {
|
|
if ($Release -Or (Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you provide a custom source of the service binary?' -Default 'n').result -eq 1) {
|
|
$LatestRelease = (Invoke-IcingaWebRequest -Uri 'https://github.com/Icinga/icinga-powershell-service/releases/latest' -UseBasicParsing).BaseResponse.ResponseUri.AbsoluteUri;
|
|
$FrameworkServiceUrl = $LatestRelease.Replace('/tag/', '/download/');
|
|
$Tag = $FrameworkServiceUrl.Split('/')[-1];
|
|
$FrameworkServiceUrl = [string]::Format('{0}/icinga-service-{1}.zip', $FrameworkServiceUrl, $Tag);
|
|
} else {
|
|
$FrameworkServiceUrl = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter the full path to your service binary repository' -Default 'v').answer;
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($FrameworkServiceUrl)) {
|
|
Write-IcingaConsoleError 'No Url to download the Icinga Service Binary from has been specified. Please try again.';
|
|
return Get-IcingaFrameworkServiceBinary;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ServiceDirectory)) {
|
|
$ServiceDirectory = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter the path you wish to install the service to' -Default 'v' -DefaultInput 'C:\Program Files\icinga-framework-service\').answer;
|
|
}
|
|
|
|
if ((Test-Path $ServiceDirectory) -eq $FALSE) {
|
|
New-Item -Path $ServiceDirectory -Force -ItemType Directory | Out-Null;
|
|
}
|
|
|
|
$TmpDirectory = New-IcingaTemporaryDirectory;
|
|
if (Test-Path $FrameworkServiceUrl) {
|
|
$ZipArchive = Join-Path -Path $TmpDirectory -ChildPath ($FrameworkServiceUrl.Replace('/', '\').Split('\')[-1]);
|
|
} else {
|
|
$ZipArchive = Join-Path -Path $TmpDirectory -ChildPath ($FrameworkServiceUrl.Split('/')[-1]);
|
|
}
|
|
|
|
$TmpServiceBin = Join-Path -Path $TmpDirectory -ChildPath 'icinga-service.exe';
|
|
$UpdateBin = Join-Path -Path $ServiceDirectory -ChildPath 'icinga-service.exe.update';
|
|
$ServiceBin = Join-Path -Path $ServiceDirectory -ChildPath 'icinga-service.exe';
|
|
|
|
if ((Invoke-IcingaWebRequest -Uri $FrameworkServiceUrl -UseBasicParsing -OutFile $ZipArchive).HasErrors) {
|
|
Write-IcingaConsoleError -Message 'Failed to download the Icinga Service Binary from "{0}". Please try again.' -Objects $FrameworkServiceUrl;
|
|
return Get-IcingaFrameworkServiceBinary;
|
|
}
|
|
|
|
if ((Expand-IcingaZipArchive -Path $ZipArchive -Destination $TmpDirectory) -eq $FALSE) {
|
|
throw 'Failed to expand the downloaded ZIP archive';
|
|
}
|
|
|
|
if ((Test-IcingaZipBinaryChecksum -Path $TmpServiceBin) -eq $FALSE) {
|
|
throw 'The checksum of the downloaded file and the required MD5 hash are not matching';
|
|
}
|
|
|
|
Copy-ItemSecure -Path $TmpServiceBin -Destination $UpdateBin -Force | Out-Null;
|
|
Start-Sleep -Seconds 1;
|
|
Remove-ItemSecure -Path $TmpDirectory -Recurse -Force | Out-Null;
|
|
|
|
return @{
|
|
'FrameworkServiceUrl' = $FrameworkServiceUrl;
|
|
'ServiceDirectory' = $ServiceDirectory;
|
|
'ServiceBin' = $ServiceBin;
|
|
};
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Download a PowerShell Module from a custom source or from GitHub
|
|
by providing a repository and the user space
|
|
.DESCRIPTION
|
|
Download a PowerShell Module from a custom source or from GitHub
|
|
by providing a repository and the user space
|
|
.FUNCTIONALITY
|
|
Download and install a PowerShell module from a custom or GitHub source
|
|
.EXAMPLE
|
|
PS>Get-IcingaPowerShellModuleArchive -ModuleName 'Plugins' -Repository 'icinga-powershell-plugins' -Release 1;
|
|
.EXAMPLE
|
|
PS>Get-IcingaPowerShellModuleArchive -ModuleName 'Plugins' -Repository 'icinga-powershell-plugins' -Release 1 -DryRun 1;
|
|
.PARAMETER DownloadUrl
|
|
The Url to a ZIP-Archive to download from (skips the wizard)
|
|
.PARAMETER ModuleName
|
|
The name which is used inside output messages
|
|
.PARAMETER Repository
|
|
The repository to download the ZIP-Archive from
|
|
.PARAMETER GitHubUser
|
|
The user from which a repository is downloaded from
|
|
.PARAMETER Release
|
|
Download the latest release
|
|
.PARAMETER Snapshot
|
|
Download the latest package from the master branch
|
|
.PARAMETER DryRun
|
|
Only return the finished build Url including the version to install but
|
|
do not modify the system in any way
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Hashtable
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaPowerShellModuleArchive()
|
|
{
|
|
param(
|
|
[string]$DownloadUrl = '',
|
|
[string]$ModuleName = '',
|
|
[string]$Repository = '',
|
|
[string]$GitHubUser = 'Icinga',
|
|
[bool]$Release = $FALSE,
|
|
[bool]$Snapshot = $FALSE,
|
|
[bool]$DryRun = $FALSE
|
|
);
|
|
|
|
Set-IcingaTLSVersion;
|
|
$ProgressPreference = "SilentlyContinue";
|
|
$Tag = 'master';
|
|
[bool]$SkipRepo = $FALSE;
|
|
|
|
if ($Release -Or $Snapshot) {
|
|
$SkipRepo = $TRUE;
|
|
}
|
|
|
|
# Fix TLS errors while connecting to GitHub with old PowerShell versions
|
|
[Net.ServicePointManager]::SecurityProtocol = "tls12, tls11";
|
|
|
|
if ([string]::IsNullOrEmpty($DownloadUrl)) {
|
|
if ($SkipRepo -Or (Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Do you provide a custom repository for "{0}"?', $ModuleName)) -Default 'n').result -eq 1) {
|
|
if ($Release -eq $FALSE -And $Snapshot -eq $FALSE) {
|
|
$branch = (Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Which version of the "{0}" do you want to install? (release/snapshot)', $ModuleName)) -Default 'v' -DefaultInput 'release').answer;
|
|
} elseif ($Release) {
|
|
$branch = 'release';
|
|
} else {
|
|
$branch = 'snapshot'
|
|
}
|
|
if ($branch.ToLower() -eq 'snapshot') {
|
|
$DownloadUrl = [string]::Format('https://github.com/{0}/{1}/archive/master.zip', $GitHubUser, $Repository);
|
|
} else {
|
|
$WebResponse = Invoke-IcingaWebRequest -Uri 'https://github.com/{0}/{1}/releases/latest' -Objects $GitHubUser, $Repository -UseBasicParsing;
|
|
|
|
if ($null -eq $WebResponse.HasErrors -Or $WebResponse.HasErrors -eq $FALSE) {
|
|
$LatestRelease = $WebResponse.BaseResponse.ResponseUri.AbsoluteUri;
|
|
$DownloadUrl = $LatestRelease.Replace('/releases/tag/', '/archive/');
|
|
$Tag = $DownloadUrl.Split('/')[-1];
|
|
} else {
|
|
Write-IcingaConsoleError -Message 'Failed to fetch latest release for "{0}" from GitHub. Either the module or the GitHub account do not exist' -Objects $ModuleName;
|
|
}
|
|
|
|
$DownloadUrl = [string]::Format('{0}/{1}.zip', $DownloadUrl, $Tag);
|
|
|
|
$CurrentVersion = Get-IcingaPowerShellModuleVersion $Repository;
|
|
|
|
if ($null -ne $CurrentVersion -And $CurrentVersion -eq $Tag) {
|
|
Write-IcingaConsoleNotice -Message 'Your "{0}" is already up-to-date' -Objects $ModuleName;
|
|
return @{
|
|
'DownloadUrl' = $DownloadUrl;
|
|
'Version' = $Tag;
|
|
'Directory' = '';
|
|
'Archive' = '';
|
|
'ModuleRoot' = (Get-IcingaForWindowsRootPath);
|
|
'Installed' = $FALSE;
|
|
};
|
|
}
|
|
}
|
|
} else {
|
|
$DownloadUrl = (Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Please enter the full path of the custom repository for the "{0}" (location of zip file)', $ModuleName)) -Default 'v').answer;
|
|
}
|
|
}
|
|
|
|
if ($DryRun) {
|
|
return @{
|
|
'DownloadUrl' = $DownloadUrl;
|
|
'Version' = $Tag;
|
|
'Directory' = '';
|
|
'Archive' = '';
|
|
'ModuleRoot' = (Get-IcingaForWindowsRootPath);
|
|
'Installed' = $FALSE;
|
|
};
|
|
}
|
|
|
|
$DownloadDirectory = New-IcingaTemporaryDirectory;
|
|
$DownloadDestination = (Join-Path -Path $DownloadDirectory -ChildPath ([string]::Format('{0}.zip', $Repository)));
|
|
Write-IcingaConsoleNotice ([string]::Format('Downloading "{0}" into "{1}"', $ModuleName, $DownloadDirectory));
|
|
|
|
if ((Invoke-IcingaWebRequest -UseBasicParsing -Uri $DownloadUrl -OutFile $DownloadDestination).HasErrors) {
|
|
Write-IcingaConsoleError ([string]::Format('Failed to download "{0}" into "{1}". Starting cleanup process', $ModuleName, $DownloadDirectory));
|
|
Start-Sleep -Seconds 2;
|
|
Remove-Item -Path $DownloadDirectory -Recurse -Force;
|
|
|
|
Write-IcingaConsoleNotice 'Starting to re-run the download wizard';
|
|
|
|
return Get-IcingaPowerShellModuleArchive -ModuleName $ModuleName -Repository $Repository;
|
|
}
|
|
|
|
return @{
|
|
'DownloadUrl' = $DownloadUrl;
|
|
'Version' = $Tag;
|
|
'Directory' = $DownloadDirectory;
|
|
'Archive' = $DownloadDestination;
|
|
'ModuleRoot' = (Get-IcingaForWindowsRootPath);
|
|
'Installed' = $TRUE;
|
|
};
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Get the version of an installed PowerShell Module
|
|
.DESCRIPTION
|
|
Get the version of an installed PowerShell Module
|
|
.FUNCTIONALITY
|
|
Get the version of an installed PowerShell Module
|
|
.EXAMPLE
|
|
PS>Get-IcingaPowerShellModuleVersion -ModuleName 'icinga-powershell-framework';
|
|
.EXAMPLE
|
|
PS>Get-IcingaPowerShellModuleVersion -ModuleName 'icinga-powershell-plugins';
|
|
.PARAMETER ModuleName
|
|
The PowerShell module to fetch the installed version from
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaPowerShellModuleVersion()
|
|
{
|
|
param(
|
|
$ModuleName
|
|
);
|
|
|
|
$ModuleDetails = Get-Module -ListAvailable $ModuleName;
|
|
|
|
if ($null -eq $ModuleDetails) {
|
|
return $null;
|
|
}
|
|
|
|
return $ModuleDetails.PrivateData.Version;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Fetches a Stopwatch system object by a given name if initialised with Start-IcingaTimer
|
|
.DESCRIPTION
|
|
Fetches a Stopwatch system object by a given name if initialised with Start-IcingaTimer
|
|
.FUNCTIONALITY
|
|
Fetches a Stopwatch system object by a given name if initialised with Start-IcingaTimer
|
|
.EXAMPLE
|
|
PS>Get-IcingaTimer;
|
|
.EXAMPLE
|
|
PS>Get-IcingaTimer -Name 'My Test Timer';
|
|
.PARAMETER Name
|
|
The name of a custom identifier to run mutliple timers at once
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Diagnostics.Stopwatch
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaTimer()
|
|
{
|
|
param (
|
|
[string]$Name = 'DefaultTimer'
|
|
);
|
|
|
|
$TimerData = Get-IcingaHashtableItem -Key $Name -Hashtable $global:IcingaDaemonData.IcingaTimers;
|
|
|
|
if ($null -eq $TimerData) {
|
|
return $null;
|
|
}
|
|
|
|
return $TimerData.Timer;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Installs the Icinga PowerShell Services as a Windows service
|
|
.DESCRIPTION
|
|
Uses the Icinga Service binary which is already installed on the system to register
|
|
it as a Windows service and sets the proper user for it
|
|
.FUNCTIONALITY
|
|
Installs the Icinga PowerShell Services as a Windows service
|
|
.EXAMPLE
|
|
PS>Install-IcingaForWindowsService -Path C:\Program Files\icinga-service\icinga-service.exe;
|
|
.EXAMPLE
|
|
PS>Install-IcingaForWindowsService -Path C:\Program Files\icinga-service\icinga-service.exe -User 'NT Authority\NetworkService';
|
|
.PARAMETER Path
|
|
The location on where the service binary executable is found
|
|
.PARAMETER User
|
|
The service user the service is running with
|
|
.PARAMETER Password
|
|
If the specified service user is requiring a password for registering you can provide it here as secure string
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Install-IcingaForWindowsService()
|
|
{
|
|
param(
|
|
$Path,
|
|
$User,
|
|
[SecureString]$Password
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Path)) {
|
|
Write-IcingaConsoleWarning 'No path specified for Framework service. Service will not be installed';
|
|
return;
|
|
}
|
|
|
|
$UpdateFile = [string]::Format('{0}.update', $Path);
|
|
|
|
$ServiceStatus = (Get-Service 'icingapowershell' -ErrorAction SilentlyContinue).Status;
|
|
|
|
if ((Test-Path $UpdateFile)) {
|
|
|
|
Write-IcingaConsoleNotice 'Updating Icinga PowerShell Service binary';
|
|
|
|
if ($ServiceStatus -eq 'Running') {
|
|
Write-IcingaConsoleNotice 'Stopping Icinga PowerShell service';
|
|
Stop-IcingaService 'icingapowershell';
|
|
Start-Sleep -Seconds 1;
|
|
}
|
|
|
|
Remove-ItemSecure -Path $Path -Force | Out-Null;
|
|
Copy-ItemSecure -Path $UpdateFile -Destination $Path -Force | Out-Null;
|
|
Remove-ItemSecure -Path $UpdateFile -Force | Out-Null;
|
|
}
|
|
|
|
if ((Test-Path $Path) -eq $FALSE) {
|
|
throw 'Please specify the path directly to the service binary';
|
|
}
|
|
|
|
$Path = [string]::Format(
|
|
'\"{0}\" \"{1}\"',
|
|
$Path,
|
|
(Get-IcingaPowerShellModuleFile)
|
|
);
|
|
|
|
if ($null -eq $ServiceStatus) {
|
|
$ServiceCreation = Start-IcingaProcess -Executable 'sc.exe' -Arguments ([string]::Format('create icingapowershell binPath= "{0}" DisplayName= "Icinga PowerShell Service" start= auto', $Path));
|
|
|
|
if ($ServiceCreation.ExitCode -ne 0) {
|
|
throw ([string]::Format('Failed to install Icinga PowerShell Service: {0}{1}', $ServiceCreation.Message, $ServiceCreation.Error));
|
|
}
|
|
} else {
|
|
Write-IcingaConsoleWarning 'The Icinga PowerShell Service is already installed';
|
|
}
|
|
|
|
# This is just a hotfix to ensure we setup the service properly before assigning it to
|
|
# a proper user, like 'NT Authority\NetworkService'. For some reason the NetworkService
|
|
# will not start without this workaround.
|
|
# Todo: Figure out the reason and fix it properly
|
|
Set-IcingaAgentServiceUser -User 'LocalSystem' -Service 'icingapowershell' | Out-Null;
|
|
Restart-IcingaService 'icingapowershell';
|
|
Start-Sleep -Seconds 1;
|
|
Stop-IcingaService 'icingapowershell';
|
|
|
|
if ($ServiceStatus -eq 'Running') {
|
|
Write-IcingaConsoleNotice 'Starting Icinga PowerShell service';
|
|
Start-IcingaService 'icingapowershell';
|
|
Start-Sleep -Seconds 1;
|
|
}
|
|
|
|
return (Set-IcingaAgentServiceUser -User $User -Password $Password -Service 'icingapowershell');
|
|
}
|
|
|
|
Set-Alias -Name 'Install-IcingaFrameworkService' -Value 'Install-IcingaForWindowsService';
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Installs a PowerShell Module within the 'icinga-powershell-' namespace
|
|
from GitHub or custom locations and installs it into the module directory
|
|
the Framework itself is installed to
|
|
.DESCRIPTION
|
|
Installs a PowerShell Module within the 'icinga-powershell-' namespace
|
|
from GitHub or custom locations and installs it into the module directory
|
|
the Framework itself is installed to
|
|
.FUNCTIONALITY
|
|
Download and install a PowerShell module from the 'icinga-powershell-' namespace
|
|
.EXAMPLE
|
|
PS>Install-IcingaFrameworkComponent -Name 'plugins' -Release;
|
|
.EXAMPLE
|
|
PS>Install-IcingaFrameworkComponent -Name 'plugins' -Release -DryRun;
|
|
.PARAMETER Name
|
|
The name of the module to install. The namespace 'icinga-powershell-' is added
|
|
by the function automatically
|
|
.PARAMETER GitHubUser
|
|
Overwrite the default GitHub user for a different one to download modules from
|
|
.PARAMETER Url
|
|
Specify a direct Url to a ZIP-Archive for external or local web ressources or
|
|
local network shares
|
|
.PARAMETER Release
|
|
Download the latest Release version from a GitHub source
|
|
.PARAMETER Snapshot
|
|
Download the latest master branch from a GitHub source
|
|
.PARAMETER DryRun
|
|
Only fetch possible Urls and return the result. No download or installation
|
|
will be done
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Hashtable
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Install-IcingaFrameworkComponent()
|
|
{
|
|
param(
|
|
[string]$Name,
|
|
[string]$GitHubUser = 'Icinga',
|
|
[string]$Url,
|
|
[switch]$Release = $FALSE,
|
|
[switch]$Snapshot = $FALSE,
|
|
[switch]$DryRun = $FALSE
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
throw 'Please specify a component name to install from a GitHub/Local space';
|
|
}
|
|
|
|
Set-IcingaTLSVersion;
|
|
|
|
$TextInfo = (Get-Culture).TextInfo;
|
|
$ComponentName = $TextInfo.ToTitleCase($Name);
|
|
$RepositoryName = [string]::Format('icinga-powershell-{0}', $Name);
|
|
$Archive = Get-IcingaPowerShellModuleArchive `
|
|
-DownloadUrl $Url `
|
|
-GitHubUser $GitHubUser `
|
|
-ModuleName (
|
|
[string]::Format(
|
|
'Icinga {0}', $ComponentName
|
|
)
|
|
) `
|
|
-Repository $RepositoryName `
|
|
-Release $Release `
|
|
-Snapshot $Snapshot `
|
|
-DryRun $DryRun;
|
|
|
|
if ($Archive.Installed -eq $FALSE -Or $DryRun) {
|
|
return @{
|
|
'RepoUrl' = $Archive.DownloadUrl
|
|
};
|
|
}
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Installing module into "{0}"', ($Archive.Directory)));
|
|
Expand-IcingaZipArchive -Path $Archive.Archive -Destination $Archive.Directory | Out-Null;
|
|
|
|
$FolderContent = Get-ChildItem -Path $Archive.Directory;
|
|
$ModuleContent = $Archive.Directory;
|
|
|
|
foreach ($entry in $FolderContent) {
|
|
if ($entry -like ([string]::Format('{0}*', $RepositoryName))) {
|
|
$ModuleContent = Join-Path -Path $ModuleContent -ChildPath $entry;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Using content of folder "{0}" for updates', $ModuleContent));
|
|
|
|
$PluginDirectory = (Join-Path -Path $Archive.ModuleRoot -ChildPath $RepositoryName);
|
|
|
|
if ((Test-Path $PluginDirectory) -eq $FALSE) {
|
|
Write-IcingaConsoleNotice ([string]::Format('{0} Module Directory "{1}" is not present. Creating Directory', $ComponentName, $PluginDirectory));
|
|
New-Item -Path $PluginDirectory -ItemType Directory | Out-Null;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Copying files to {0}', $ComponentName));
|
|
Copy-ItemSecure -Path (Join-Path -Path $ModuleContent -ChildPath '/*') -Destination $PluginDirectory -Recurse -Force | Out-Null;
|
|
|
|
Write-IcingaConsoleNotice 'Cleaning temporary content';
|
|
Start-Sleep -Seconds 1;
|
|
Remove-ItemSecure -Path $Archive.Directory -Recurse -Force | Out-Null;
|
|
|
|
Unblock-IcingaPowerShellFiles -Path $PluginDirectory;
|
|
|
|
# In case the plugins are not installed before, load the framework again to
|
|
# include the plugins
|
|
Use-Icinga;
|
|
|
|
# Unload the module if it was loaded before
|
|
Remove-Module $PluginDirectory -Force -ErrorAction SilentlyContinue;
|
|
# Now import the module
|
|
Import-Module $PluginDirectory;
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Icinga {0} update has been completed. Please start a new PowerShell to apply it', $ComponentName));
|
|
|
|
return @{
|
|
'RepoUrl' = $Archive.DownloadUrl
|
|
};
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Installs the Icinga Plugins PowerShell module from a remote or local source
|
|
.DESCRIPTION
|
|
Installs the Icinga PowerShell Plugins from a remote or local source into the
|
|
PowerShell module folder and makes them available for usage with Icinga 2 or
|
|
other components.
|
|
.FUNCTIONALITY
|
|
Installs the Icinga Plugins PowerShell module from a remote or local source
|
|
.EXAMPLE
|
|
PS>Install-IcingaFrameworkPlugins;
|
|
.EXAMPLE
|
|
PS>Install-IcingaFrameworkPlugins -PluginsUrl 'C:/icinga/icinga-plugins.zip';
|
|
.EXAMPLE
|
|
PS>Install-IcingaFrameworkPlugins -PluginsUrl 'https://github.com/Icinga/icinga-powershell-plugins/archive/v1.0.0.zip';
|
|
.PARAMETER PluginsUrl
|
|
The URL pointing either to a local or remote ressource to download the plugins from. This requires to be the
|
|
full path to the .zip file to download.
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Hashtable
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Install-IcingaFrameworkPlugins()
|
|
{
|
|
param(
|
|
[string]$PluginsUrl
|
|
);
|
|
|
|
[Hashtable]$Result = Install-IcingaFrameworkComponent `
|
|
-Name 'plugins' `
|
|
-GitHubUser 'Icinga' `
|
|
-Url $PluginsUrl;
|
|
|
|
return @{
|
|
'PluginUrl' = $Result.RepoUrl;
|
|
};
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Update the current version of the PowerShell Framework with a newer or older one
|
|
.DESCRIPTION
|
|
Allows you to specify a download url or being asked by a wizard on where a update for
|
|
the PowerShell framework can be fetched from and applies the up- or downgrade
|
|
.FUNCTIONALITY
|
|
Update the current version of the PowerShell Framework with a newer or older one
|
|
.EXAMPLE
|
|
PS>Install-IcingaFrameworkUpdate;
|
|
.EXAMPLE
|
|
PS>Install-IcingaFrameworkUpdate -FrameworkUrl 'C:/icinga/framework.zip';
|
|
.EXAMPLE
|
|
PS>Install-IcingaFrameworkUpdate -FrameworkUrl 'https://github.com/Icinga/icinga-powershell-framework/archive/v1.0.2.zip';
|
|
.PARAMETER FrameworkUrl
|
|
The url to a remote or local ressource pointing directly to a .zip file containing the required files for updating
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
Null
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Install-IcingaFrameworkUpdate()
|
|
{
|
|
param(
|
|
[string]$FrameworkUrl
|
|
);
|
|
|
|
$RepositoryName = 'icinga-powershell-framework';
|
|
$Archive = Get-IcingaPowerShellModuleArchive -DownloadUrl $FrameworkUrl -ModuleName 'Icinga Framework' -Repository $RepositoryName;
|
|
|
|
if ($Archive.Installed -eq $FALSE) {
|
|
return @{
|
|
'PluginUrl' = $Archive.DownloadUrl
|
|
};
|
|
}
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Installing module into "{0}"', ($Archive.Directory)));
|
|
Expand-IcingaZipArchive -Path $Archive.Archive -Destination $Archive.Directory | Out-Null;
|
|
|
|
$FolderContent = Get-ChildItem -Path $Archive.Directory;
|
|
$ModuleContent = $Archive.Directory;
|
|
|
|
foreach ($entry in $FolderContent) {
|
|
if ($entry -like ([string]::Format('{0}*', $RepositoryName))) {
|
|
$ModuleContent = Join-Path -Path $ModuleContent -ChildPath $entry;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Using content of folder "{0}" for updates', $ModuleContent));
|
|
|
|
$ServiceStatus = (Get-Service 'icingapowershell' -ErrorAction SilentlyContinue).Status;
|
|
$AgentStatus = (Get-Service 'icinga2' -ErrorAction SilentlyContinue).Status;
|
|
|
|
if ($ServiceStatus -eq 'Running') {
|
|
Write-IcingaConsoleNotice 'Stopping Icinga PowerShell service';
|
|
Stop-IcingaService 'icingapowershell';
|
|
Start-Sleep -Seconds 1;
|
|
}
|
|
if ($AgentStatus -eq 'Running') {
|
|
Write-IcingaConsoleNotice 'Stopping Icinga Agent service';
|
|
Stop-IcingaService 'icinga2';
|
|
Start-Sleep -Seconds 1;
|
|
}
|
|
|
|
$ModuleDirectory = (Join-Path -Path $Archive.ModuleRoot -ChildPath $RepositoryName);
|
|
|
|
if ((Test-Path $ModuleDirectory) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'Failed to update the component. Module Root-Directory was not found';
|
|
return;
|
|
}
|
|
|
|
$Files = Get-ChildItem $ModuleDirectory -File '*';
|
|
|
|
Write-IcingaConsoleNotice 'Removing files from framework';
|
|
|
|
foreach ($ModuleFile in $Files) {
|
|
Remove-ItemSecure -Path $ModuleFile -Force | Out-Null;
|
|
}
|
|
|
|
Remove-ItemSecure -Path (Join-Path $ModuleDirectory -ChildPath 'doc') -Recurse -Force | Out-Null;
|
|
Remove-ItemSecure -Path (Join-Path $ModuleDirectory -ChildPath 'lib') -Recurse -Force | Out-Null;
|
|
Remove-ItemSecure -Path (Join-Path $ModuleDirectory -ChildPath 'manifests') -Recurse -Force | Out-Null;
|
|
|
|
Write-IcingaConsoleNotice 'Copying new files to framework';
|
|
Copy-ItemSecure -Path (Join-Path $ModuleContent -ChildPath 'doc') -Destination $ModuleDirectory -Recurse -Force | Out-Null;
|
|
Copy-ItemSecure -Path (Join-Path $ModuleContent -ChildPath 'lib') -Destination $ModuleDirectory -Recurse -Force | Out-Null;
|
|
Copy-ItemSecure -Path (Join-Path $ModuleContent -ChildPath 'manifests') -Destination $ModuleDirectory -Recurse -Force | Out-Null;
|
|
Copy-ItemSecure -Path (Join-Path -Path $ModuleContent -ChildPath '/*') -Destination $ModuleDirectory -Recurse -Force | Out-Null;
|
|
|
|
Unblock-IcingaPowerShellFiles -Path $ModuleDirectory;
|
|
|
|
Write-IcingaConsoleNotice 'Cleaning temporary content';
|
|
Start-Sleep -Seconds 1;
|
|
Remove-ItemSecure -Path $Archive.Directory -Recurse -Force | Out-Null;
|
|
|
|
Write-IcingaConsoleNotice 'Updating Framework cache file';
|
|
if (Test-IcingaFunction 'Write-IcingaFrameworkCodeCache') {
|
|
Write-IcingaFrameworkCodeCache;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Framework update has been completed. Please start a new PowerShell instance now to complete the update';
|
|
|
|
Test-IcingaAgent;
|
|
|
|
if ($ServiceStatus -eq 'Running') {
|
|
Write-IcingaConsoleNotice 'Starting Icinga PowerShell service';
|
|
Start-IcingaService 'icingapowershell';
|
|
}
|
|
if ($AgentStatus -eq 'Running') {
|
|
Write-IcingaConsoleNotice 'Starting Icinga Agent service';
|
|
Start-IcingaService 'icinga2';
|
|
}
|
|
}
|
|
|
|
function Invoke-IcingaInternalServiceCall()
|
|
{
|
|
param (
|
|
[string]$Command = '',
|
|
[array]$Arguments = @()
|
|
);
|
|
|
|
# If our Framework is running as daemon, never call our api
|
|
if ($global:IcingaDaemonData.FrameworkRunningAsDaemon) {
|
|
return;
|
|
}
|
|
|
|
# If the API forward feature is disabled, do nothing
|
|
if ((Get-IcingaFrameworkApiChecks) -eq $FALSE) {
|
|
return;
|
|
}
|
|
|
|
# Test our Icinga for Windows service. If the service is not installed or not running, execute the plugin locally
|
|
$IcingaForWindowsService = (Get-Service 'icingapowershell' -ErrorAction SilentlyContinue);
|
|
|
|
if ($null -eq $IcingaForWindowsService -Or $IcingaForWindowsService.Status -ne 'Running') {
|
|
return;
|
|
}
|
|
|
|
# In case the REST-Api module ist not configured, do nothing
|
|
$BackgroundDaemons = Get-IcingaBackgroundDaemons;
|
|
|
|
if ($null -eq $BackgroundDaemons -Or $BackgroundDaemons.ContainsKey('Start-IcingaWindowsRESTApi') -eq $FALSE) {
|
|
return;
|
|
}
|
|
|
|
# If neither 'icinga-powershell-restapi' or 'icinga-powershell-apichecks' is installed, execute the plugin locally
|
|
if ((Test-IcingaFunction 'Invoke-IcingaApiChecksRESTCall') -eq $FALSE -Or (Test-IcingaFunction 'Start-IcingaWindowsRESTApi') -eq $FALSE) {
|
|
return;
|
|
}
|
|
|
|
$RestApiPort = 5668;
|
|
[int]$Timeout = 30;
|
|
$Daemon = $BackgroundDaemons['Start-IcingaWindowsRESTApi'];
|
|
|
|
# Fetch our deamon configuration
|
|
if ($Daemon.ContainsKey('-Port')) {
|
|
$RestApiPort = $Daemon['-Port'];
|
|
} elseif ($Daemon.ContainsKey('Port')) {
|
|
$RestApiPort = $Daemon['Port'];
|
|
}
|
|
if ($Daemon.ContainsKey('-Timeout')) {
|
|
$Timeout = $Daemon['-Timeout'];
|
|
} elseif ($Daemon.ContainsKey('Timeout')) {
|
|
$Timeout = $Daemon['Timeout'];
|
|
}
|
|
|
|
Set-IcingaTLSVersion;
|
|
Enable-IcingaUntrustedCertificateValidation -SuppressMessages;
|
|
|
|
[hashtable]$CommandArguments = @{ };
|
|
[int]$ArgumentIndex = 0;
|
|
|
|
# Resolve our array arguments provided by $args and build proper check arguments
|
|
while ($ArgumentIndex -lt $Arguments.Count) {
|
|
$Value = $Arguments[$ArgumentIndex];
|
|
[string]$Argument = [string]$Value;
|
|
$ArgumentValue = $null;
|
|
|
|
if ($Value[0] -eq '-') {
|
|
if (($ArgumentIndex + 1) -lt $Arguments.Count) {
|
|
[string]$NextValue = $Arguments[$ArgumentIndex + 1];
|
|
if ($NextValue[0] -eq '-') {
|
|
$ArgumentValue = $TRUE;
|
|
} else {
|
|
$ArgumentValue = $Arguments[$ArgumentIndex + 1];
|
|
}
|
|
} else {
|
|
$ArgumentValue = $TRUE;
|
|
}
|
|
} else {
|
|
$ArgumentIndex += 1;
|
|
continue;
|
|
}
|
|
|
|
$Argument = $Argument.Replace('-', '');
|
|
|
|
$CommandArguments.Add($Argument, $ArgumentValue);
|
|
$ArgumentIndex += 1;
|
|
}
|
|
|
|
# Now queue the check inside our REST-Api
|
|
try {
|
|
$ApiResult = Invoke-WebRequest -Method POST -UseBasicParsing -Uri ([string]::Format('https://localhost:{0}/v1/checker?command={1}', $RestApiPort, $Command)) -Body (ConvertTo-JsonUTF8Bytes -InputObject $CommandArguments -Depth 100 -Compress) -ContentType 'application/json' -TimeoutSec $Timeout;
|
|
} catch {
|
|
# Something went wrong -> fallback to local execution
|
|
$ExMsg = $_.Exception.message;
|
|
# Fallback to execute plugin locally
|
|
Write-IcingaEventMessage -Namespace 'Framework' -EventId 1553 -Objects $ExMsg, $Command, $CommandArguments;
|
|
return;
|
|
}
|
|
|
|
# Resolve our result from the API
|
|
$IcingaResult = ConvertFrom-JsonUTF8 -InputObject $ApiResult.Content;
|
|
$IcingaCR = '';
|
|
|
|
# In case we didn't receive a check result, fallback to local execution
|
|
if ([string]::IsNullOrEmpty($IcingaResult.$Command.checkresult)) {
|
|
Write-IcingaEventMessage -Namespace 'Framework' -EventId 1553 -Objects 'The check result for the executed command was empty', $Command, $CommandArguments;
|
|
return;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($IcingaResult.$Command.exitcode)) {
|
|
Write-IcingaEventMessage -Namespace 'Framework' -EventId 1553 -Objects 'The check result for the executed command was empty', $Command, $CommandArguments;
|
|
return;
|
|
}
|
|
|
|
$IcingaCR = ($IcingaResult.$Command.checkresult.Replace("`r`n", "`n"));
|
|
|
|
if ($IcingaResult.$Command.perfdata.Count -ne 0) {
|
|
$IcingaCR += ' | ';
|
|
foreach ($perfdata in $IcingaResult.$Command.perfdata) {
|
|
$IcingaCR += $perfdata;
|
|
}
|
|
}
|
|
|
|
# Print our response and exit with the provide exit code
|
|
Write-IcingaConsolePlain $IcingaCR;
|
|
exit $IcingaResult.$Command.exitcode;
|
|
}
|
|
|
|
function Invoke-IcingaNamespaceCmdlets()
|
|
{
|
|
param (
|
|
[string]$Command
|
|
);
|
|
|
|
[Hashtable]$CommandConfig = @{};
|
|
|
|
if ($Command.Contains('*') -eq $FALSE) {
|
|
$Command = [string]::Format('{0}*', $Command);
|
|
}
|
|
|
|
$CommandList = Get-Command $Command;
|
|
|
|
foreach ($Cmdlet in $CommandList) {
|
|
try {
|
|
$CommandName = $Cmdlet.Name;
|
|
Import-Module $Cmdlet.Module.Path -WarningAction SilentlyContinue -ErrorAction Stop;
|
|
|
|
$Content = (& $CommandName);
|
|
Add-IcingaHashtableItem `
|
|
-Hashtable $CommandConfig `
|
|
-Key $Cmdlet.Name `
|
|
-Value $Content | Out-Null;
|
|
} catch {
|
|
# TODO: Add event log logging on exceptions
|
|
}
|
|
}
|
|
|
|
return $CommandConfig;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Create a new environment in which we can store check results, performance data
|
|
and values over time or executed plugins.
|
|
|
|
Usage:
|
|
|
|
Access the string plugin output by calling `Get-IcingaCheckSchedulerPluginOutput`
|
|
Access possible performance data with `Get-IcingaCheckSchedulerPerfData`
|
|
|
|
If you execute check plugins, ensure you read both of these functions to fetch the
|
|
result of the plugin call and to clear the stack and memory of the check data.
|
|
|
|
If you do not require the output, you can write them to Null
|
|
|
|
Get-IcingaCheckSchedulerPluginOutput | Out-Null;
|
|
Get-IcingaCheckSchedulerPerfData | Out-Null;
|
|
|
|
IMPORTANT:
|
|
In addition each value for each object created with `New-IcingaCheck` is stored
|
|
with a timestamp for the check command inside a hashtable. If you do not require
|
|
these data, you MUST call `Clear-IcingaCheckSchedulerCheckData` to free memory
|
|
and clear data from the stack!
|
|
|
|
If you are finished with all data processing and do not require anything within
|
|
memory anyway, you can safely call `Clear-IcingaCheckSchedulerEnvironment` to
|
|
do the same thing in one call.
|
|
.DESCRIPTION
|
|
Fetch the raw output values for a check command for each single object
|
|
processed by New-IcingaCheck
|
|
.FUNCTIONALITY
|
|
Fetch the raw output values for a check command for each single object
|
|
processed by New-IcingaCheck
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function New-IcingaCheckSchedulerEnvironment()
|
|
{
|
|
# Legacy code
|
|
if ($IcingaDaemonData.IcingaThreadContent.ContainsKey('Scheduler') -eq $FALSE) {
|
|
$IcingaDaemonData.IcingaThreadContent.Add('Scheduler', @{ });
|
|
}
|
|
|
|
if ($null -eq $global:Icinga) {
|
|
$global:Icinga = @{ };
|
|
}
|
|
|
|
if ($global:Icinga.ContainsKey('CheckResults') -eq $FALSE) {
|
|
$global:Icinga.Add('CheckResults', @());
|
|
}
|
|
if ($global:Icinga.ContainsKey('PerfData') -eq $FALSE) {
|
|
$global:Icinga.Add('PerfData', @());
|
|
}
|
|
if ($global:Icinga.ContainsKey('CheckData') -eq $FALSE) {
|
|
$global:Icinga.Add('CheckData', @{ });
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Fetches plugins within the namespace `Invoke-IcingaCheck*` for a given
|
|
component name or the direct path and creates Icinga Director as well as
|
|
Icinga 2 configuration files.
|
|
|
|
The configuration files are printed within a `config` folder of the
|
|
specific module and splitted into `director` and `icinga`
|
|
.DESCRIPTION
|
|
etches plugins within the namespace `Invoke-IcingaCheck*` for a given
|
|
component name or the direct path and creates Icinga Director as well as
|
|
Icinga 2 configuration files.
|
|
|
|
The configuration files are printed within a `config` folder of the
|
|
specific module and splitted into `director` and `icinga`
|
|
.FUNCTIONALITY
|
|
Creates Icinga 2 and Icinga Director configuration files for plugins
|
|
.EXAMPLE
|
|
PS>Publish-IcingaPluginConfiguration -ComponentName 'plugins';
|
|
.EXAMPLE
|
|
PS>Publish-IcingaPluginConfiguration -ComponentPath 'C:\Program Files\WindowsPowerShell\modules\icinga-powershell-plugins';
|
|
.PARAMETER ComponentName
|
|
The name of the component to lookup for plugins and write configuration for.
|
|
The leading icinga-powershell- is not required and you should simply use the name,
|
|
like 'plugins' or 'mssql'
|
|
.PARAMETER ComponentPath
|
|
The path to the root directory of a PowerShell Plugin repository, like
|
|
'C:\Program Files\WindowsPowerShell\modules\icinga-powershell-plugins'
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Publish-IcingaPluginConfiguration()
|
|
{
|
|
param (
|
|
[string]$ComponentName,
|
|
[string]$ComponentPath
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($ComponentName) -And [string]::IsNullOrEmpty($ComponentPath)) {
|
|
Write-IcingaConsoleError 'Please specify either a component name like "plugins" or set the component path to the root folder if a component, like "C:\Program Files\WindowsPowerShell\modules\icinga-powershell\plugins".';
|
|
return;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ComponentPath)) {
|
|
$ComponentPath = Join-Path -Path (Get-IcingaForWindowsRootPath) -ChildPath ([string]::Format('icinga-powershell-{0}', $ComponentName));
|
|
}
|
|
|
|
if ((Test-Path $ComponentPath) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'The path "{0}" for the Icinga for Windows component is not valid' -Objects $ComponentPath;
|
|
return;
|
|
}
|
|
|
|
try {
|
|
Import-Module $ComponentPath -Global -Force -ErrorAction Stop;
|
|
} catch {
|
|
[string]$Message = $_.Exception.Message;
|
|
Write-IcingaConsoleError 'Failed to import the module on path "{0}". Please verify that this is a valid PowerShell module root folder. Exception: {1}{2}' -Objects $ComponentPath, (New-IcingaNewLine), $Message;
|
|
return;
|
|
}
|
|
|
|
$CheckCommands = Get-Command -ListImported -Name 'Invoke-IcingaCheck*' -ErrorAction SilentlyContinue;
|
|
|
|
if ($null -eq $CheckCommands) {
|
|
Write-IcingaConsoleError 'No Icinga CheckCommands were configured for module "{0}". Please verify that this is a valid PowerShell module root folder. Exception: {1}{2}' -Objects $ComponentPath, (New-IcingaNewLine), $Message;
|
|
return;
|
|
}
|
|
|
|
[array]$CheckList = @();
|
|
|
|
[string]$BasketConfigDir = Join-Path -Path $ComponentPath -ChildPath 'config\director';
|
|
[string]$IcingaConfigDir = Join-Path -Path $ComponentPath -ChildPath 'config\icinga';
|
|
|
|
if ((Test-Path $BasketConfigDir)) {
|
|
Remove-Item -Path $BasketConfigDir -Recurse -Force | Out-Null;
|
|
}
|
|
if ((Test-Path $IcingaConfigDir)) {
|
|
Remove-Item -Path $IcingaConfigDir -Recurse -Force | Out-Null;
|
|
}
|
|
|
|
if ((Test-Path $BasketConfigDir) -eq $FALSE) {
|
|
New-Item -Path $BasketConfigDir -ItemType Directory | Out-Null;
|
|
}
|
|
if ((Test-Path $IcingaConfigDir) -eq $FALSE) {
|
|
New-Item -Path $IcingaConfigDir -ItemType Directory | Out-Null;
|
|
}
|
|
|
|
foreach ($check in $CheckCommands) {
|
|
[string]$CheckPath = $check.Module.ModuleBase;
|
|
|
|
if ($CheckPath.Contains($ComponentPath) -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
$CheckList += [string]$check;
|
|
Get-IcingaCheckCommandConfig -CheckName $check -OutDirectory $BasketConfigDir -FileName $check;
|
|
Get-IcingaCheckCommandConfig -CheckName $check -OutDirectory $IcingaConfigDir -FileName $check -IcingaConfig;
|
|
}
|
|
|
|
Get-IcingaCheckCommandConfig -CheckName $CheckList -OutDirectory $BasketConfigDir -FileName ([string]::Format('{0}_Bundle', (Get-Culture).TextInfo.ToTitleCase($ComponentName)));
|
|
Get-IcingaCheckCommandConfig -CheckName $CheckList -OutDirectory $IcingaConfigDir -FileName ([string]::Format('{0}_Bundle', (Get-Culture).TextInfo.ToTitleCase($ComponentName))) -IcingaConfig;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Wrapper for Remove-Item to secuerly remove items allowing better handling for errors
|
|
.DESCRIPTION
|
|
Removes files and folders from disk and catches possible exceptions with proper return
|
|
values to handle errors better
|
|
.FUNCTIONALITY
|
|
Wrapper for Remove-Item to secuerly remove items allowing better handling for errors
|
|
.EXAMPLE
|
|
PS>Remove-ItemSecure -Path C:\icinga;
|
|
.EXAMPLE
|
|
PS>Remove-ItemSecure -Path C:\icinga -Recurse;
|
|
.EXAMPLE
|
|
PS>Remove-ItemSecure -Path C:\icinga -Recurse -Force;
|
|
.PARAMETER Path
|
|
The path to a file or folder you wish you delete
|
|
.PARAMETER Recurse
|
|
Removes sub-folders and sub-files for a given location
|
|
.PARAMETER Force
|
|
Tries to forefully removes a files and folders if they are either being used or a folder is
|
|
still containing items
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Remove-ItemSecure()
|
|
{
|
|
param(
|
|
[string]$Path,
|
|
[switch]$Recurse,
|
|
[switch]$Force
|
|
)
|
|
|
|
if ((Test-Path $Path) -eq $FALSE) {
|
|
return $FALSE;
|
|
}
|
|
|
|
try {
|
|
if ($Recurse -And $Force) {
|
|
Remove-Item -Path $Path -Recurse -Force;
|
|
} elseif ($Recurse -And -Not $Force) {
|
|
Remove-Item -Path $Path -Recurse;
|
|
} elseif (-Not $Recurse -And $Force) {
|
|
Remove-Item -Path $Path -Force;
|
|
} else {
|
|
Remove-Item -Path $Path;
|
|
}
|
|
return $TRUE;
|
|
} catch {
|
|
Write-IcingaConsoleError ([string]::Format('Failed to remove items from path "{0}": {1}', $Path, $_.Exception));
|
|
}
|
|
return $FALSE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Wrapper for Restart-Service which catches errors and prints proper output messages
|
|
.DESCRIPTION
|
|
Restarts a service if it is installed and prints console messages if a restart
|
|
was triggered or the service is not installed
|
|
.FUNCTIONALITY
|
|
Wrapper for restart service which catches errors and prints proper output messages
|
|
.EXAMPLE
|
|
PS>Restart-IcingaService -Service 'icinga2';
|
|
.PARAMETER Service
|
|
The name of the service to be restarted
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
Null
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Restart-IcingaService()
|
|
{
|
|
param(
|
|
$Service
|
|
);
|
|
|
|
if (Get-Service "$Service" -ErrorAction SilentlyContinue) {
|
|
Write-IcingaConsoleNotice ([string]::Format('Restarting service "{0}"', $Service));
|
|
powershell.exe -Command {
|
|
$Service = $args[0]
|
|
|
|
Restart-Service "$Service";
|
|
} -Args $Service;
|
|
} else {
|
|
Write-IcingaConsoleWarning -Message 'The service "{0}" is not installed' -Objects $Service;
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Returns the spent time since Start-IcingaTimer was executed in seconds for
|
|
a specific timer name
|
|
.DESCRIPTION
|
|
Returns the spent time since Start-IcingaTimer was executed in seconds for
|
|
a specific timer name
|
|
.FUNCTIONALITY
|
|
Returns the spent time since Start-IcingaTimer was executed in seconds for
|
|
a specific timer name
|
|
.EXAMPLE
|
|
PS>Show-IcingaTimer;
|
|
.EXAMPLE
|
|
PS>Show-IcingaTimer -Name 'My Test Timer';
|
|
.PARAMETER Name
|
|
The name of a custom identifier to run mutliple timers at once
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
Single
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Show-IcingaTimer()
|
|
{
|
|
param (
|
|
[string]$Name = 'DefaultTimer',
|
|
[switch]$ShowAll = $FALSE
|
|
);
|
|
|
|
$TimerObject = Get-IcingaTimer -Name $Name;
|
|
|
|
if (-Not $ShowAll) {
|
|
if ($null -eq $TimerObject) {
|
|
Write-IcingaConsoleNotice 'A timer with the name "{0}" does not exist' -Objects $Name;
|
|
return;
|
|
}
|
|
|
|
$TimerOutput = New-Object -TypeName PSObject;
|
|
$TimerOutput | Add-Member -MemberType NoteProperty -Name 'Timer Name' -Value $Name;
|
|
$TimerOutput | Add-Member -MemberType NoteProperty -Name 'Elapsed Seconds' -Value $TimerObject.Elapsed.TotalSeconds;
|
|
|
|
$TimerOutput | Format-Table -AutoSize;
|
|
} else {
|
|
$TimerObjects = Get-IcingaHashtableItem -Key 'IcingaTimers' -Hashtable $global:IcingaDaemonData;
|
|
|
|
[array]$MultiOutput = @();
|
|
|
|
foreach ($TimerName in $TimerObjects.Keys) {
|
|
$TimerObject = $TimerObjects[$TimerName].Timer;
|
|
|
|
$TimerOutput = New-Object -TypeName PSObject;
|
|
$TimerOutput | Add-Member -MemberType NoteProperty -Name 'Timer Name' -Value $TimerName;
|
|
$TimerOutput | Add-Member -MemberType NoteProperty -Name 'Elapsed Seconds' -Value $TimerObject.Elapsed.TotalSeconds;
|
|
$MultiOutput += $TimerOutput;
|
|
}
|
|
|
|
$MultiOutput | Format-Table -AutoSize;
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Wrapper for Start-Service which catches errors and prints proper output messages
|
|
.DESCRIPTION
|
|
Starts a service if it is installed and prints console messages if a start
|
|
was triggered or the service is not installed
|
|
.FUNCTIONALITY
|
|
Wrapper for Start-Service which catches errors and prints proper output messages
|
|
.EXAMPLE
|
|
PS>Start-IcingaService -Service 'icinga2';
|
|
.PARAMETER Service
|
|
The name of the service to be started
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
Null
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Start-IcingaService()
|
|
{
|
|
param(
|
|
$Service
|
|
);
|
|
|
|
if (Get-Service $Service -ErrorAction SilentlyContinue) {
|
|
Write-IcingaConsoleNotice -Message 'Starting service "{0}"' -Objects $Service;
|
|
powershell.exe -Command {
|
|
$Service = $args[0]
|
|
|
|
Start-Service "$Service";
|
|
} -Args $Service;
|
|
} else {
|
|
Write-IcingaConsoleWarning -Message 'The service "{0}" is not installed' -Objects $Service;
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Start a new timer for a given name and stores it within the $globals section
|
|
of the Icinga PowerShell Framework
|
|
.DESCRIPTION
|
|
Start a new timer for a given name and stores it within the $globals section
|
|
of the Icinga PowerShell Framework
|
|
.FUNCTIONALITY
|
|
Start a new timer for a given name and stores it within the $globals section
|
|
of the Icinga PowerShell Framework
|
|
.EXAMPLE
|
|
PS>Start-IcingaTimer;
|
|
.EXAMPLE
|
|
PS>Start-IcingaTimer -Name 'My Test Timer';
|
|
.PARAMETER Name
|
|
The name of a custom identifier to run mutliple timers at once
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Start-IcingaTimer()
|
|
{
|
|
param (
|
|
[string]$Name = 'DefaultTimer'
|
|
);
|
|
|
|
if ((Test-IcingaTimer -Name $Name)) {
|
|
Write-IcingaConsoleNotice 'The timer with the name "{0}" is already active' -Objects $Name;
|
|
return;
|
|
}
|
|
|
|
# Load the library first
|
|
[System.Reflection.Assembly]::LoadWithPartialName("System.Diagnostics") | Out-Null;
|
|
$TimerObject = New-Object System.Diagnostics.Stopwatch;
|
|
$TimerObject.Start();
|
|
|
|
Add-IcingaHashtableItem -Key $Name -Value (
|
|
[hashtable]::Synchronized(
|
|
@{
|
|
'Active' = $TRUE;
|
|
'Timer' = $TimerObject;
|
|
}
|
|
)
|
|
) -Hashtable $global:IcingaDaemonData.IcingaTimers -Override | Out-Null;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Wrapper for Stop-Service which catches errors and prints proper output messages
|
|
.DESCRIPTION
|
|
Stops a service if it is installed and prints console messages if a stop
|
|
was triggered or the service is not installed
|
|
.FUNCTIONALITY
|
|
Wrapper for Stop-Service which catches errors and prints proper output messages
|
|
.EXAMPLE
|
|
PS>Stop-IcingaService -Service 'icinga2';
|
|
.PARAMETER Service
|
|
The name of the service to be stopped
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
Null
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Stop-IcingaService()
|
|
{
|
|
param(
|
|
$Service
|
|
);
|
|
|
|
if (Get-Service $Service -ErrorAction SilentlyContinue) {
|
|
Write-IcingaConsoleNotice -Message 'Stopping service "{0}"' -Objects $Service;
|
|
powershell.exe -Command {
|
|
$Service = $args[0]
|
|
|
|
Stop-Service "$Service";
|
|
} -Args $Service;
|
|
} else {
|
|
Write-IcingaConsoleWarning -Message 'The service "{0}" is not installed' -Objects $Service;
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Stops a timer object started with Start-IcingaTimer for a specific
|
|
named timer
|
|
.DESCRIPTION
|
|
Stops a timer object started with Start-IcingaTimer for a specific
|
|
named timer
|
|
.FUNCTIONALITY
|
|
Stops a timer object started with Start-IcingaTimer for a specific
|
|
named timer
|
|
.EXAMPLE
|
|
PS>Stop-IcingaTimer;
|
|
.EXAMPLE
|
|
PS>Stop-IcingaTimer -Name 'My Test Timer';
|
|
.PARAMETER Name
|
|
The name of a custom identifier to run mutliple timers at once
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Stop-IcingaTimer()
|
|
{
|
|
param (
|
|
[string]$Name = 'DefaultTimer'
|
|
);
|
|
|
|
$TimerObject = Get-IcingaTimer -Name $Name;
|
|
|
|
if ($null -eq $TimerObject) {
|
|
return;
|
|
}
|
|
|
|
if ($TimerObject.IsRunning) {
|
|
$TimerObject.Stop();
|
|
}
|
|
Add-IcingaHashtableItem -Key $Name -Value (
|
|
[hashtable]::Synchronized(
|
|
@{
|
|
'Active' = $FALSE;
|
|
'Timer' = $TimerObject;
|
|
}
|
|
)
|
|
) -Hashtable $global:IcingaDaemonData.IcingaTimers -Override | Out-Null;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Allows to test if console output can be written or not for this PowerShell session
|
|
.DESCRIPTION
|
|
Allows to test if console output can be written or not for this PowerShell session
|
|
.FUNCTIONALITY
|
|
Allows to test if console output can be written or not for this PowerShell session
|
|
.EXAMPLE
|
|
PS>Enable-IcingaFrameworkConsoleOutput;
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Test-IcingaFrameworkConsoleOutput()
|
|
{
|
|
if ($null -eq $global:Icinga) {
|
|
return $TRUE;
|
|
}
|
|
|
|
if ($global:Icinga.ContainsKey('DisableConsoleOutput') -eq $FALSE) {
|
|
return $TRUE;
|
|
}
|
|
|
|
return (-Not ($global:Icinga.DisableConsoleOutput));
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Tests if a specific timer object is already present and started with Start-IcingaTimer
|
|
.DESCRIPTION
|
|
Tests if a specific timer object is already present and started with Start-IcingaTimer
|
|
.FUNCTIONALITY
|
|
Tests if a specific timer object is already present and started with Start-IcingaTimer
|
|
.EXAMPLE
|
|
PS>Test-IcingaTimer;
|
|
.EXAMPLE
|
|
PS>Test-IcingaTimer -Name 'My Test Timer';
|
|
.PARAMETER Name
|
|
The name of a custom identifier to run mutliple timers at once
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Test-IcingaTimer()
|
|
{
|
|
param (
|
|
[string]$Name = 'DefaultTimer'
|
|
);
|
|
|
|
$TimerData = Get-IcingaHashtableItem -Key $Name -Hashtable $global:IcingaDaemonData.IcingaTimers;
|
|
|
|
if ($null -eq $TimerData) {
|
|
return $FALSE;
|
|
}
|
|
|
|
return $TimerData.Active;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Compares a binary within a .zip file to a included .md5 to ensure
|
|
the checksum is matching
|
|
.DESCRIPTION
|
|
Compares a possible included .md5 checksum file with the provided binary
|
|
to ensure they are identical
|
|
.FUNCTIONALITY
|
|
Compares a binary within a .zip file to a included .md5 to ensure
|
|
the checksum is matching.
|
|
.EXAMPLE
|
|
PS>Test-IcingaZipBinaryChecksum -Path 'C:\Program Files\icinga-service\icinga-service.exe';
|
|
.PARAMETER Path
|
|
Path to the binary to be checked for. A Corresponding .md5 file with the
|
|
extension added on the file is required, like icinga-service.exe.md5
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
Null
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Test-IcingaZipBinaryChecksum()
|
|
{
|
|
param(
|
|
$Path
|
|
);
|
|
|
|
$MD5Path = [string]::Format('{0}.md5', $Path);
|
|
|
|
if ((Test-Path $MD5Path) -eq $FALSE) {
|
|
return $TRUE;
|
|
}
|
|
|
|
[string]$MD5Checksum = Get-Content $MD5Path;
|
|
$MD5Checksum = ($MD5Checksum.Split(' ')[0]).ToLower();
|
|
|
|
$FileHash = ((Get-FileHash $Path -Algorithm MD5).Hash).ToLower();
|
|
|
|
if ($MD5Checksum -ne $FileHash) {
|
|
return $FALSE;
|
|
}
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Unblocks a folder with PowerShell module/script files to make them usable
|
|
on certain environments
|
|
.DESCRIPTION
|
|
Wrapper command to unblock recursively a certain folder for PowerShell script
|
|
and module files
|
|
.FUNCTIONALITY
|
|
Unblocks a folder with PowerShell module/script files to make them usable
|
|
on certain environments
|
|
.EXAMPLE
|
|
PS>Unblock-IcingaPowerShellFiles -Path 'C:\Program Files\WindowsPowerShell\Modules\my-module';
|
|
.PARAMETER Path
|
|
The path to a PowerShell module folder or script file to unblock it
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
Null
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Unblock-IcingaPowerShellFiles()
|
|
{
|
|
param(
|
|
$Path
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Path)) {
|
|
Write-IcingaConsoleError 'The specified directory was not found';
|
|
return;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Unblocking Icinga PowerShell Files';
|
|
Get-ChildItem -Path $Path -Recurse | Unblock-File;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Uninstalls every PowerShell module within the icinga-powershell-* namespace
|
|
including the Icinga Agent with all components (like certificates) as well as
|
|
the Icinga for Windows service and the Icinga PowerShell Framework.
|
|
.DESCRIPTION
|
|
Uninstalls every PowerShell module within the icinga-powershell-* namespace
|
|
including the Icinga Agent with all components (like certificates) as well as
|
|
the Icinga for Windows service and the Icinga PowerShell Framework.
|
|
.FUNCTIONALITY
|
|
Uninstalls every PowerShell module within the icinga-powershell-* namespace
|
|
including the Icinga Agent with all components (like certificates) as well as
|
|
the Icinga for Windows service and the Icinga PowerShell Framework.
|
|
.PARAMETER Force
|
|
Suppress the question if you are sure to uninstall everything
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
Null
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Uninstall-IcingaForWindows()
|
|
{
|
|
param (
|
|
[switch]$Force = $FALSE
|
|
);
|
|
|
|
$ModuleList = Get-Module 'icinga-powershell-*' -ListAvailable;
|
|
[string]$Modules = [string]::Join(', ', $ModuleList.Name);
|
|
|
|
if ($Force -eq $FALSE) {
|
|
Write-IcingaConsoleWarning -Message 'You are about to uninstall the Icinga Agent with all components (including certificates) and all Icinga for Windows Components: {0}{1}Are you sure you want to proceed? (y/N)' -Objects $Modules, (New-IcingaNewLine);
|
|
$Input = Read-Host 'Confirm uninstall';
|
|
if ($input -ne 'y') {
|
|
return;
|
|
}
|
|
}
|
|
|
|
$CurrentLocation = Get-Location;
|
|
|
|
if ($CurrentLocation -eq (Get-IcingaFrameworkRootPath)) {
|
|
Set-Location -Path (Get-IcingaForWindowsRootPath);
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Uninstalling Icinga for Windows from this host';
|
|
Write-IcingaConsoleNotice 'Uninstalling Icinga Agent';
|
|
Uninstall-IcingaAgent -RemoveDataFolder | Out-Null;
|
|
Write-IcingaConsoleNotice 'Uninstalling Icinga for Windows service';
|
|
Uninstall-IcingaForWindowsService | Out-Null;
|
|
|
|
$HasErrors = $FALSE;
|
|
|
|
foreach ($module in $ModuleList.Name) {
|
|
[string]$ModuleName = $module.Replace('icinga-powershell-', '');
|
|
|
|
if ((Uninstall-IcingaFrameworkComponent -Name $ModuleName)) {
|
|
continue;
|
|
}
|
|
|
|
$HasErrors = $TRUE;
|
|
}
|
|
|
|
Remove-Module 'icinga-powershell-framework' -Force -ErrorAction SilentlyContinue;
|
|
|
|
if ($HasErrors) {
|
|
Write-IcingaConsoleWarning 'Not all components could be removed. Please ensure no other PowerShell/Application is currently open and accessing Icinga for Windows files';
|
|
} else {
|
|
Write-IcingaConsoleNotice 'Icinga for Windows was removed from this host.';
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Uninstalls the Icinga PowerShell Service as a Windows Service
|
|
.DESCRIPTION
|
|
Uninstalls the Icinga PowerShell Service as a Windows Service. The service binary
|
|
will be left on the system.
|
|
.FUNCTIONALITY
|
|
Uninstalls the Icinga PowerShell Service as a Windows Service
|
|
.EXAMPLE
|
|
PS>Uninstall-IcingaForWindowsService;
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Uninstall-IcingaForWindowsService()
|
|
{
|
|
param (
|
|
[switch]$RemoveFiles = $FALSE
|
|
);
|
|
|
|
$ServiceData = Get-IcingaForWindowsServiceData;
|
|
|
|
Stop-IcingaService 'icingapowershell';
|
|
Start-Sleep -Seconds 1;
|
|
|
|
$ServiceCreation = Start-IcingaProcess -Executable 'sc.exe' -Arguments 'delete icingapowershell';
|
|
|
|
switch ($ServiceCreation.ExitCode) {
|
|
0 {
|
|
Write-IcingaConsoleNotice 'Icinga PowerShell Service was successfully removed';
|
|
}
|
|
1060 {
|
|
Write-IcingaConsoleWarning 'The Icinga PowerShell Service is not installed';
|
|
}
|
|
Default {
|
|
throw ([string]::Format('Failed to install Icinga PowerShell Service: {0}{1}', $ServiceCreation.Message, $ServiceCreation.Error));
|
|
}
|
|
}
|
|
|
|
if ($RemoveFiles -eq $FALSE) {
|
|
return $TRUE;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ServiceData.Directory) -Or (Test-Path $ServiceData.Directory) -eq $FALSE) {
|
|
return $TRUE;
|
|
}
|
|
|
|
$ServiceFolderContent = Get-ChildItem -Path $ServiceData.Directory;
|
|
|
|
foreach ($entry in $ServiceFolderContent) {
|
|
if ($entry.Name -eq 'icinga-service.exe' -Or $entry.Name -eq 'icinga-service.exe.md5' -Or $entry.Name -eq 'icinga-service.exe.update') {
|
|
Remove-Item $entry.FullName -Force;
|
|
Write-IcingaConsoleNotice 'Removing file "{0}"' -Objects $entry.FullName;
|
|
}
|
|
}
|
|
|
|
$ServiceFolderContent = Get-ChildItem -Path $ServiceData.Directory;
|
|
|
|
if ($ServiceFolderContent.Count -eq 0) {
|
|
Remove-Item $ServiceData.Directory;
|
|
Write-IcingaConsoleNotice 'Removing directory "{0}"' -Objects $ServiceData.Directory;
|
|
} else {
|
|
Write-IcingaConsoleWarning 'Unable to remove folder "{0}", because there are still files inside.' -Objects $ServiceData.Directory;
|
|
}
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
Set-Alias -Name 'Uninstall-IcingaFrameworkService' -Value 'Uninstall-IcingaForWindowsService';
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Uninstalls a specific module within the icinga-powershell-* namespace
|
|
inside your PowerShell module folder
|
|
.DESCRIPTION
|
|
Uninstalls a specific module within the icinga-powershell-* namespace
|
|
inside your PowerShell module folder
|
|
.FUNCTIONALITY
|
|
Uninstalls a specific module within the icinga-powershell-* namespace
|
|
inside your PowerShell module folder
|
|
.PARAMETER Name
|
|
The component you want to uninstall, like 'plugins' or 'mssql'
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
Null
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Uninstall-IcingaFrameworkComponent()
|
|
{
|
|
param (
|
|
[string]$Name = ''
|
|
);
|
|
|
|
$ModuleBase = Get-IcingaForWindowsRootPath;
|
|
$UninstallComponent = [string]::Format('icinga-powershell-{0}', $Name);
|
|
$UninstallPath = Join-Path -Path $ModuleBase -ChildPath $UninstallComponent;
|
|
|
|
if ((Test-Path $UninstallPath) -eq $FALSE) {
|
|
Write-IcingaConsoleNotice -Message 'The Icinga for Windows component "{0}" at "{1}" could not ne found.' -Objects $UninstallComponent, $UninstallPath;
|
|
return $FALSE;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice -Message 'Uninstalling Icinga for Windows component "{0}" from "{1}"' -Objects $UninstallComponent, $UninstallPath;
|
|
if (Remove-ItemSecure -Path $UninstallPath -Recurse -Force) {
|
|
Write-IcingaConsoleNotice -Message 'Successfully removed Icinga for Windows component "{0}" from "{1}"' -Objects $UninstallComponent, $UninstallPath;
|
|
if ($UninstallComponent -ne 'icinga-powershell-framework') {
|
|
Remove-Module $UninstallComponent -Force -ErrorAction SilentlyContinue;
|
|
}
|
|
return $TRUE;
|
|
} else {
|
|
Write-IcingaConsoleError -Message 'Unable to uninstall Icinga for Windows component "{0}" from "{1}"' -Objects $UninstallComponent, $UninstallPath;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
function Find-IcingaAgentObjects()
|
|
{
|
|
param(
|
|
$Find = @(),
|
|
$OutFile = $null
|
|
);
|
|
|
|
if ($Find.Length -eq 0) {
|
|
throw 'Please specify content you want to look for';
|
|
}
|
|
|
|
[array]$ObjectList = (Get-IcingaAgentObjectList).Split("`r`n");
|
|
[int]$lineIndex = 0;
|
|
[array]$Result = @();
|
|
|
|
foreach ($line in $ObjectList) {
|
|
if ([string]::IsNullOrEmpty($line)) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($entry in $Find) {
|
|
if ($line -like $entry) {
|
|
[string]$ResultLine = [string]::Format(
|
|
'Line #{0} => "{1}"',
|
|
$lineIndex,
|
|
$line
|
|
);
|
|
$Result += $ResultLine;
|
|
}
|
|
}
|
|
|
|
$lineIndex += 1;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($OutFile)) {
|
|
Write-Output $Result;
|
|
} else {
|
|
Set-Content -Path $OutFile -Value $Result;
|
|
}
|
|
}
|
|
|
|
function Disable-IcingaFirewall()
|
|
{
|
|
param(
|
|
[switch]$LegacyOnly
|
|
);
|
|
|
|
$FirewallConfig = Get-IcingaFirewallConfig -NoOutput;
|
|
|
|
if ($FirewallConfig.LegacyFirewall) {
|
|
$Firewall = Start-IcingaProcess -Executable 'netsh' -Arguments 'advfirewall firewall delete rule name="Icinga 2 Agent Inbound by PS-Module"';
|
|
if ($Firewall.ExitCode -ne 0) {
|
|
Write-IcingaConsoleError ([string]::Format('Failed to remove legacy firewall: {0}{1}', $Firewall.Message, $Firewall.Error));
|
|
} else {
|
|
Write-IcingaConsoleNotice 'Successfully removed legacy firewall rule';
|
|
}
|
|
}
|
|
|
|
if ($LegacyOnly) {
|
|
return;
|
|
}
|
|
|
|
if ($FirewallConfig.IcingaFirewall) {
|
|
$Firewall = Start-IcingaProcess -Executable 'netsh' -Arguments 'advfirewall firewall delete rule name="Icinga Agent Inbound"';
|
|
if ($Firewall.ExitCode -ne 0) {
|
|
Write-IcingaConsoleError ([string]::Format('Failed to remove Icinga firewall: {0}{1}', $Firewall.Message, $Firewall.Error));
|
|
} else {
|
|
Write-IcingaConsoleNotice 'Successfully removed Icinga firewall rule';
|
|
}
|
|
}
|
|
}
|
|
|
|
function Enable-IcingaFirewall()
|
|
{
|
|
param(
|
|
[int]$IcingaPort = 5665,
|
|
[switch]$Force
|
|
);
|
|
|
|
$FirewallConfig = Get-IcingaFirewallConfig -NoOutput;
|
|
|
|
if ($FirewallConfig.IcingaFirewall -And $Force -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'Icinga Firewall is already enabled'
|
|
return;
|
|
}
|
|
|
|
if ($Force) {
|
|
Disable-IcingaFirewall;
|
|
}
|
|
|
|
$IcingaBinary = Get-IcingaAgentBinary;
|
|
[string]$FirewallRule = [string]::Format(
|
|
'advfirewall firewall add rule dir=in action=allow program="{0}" name="{1}" description="{2}" enable=yes remoteip=any localip=any localport={3} protocol=tcp',
|
|
$IcingaBinary,
|
|
'Icinga Agent Inbound',
|
|
'Inbound Firewall Rule to allow Icinga 2 masters / satellites to connect to the Icinga 2 Agent installed on this system.',
|
|
$IcingaPort
|
|
);
|
|
|
|
$FirewallResult = Start-IcingaProcess -Executable 'netsh' -Arguments $FirewallRule;
|
|
|
|
if ($FirewallResult.ExitCode -ne 0) {
|
|
Write-IcingaConsoleError ([string]::Format('Failed to open Icinga firewall for port "{0}": {1}[2}', $IcingaPort, $FirewallResult.Message, $FirewallResult.Error));
|
|
} else {
|
|
Write-IcingaConsoleNotice ([string]::Format('Successfully enabled firewall for port "{0}"', $IcingaPort));
|
|
}
|
|
}
|
|
|
|
function Get-IcingaFirewallConfig()
|
|
{
|
|
param(
|
|
[switch]$NoOutput
|
|
);
|
|
|
|
[bool]$LegacyFirewallPresent = $FALSE;
|
|
[bool]$IcingaFirewallPresent = $FALSE;
|
|
|
|
$LegacyFirewall = Start-IcingaProcess -Executable 'netsh' -Arguments 'advfirewall firewall show rule name="Icinga 2 Agent Inbound by PS-Module"';
|
|
|
|
if ($LegacyFirewall.ExitCode -eq 0) {
|
|
if ($NoOutput -eq $FALSE) {
|
|
Write-IcingaConsoleWarning 'Legacy firewall configuration has been detected.';
|
|
}
|
|
$LegacyFirewallPresent = $TRUE;
|
|
}
|
|
|
|
$IcingaFirewall = Start-IcingaProcess -Executable 'netsh' -Arguments 'advfirewall firewall show rule name="Icinga Agent Inbound"';
|
|
|
|
if ($IcingaFirewall.ExitCode -eq 0) {
|
|
if ($NoOutput -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'Icinga firewall is present.';
|
|
}
|
|
$IcingaFirewallPresent = $TRUE;
|
|
} else {
|
|
if ($NoOutput -eq $FALSE) {
|
|
Write-IcingaConsoleError 'Icinga firewall is not present';
|
|
}
|
|
}
|
|
|
|
return @{
|
|
'LegacyFirewall' = $LegacyFirewallPresent;
|
|
'IcingaFirewall' = $IcingaFirewallPresent;
|
|
}
|
|
}
|
|
|
|
function Get-IcingaAgentArchitecture()
|
|
{
|
|
$IcingaAgent = Get-IcingaAgentInstallation;
|
|
|
|
return $IcingaAgent.Architecture;
|
|
}
|
|
|
|
function Get-IcingaAgentBinary()
|
|
{
|
|
$IcingaRootDir = Get-IcingaAgentRootDirectory;
|
|
if ([string]::IsNullOrEmpty($IcingaRootDir)) {
|
|
throw 'The Icinga Agent seems not to be installed';
|
|
}
|
|
|
|
$IcingaBinary = (Join-Path -Path $IcingaRootDir -ChildPath '\sbin\icinga2.exe');
|
|
|
|
if ((Test-Path $IcingaBinary) -eq $FALSE) {
|
|
throw 'Icinga Agent binary could not be found';
|
|
}
|
|
|
|
return $IcingaBinary;
|
|
}
|
|
|
|
function Get-IcingaAgentConfigDirectory()
|
|
{
|
|
return (Join-Path -Path $Env:ProgramData -ChildPath 'icinga2\etc\icinga2\')
|
|
}
|
|
|
|
function Get-IcingaAgentFeatures()
|
|
{
|
|
$Binary = Get-IcingaAgentBinary;
|
|
$ConfigResult = Start-IcingaProcess -Executable $Binary -Arguments 'feature list';
|
|
|
|
if ($ConfigResult.ExitCode -ne 0) {
|
|
return @{
|
|
'Enabled' = @();
|
|
'Disabled' = @();
|
|
}
|
|
}
|
|
|
|
$DisabledFeatures = (
|
|
$ConfigResult.Message.SubString(
|
|
0,
|
|
$ConfigResult.Message.IndexOf('Enabled features')
|
|
)
|
|
).Replace('Disabled features: ', '').Replace("`r`n", '').Replace("`r", '').Replace("`n", '');
|
|
|
|
$EnabledFeatures = (
|
|
$ConfigResult.Message.SubString(
|
|
$ConfigResult.Message.IndexOf('Enabled features'),
|
|
$ConfigResult.Message.Length - $ConfigResult.Message.IndexOf('Enabled features')
|
|
)
|
|
).Replace('Enabled features: ', '').Replace("`r`n", '').Replace("`r", '').Replace("`n", '');
|
|
|
|
return @{
|
|
'Enabled' = ($EnabledFeatures.Split(' '));
|
|
'Disabled' = ($DisabledFeatures.Split(' '));
|
|
}
|
|
}
|
|
|
|
function Get-IcingaAgentHostCertificate()
|
|
{
|
|
# Default for Icinga 2.8.0 and above
|
|
[string]$CertDirectory = (Join-Path -Path $Env:ProgramData -ChildPath 'icinga2\var\lib\icinga2\certs\*');
|
|
$FolderContent = Get-ChildItem -Path $CertDirectory -Filter '*.crt' -Exclude 'ca.crt';
|
|
$Hostname = Get-IcingaHostname -LowerCase $TRUE;
|
|
$CertPath = $null;
|
|
|
|
foreach ($certFile in $FolderContent) {
|
|
if ($certFile.Name -like ([string]::Format('{0}.crt', $Hostname))) {
|
|
$CertPath = $certFile.FullName;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($CertPath)) {
|
|
return $null;
|
|
}
|
|
|
|
$Certificate = New-Object Security.Cryptography.X509Certificates.X509Certificate2 $CertPath;
|
|
|
|
return @{
|
|
'CertFile' = $CertPath;
|
|
'Subject' = $Certificate.Subject;
|
|
'Thumbprint' = $Certificate.Thumbprint;
|
|
};
|
|
}
|
|
|
|
function Get-IcingaAgentInstallation()
|
|
{
|
|
[string]$architecture = '';
|
|
if ([IntPtr]::Size -eq 4) {
|
|
$architecture = "x86";
|
|
$regPath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*';
|
|
} else {
|
|
$architecture = "x86_64";
|
|
$regPath = @('HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*');
|
|
}
|
|
|
|
$RegistryData = Get-ItemProperty $regPath;
|
|
$IcingaData = $null;
|
|
foreach ($entry in $RegistryData) {
|
|
if ($entry.DisplayName -eq 'Icinga 2') {
|
|
$IcingaData = $entry;
|
|
break;
|
|
}
|
|
}
|
|
|
|
$IcingaService = Get-IcingaServices -Service 'icinga2';
|
|
$ServiceUser = 'NT AUTHORITY\NetworkService';
|
|
|
|
if ($null -ne $IcingaService) {
|
|
$ServiceUser = $IcingaService.icinga2.configuration.ServiceUser;
|
|
}
|
|
|
|
if ($null -eq $IcingaData) {
|
|
return @{
|
|
'Installed' = $FALSE;
|
|
'RootDir' = '';
|
|
'Version' = (Split-IcingaVersion);
|
|
'Architecture' = $architecture;
|
|
'Uninstaller' = '';
|
|
'InstallDate' = '';
|
|
'User' = $ServiceUser;
|
|
};
|
|
}
|
|
|
|
return @{
|
|
'Installed' = $TRUE;
|
|
'RootDir' = $IcingaData.InstallLocation;
|
|
'Version' = (Split-IcingaVersion $IcingaData.DisplayVersion);
|
|
'Architecture' = $architecture;
|
|
'Uninstaller' = $IcingaData.UninstallString.Replace("MsiExec.exe ", "");
|
|
'InstallDate' = $IcingaData.InstallDate;
|
|
'User' = $ServiceUser;
|
|
};
|
|
}
|
|
|
|
function Get-IcingaAgentInstallerAnswerInput()
|
|
{
|
|
param(
|
|
$Prompt,
|
|
[ValidateSet("y", "n", "v")]
|
|
$Default,
|
|
$DefaultInput = '',
|
|
[switch]$Secure
|
|
);
|
|
|
|
$DefaultAnswer = '';
|
|
|
|
if ($Default -eq 'y') {
|
|
$DefaultAnswer = ' (Y/n)';
|
|
} elseif ($Default -eq 'n') {
|
|
$DefaultAnswer = ' (y/N)';
|
|
} elseif ($Default -eq 'v') {
|
|
if ([string]::IsNullOrEmpty($DefaultInput) -eq $FALSE) {
|
|
$DefaultAnswer = [string]::Format(' (Defaults: "{0}")', $DefaultInput);
|
|
}
|
|
}
|
|
|
|
if (-Not $Secure) {
|
|
$answer = Read-Host -Prompt ([string]::Format('{0}{1}', $Prompt, $DefaultAnswer));
|
|
} else {
|
|
$answer = Read-Host -Prompt ([string]::Format('{0}{1}', $Prompt, $DefaultAnswer)) -AsSecureString;
|
|
}
|
|
|
|
if ($Default -ne 'v') {
|
|
$answer = $answer.ToLower();
|
|
|
|
$returnValue = 0;
|
|
if ([string]::IsNullOrEmpty($answer) -Or $answer -eq $Default) {
|
|
$returnValue = 1;
|
|
} else {
|
|
$returnValue = 0;
|
|
}
|
|
|
|
return @{
|
|
'result' = $returnValue;
|
|
'answer' = '';
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($answer)) {
|
|
$answer = $DefaultInput;
|
|
}
|
|
|
|
return @{
|
|
'result' = 2;
|
|
'answer' = $answer;
|
|
}
|
|
}
|
|
|
|
function Get-IcingaAgentLogDirectory()
|
|
{
|
|
return (Join-Path -Path $Env:ProgramData -ChildPath 'icinga2\var\log\icinga2\')
|
|
}
|
|
|
|
function Get-IcingaAgentMSIPackage()
|
|
{
|
|
param(
|
|
[string]$Source,
|
|
[string]$Version,
|
|
[switch]$SkipDownload
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Version)) {
|
|
throw 'Please specify a valid version: "release", "snapshot" or a specific version like "2.11.0"';
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Source)) {
|
|
throw 'Please specify a valid download URL, like "https://packages.icinga.com/windows/"';
|
|
}
|
|
|
|
Set-IcingaTLSVersion;
|
|
# Disable the progress bar for the WebRequest
|
|
$ProgressPreference = "SilentlyContinue";
|
|
$Architecture = Get-IcingaAgentArchitecture;
|
|
$LastUpdate = $null;
|
|
$Version = $Version.ToLower();
|
|
|
|
if ($Version -eq 'snapshot' -Or $Version -eq 'release') {
|
|
if (Test-Path $Source) {
|
|
$Content = Get-ChildItem -Path $Source;
|
|
|
|
foreach ($entry in $Content) {
|
|
# Only check for MSI packages
|
|
if ($entry.Extension.ToLower() -ne '.msi') {
|
|
continue;
|
|
}
|
|
|
|
$PackageVersion = '';
|
|
|
|
if ($entry.Name.ToLower().Contains('-')) {
|
|
$PackageVersion = ($entry.Name.Split('-')[1]).Replace('v', '');
|
|
}
|
|
|
|
if ($Version -eq 'snapshot') {
|
|
if ($PackageVersion -eq 'snapshot') {
|
|
$UseVersion = 'snapshot';
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if ($PackageVersion -eq 'snapshot') {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
if ($null -eq $UseVersion -Or [version]$PackageVersion -ge [version]$UseVersion) {
|
|
$UseVersion = $PackageVersion;
|
|
}
|
|
} catch {
|
|
# Nothing to catch specifically
|
|
}
|
|
}
|
|
} else {
|
|
$Content = (Invoke-IcingaWebRequest -Uri $Source -UseBasicParsing).RawContent.Split("`r`n");
|
|
$UsePackage = $null;
|
|
$UseVersion = $null;
|
|
|
|
foreach ($line in $Content) {
|
|
if ($line -like '*.msi*' -And $line -like "*$Architecture.msi*") {
|
|
$MSIPackage = $line.SubString(
|
|
$line.IndexOf('Icinga2-'),
|
|
$line.IndexOf('.msi') - $line.IndexOf('Icinga2-')
|
|
);
|
|
$LastUpdate = $line.SubString(
|
|
$line.IndexOf('indexcollastmod">') + 17,
|
|
$line.Length - $line.IndexOf('indexcollastmod">') - 17
|
|
);
|
|
$LastUpdate = $LastUpdate.SubString(0, $LastUpdate.IndexOf(' '));
|
|
$LastUpdate = $LastUpdate.Replace('-', '');
|
|
$MSIPackage = [string]::Format('{0}.msi', $MSIPackage);
|
|
$PackageVersion = ($MSIPackage.Split('-')[1]).Replace('v', '');
|
|
|
|
if ($Version -eq 'snapshot') {
|
|
if ($PackageVersion -eq 'snapshot') {
|
|
$UseVersion = 'snapshot';
|
|
break;
|
|
}
|
|
} elseif ($Version -eq 'release') {
|
|
if ($line -like '*snapshot*' -Or $line -like '*-rc*') {
|
|
continue;
|
|
}
|
|
|
|
if ($null -eq $UseVersion -Or [version]$PackageVersion -ge [version]$UseVersion) {
|
|
$UseVersion = $PackageVersion;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($Version -eq 'snapshot') {
|
|
$UsePackage = [string]::Format('Icinga2-{0}-{1}.msi', $UseVersion, $Architecture);
|
|
} else {
|
|
$UsePackage = [string]::Format('Icinga2-v{0}-{1}.msi', $UseVersion, $Architecture);
|
|
}
|
|
} else {
|
|
$UsePackage = [string]::Format('Icinga2-v{0}-{1}.msi', $Version, $Architecture);
|
|
}
|
|
|
|
if ($null -eq $UsePackage) {
|
|
throw 'No Icinga installation MSI package for your architecture could be found for the provided version and source';
|
|
}
|
|
|
|
if ($SkipDownload -eq $FALSE) {
|
|
$DownloadPath = Join-Path $Env:TEMP -ChildPath $UsePackage;
|
|
Write-IcingaConsoleNotice ([string]::Format('Downloading Icinga 2 Agent installer "{0}" into temp directory "{1}"', $UsePackage, $DownloadPath));
|
|
Invoke-IcingaWebRequest -Uri (Join-WebPath -Path $Source -ChildPath $UsePackage) -OutFile $DownloadPath;
|
|
}
|
|
|
|
return @{
|
|
'InstallerPath' = $DownloadPath;
|
|
'Version' = ($UsePackage).Replace('Icinga2-v', '').Replace('Icinga2-', '').Replace([string]::Format('-{0}.msi', $Architecture), '')
|
|
'LastUpdate' = $LastUpdate;
|
|
}
|
|
}
|
|
|
|
function Get-IcingaAgentObjectList()
|
|
{
|
|
$Binary = Get-IcingaAgentBinary;
|
|
$ObjectList = Start-IcingaProcess -Executable $Binary -Arguments 'object list';
|
|
|
|
return $ObjectList.Message;
|
|
}
|
|
|
|
function Get-IcingaAgentRootDirectory()
|
|
{
|
|
$IcingaAgent = Get-IcingaAgentInstallation;
|
|
if ($IcingaAgent.Installed -eq $FALSE) {
|
|
return '';
|
|
}
|
|
|
|
return $IcingaAgent.RootDir;
|
|
}
|
|
|
|
function Get-IcingaAgentServicePermission()
|
|
{
|
|
$SystemPermissions = New-IcingaTemporaryFile;
|
|
$SystemOutput = Start-IcingaProcess -Executable 'secedit.exe' -Arguments ([string]::Format('/export /cfg "{0}.inf"', $SystemPermissions));
|
|
|
|
if ($SystemOutput.ExitCode -ne 0) {
|
|
throw ([string]::Format('Unable to fetch system permission information: {0}', $SystemOutput.Message));
|
|
return $null;
|
|
}
|
|
|
|
$SystemContent = Get-Content "$SystemPermissions.inf";
|
|
|
|
Remove-Item $SystemPermissions*;
|
|
|
|
return $SystemContent;
|
|
}
|
|
|
|
function Get-IcingaAgentVersion()
|
|
{
|
|
$IcingaAgent = Get-IcingaAgentInstallation;
|
|
|
|
return $IcingaAgent.Version;
|
|
}
|
|
|
|
function Get-IcingaHostname()
|
|
{
|
|
param(
|
|
[string]$Hostname,
|
|
[bool]$AutoUseFQDN = $FALSE,
|
|
[bool]$AutoUseHostname = $FALSE,
|
|
[bool]$UpperCase = $FALSE,
|
|
[bool]$LowerCase = $FALSE
|
|
);
|
|
|
|
[string]$UseHostname = '';
|
|
if ([string]::IsNullOrEmpty($Hostname) -eq $FALSE) {
|
|
$UseHostname = $Hostname;
|
|
} elseif ($AutoUseFQDN) {
|
|
$UseHostname = [System.Net.Dns]::GetHostEntry("localhost").HostName;
|
|
} else {
|
|
$UseHostname = [System.Net.Dns]::GetHostName();
|
|
}
|
|
|
|
if ($UpperCase) {
|
|
$UseHostname = $UseHostname.ToUpper();
|
|
} elseif ($LowerCase) {
|
|
$UseHostname = $UseHostname.ToLower();
|
|
}
|
|
|
|
return $UseHostname;
|
|
}
|
|
|
|
function Get-IcingaNetbiosName()
|
|
{
|
|
$ComputerData = Get-IcingaWindowsInformation Win32_ComputerSystem;
|
|
|
|
return $ComputerData.Name;
|
|
}
|
|
|
|
function Get-IcingaServiceUser()
|
|
{
|
|
$Services = Get-IcingaServices -Service 'icinga2';
|
|
if ($null -eq $Services) {
|
|
throw 'Icinga Service not installed';
|
|
}
|
|
|
|
$Services = $Services.GetEnumerator() | Select-Object -First 1;
|
|
$ServiceUser = ($Services.Value.configuration.ServiceUser).Replace('.\', '');
|
|
|
|
if ($ServiceUser -eq 'LocalSystem') {
|
|
$ServiceUser = 'NT Authority\SYSTEM';
|
|
}
|
|
|
|
return $ServiceUser;
|
|
}
|
|
|
|
function Install-IcingaAgent()
|
|
{
|
|
param(
|
|
[string]$Version,
|
|
[string]$Source = 'https://packages.icinga.com/windows/',
|
|
[string]$InstallDir = '',
|
|
[bool]$AllowUpdates = $FALSE
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Version)) {
|
|
Write-IcingaConsoleError 'No Icinga Agent version specified. Skipping installation.';
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($IcingaData.Installed -eq $TRUE -and $AllowUpdates -eq $FALSE) {
|
|
Write-IcingaConsoleWarning 'The Icinga Agent is already installed on this system. To perform updates or downgrades, please add the "-AllowUpdates" argument';
|
|
return $FALSE;
|
|
}
|
|
|
|
$IcingaData = Get-IcingaAgentInstallation;
|
|
$InstalledVersion = Get-IcingaAgentVersion;
|
|
$IcingaInstaller = Get-IcingaAgentMSIPackage -Source $Source -Version $Version -SkipDownload;
|
|
$InstallTarget = $IcingaData.RootDir;
|
|
|
|
if ($Version -eq 'snapshot') {
|
|
if ($IcingaData.InstallDate -ge $IcingaInstaller.LastUpdate -And [string]::IsNullOrEmpty($InstalledVersion.Snapshot) -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'There is no new snapshot package available which requires to be installed.'
|
|
return $FALSE;
|
|
}
|
|
$IcingaInstaller.Version = 'snapshot';
|
|
} elseif ($IcingaInstaller.Version -eq $InstalledVersion.Full) {
|
|
Write-IcingaConsoleNotice (
|
|
[string]::Format(
|
|
'No installation required. Your installed version [{0}] is matching the online version [{1}]',
|
|
$InstalledVersion.Full,
|
|
$IcingaInstaller.Version
|
|
)
|
|
);
|
|
return $FALSE;
|
|
}
|
|
|
|
$IcingaInstaller = Get-IcingaAgentMSIPackage -Source $Source -Version $IcingaInstaller.Version;
|
|
|
|
if ((Test-Path $IcingaInstaller.InstallerPath) -eq $FALSE) {
|
|
throw 'Failed to locate Icinga Agent installer file';
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($InstallDir) -eq $FALSE) {
|
|
if ((Test-Path $InstallDir) -eq $FALSE) {
|
|
New-Item -Path $InstallDir -ItemType Directory -Force | Out-Null;
|
|
}
|
|
$InstallTarget = $InstallDir;
|
|
}
|
|
|
|
[string]$InstallFolderMsg = $InstallTarget;
|
|
|
|
if ([string]::IsNullOrEmpty($InstallTarget) -eq $FALSE) {
|
|
$InstallTarget = [string]::Format(' INSTALL_ROOT="{0}"', $InstallTarget);
|
|
} else {
|
|
$InstallTarget = '';
|
|
if ($IcingaData.Architecture -eq 'x86') {
|
|
$InstallFolderMsg = Join-Path -Path ${env:ProgramFiles(x86)} -ChildPath 'ICINGA2';
|
|
} else {
|
|
$InstallFolderMsg = Join-Path -Path $env:ProgramFiles -ChildPath 'ICINGA2';
|
|
}
|
|
}
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Installing new Icinga Agent version into "{0}"', $InstallFolderMsg));
|
|
|
|
if ($IcingaData.Installed) {
|
|
if ((Uninstall-IcingaAgent) -eq $FALSE) {
|
|
return $FALSE;
|
|
}
|
|
}
|
|
|
|
$InstallProcess = powershell.exe -Command {
|
|
$IcingaInstaller = $args[0];
|
|
$InstallTarget = $args[1];
|
|
Use-Icinga;
|
|
|
|
$InstallProcess = Start-IcingaProcess -Executable 'MsiExec.exe' -Arguments ([string]::Format('/quiet /i "{0}" {1}', $IcingaInstaller.InstallerPath, $InstallTarget)) -FlushNewLines;
|
|
|
|
return $InstallProcess;
|
|
} -Args $IcingaInstaller, $InstallTarget;
|
|
|
|
if ($InstallProcess.ExitCode -ne 0) {
|
|
Write-IcingaConsoleError -Message 'Failed to install Icinga 2 Agent: {0}{1}' -Objects $InstallProcess.Message, $InstallProcess.Error;
|
|
return $FALSE;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Icinga Agent was successfully installed';
|
|
return $TRUE;
|
|
}
|
|
|
|
function Install-IcingaAgentBaseFeatures()
|
|
{
|
|
Disable-IcingaAgentFeature -Feature 'checker';
|
|
Disable-IcingaAgentFeature -Feature 'notification';
|
|
Enable-IcingaAgentFeature -Feature 'api';
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Installs the required certificates for the Icinga Agent including the entire
|
|
signing process either by using the CA-Proxy, the CA-Server directly or
|
|
by manually signing the request on the CA master
|
|
.DESCRIPTION
|
|
Installs the required certificates for the Icinga Agent including the entire
|
|
signing process either by using the CA-Proxy, the CA-Server directly or
|
|
by manually signing the request on the CA master
|
|
.FUNCTIONALITY
|
|
Creates, installs and signs required certificates for the Icinga Agent
|
|
.EXAMPLE
|
|
# Connect to the CA server with a ticket to fully complete the request
|
|
PS>Install-IcingaAgentCertificates -Hostname 'windows.example.com' -Endpoint 'icinga2.example.com' -Ticket 'my_secret_ticket';
|
|
.EXAMPLE
|
|
# Connect to the CA server without a ticket, to create the sign request on the master
|
|
PS>Install-IcingaAgentCertificates -Hostname 'windows.example.com' -Endpoint 'icinga2.example.com';
|
|
.EXAMPLE
|
|
# Uses the Icinga ca.crt from a local filesystem and prepares the Icinga Agent for receiving connections from the Master/Satellite for signing
|
|
PS>Install-IcingaAgentCertificates -Hostname 'windows.example.com' -CACert 'C:\users\public\icinga2\ca.crt';
|
|
.EXAMPLE
|
|
# Uses the Icinga ca.crt from a web resource and prepares the Icinga Agent for receiving connections from the Master/Satellite for signing
|
|
PS>Install-IcingaAgentCertificates -Hostname 'windows.example.com' -CACert 'https://example.com/icinga2/ca.crt';
|
|
.PARAMETER Hostname
|
|
The hostname of the local system. Has to match the object name within the Icinga configuration
|
|
.PARAMETER Endpoint
|
|
The address of either the Icinga CA master or a parent node of the Agent to transmit the request to the CA master
|
|
.PARAMETER Port
|
|
The port used for Icinga communication. Uses 5665 as default
|
|
.PARAMETER CACert
|
|
Allows to specify the path to the ca.crt from the Icinga CA master on a local, network or web share to allow certificate generation
|
|
in case the Icinga Agent is not able to connect to it's parent hosts
|
|
.PARAMETER Ticket
|
|
The ticket number for the signing request which is either generated by Icinga 2 or the Icinga Director
|
|
.PARAMETER Force
|
|
Ignores existing certificates and will force the creation, overriding existing certificates
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Install-IcingaAgentCertificates()
|
|
{
|
|
param(
|
|
[string]$Hostname,
|
|
[string]$Endpoint,
|
|
[int]$Port = 5665,
|
|
[string]$CACert,
|
|
[string]$Ticket,
|
|
[switch]$Force = $FALSE
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Hostname)) {
|
|
Write-IcingaConsoleError 'Failed to install Icinga Agent certificates. Please provide a hostname';
|
|
return $FALSE;
|
|
}
|
|
|
|
# Default for Icinga 2.8.0 and above
|
|
[string]$NewCertificateDirectory = (Join-Path -Path $Env:ProgramData -ChildPath 'icinga2\var\lib\icinga2\certs\');
|
|
[string]$OldCertificateDirectory = (Join-Path -Path $Env:ProgramData -ChildPath 'icinga2\etc\icinga2\pki\');
|
|
[string]$CertificateDirectory = $NewCertificateDirectory;
|
|
if ((Compare-IcingaVersions -RequiredVersion '2.8.0') -eq $FALSE) {
|
|
# Certificate path for versions older than 2.8.0
|
|
$CertificateDirectory = $OldCertificateDirectory;
|
|
Move-IcingaAgentCertificates -Source $NewCertificateDirectory -Destination $OldCertificateDirectory;
|
|
} else {
|
|
Move-IcingaAgentCertificates -Source $OldCertificateDirectory -Destination $NewCertificateDirectory;
|
|
}
|
|
|
|
if (-Not (Test-IcingaAgentCertificates -CertDirectory $CertificateDirectory -Hostname $Hostname -Force $Force)) {
|
|
Write-IcingaConsoleNotice ([string]::Format('Generating host certificates for host "{0}"', $Hostname));
|
|
|
|
$arguments = [string]::Format('pki new-cert --cn {0} --key {1}{0}.key --cert {1}{0}.crt',
|
|
$Hostname,
|
|
$CertificateDirectory
|
|
);
|
|
|
|
if ((Start-IcingaAgentCertificateProcess -Arguments $arguments) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'Failed to generate host certificate';
|
|
return $FALSE;
|
|
}
|
|
|
|
# Once we generated new host certificates, we always require to sign them if possible
|
|
$Force = $TRUE;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Endpoint) -And [string]::IsNullOrEmpty($CACert)) {
|
|
Write-IcingaConsoleWarning 'Your host certificates have been generated successfully. Please either specify an endpoint to connect to or provide the path to a valid ca.crt';
|
|
return $FALSE;
|
|
}
|
|
|
|
if (-Not [string]::IsNullOrEmpty($Endpoint)) {
|
|
if (-Not (Test-IcingaAgentCertificates -CertDirectory $CertificateDirectory -Hostname $Hostname -TestTrustedParent -Force $Force)) {
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Fetching trusted master certificate from "{0}"', $Endpoint));
|
|
|
|
# Argument --key for save-cert is deprecated starting with Icinga 2.12.0
|
|
if (Compare-IcingaVersions -RequiredVersion '2.12.0') {
|
|
$arguments = [string]::Format('pki save-cert --trustedcert {0}trusted-parent.crt --host {1} --port {2}',
|
|
$CertificateDirectory,
|
|
$Endpoint,
|
|
$Port
|
|
);
|
|
} else {
|
|
$arguments = [string]::Format('pki save-cert --key {0}{1}.key --trustedcert {0}trusted-parent.crt --host {2} --port {3}',
|
|
$CertificateDirectory,
|
|
$Hostname,
|
|
$Endpoint,
|
|
$Port
|
|
);
|
|
}
|
|
|
|
if ((Start-IcingaAgentCertificateProcess -Arguments $arguments) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'Unable to connect to your provided Icinga CA. Please verify the entered configuration is correct.' `
|
|
'If you are not able to connect to your Icinga CA from this machine, you will have to provide the path' `
|
|
'to your Icinga ca.crt and use the CA-Proxy certificate handling.';
|
|
return $FALSE;
|
|
}
|
|
}
|
|
|
|
if (-Not (Test-IcingaAgentCertificates -CertDirectory $CertificateDirectory -Hostname $Hostname -TestCACert -Force $Force)) {
|
|
[string]$PKIRequest = 'pki request --host {0} --port {1} --ticket {4} --key {2}{3}.key --cert {2}{3}.crt --trustedcert {2}trusted-parent.crt --ca {2}ca.crt';
|
|
|
|
if ([string]::IsNullOrEmpty($Ticket)) {
|
|
$PKIRequest = 'pki request --host {0} --port {1} --key {2}{3}.key --cert {2}{3}.crt --trustedcert {2}trusted-parent.crt --ca {2}ca.crt';
|
|
}
|
|
|
|
$arguments = [string]::Format($PKIRequest,
|
|
$Endpoint,
|
|
$Port,
|
|
$CertificateDirectory,
|
|
$Hostname,
|
|
$Ticket
|
|
);
|
|
|
|
if ((Start-IcingaAgentCertificateProcess -Arguments $arguments) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'Failed to sign Icinga certificate';
|
|
return $FALSE;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Ticket)) {
|
|
Write-IcingaConsoleNotice 'Your certificates were generated successfully. Please sign the certificate now on your Icinga CA master. You can lookup open requests with "icinga2 ca list"';
|
|
} else {
|
|
Write-IcingaConsoleNotice 'Icinga certificates successfully installed';
|
|
}
|
|
}
|
|
|
|
return $TRUE;
|
|
} elseif (-Not [string]::IsNullOrEmpty($CACert)) {
|
|
if (-Not (Copy-IcingaAgentCACertificate -CAPath $CACert -Desination $CertificateDirectory)) {
|
|
return $FALSE;
|
|
}
|
|
Write-IcingaConsoleNotice 'Host-Certificates and ca.crt are present. Please start your Icinga Agent now and manually sign your certificate request on your CA master. You can lookup open requests with "icinga2 ca list"';
|
|
}
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
function Start-IcingaAgentCertificateProcess()
|
|
{
|
|
param(
|
|
$Arguments
|
|
);
|
|
|
|
$Binary = Get-IcingaAgentBinary;
|
|
$Process = Start-IcingaProcess -Executable $Binary -Arguments $Arguments;
|
|
|
|
if ($Process.ExitCode -ne 0) {
|
|
Write-IcingaConsoleError ([string]::Format('Failed to create certificate.{0}Arguments: {1}{0}Error:{2} {3}', "`r`n", $Arguments, $Process.Message, $Process.Error));
|
|
return $FALSE;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice $Process.Message;
|
|
return $TRUE;
|
|
}
|
|
|
|
function Move-IcingaAgentCertificates()
|
|
{
|
|
param(
|
|
[string]$Source,
|
|
[string]$Destination
|
|
);
|
|
|
|
$SourceDir = Join-Path -Path $Source -ChildPath '\*';
|
|
$TargetDir = Join-Path -Path $Destination -ChildPath '\';
|
|
|
|
Move-Item -Path $SourceDir -Destination $TargetDir;
|
|
}
|
|
|
|
function Test-IcingaAgentCertificates()
|
|
{
|
|
param(
|
|
[string]$CertDirectory,
|
|
[string]$Hostname,
|
|
[switch]$TestCACert,
|
|
[switch]$TestTrustedParent,
|
|
[bool]$Force
|
|
);
|
|
|
|
if ($Force) {
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($TestCACert) {
|
|
if (Test-Path (Join-Path -Path $CertDirectory -ChildPath 'ca.crt')) {
|
|
Write-IcingaConsoleNotice 'Your ca.crt is present. No generation or fetching required';
|
|
return $TRUE;
|
|
} else {
|
|
Write-IcingaConsoleWarning 'Your ca.crt is not present. Manuall copy or fetching from your Icinga CA is required.';
|
|
return $FALSE;
|
|
}
|
|
}
|
|
|
|
if ($TestTrustedParent) {
|
|
if (Test-Path (Join-Path -Path $CertDirectory -ChildPath 'trusted-parent.crt')) {
|
|
Write-IcingaConsoleNotice 'Your trusted-parent.crt is present. No fetching or generation required';
|
|
return $TRUE;
|
|
} else {
|
|
Write-IcingaConsoleWarning 'Your trusted master certificate is not present. Fetching from your CA server is required';
|
|
return $FALSE;
|
|
}
|
|
}
|
|
|
|
if ((-Not (Test-Path ((Join-Path -Path $CertDirectory -ChildPath $Hostname) + '.key'))) `
|
|
-Or -Not (Test-Path ((Join-Path -Path $CertDirectory -ChildPath $Hostname) + '.crt'))) {
|
|
return $FALSE;
|
|
}
|
|
|
|
[string]$hostCRT = [string]::Format('{0}.crt', $Hostname);
|
|
[string]$hostKEY = [string]::Format('{0}.key', $Hostname);
|
|
[bool]$CertNameInvalid = $FALSE;
|
|
|
|
$certificates = Get-ChildItem -Path $CertDirectory;
|
|
# Now loop each file and match their name with our hostname
|
|
foreach ($cert in $certificates) {
|
|
if ($cert.Name.toLower() -eq $hostCRT.toLower() -Or $cert.Name.toLower() -eq $hostKEY.toLower()) {
|
|
$file = $cert.Name.Replace('.key', '').Replace('.crt', '');
|
|
if (-Not ($file -clike $Hostname)) {
|
|
Write-IcingaConsoleWarning ([string]::Format('Certificate file {0} is not matching the hostname {1}. Certificate generation is required.', $cert.Name, $Hostname));
|
|
$CertNameInvalid = $TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($CertNameInvalid) {
|
|
Remove-Item -Path (Join-Path -Path $CertDirectory -ChildPath $hostCRT) -Force;
|
|
Remove-Item -Path (Join-Path -Path $CertDirectory -ChildPath $hostKEY) -Force;
|
|
return $FALSE;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Icinga host certificates are present and valid. No generation required';
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
function Copy-IcingaAgentCACertificate()
|
|
{
|
|
param(
|
|
[string]$CAPath,
|
|
[string]$Desination
|
|
);
|
|
|
|
# Copy ca.crt from local path or network share to certificate path
|
|
if ((Test-Path $CAPath)) {
|
|
Copy-Item -Path $CAPath -Destination (Join-Path -Path $Desination -ChildPath 'ca.crt') | Out-Null;
|
|
Write-IcingaConsoleNotice ([string]::Format('Copied ca.crt from "{0}" to "{1}', $CAPath, $Desination));
|
|
} else {
|
|
Set-IcingaTLSVersion;
|
|
# It could also be a web ressource
|
|
try {
|
|
$response = Invoke-IcingaWebRequest $CAPath -UseBasicParsing;
|
|
[int]$Index = $response.RawContent.IndexOf("`r`n`r`n") + 4;
|
|
|
|
[string]$CAContent = $response.RawContent.SubString(
|
|
$Index,
|
|
$response.RawContent.Length - $Index
|
|
);
|
|
Set-Content -Path (Join-Path $Desination -ChildPath 'ca.crt') -Value $CAContent;
|
|
Write-IcingaConsoleNotice ([string]::Format('Downloaded ca.crt from "{0}" to "{1}', $CAPath, $Desination))
|
|
} catch {
|
|
Write-IcingaConsoleError 'Failed to load any provided ca.crt ressource';
|
|
return $FALSE;
|
|
}
|
|
}
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
Export-ModuleMember -Function @('Install-IcingaAgentCertificates');
|
|
|
|
function Uninstall-IcingaAgent()
|
|
{
|
|
param (
|
|
[switch]$RemoveDataFolder = $FALSE
|
|
);
|
|
|
|
$IcingaData = Get-IcingaAgentInstallation;
|
|
[string]$IcingaProgramData = Join-Path -Path $Env:ProgramData -ChildPath 'icinga2';
|
|
|
|
if ($IcingaData.Installed -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'Unable to uninstall the Icinga Agent. The Agent is not installed';
|
|
if ($RemoveDataFolder) {
|
|
if (Test-Path $IcingaProgramData) {
|
|
Write-IcingaConsoleNotice -Message 'Removing Icinga Agent directory: "{0}"' -Objects $IcingaProgramData;
|
|
return ((Remove-ItemSecure -Path $IcingaProgramData -Recurse -Force) -eq $FALSE);
|
|
} else {
|
|
Write-IcingaConsoleNotice -Message 'Icinga Agent directory "{0}" does not exist' -Objects $IcingaProgramData;
|
|
}
|
|
}
|
|
return $FALSE;
|
|
}
|
|
|
|
$Uninstaller = powershell.exe -Command {
|
|
$IcingaData = $args[0]
|
|
Use-Icinga;
|
|
|
|
Stop-Service 'icinga2' -ErrorAction SilentlyContinue | Out-Null;
|
|
|
|
$Uninstaller = Start-IcingaProcess -Executable 'MsiExec.exe' -Arguments ([string]::Format('{0} /q', $IcingaData.Uninstaller)) -FlushNewLine;
|
|
|
|
return $Uninstaller;
|
|
} -Args $IcingaData;
|
|
|
|
if ($Uninstaller.ExitCode -ne 0) {
|
|
Write-IcingaConsoleError ([string]::Format('Failed to remove Icinga Agent: {0}{1}', $Uninstaller.Message, $Uninstaller.Error));
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($RemoveDataFolder) {
|
|
Write-IcingaConsoleNotice -Message 'Removing Icinga Agent directory: "{0}"' -Objects $IcingaProgramData;
|
|
if ((Remove-ItemSecure -Path $IcingaProgramData -Recurse -Force) -eq $FALSE) {
|
|
return $FALSE;
|
|
}
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Icinga Agent was successfully removed';
|
|
return $TRUE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Clears the entire content of the Icinga Agent API directory located
|
|
at Program Data\icinga2\var\lib\icinga2\api\
|
|
.DESCRIPTION
|
|
Clears the entire content of the Icinga Agent API directory located
|
|
at Program Data\icinga2\var\lib\icinga2\api\
|
|
.FUNCTIONALITY
|
|
Clears the entire content of the Icinga Agent API directory located
|
|
at Program Data\icinga2\var\lib\icinga2\api\
|
|
.EXAMPLE
|
|
PS>Clear-IcingaAgentApiDirectory;
|
|
.EXAMPLE
|
|
PS>Clear-IcingaAgentApiDirectory -Force;
|
|
.PARAMETER Force
|
|
In case the Icinga Agent service is running while executing the command,
|
|
the force argument will ensure the service is stopped before the API
|
|
directory is flushed and restarted afterwards
|
|
.INPUTS
|
|
System.Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Clear-IcingaAgentApiDirectory()
|
|
{
|
|
param (
|
|
[switch]$Force = $FALSE
|
|
);
|
|
|
|
$IcingaService = (Get-IcingaServices -Service icinga2).icinga2;
|
|
$ApiDirectory = (Join-Path -Path $Env:ProgramData -ChildPath 'icinga2\var\lib\icinga2\api\');
|
|
|
|
if ((Test-Path $ApiDirectory) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'The Icinga Agent API directory is not present on this system. Please check if the Icinga Agent is installed';
|
|
return;
|
|
}
|
|
|
|
if ($IcingaService.configuration.Status.raw -eq 4 -And $Force -eq $FALSE) {
|
|
Write-IcingaConsoleError 'The API directory can not be deleted while the Icinga Agent is running. Use the "-Force" argument to stop the service, flush the directory and restart the service again.';
|
|
return;
|
|
}
|
|
|
|
if ($IcingaService.configuration.Status.raw -eq 4) {
|
|
Stop-IcingaService icinga2;
|
|
Start-Sleep -Seconds 1;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Flushing Icinga Agent API directory';
|
|
Remove-ItemSecure -Path (Join-Path -Path $ApiDirectory -ChildPath '*') -Recurse -Force | Out-Null;
|
|
Start-Sleep -Seconds 1;
|
|
|
|
if ($IcingaService.configuration.Status.raw -eq 4) {
|
|
Start-IcingaService icinga2;
|
|
}
|
|
}
|
|
|
|
function Compare-IcingaVersions()
|
|
{
|
|
param(
|
|
$CurrentVersion,
|
|
$RequiredVersion
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($RequiredVersion)) {
|
|
return $FALSE;
|
|
}
|
|
|
|
$RequiredVersion = Split-IcingaVersion -Version $RequiredVersion;
|
|
|
|
if ([string]::IsNullOrEmpty($CurrentVersion) -eq $FALSE) {
|
|
$CurrentVersion = Split-IcingaVersion -Version $CurrentVersion;
|
|
} else {
|
|
$CurrentVersion = Get-IcingaAgentVersion;
|
|
}
|
|
|
|
if ($requiredVersion.Mayor -gt $currentVersion.Mayor) {
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($requiredVersion.Minor -gt $currentVersion.Minor) {
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($requiredVersion.Minor -ge $currentVersion.Minor -And $requiredVersion.Fixes -gt $currentVersion.Fixes) {
|
|
return $FALSE;
|
|
}
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
function Convert-IcingaDirectorSelfServiceArguments()
|
|
{
|
|
param(
|
|
$JsonInput
|
|
);
|
|
|
|
if ($null -eq $JsonInput) {
|
|
return @{};
|
|
}
|
|
|
|
[hashtable]$DirectorArguments = @{
|
|
PackageSource = $JsonInput.download_url;
|
|
AgentVersion = $JsonInput.agent_version;
|
|
CAPort = $JsonInput.agent_listen_port;
|
|
AllowVersionChanges = $JsonInput.allow_updates;
|
|
GlobalZones = $JsonInput.global_zones;
|
|
ParentZone = $JsonInput.parent_zone;
|
|
#CAEndpoint = $JsonInput.ca_server;
|
|
Endpoints = $JsonInput.parent_endpoints;
|
|
AddFirewallRule = $JsonInput.agent_add_firewall_rule;
|
|
AcceptConnections = $JsonInput.agent_add_firewall_rule;
|
|
ServiceUser = $JsonInput.icinga_service_user;
|
|
IcingaMaster = $JsonInput.IcingaMaster;
|
|
InstallFrameworkService = $JsonInput.install_framework_service;
|
|
ServiceDirectory = $JsonInput.framework_service_directory;
|
|
FrameworkServiceUrl = $JsonInput.framework_service_url;
|
|
InstallFrameworkPlugins = $JsonInput.install_framework_plugins;
|
|
PluginsUrl = $JsonInput.framework_plugins_url;
|
|
ConvertEndpointIPConfig = $JsonInput.resolve_parent_host;
|
|
UpdateAgent = $TRUE;
|
|
AddDirectorGlobal = $FALSE;
|
|
AddGlobalTemplates = $FALSE;
|
|
RunInstaller = $TRUE;
|
|
};
|
|
|
|
# Use NetworkService as default if nothing was transmitted by Director
|
|
if ([string]::IsNullOrEmpty($DirectorArguments['ServiceUser'])) {
|
|
$DirectorArguments['ServiceUser'] = 'NT Authority\NetworkService';
|
|
}
|
|
|
|
if ($JsonInput.transform_hostname -eq 1) {
|
|
$DirectorArguments.Add(
|
|
'LowerCase', $TRUE
|
|
);
|
|
}
|
|
|
|
if ($JsonInput.transform_hostname -eq 2) {
|
|
$DirectorArguments.Add(
|
|
'UpperCase', $TRUE
|
|
);
|
|
}
|
|
|
|
if ($JsonInput.fetch_agent_fqdn) {
|
|
$DirectorArguments.Add(
|
|
'AutoUseFQDN', $TRUE
|
|
);
|
|
} elseif ($JsonInput.fetch_agent_name) {
|
|
$DirectorArguments.Add(
|
|
'AutoUseHostname', $TRUE
|
|
);
|
|
}
|
|
|
|
$NetworkDefault = '';
|
|
foreach ($Endpoint in $JsonInput.parent_endpoints) {
|
|
$NetworkDefault += [string]::Format('[{0}]:{1},', $Endpoint, $JsonInput.agent_listen_port);
|
|
}
|
|
if ([string]::IsNullOrEmpty($NetworkDefault) -eq $FALSE) {
|
|
$NetworkDefault = $NetworkDefault.Substring(0, $NetworkDefault.Length - 1).Split(',');
|
|
$DirectorArguments.Add(
|
|
'EndpointConnections', $NetworkDefault
|
|
);
|
|
|
|
$EndpointConnections = $NetworkDefault;
|
|
$DirectorArguments.Add(
|
|
'CAEndpoint', (Get-IPConfigFromString $EndpointConnections[0]).address
|
|
);
|
|
}
|
|
|
|
return $DirectorArguments;
|
|
}
|
|
|
|
function Disable-IcingaAgentFeature()
|
|
{
|
|
param(
|
|
[string]$Feature
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Feature)) {
|
|
throw 'Please specify a valid feature';
|
|
}
|
|
|
|
if ((Test-IcingaAgentFeatureEnabled -Feature $Feature) -eq $FALSE) {
|
|
Write-IcingaConsoleNotice ([string]::Format('This feature is already disabled [{0}]', $Feature));
|
|
return;
|
|
}
|
|
|
|
$Binary = Get-IcingaAGentBinary;
|
|
$Process = Start-IcingaProcess -Executable $Binary -Arguments ([string]::Format('feature disable {0}', $Feature));
|
|
|
|
if ($Process.ExitCode -ne 0) {
|
|
throw ([string]::Format('Failed to disable Icinga Feature: {0}', $Process.Message));
|
|
}
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Feature "{0}" was successfully disabled', $Feature));
|
|
}
|
|
|
|
function Enable-IcingaAgentFeature()
|
|
{
|
|
param(
|
|
[string]$Feature
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Feature)) {
|
|
throw 'Please specify a valid feature';
|
|
}
|
|
|
|
if ((Test-IcingaAgentFeatureEnabled -Feature $Feature)) {
|
|
Write-IcingaConsoleNotice ([string]::Format('This feature is already enabled [{0}]', $Feature));
|
|
return;
|
|
}
|
|
|
|
$Binary = Get-IcingaAgentBinary;
|
|
$Process = Start-IcingaProcess -Executable $Binary -Arguments ([string]::Format('feature enable {0}', $Feature));
|
|
|
|
if ($Process.ExitCode -ne 0) {
|
|
throw ([string]::Format('Failed to enable Icinga Feature: {0}', $Process.Message));
|
|
}
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Feature "{0}" was successfully enabled', $Feature));
|
|
}
|
|
|
|
function Move-IcingaAgentDefaultConfig()
|
|
{
|
|
$ConfigDir = Get-IcingaAgentConfigDirectory;
|
|
$BackupFile = Join-Path -Path $ConfigDir -ChildPath 'ps_backup\backup_executed.key';
|
|
|
|
if ((Test-Path $BackupFile)) {
|
|
Write-IcingaConsoleNotice 'A backup of your default configuration is not required. A backup was already made';
|
|
return;
|
|
}
|
|
|
|
New-Item (Join-Path -Path $ConfigDir -ChildPath 'ps_backup') -ItemType Directory | Out-Null;
|
|
|
|
Move-Item -Path (Join-Path -Path $ConfigDir -ChildPath 'conf.d') -Destination (Join-Path -Path $ConfigDir -ChildPath 'ps_backup\conf.d');
|
|
Move-Item -Path (Join-Path -Path $ConfigDir -ChildPath 'zones.conf') -Destination (Join-Path -Path $ConfigDir -ChildPath 'ps_backup\zones.conf');
|
|
Copy-Item -Path (Join-Path -Path $ConfigDir -ChildPath 'constants.conf') -Destination (Join-Path -Path $ConfigDir -ChildPath 'ps_backup\constants.conf');
|
|
Copy-Item -Path (Join-Path -Path $ConfigDir -ChildPath 'features-available') -Destination (Join-Path -Path $ConfigDir -ChildPath 'ps_backup\features-available');
|
|
|
|
New-Item (Join-Path -Path $ConfigDir -ChildPath 'conf.d') -ItemType Directory | Out-Null;
|
|
New-Item (Join-Path -Path $ConfigDir -ChildPath 'zones.conf') -ItemType File | Out-Null;
|
|
New-Item -Path $BackupFile -ItemType File | Out-Null;
|
|
|
|
Write-IcingaConsoleNotice 'Successfully backed up Icinga 2 Agent default config';
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Checks for old configurations provided by the old PowerShell module
|
|
and restores the original configuration file
|
|
.DESCRIPTION
|
|
Restores the original Icinga 2 configuration by replacing the existing
|
|
configuration created by the old PowerShell module with the plain one
|
|
from the Icinga 2 backup file
|
|
.FUNCTIONALITY
|
|
Restores original Icinga 2 configuration icinga2.conf
|
|
.EXAMPLE
|
|
PS>Reset-IcingaAgentConfigFile;
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Reset-IcingaAgentConfigFile()
|
|
{
|
|
$ConfigDir = Get-IcingaAgentConfigDirectory;
|
|
$OldConfig = Join-Path -Path $ConfigDir -ChildPath 'icinga2.conf';
|
|
$OldConfigBackup = Join-Path -Path $ConfigDir -ChildPath 'icinga2.conf.old.module';
|
|
$OriginalConfig = Join-Path -Path $ConfigDir -ChildPath 'icinga2.confdirector.bak';
|
|
|
|
if ((Test-Path $OriginalConfig)) {
|
|
Write-IcingaConsoleWarning 'Found icinga2.conf backup file created by old PowerShell module. Restoring original configuration';
|
|
|
|
Move-Item -Path $OldConfig -Destination $OldConfigBackup;
|
|
Move-Item -Path $OriginalConfig -Destination $OldConfig;
|
|
}
|
|
}
|
|
|
|
function Show-IcingaAgentObjects()
|
|
{
|
|
$Binary = Get-IcingaAgentBinary;
|
|
$Output = Start-IcingaProcess -Executable $Binary -Arguments 'object list';
|
|
|
|
if ($Output.ExitCode -ne 0) {
|
|
Write-IcingaConsoleError ([string]::Format('Failed to fetch Icinga Agent objects list: {0}{1}', $Output.Message, $Output.Error));
|
|
return $null;
|
|
}
|
|
|
|
return $Output.Message;
|
|
}
|
|
|
|
function Split-IcingaVersion()
|
|
{
|
|
param(
|
|
[string]$Version
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Version)) {
|
|
return @{
|
|
'Full' = '';
|
|
'Mayor' = $null;
|
|
'Minor' = $null;
|
|
'Fixes' = $null;
|
|
'Snapshot' = $null;
|
|
}
|
|
}
|
|
|
|
[array]$IcingaVersion = $Version.Split('.');
|
|
$Snapshot = $null;
|
|
|
|
if ([string]::IsNullOrEmpty($IcingaVersion[3]) -eq $FALSE) {
|
|
$Snapshot = [int]$IcingaVersion[3];
|
|
}
|
|
|
|
return @{
|
|
'Full' = $Version;
|
|
'Mayor' = [int]$IcingaVersion[0];
|
|
'Minor' = [int]$IcingaVersion[1];
|
|
'Fixes' = [int]$IcingaVersion[2];
|
|
'Snapshot' = $Snapshot;
|
|
}
|
|
}
|
|
|
|
function Start-IcingaAgentDirectorWizard()
|
|
{
|
|
param(
|
|
[string]$DirectorUrl,
|
|
[string]$SelfServiceAPIKey = $null,
|
|
$OverrideDirectorVars = $null,
|
|
[bool]$RunInstaller = $FALSE,
|
|
[switch]$ForceTemplateKey = $FALSE
|
|
);
|
|
|
|
[hashtable]$DirectorOverrideArgs = @{ }
|
|
if ([string]::IsNullOrEmpty($DirectorUrl)) {
|
|
$DirectorUrl = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the Url pointing to your Icinga Director (Example: "https://example.com/icingaweb2/director")' -Default 'v').answer;
|
|
}
|
|
|
|
[bool]$HostKnown = $FALSE;
|
|
[string]$TemplateKey = $SelfServiceAPIKey;
|
|
|
|
if ($null -eq $OverrideDirectorVars -And $RunInstaller -eq $FALSE) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to manually override arguments provided by the Director API?' -Default 'n').result -eq 0) {
|
|
$OverrideDirectorVars = $TRUE;
|
|
} else {
|
|
$OverrideDirectorVars = $FALSE;
|
|
}
|
|
}
|
|
|
|
$LocalAPIKey = Get-IcingaPowerShellConfig -Path 'IcingaDirector.SelfService.ApiKey';
|
|
|
|
if ($ForceTemplateKey) {
|
|
if ($SelfServiceAPIKey -eq $LocalAPIKey) {
|
|
$ForceTemplateKey = $FALSE;
|
|
}
|
|
}
|
|
|
|
if ($ForceTemplateKey -eq $FALSE) {
|
|
if ([string]::IsNullOrEmpty($LocalAPIKey)) {
|
|
$LegacyTokenPath = Join-Path -Path Get-IcingaAgentConfigDirectory -ChildPath 'icingadirector.token';
|
|
if (Test-Path $LegacyTokenPath) {
|
|
$SelfServiceAPIKey = Get-Content -Path $LegacyTokenPath;
|
|
Set-IcingaPowerShellConfig -Path 'IcingaDirector.SelfService.ApiKey' -Value $SelfServiceAPIKey;
|
|
} else {
|
|
$ForceTemplateKey = $TRUE;
|
|
}
|
|
} else {
|
|
$SelfServiceAPIKey = $LocalAPIKey;
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($SelfServiceAPIKey)) {
|
|
$SelfServiceAPIKey = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter your Self-Service API key' -Default 'v').answer;
|
|
} else {
|
|
if ($ForceTemplateKey -eq $FALSE) {
|
|
$HostKnown = $TRUE;
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($LocalAPIKey) -eq $FALSE -And $LocalAPIKey -ne $TemplateKey -And $ForceTemplateKey -eq $FALSE) {
|
|
try {
|
|
$Arguments = Get-IcingaDirectorSelfServiceConfig -DirectorUrl $DirectorUrl -ApiKey $LocalAPIKey;
|
|
} catch {
|
|
Write-IcingaConsoleError 'Your local stored host key is no longer valid. Using provided template key';
|
|
|
|
return Start-IcingaAgentDirectorWizard `
|
|
-DirectorUrl $DirectorUrl `
|
|
-SelfServiceAPIKey $TemplateKey `
|
|
-OverrideDirectorVars $OverrideDirectorVars `
|
|
-ForceTemplateKey;
|
|
}
|
|
} else {
|
|
try {
|
|
$Arguments = Get-IcingaDirectorSelfServiceConfig -DirectorUrl $DirectorUrl -ApiKey $SelfServiceAPIKey;
|
|
} catch {
|
|
Write-IcingaConsoleError ([string]::Format('Failed to connect to your Icinga Director at "{0}". Please try again', $DirectorUrl));
|
|
|
|
return Start-IcingaAgentDirectorWizard `
|
|
-SelfServiceAPIKey ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Please re-enter your SelfService API Key for the Host-Template in case the key is no longer assigned to your host' -Default 'v' -DefaultInput $SelfServiceAPIKey).answer) `
|
|
-OverrideDirectorVars $OverrideDirectorVars;
|
|
}
|
|
}
|
|
|
|
$Arguments = Convert-IcingaDirectorSelfServiceArguments -JsonInput $Arguments;
|
|
|
|
if ($OverrideDirectorVars -eq $TRUE -And -Not $RunInstaller) {
|
|
$DirectorOverrideArgs = Start-IcingaDirectorAPIArgumentOverride -Arguments $Arguments;
|
|
foreach ($entry in $DirectorOverrideArgs.Keys) {
|
|
if ($Arguments.ContainsKey($entry)) {
|
|
$Arguments[$entry] = $DirectorOverrideArgs[$entry];
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($HostKnown -eq $FALSE) {
|
|
while ($TRUE) {
|
|
try {
|
|
$SelfServiceAPIKey = Register-IcingaDirectorSelfServiceHost -DirectorUrl $DirectorUrl -ApiKey $SelfServiceAPIKey -Hostname (Get-IcingaHostname @Arguments) -Endpoint $Arguments.IcingaMaster;
|
|
break;
|
|
} catch {
|
|
$SelfServiceAPIKey = (Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Failed to register host within Icinga Director. Full error: "{0}". Please re-enter your SelfService API Key. If this prompt continues ensure you are using an Agent template or drop your host key at "Hosts -> {1} -> Agent"', $_.Exception.Message, (Get-IcingaHostname @Arguments))) -Default 'v' -DefaultInput $SelfServiceAPIKey).answer;
|
|
}
|
|
}
|
|
|
|
# Host is already registered
|
|
if ($null -eq $SelfServiceAPIKey) {
|
|
Write-IcingaConsoleError 'The wizard is unable to complete as this host is already registered but the local API key is not stored within the config'
|
|
return;
|
|
}
|
|
|
|
$Arguments = Get-IcingaDirectorSelfServiceConfig -DirectorUrl $DirectorUrl -ApiKey $SelfServiceAPIKey;
|
|
$Arguments = Convert-IcingaDirectorSelfServiceArguments -JsonInput $Arguments;
|
|
if ($OverrideDirectorVars -eq $TRUE -And -Not $RunInstaller) {
|
|
$DirectorOverrideArgs = Start-IcingaDirectorAPIArgumentOverride -Arguments $Arguments;
|
|
foreach ($entry in $DirectorOverrideArgs.Keys) {
|
|
if ($Arguments.ContainsKey($entry)) {
|
|
$Arguments[$entry] = $DirectorOverrideArgs[$entry];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$IcingaTicket = Get-IcingaDirectorSelfServiceTicket -DirectorUrl $DirectorUrl -ApiKey $SelfServiceAPIKey;
|
|
|
|
$DirectorOverrideArgs.Add(
|
|
'DirectorUrl', $DirectorUrl
|
|
);
|
|
$DirectorOverrideArgs.Add(
|
|
'Ticket', $IcingaTicket
|
|
);
|
|
$DirectorOverrideArgs.Add(
|
|
'OverrideDirectorVars', 0
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($TemplateKey) -eq $FALSE) {
|
|
$DirectorOverrideArgs.Add(
|
|
'SelfServiceAPIKey', $TemplateKey
|
|
);
|
|
}
|
|
|
|
return @{
|
|
'Arguments' = $Arguments;
|
|
'Overrides' = $DirectorOverrideArgs;
|
|
};
|
|
}
|
|
|
|
function Start-IcingaDirectorAPIArgumentOverride()
|
|
{
|
|
param(
|
|
$Arguments
|
|
);
|
|
|
|
$NewArguments = @{};
|
|
Write-IcingaConsoleNotice 'Please follow the wizard and manually override all entries you intend to';
|
|
Write-IcingaConsoleNotice '====';
|
|
|
|
foreach ($entry in $Arguments.Keys) {
|
|
$value = (Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Please enter the new value for the argument "{0}"', $entry)) -Default 'v' -DefaultInput $Arguments[$entry]).answer;
|
|
if ($Arguments[$entry] -is [array] -Or ($value -is [string] -And $value.Contains(','))) {
|
|
if ([string]::IsNullOrEmpty($value) -eq $FALSE) {
|
|
while ($value.Contains(', ')) {
|
|
$value = $value.Replace(', ', ',');
|
|
}
|
|
[array]$tmpArray = $value.Split(',');
|
|
if ($null -ne (Compare-Object -ReferenceObject $Arguments[$entry] -DifferenceObject $tmpArray)) {
|
|
$NewArguments.Add(
|
|
$entry,
|
|
$tmpArray
|
|
);
|
|
}
|
|
}
|
|
continue;
|
|
} elseif ($Arguments[$entry] -is [bool]) {
|
|
if ($value -eq 'true' -or $value -eq 'y' -or $value -eq '1' -or $value -eq 'yes' -or $value -eq 1) {
|
|
$value = 1;
|
|
} else {
|
|
$value = 0;
|
|
}
|
|
}
|
|
|
|
if ($Arguments[$entry] -ne $value) {
|
|
$NewArguments.Add($entry, $value);
|
|
}
|
|
}
|
|
|
|
return $NewArguments;
|
|
}
|
|
|
|
Export-ModuleMember -Function @( 'Start-IcingaAgentDirectorWizard' );
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
A installation wizard that will guide you through the entire installation and
|
|
configuration of Icinga for Windows including the Icinga Agent
|
|
.DESCRIPTION
|
|
A installation wizard that will guide you through the entire installation and
|
|
configuration of Icinga for Windows including the Icinga Agent
|
|
.FUNCTIONALITY
|
|
Makes initial installation and first configuration of Icinga for Windows and
|
|
the Icinga Agent very easy
|
|
.PARAMETER Hostname
|
|
Set a specific hostname to the system and do not lookup anything automatically
|
|
.PARAMETER AutoUseFQDN
|
|
Tells the wizard if you want to use the FQDN for the Icinga Agent or not.
|
|
Set it to 1 to use FQDN and 0 to do not use it. Leave it empty to be prompted the wizard question.
|
|
Ignores `AutoUseHostname`
|
|
.PARAMETER AutoUseHostname
|
|
Tells the wizard if you want to use the hostname for the Icinga Agent or not.
|
|
Set it to 1 to use hostname only 0 to not use it. Leave it empty to be prompted the wizard question.
|
|
Overwritten by `AutoUseFQDN`
|
|
.PARAMETER LowerCase
|
|
Tells the wizard if the provided hostname should be converted to lower case characters.
|
|
Set it to 1 to lower case the name and 0 to do nothing. Leave it empty to be prompted the wizard question
|
|
.PARAMETER UpperCase
|
|
Tells the wizard if the provided hostname should be converted to upper case characters.
|
|
Set it to 1 to upper case the name and 0 to do nothing. Leave it empty to be prompted the wizard question
|
|
.PARAMETER AddDirectorGlobal
|
|
Tells the wizard to add the `director-global` zone to your Icinga Agent configuration.
|
|
Set it to 1 to add it and 0 to not add it. Leave it empty to be prompted the wizard question
|
|
.PARAMETER AddGlobalTemplates
|
|
Tells the wizard to add the `global-templates` zone to your Icinga Agent configuration.
|
|
Set it to 1 to add it and 0 to not add it. Leave it empty to be prompted the wizard question
|
|
.PARAMETER PackageSource
|
|
Tells the wizard from which source we can download the Icinga Agent from. Use https://packages.icinga.com/windows/ if you can reach the internet
|
|
Set the source to either web, local or network share. Leave it empty to be prompted the wizard question
|
|
.PARAMETER AgentVersion
|
|
Tells the wizard which Icinga Agent version to install. You can provide latest, snapshot or a specific version like 2.11.6
|
|
Set the value to one mentioned above. Leave it empty to be prompted the wizard question
|
|
.PARAMETER InstallDir
|
|
Tells the wizard which directory the Icinga Agent will beinstalled into. Default is `C:\Program Files\ICINGA2`
|
|
Set the value to one mentioned above.
|
|
.PARAMETER AllowVersionChanges
|
|
Tells the wizard if the Icinga Agent should be updated/downgraded in case the current/target version are not matching
|
|
Should be equal to `UpdateAgent`
|
|
Set it to 1 to allow updates/downgrades 0 to not allow it. Leave it empty to be prompted the wizard question
|
|
.PARAMETER UpdateAgent
|
|
Tells the wizard if the Icinga Agent should be updated/downgraded in case the current/target version are not matching
|
|
Should be equal to `AllowVersionChanges`
|
|
Set it to 1 to allow updates/downgrades 0 to not allow it. Leave it empty to be prompted the wizard question
|
|
.PARAMETER AddFirewallRule
|
|
Tells the wizard if the used Icinga Agent port should be opened for incoming traffic on the Windows Firewall
|
|
Set it to 1 to set the firewall rule 0 to do nothing. Leave it empty to be prompted the wizard question
|
|
.PARAMETER AcceptConnections
|
|
Tells the wizard if the Icinga Agent is accepting incoming connections.
|
|
Might require `AddFirewallRule` being enabled in case this value is set to 1
|
|
Set it to 1 to accept connections 0 to not accept them. Leave it empty to be prompted the wizard question
|
|
.PARAMETER Endpoints
|
|
Tells the wizard which endpoints this Icinga Agent has as parent. Example: master-icinga1, master-icinga2
|
|
Set all parent endpoint names in a comma separated list. Leave it empty to be prompted the wizard question
|
|
.PARAMETER EndpointConnections
|
|
Tells the wizard the connection configuration for provided endpoints. The order of this argument has to match
|
|
the endpoint configuration on the `Endpoints` argument. Example: [master-icinga1.example.com]:5665, 192.168.0.5
|
|
Set all parent endpoint connections as comma separated list. Leave it empty to be prompted the wizard question
|
|
.PARAMETER ConvertEndpointIPConfig
|
|
Tells the wizard if FQDN for parent connections should be looked up and resolved to IP addresses. Example: example.com => 93.184.216.34
|
|
Set it to 1 to lookup the up and 0 to do nothing. Leave it empty to be prompted the wizard question
|
|
.PARAMETER ParentZone
|
|
Tells the wizard which parent zone name to use for Icinga Agent configuration.
|
|
Set it to the name of the parent zone. Leave it empty to be prompted the wizard question
|
|
.PARAMETER GlobalZones
|
|
Tells the wizard to add additional global zones to your configuration. You can provide a comma separated list for this
|
|
Add additional global zones as comma separated list, use @() to not add anything. Leave it empty to be prompted the wizard question
|
|
.PARAMETER CAEndpoint
|
|
Tells the wizard which address/fqdn to use for Icinga Agent certificate signing.
|
|
Set the IP/FQDN of your CA Server/Icinga parent node or leave it empty if no connection is possible
|
|
.PARAMETER CAPort
|
|
Tells the wizard which port to use for Icinga Agent certificate signing.
|
|
Set the port of your CA Server/Icinga parent node or leave it empty if no connection is possible
|
|
.PARAMETER Ticket
|
|
Tells the wizard which ticket to use for Icinga Agent certificate signing.
|
|
Set the ticket of your certificate request for this host or leave it empty if no ticket is available.
|
|
If you leave this argument empty, you will have to set `-EmptyTicket` to 1 and otherwise to 0
|
|
.PARAMETER EmptyTicket
|
|
Tells the wizard to use a provided `-Ticket` or skip it. If `-Ticket` is empty you do not want to use it,
|
|
set this argument to 1. If you set `-Ticket` with a ticket to use, set this argument to 0
|
|
Leave it empty to be prompted the wizard question
|
|
.PARAMETER CAFile
|
|
Tells the wizard if the Icinga CA Server ca.crt shall be used for signing certificate request.
|
|
You can specify a web, local or network share as source to lookup the `ca.crt`.
|
|
If this argument is set to be empty, ensure to also set `-EmptyCA` to 1
|
|
.PARAMETER EmptyCA
|
|
Tells the wizard if the argument `-CAFile` is set or not. Set this argument to 1 if `-CAFile` is
|
|
set and to 0 if `-CAFile` is not used
|
|
.PARAMETER RunInstaller
|
|
Tells the wizard to skip the question if the configuration is correct and skips the question if you
|
|
want to execute the wizard.
|
|
.PARAMETER Reconfigure
|
|
Tells the wizard to execute all arguments again and configure certificates any thing else even if no
|
|
change to the Icinga Agent was made. This is mostly required if you run the wizard again with the same
|
|
Icinga Agent version being installed and available
|
|
.PARAMETER ServiceUser
|
|
Tells the wizard which service user should be used for the Icinga Agent and PowerShell Service.
|
|
Add 'NT Authority\NetworkService' to use the default one or specify a custom user
|
|
Leave it empty to be prompted the wizard question.
|
|
.PARAMETER ServicePass
|
|
Tells the wizard to use a special password for service users in case you are running a custom user
|
|
instead of local service accounts.
|
|
.PARAMETER InstallFrameworkService
|
|
Tells the wizard if you want to install the Icinga PowerShell service
|
|
Set it to 1 to install it and 0 to not install it. Leave it empty to be prompted the wizard question
|
|
.PARAMETER FrameworkServiceUrl
|
|
Tells the wizard where to download the Icinga PowerShell Service binary from. Example: https://github.com/Icinga/icinga-powershell-service/releases/download/v1.1.0/icinga-service-v1.1.0.zip
|
|
This argument is only required if `-InstallFrameworkService` is set to 1
|
|
.PARAMETER ServiceDirectory
|
|
Tells the wizard where to install the Icinga PowerShell Service binary into. Use `C:\Program Files\icinga-framework-service` as default
|
|
This argument is only required if `-InstallFrameworkService` is set to 1
|
|
.PARAMETER ServiceBin
|
|
Tells the wizard the exact path of the service binary. Must match the path of `-ServiceDirectory` and add the binary at the end. Use `C:\Program Files\icinga-framework-service\icinga-service.exe` as default
|
|
This argument is only required if `-InstallFrameworkService` is set to 1
|
|
.PARAMETER UseDirectorSelfService
|
|
Tells the wizard to use the Icinga Director Self-Service API.
|
|
Set it to 1 to use the SelfService and 0 to not use it. Leave it empty to prompt the wizard question
|
|
.PARAMETER SkipDirectorQuestion
|
|
Tells the wizard to skip all related Icinga Director questions.
|
|
Set it to 1 to skip possible questions and 0 if you continue with Icinga Director. Leave it empty to prompt the wizard question
|
|
.PARAMETER DirectorUrl
|
|
Tells the wizard which URL to use for the Icinga Director. Only required if `-UseDirectorSelfService` is set to 1
|
|
Specify the URL targeting your Icinga Director. Leave it empty to prompt the wizard question
|
|
.PARAMETER SelfServiceAPIKey
|
|
Tells the wizard which SelfService API key to use for registering this host. In case wizard already run once,
|
|
this argument is always overwritten by the local stored argument. Only required if `-UseDirectorSelfService` is set to 1
|
|
Specify the SelfService API key being used for configuration. Leave it empty to prompt the wizard question in case the registration was not yet done for this host
|
|
.PARAMETER OverrideDirectorVars
|
|
Tells the wizard of variables shipped by the Icinga Director SelfService should be overwritten. Only required if `-UseDirectorSelfService` is set to 1
|
|
Set it to 1 to override arguments and 0 to do nothing. Leave it empty to prompt the wizard question
|
|
.PARAMETER InstallFrameworkPlugins
|
|
Tells the wizard if you want to install the Icinga PowerShell Plugins
|
|
Set it to 1 to install them and 0 to not install them. Leave it empty to be prompted the wizard question
|
|
.PARAMETER PluginsUrl
|
|
Tells the wizard where to download the Icinga PowerShell Plugins from. Example: https://github.com/Icinga/icinga-powershell-plugins/archive/v1.2.0.zip
|
|
This argument is only required if `-InstallFrameworkPlugins` is set to 1
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Start-IcingaAgentInstallWizard()
|
|
{
|
|
param(
|
|
[string]$Hostname,
|
|
$AutoUseFQDN,
|
|
$AutoUseHostname,
|
|
$LowerCase,
|
|
$UpperCase,
|
|
$AddDirectorGlobal = $null,
|
|
$AddGlobalTemplates = $null,
|
|
[string]$PackageSource,
|
|
[string]$AgentVersion,
|
|
[string]$InstallDir,
|
|
$AllowVersionChanges,
|
|
$UpdateAgent = $null,
|
|
$AddFirewallRule = $null,
|
|
$AcceptConnections = $null,
|
|
[array]$Endpoints = @(),
|
|
[array]$EndpointConnections = @(),
|
|
$ConvertEndpointIPConfig = $null,
|
|
[string]$ParentZone,
|
|
[array]$GlobalZones = $null,
|
|
[string]$CAEndpoint,
|
|
$CAPort = $null,
|
|
[string]$Ticket,
|
|
$EmptyTicket,
|
|
[string]$CAFile = $null,
|
|
$EmptyCA = $null,
|
|
[switch]$RunInstaller,
|
|
[switch]$Reconfigure,
|
|
[string]$ServiceUser,
|
|
[securestring]$ServicePass = $null,
|
|
$InstallFrameworkService = $null,
|
|
$FrameworkServiceUrl = $null,
|
|
$ServiceDirectory = $null,
|
|
$ServiceBin = $null,
|
|
$UseDirectorSelfService = $null,
|
|
[bool]$SkipDirectorQuestion = $FALSE,
|
|
[string]$DirectorUrl,
|
|
[string]$SelfServiceAPIKey = $null,
|
|
$OverrideDirectorVars = $null,
|
|
$InstallFrameworkPlugins = $null,
|
|
$PluginsUrl = $null
|
|
);
|
|
|
|
[array]$InstallerArguments = @();
|
|
[array]$GlobalZoneConfig = @();
|
|
|
|
if ($SkipDirectorQuestion -eq $FALSE) {
|
|
if ($null -eq $UseDirectorSelfService) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to use the Icinga Director Self-Service API?' -Default 'y').result -eq 1) {
|
|
$UseDirectorSelfService = $TRUE;
|
|
} else {
|
|
$UseDirectorSelfService = $FALSE;
|
|
$InstallerArguments += '-UseDirectorSelfService 0';
|
|
}
|
|
}
|
|
if ($UseDirectorSelfService) {
|
|
|
|
$InstallerArguments += '-UseDirectorSelfService 1';
|
|
$DirectorArgs = Start-IcingaAgentDirectorWizard `
|
|
-DirectorUrl $DirectorUrl `
|
|
-SelfServiceAPIKey $SelfServiceAPIKey `
|
|
-OverrideDirectorVars $OverrideDirectorVars `
|
|
-RunInstaller $RunInstaller;
|
|
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'DirectorUrl' -Value $DirectorUrl -InstallerArguments $InstallerArguments;
|
|
$DirectorUrl = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'SelfServiceAPIKey' -Value $SelfServiceAPIKey -InstallerArguments $InstallerArguments -Default $null;
|
|
|
|
if ([string]::IsNullOrEmpty($Result.Value) -eq $FALSE) {
|
|
$SelfServiceAPIKey = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
}
|
|
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'Ticket' -Value $Ticket -InstallerArguments $InstallerArguments;
|
|
$Ticket = $Result.Value;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'PackageSource' -Value $PackageSource -InstallerArguments $InstallerArguments;
|
|
$PackageSource = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'AgentVersion' -Value $AgentVersion -InstallerArguments $InstallerArguments;
|
|
$AgentVersion = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'InstallDir' -Value $InstallDir -InstallerArguments $InstallerArguments;
|
|
$InstallDir = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'CAPort' -Value $CAPort -InstallerArguments $InstallerArguments;
|
|
$CAPort = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'AllowVersionChanges' -Value $AllowVersionChanges -InstallerArguments $InstallerArguments;
|
|
$AllowVersionChanges = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'GlobalZones' -Value $GlobalZones -InstallerArguments $InstallerArguments;
|
|
$GlobalZones = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'ParentZone' -Value $ParentZone -InstallerArguments $InstallerArguments;
|
|
$ParentZone = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'CAEndpoint' -Value $CAEndpoint -InstallerArguments $InstallerArguments;
|
|
$CAEndpoint = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'Endpoints' -Value $Endpoints -InstallerArguments $InstallerArguments;
|
|
$Endpoints = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'AddFirewallRule' -Value $AddFirewallRule -InstallerArguments $InstallerArguments;
|
|
$AddFirewallRule = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'AcceptConnections' -Value $AcceptConnections -InstallerArguments $InstallerArguments;
|
|
$AcceptConnections = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'ServiceUser' -Value $ServiceUser -InstallerArguments $InstallerArguments;
|
|
$ServiceUser = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'UpdateAgent' -Value $UpdateAgent -InstallerArguments $InstallerArguments;
|
|
$UpdateAgent = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'AddDirectorGlobal' -Value $AddDirectorGlobal -InstallerArguments $InstallerArguments;
|
|
$AddDirectorGlobal = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'AddGlobalTemplates' -Value $AddGlobalTemplates -InstallerArguments $InstallerArguments;
|
|
$AddGlobalTemplates = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'LowerCase' -Value $LowerCase -Default $FALSE -InstallerArguments $InstallerArguments;
|
|
$LowerCase = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'UpperCase' -Value $UpperCase -Default $FALSE -InstallerArguments $InstallerArguments;
|
|
$UpperCase = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'AutoUseFQDN' -Value $AutoUseFQDN -Default $FALSE -InstallerArguments $InstallerArguments;
|
|
$AutoUseFQDN = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'AutoUseHostname' -Value $AutoUseHostname -Default $FALSE -InstallerArguments $InstallerArguments;
|
|
$AutoUseHostname = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'EndpointConnections' -Value $EndpointConnections -InstallerArguments $InstallerArguments;
|
|
$EndpointConnections = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'OverrideDirectorVars' -Value $OverrideDirectorVars -InstallerArguments $InstallerArguments;
|
|
$OverrideDirectorVars = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'InstallFrameworkService' -Value $InstallFrameworkService -InstallerArguments $InstallerArguments;
|
|
$InstallFrameworkService = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'ServiceDirectory' -Value $ServiceDirectory -InstallerArguments $InstallerArguments;
|
|
$ServiceDirectory = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'FrameworkServiceUrl' -Value $FrameworkServiceUrl -InstallerArguments $InstallerArguments;
|
|
$FrameworkServiceUrl = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'InstallFrameworkPlugins' -Value $InstallFrameworkPlugins -InstallerArguments $InstallerArguments;
|
|
$InstallFrameworkPlugins = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'PluginsUrl' -Value $PluginsUrl -InstallerArguments $InstallerArguments;
|
|
$PluginsUrl = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
$Result = Set-IcingaWizardArgument -DirectorArgs $DirectorArgs -WizardArg 'ConvertEndpointIPConfig' -Value $ConvertEndpointIPConfig -InstallerArguments $InstallerArguments;
|
|
$ConvertEndpointIPConfig = $Result.Value;
|
|
$InstallerArguments = $Result.Args;
|
|
}
|
|
}
|
|
|
|
# 'latest' is deprecated starting with 1.1.0
|
|
if ($AgentVersion -eq 'latest') {
|
|
$AgentVersion = 'release';
|
|
Write-IcingaConsoleWarning -Message 'The value "latest" for the argmument "AgentVersion" is deprecated. Please use the value "release" in the future!';
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Hostname) -And $null -eq $AutoUseFQDN -And $null -eq $AutoUseHostname) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to specify the hostname manually?' -Default 'n').result -eq 1) {
|
|
$HostFQDN = Get-IcingaHostname -AutoUseFQDN 1 -AutoUseHostname 0 -LowerCase 1 -UpperCase 0;
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Do you want to automatically fetch the hostname as FQDN? (Result: "{0}")', $HostFQDN)) -Default 'y').result -eq 1) {
|
|
$InstallerArguments += '-AutoUseFQDN 1';
|
|
$InstallerArguments += '-AutoUseHostname 0';
|
|
$AutoUseFQDN = $TRUE;
|
|
$AutoUseHostname = $FALSE;
|
|
} else {
|
|
$InstallerArguments += '-AutoUseFQDN 0';
|
|
$InstallerArguments += '-AutoUseHostname 1';
|
|
$AutoUseFQDN = $FALSE;
|
|
$AutoUseHostname = $TRUE;
|
|
}
|
|
$Hostname = Get-IcingaHostname -AutoUseFQDN $AutoUseFQDN -AutoUseHostname $AutoUseHostname -LowerCase 1 -UpperCase 0;
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Do you want to convert the hostname into lower case characters? (Result: "{0}")', $Hostname)) -Default 'y').result -eq 1) {
|
|
$InstallerArguments += '-LowerCase 1';
|
|
$InstallerArguments += '-UpperCase 0';
|
|
$LowerCase = $TRUE;
|
|
$UpperCase = $FALSE;
|
|
} else {
|
|
$Hostname = Get-IcingaHostname -AutoUseFQDN $AutoUseFQDN -AutoUseHostname $AutoUseHostname -LowerCase 0 -UpperCase 1;
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Do you want to convert the hostname into upper case characters? (Result: "{0}")', $Hostname)) -Default 'y').result -eq 1) {
|
|
$InstallerArguments += '-LowerCase 0';
|
|
$InstallerArguments += '-UpperCase 1';
|
|
$LowerCase = $FALSE;
|
|
$UpperCase = $TRUE;
|
|
} else {
|
|
$InstallerArguments += '-LowerCase 0';
|
|
$InstallerArguments += '-UpperCase 0';
|
|
$LowerCase = $FALSE;
|
|
$UpperCase = $FALSE;
|
|
}
|
|
}
|
|
$Hostname = Get-IcingaHostname -AutoUseFQDN $AutoUseFQDN -AutoUseHostname $AutoUseHostname -LowerCase $LowerCase -UpperCase $UpperCase;
|
|
} else {
|
|
$Hostname = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the hostname to use' -Default 'v').answer;
|
|
}
|
|
} else {
|
|
if ($AutoUseFQDN -Or $AutoUseHostname) {
|
|
$Hostname = Get-IcingaHostname -AutoUseFQDN $AutoUseFQDN -AutoUseHostname $AutoUseHostname -LowerCase $LowerCase -UpperCase $UpperCase;
|
|
}
|
|
}
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Using hostname "{0}" for the Icinga Agent configuration', $Hostname));
|
|
|
|
$IcingaAgent = Get-IcingaAgentInstallation;
|
|
if ($IcingaAgent.Installed -eq $FALSE) {
|
|
if ([string]::IsNullOrEmpty($PackageSource)) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to install the Icinga Agent now?' -Default 'y').result -eq 1) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to use a different package source? (Defaults: "https://packages.icinga.com/windows/")' -Default 'n').result -eq 0) {
|
|
$PackageSource = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify your package source' -Default 'v').answer;
|
|
$InstallerArguments += "-PackageSource '$PackageSource'";
|
|
} else {
|
|
$PackageSource = 'https://packages.icinga.com/windows/'
|
|
$InstallerArguments += "-PackageSource '$PackageSource'";
|
|
}
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Using package source "{0}" for the Icinga Agent package', $PackageSource));
|
|
$AllowVersionChanges = $TRUE;
|
|
$InstallerArguments += '-AllowVersionChanges 1';
|
|
|
|
if ([string]::IsNullOrEmpty($AgentVersion)) {
|
|
$AgentVersion = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the version you want to install ("release", "snapshot" or a specific version like "2.11.3")' -Default 'v' -DefaultInput 'release').answer;
|
|
$InstallerArguments += "-AgentVersion '$AgentVersion'";
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Installing Icinga version: "{0}"', $AgentVersion));
|
|
}
|
|
} else {
|
|
$AllowVersionChanges = $FALSE;
|
|
$InstallerArguments += '-AllowVersionChanges 0';
|
|
$InstallerArguments += "-AgentVersion '$AgentVersion'";
|
|
$AgentVersion = '';
|
|
}
|
|
}
|
|
} else {
|
|
if ($null -eq $UpdateAgent) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'The Icinga Agent is already installed. Would you like to update it?' -Default 'y').result -eq 1) {
|
|
$UpdateAgent = 1;
|
|
$AllowVersionChanges = $TRUE;
|
|
$InstallerArguments += '-AllowVersionChanges 1';
|
|
} else {
|
|
$UpdateAgent = 0;
|
|
$AllowVersionChanges = $FALSE;
|
|
$InstallerArguments += '-AllowVersionChanges 0';
|
|
}
|
|
$InstallerArguments += "-UpdateAgent $UpdateAgent";
|
|
}
|
|
|
|
if ($UpdateAgent -eq 1) {
|
|
if ([string]::IsNullOrEmpty($AgentVersion)) {
|
|
$AgentVersion = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the version you want to install ("release", "snapshot" or a specific version like "2.11.3")' -Default 'v' -DefaultInput 'release').answer;
|
|
$InstallerArguments += "-AgentVersion '$AgentVersion'";
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Updating/Downgrading Icinga 2 Agent to version: "{0}"', $AgentVersion));
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($PackageSource)) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to use a different package source then "https://packages.icinga.com/windows/" ?' -Default 'n').result -eq 0) {
|
|
$PackageSource = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify your package source' -Default 'v').answer;
|
|
$InstallerArguments += "-PackageSource '$PackageSource'";
|
|
} else {
|
|
$PackageSource = 'https://packages.icinga.com/windows/'
|
|
$InstallerArguments += "-PackageSource '$PackageSource'";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($Endpoints.Count -eq 0) {
|
|
$ArrayString = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the parent node(s) separated by "," (Examples: "master1, master2" or "master1.example.com, master2.example.com")' -Default 'v').answer;
|
|
$Endpoints = ($ArrayString.Replace(' ', '')).Split(',');
|
|
$InstallerArguments += ("-Endpoints " + ([string]::Join(',', $Endpoints)));
|
|
}
|
|
|
|
if ($null -eq $CAPort) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Are you using another port than 5665 for Icinga communication?' -Default 'n').result -eq 0) {
|
|
$CAPort = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter the port for Icinga communication' -Default 'v' -DefaultInput '5665').answer;
|
|
$InstallerArguments += "-CAPort $CAPort";
|
|
} else {
|
|
$InstallerArguments += "-CAPort 5665";
|
|
$CAPort = 5665;
|
|
}
|
|
}
|
|
|
|
[bool]$CanConnectToParent = $FALSE;
|
|
|
|
if ($null -eq $AcceptConnections) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt "Is this Agent able to connect to its parent node(s)?" -Default 'y').result -eq 1) {
|
|
$CanConnectToParent = $TRUE;
|
|
$AcceptConnections = 0;
|
|
$InstallerArguments += ("-AcceptConnections 0");
|
|
} else {
|
|
$AcceptConnections = 1;
|
|
$InstallerArguments += ("-AcceptConnections 1");
|
|
}
|
|
} else {
|
|
if ((Test-IcingaWizardArgument -Argument 'AcceptConnections') -eq $FALSE) {
|
|
$InstallerArguments += ([string]::Format('-AcceptConnections {0}', [int]$AcceptConnections));
|
|
}
|
|
|
|
if ($AcceptConnections -eq $FALSE) {
|
|
$CanConnectToParent = $TRUE;
|
|
}
|
|
}
|
|
|
|
if ($null -eq $AddFirewallRule -And $CanConnectToParent -eq $FALSE) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Do you want to open the Windows Firewall for incoming traffic on Port "{0}"?', $CAPort)) -Default 'y').result -eq 1) {
|
|
$InstallerArguments += "-AddFirewallRule 1";
|
|
$AddFirewallRule = $TRUE;
|
|
} else {
|
|
$InstallerArguments += "-AddFirewallRule 0";
|
|
$AddFirewallRule = $FALSE;
|
|
}
|
|
} else {
|
|
if ($CanConnectToParent -eq $TRUE) {
|
|
$InstallerArguments += "-AddFirewallRule 0";
|
|
$AddFirewallRule = $FALSE;
|
|
}
|
|
}
|
|
|
|
if ($null -eq $ConvertEndpointIPConfig -And $CanConnectToParent -eq $TRUE) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to convert parent node(s) connection data to IP adresses?' -Default 'y').result -eq 1) {
|
|
$InstallerArguments += "-ConvertEndpointIPConfig 1";
|
|
$ConvertEndpointIPConfig = $TRUE;
|
|
if ($EndpointConnections.Count -eq 0) {
|
|
$EndpointsConversion = Convert-IcingaEndpointsToIPv4 -NetworkConfig $Endpoints.Split(',');
|
|
} else {
|
|
$EndpointsConversion = Convert-IcingaEndpointsToIPv4 -NetworkConfig $EndpointConnections;
|
|
}
|
|
if ($EndpointsConversion.HasErrors) {
|
|
Write-IcingaConsoleWarning -Message 'Not all of your endpoint connection data could be resolved. These endpoints were dropped: {0}' -Objects ([string]::Join(', ', $EndpointsConversion.Unresolved));
|
|
}
|
|
$EndpointConnections = $EndpointsConversion.Network;
|
|
} else {
|
|
$InstallerArguments += "-ConvertEndpointIPConfig 0";
|
|
$ConvertEndpointIPConfig = $FALSE;
|
|
}
|
|
}
|
|
|
|
if ($EndpointConnections.Count -eq 0 -And $AcceptConnections -eq 0) {
|
|
$NetworkDefault = '';
|
|
foreach ($Endpoint in $Endpoints) {
|
|
$NetworkDefault += [string]::Format('[{0}]:{1},', $Endpoint, $CAPort);
|
|
}
|
|
if ([string]::IsNullOrEmpty($NetworkDefault) -eq $FALSE) {
|
|
$NetworkDefault = $NetworkDefault.Substring(0, $NetworkDefault.Length - 1);
|
|
}
|
|
$ArrayString = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the network destinations this Agent will connect to separated by "," (Examples: 192.168.0.1, [192.168.0.2]:5665, [icinga2.example.com]:5665)' -Default 'v' -DefaultInput $NetworkDefault).answer;
|
|
$EndpointConnections = ($ArrayString.Replace(' ', '')).Split(',');
|
|
|
|
if ($ConvertEndpointIPConfig) {
|
|
$EndpointsConversion = Convert-IcingaEndpointsToIPv4 -NetworkConfig $EndpointConnections.Split(',');
|
|
if ($EndpointsConversion.HasErrors -eq $FALSE) {
|
|
$EndpointConnections = $EndpointsConversion.Network;
|
|
}
|
|
}
|
|
$InstallerArguments += ("-EndpointConnections " + ([string]::Join(',', $EndpointConnections)));
|
|
} elseif ($EndpointConnections.Count -ne 0 -And $AcceptConnections -eq 0 -And $ConvertEndpointIPConfig) {
|
|
$EndpointsConversion = Convert-IcingaEndpointsToIPv4 -NetworkConfig $EndpointConnections;
|
|
if ($EndpointsConversion.HasErrors) {
|
|
Write-IcingaConsoleWarning -Message 'Not all of your endpoint connection data could be resolved. These endpoints were dropped: {0}' -Objects ([string]::Join(', ', $EndpointsConversion.Unresolved));
|
|
}
|
|
$EndpointConnections = $EndpointsConversion.Network;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ParentZone)) {
|
|
$ParentZone = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the parent zone this Agent will connect to' -Default 'v' -DefaultInput 'master').answer;
|
|
$InstallerArguments += "-ParentZone $ParentZone";
|
|
}
|
|
|
|
if ($null -eq $AddDirectorGlobal) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to add the global zone "director-global"?' -Default 'y').result -eq 1) {
|
|
$AddDirectorGlobal = $TRUE;
|
|
$InstallerArguments += ("-AddDirectorGlobal 1");
|
|
} else {
|
|
$AddDirectorGlobal = $FALSE;
|
|
$InstallerArguments += ("-AddDirectorGlobal 0");
|
|
}
|
|
}
|
|
|
|
if ($AddDirectorGlobal) {
|
|
$GlobalZoneConfig += 'director-global';
|
|
}
|
|
|
|
if ($null -eq $AddGlobalTemplates) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to add the global zone "global-templates"?' -Default 'y').result -eq 1) {
|
|
$AddGlobalTemplates = $TRUE;
|
|
$InstallerArguments += ("-AddGlobalTemplates 1");
|
|
} else {
|
|
$AddGlobalTemplates = $FALSE;
|
|
$InstallerArguments += ("-AddGlobalTemplates 0");
|
|
}
|
|
}
|
|
|
|
if ($AddGlobalTemplates) {
|
|
$GlobalZoneConfig += 'global-templates';
|
|
}
|
|
|
|
if ($null -eq $GlobalZones) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to add custom global zones?' -Default 'n').result -eq 0) {
|
|
$ArrayString = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify your additional zones seperated by "," (Example: "global-zone1, global-zone2")' -Default 'v').answer;
|
|
if ([string]::IsNullOrEmpty($ArrayString) -eq $FALSE) {
|
|
$GlobalZones = ($ArrayString.Replace(' ', '')).Split(',')
|
|
$GlobalZoneConfig += $GlobalZones;
|
|
$InstallerArguments += ("-GlobalZones " + ([string]::Join(',', $GlobalZones)));
|
|
} else {
|
|
$GlobalZones = @();
|
|
$InstallerArguments += ("-GlobalZones @()");
|
|
}
|
|
} else {
|
|
$GlobalZones = @();
|
|
$InstallerArguments += ("-GlobalZones @()");
|
|
}
|
|
} else {
|
|
$GlobalZoneConfig += $GlobalZones;
|
|
}
|
|
|
|
if ($CanConnectToParent) {
|
|
if ([string]::IsNullOrEmpty($CAEndpoint)) {
|
|
$CAEndpoint = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter the connection data of the parent node that handles certificate requests' -Default 'v' -DefaultInput (Get-IPConfigFromString $EndpointConnections[0]).address).answer;
|
|
$InstallerArguments += "-CAEndpoint $CAEndpoint";
|
|
}
|
|
if ([string]::IsNullOrEmpty($Ticket) -And $null -eq $EmptyTicket) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you have a PKI Ticket to sign your certificate request?' -Default 'y').result -eq 1) {
|
|
$Ticket = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter your PKI Ticket' -Default 'v').answer;
|
|
if ([string]::IsNullOrEmpty($Ticket)) {
|
|
$InstallerArguments += "-EmptyTicket 1"
|
|
} else {
|
|
$InstallerArguments += "-EmptyTicket 0"
|
|
}
|
|
$InstallerArguments += "-Ticket '$Ticket'";
|
|
} else {
|
|
$InstallerArguments += "-Ticket ''";
|
|
$InstallerArguments += "-EmptyTicket 1"
|
|
}
|
|
} else {
|
|
if ([string]::IsNullOrEmpty($Ticket)) {
|
|
$InstallerArguments += "-Ticket ''";
|
|
} else {
|
|
$InstallerArguments += "-Ticket '$Ticket'";
|
|
}
|
|
if ($null -eq $EmptyTicket) {
|
|
$InstallerArguments += "-EmptyTicket 1"
|
|
} else {
|
|
$InstallerArguments += "-EmptyTicket $EmptyTicket"
|
|
}
|
|
}
|
|
} else {
|
|
if ([string]::IsNullOrEmpty($CAFile) -And $null -eq $EmptyCA) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Is your public Icinga 2 CA (ca.crt) available on a local, network or web share?' -Default 'y').result -eq 1) {
|
|
$CAFile = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please provide the full path to your ca.crt file (Examples: "C:\icinga2\ca.crt", "https://icinga.example.com/ca.crt"' -Default 'v').answer;
|
|
if ([string]::IsNullOrEmpty($CAFile)) {
|
|
$InstallerArguments += "-EmptyCA 1"
|
|
} else {
|
|
$InstallerArguments += "-EmptyCA 0"
|
|
}
|
|
$InstallerArguments += "-CAFile '$CAFile'";
|
|
} else {
|
|
$InstallerArguments += "-CAFile ''";
|
|
$InstallerArguments += "-EmptyCA 1";
|
|
$EmptyCA = $TRUE;
|
|
}
|
|
} else {
|
|
if ([string]::IsNullOrEmpty($CAFile)) {
|
|
$InstallerArguments += "-CAFile ''";
|
|
} else {
|
|
$InstallerArguments += "-CAFile '$CAFile'";
|
|
}
|
|
if ($null -eq $EmptyCA) {
|
|
$InstallerArguments += "-EmptyCA 1"
|
|
} else {
|
|
$InstallerArguments += "-EmptyCA $EmptyCA"
|
|
}
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ServiceUser)) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to change the user of the Icinga Agent service? (Defaults: "NT Authority\NetworkService")' -Default 'n').result -eq 0) {
|
|
$ServiceUser = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter a custom user for the Icinga Agent service' -Default 'v' -DefaultInput 'NT Authority\NetworkService').answer;
|
|
$InstallerArguments += "-ServiceUser $ServiceUser";
|
|
if ($null -eq $ServicePass) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Does your Icinga Agent service user require a password to login? (Not required for System users)' -Default 'y').result -eq 1) {
|
|
$ServicePass = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter the password for your service user' -Secure -Default 'v').answer;
|
|
$InstallerArguments += "-ServicePass $ServicePass";
|
|
} else {
|
|
$ServicePass = $null
|
|
$InstallerArguments += '-ServicePass $null';
|
|
}
|
|
}
|
|
} else {
|
|
$InstallerArguments += "-ServiceUser 'NT Authority\NetworkService'";
|
|
$ServiceUser = 'NT Authority\NetworkService';
|
|
}
|
|
}
|
|
|
|
if ($null -eq $InstallFrameworkPlugins) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to install the Icinga PowerShell Plugins?' -Default 'y').result -eq 1) {
|
|
$result = Install-IcingaFrameworkPlugins -PluginsUrl $PluginsUrl;
|
|
$PluginsUrl = $result.PluginUrl;
|
|
$InstallerArguments += "-InstallFrameworkPlugins 1";
|
|
$InstallerArguments += "-PluginsUrl '$PluginsUrl'";
|
|
} else {
|
|
$InstallerArguments += "-InstallFrameworkPlugins 0";
|
|
}
|
|
} elseif ($InstallFrameworkPlugins -eq 1) {
|
|
$result = Install-IcingaFrameworkPlugins -PluginsUrl $PluginsUrl;
|
|
$InstallerArguments += "-InstallFrameworkPlugins 1";
|
|
$InstallerArguments += "-PluginsUrl '$PluginsUrl'";
|
|
} else {
|
|
if ((Test-IcingaWizardArgument -Argument 'InstallFrameworkPlugins') -eq $FALSE) {
|
|
$InstallerArguments += "-InstallFrameworkPlugins 0";
|
|
}
|
|
}
|
|
|
|
if ($null -eq $InstallFrameworkService) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to install the Icinga PowerShell Framework as a service?' -Default 'y').result -eq 1) {
|
|
$result = Get-IcingaFrameworkServiceBinary;
|
|
$InstallerArguments += "-InstallFrameworkService 1";
|
|
$InstallerArguments += [string]::Format("-FrameworkServiceUrl '{0}'", $result.FrameworkServiceUrl);
|
|
$InstallerArguments += [string]::Format("-ServiceDirectory '{0}'", $result.ServiceDirectory);
|
|
$InstallerArguments += [string]::Format("-ServiceBin '{0}'", $result.ServiceBin);
|
|
$ServiceBin = $result.ServiceBin;
|
|
} else {
|
|
$InstallerArguments += "-InstallFrameworkService 0";
|
|
}
|
|
} elseif ($InstallFrameworkService -eq $TRUE) {
|
|
$result = Get-IcingaFrameworkServiceBinary -FrameworkServiceUrl $FrameworkServiceUrl -ServiceDirectory $ServiceDirectory;
|
|
$ServiceBin = $result.ServiceBin;
|
|
} else {
|
|
$InstallerArguments += "-InstallFrameworkService 0";
|
|
}
|
|
|
|
if ($InstallerArguments.Count -ne 0) {
|
|
$InstallerArguments += "-RunInstaller";
|
|
Write-IcingaConsoleNotice 'The wizard is complete. These are the configured settings:';
|
|
|
|
Write-IcingaConsolePlain '========';
|
|
Write-IcingaConsolePlain ($InstallerArguments | Out-String);
|
|
Write-IcingaConsolePlain '========';
|
|
|
|
if (-Not $RunInstaller) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Is this configuration correct?' -Default 'y').result -eq 1) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to run the installer now? (Otherwise only the configuration command will be printed)' -Default 'y').result -eq 1) {
|
|
Write-IcingaConsoleNotice 'To execute your Icinga Agent installation based on your answers again on this or another machine, simply run this command:';
|
|
|
|
$RunInstaller = $TRUE;
|
|
} else {
|
|
Write-IcingaConsoleNotice 'To execute your Icinga Agent installation based on your answers, simply run this command:';
|
|
}
|
|
} else {
|
|
Write-IcingaConsoleNotice 'Please run the wizard again to modify your answers or modify the command below:';
|
|
}
|
|
}
|
|
Get-IcingaAgentInstallCommand -InstallerArguments $InstallerArguments -PrintConsole;
|
|
}
|
|
|
|
if ($RunInstaller) {
|
|
if ((Test-IcingaAgentNETFrameworkDependency) -eq $FALSE) {
|
|
Write-IcingaConsoleError -Message 'You cannot install the Icinga Agent on this system as the required .NET Framework version is not installed. Please install .NET Framework 4.6.0 or later and use the above provided install arguments to try again.'
|
|
return;
|
|
}
|
|
|
|
if ((Install-IcingaAgent -Version $AgentVersion -Source $PackageSource -AllowUpdates $AllowVersionChanges -InstallDir $InstallDir) -Or $Reconfigure) {
|
|
Reset-IcingaAgentConfigFile;
|
|
Move-IcingaAgentDefaultConfig;
|
|
Set-IcingaAgentNodeName -Hostname $Hostname;
|
|
Set-IcingaAgentServiceUser -User $ServiceUser -Password $ServicePass -SetPermission | Out-Null;
|
|
if ($InstallFrameworkService) {
|
|
Install-IcingaForWindowsService -Path $ServiceBin -User $ServiceUser -Password $ServicePass | Out-Null;
|
|
}
|
|
Register-IcingaBackgroundDaemon -Command 'Start-IcingaServiceCheckDaemon';
|
|
Install-IcingaAgentBaseFeatures;
|
|
$CertsInstalled = Install-IcingaAgentCertificates -Hostname $Hostname -Endpoint $CAEndpoint -Port $CAPort -CACert $CAFile -Ticket $Ticket;
|
|
Write-IcingaAgentApiConfig -Port $CAPort;
|
|
if ($EmptyCA -eq $TRUE -And $CertsInstalled -eq $FALSE) {
|
|
Disable-IcingaAgentFeature 'api';
|
|
Write-IcingaConsoleWarning `
|
|
-Message '{0}{1}{2}{3}{4}' `
|
|
-Objects (
|
|
'Your Icinga Agent API feature has been disabled. Please provide either your ca.crt ',
|
|
'or connect to a parent node for certificate requests. You can run "Install-IcingaAgentCertificates" ',
|
|
'with your configuration to properly create the host certificate and a valid certificate request. ',
|
|
'After this you can enable the API feature by using "Enable-IcingaAgentFeature api" and restart the ',
|
|
'Icinga Agent service "Restart-IcingaService icinga2"'
|
|
);
|
|
}
|
|
Write-IcingaAgentZonesConfig -Endpoints $Endpoints -EndpointConnections $EndpointConnections -ParentZone $ParentZone -GlobalZones $GlobalZoneConfig -Hostname $Hostname;
|
|
if ($AddFirewallRule) {
|
|
# First cleanup the system by removing all old Firewalls
|
|
Enable-IcingaFirewall -IcingaPort $CAPort -Force;
|
|
}
|
|
Test-IcingaAgent;
|
|
if ($InstallFrameworkService) {
|
|
Restart-IcingaService 'icingapowershell';
|
|
}
|
|
Restart-IcingaService 'icinga2';
|
|
}
|
|
}
|
|
}
|
|
|
|
function Add-InstallerArgument()
|
|
{
|
|
param(
|
|
$InstallerArguments,
|
|
[string]$Key,
|
|
$Value,
|
|
[switch]$ReturnValue
|
|
);
|
|
|
|
[bool]$IsArray = $Value -is [array];
|
|
|
|
# Check for arrays
|
|
if ($IsArray) {
|
|
[array]$NewArray = @();
|
|
foreach ($entry in $Value) {
|
|
$NewArray += Add-InstallerArgument -Value $entry -ReturnValue;
|
|
}
|
|
|
|
if ($ReturnValue) {
|
|
return ([string]::Join(',', $NewArray));
|
|
}
|
|
|
|
$InstallerArguments += [string]::Format(
|
|
'-{0} {1}',
|
|
$Key,
|
|
[string]::Join(',', $NewArray)
|
|
);
|
|
|
|
return $InstallerArguments;
|
|
}
|
|
|
|
# Check for integers
|
|
if (Test-Numeric $Value) {
|
|
if ($ReturnValue) {
|
|
return $Value;
|
|
}
|
|
|
|
$InstallerArguments += [string]::Format(
|
|
'-{0} {1}',
|
|
$Key,
|
|
$Value
|
|
);
|
|
|
|
return $InstallerArguments;
|
|
}
|
|
|
|
# Check for integer conversion
|
|
$IntValue = ConvertTo-Integer -Value $Value;
|
|
if ([string]$Value -ne [string]$IntValue) {
|
|
if ($ReturnValue) {
|
|
return $IntValue;
|
|
}
|
|
|
|
$InstallerArguments += [string]::Format(
|
|
'-{0} {1}',
|
|
$Key,
|
|
$IntValue
|
|
);
|
|
|
|
return $InstallerArguments;
|
|
}
|
|
|
|
$Type = $Value.GetType().Name;
|
|
$NewValue = $null;
|
|
|
|
if ($Type -eq 'String') {
|
|
$NewValue = [string]::Format(
|
|
"'{0}'",
|
|
$Value
|
|
);
|
|
|
|
if ($ReturnValue) {
|
|
return $NewValue;
|
|
}
|
|
|
|
$InstallerArguments += [string]::Format(
|
|
'-{0} {1}',
|
|
$Key,
|
|
$NewValue
|
|
);
|
|
|
|
return $InstallerArguments;
|
|
}
|
|
}
|
|
|
|
function Test-IcingaWizardArgument()
|
|
{
|
|
param(
|
|
[string]$Argument
|
|
);
|
|
|
|
foreach ($entry in $InstallerArguments) {
|
|
if ($entry -like [string]::Format('-{0} *', $Argument)) {
|
|
return $TRUE;
|
|
}
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
function Set-IcingaWizardArgument()
|
|
{
|
|
param(
|
|
[hashtable]$DirectorArgs,
|
|
[string]$WizardArg,
|
|
$Value,
|
|
$Default = $null,
|
|
$InstallerArguments
|
|
);
|
|
|
|
if ($DirectorArgs.Overrides.ContainsKey($WizardArg)) {
|
|
|
|
$InstallerArguments = Add-InstallerArgument `
|
|
-InstallerArguments $InstallerArguments `
|
|
-Key $WizardArg `
|
|
-Value $DirectorArgs.Overrides[$WizardArg];
|
|
|
|
return @{
|
|
'Value' = $DirectorArgs.Overrides[$WizardArg];
|
|
'Args' = $InstallerArguments;
|
|
};
|
|
}
|
|
|
|
$RetValue = $null;
|
|
|
|
if ($DirectorArgs.Arguments.ContainsKey($WizardArg)) {
|
|
$RetValue = $DirectorArgs.Arguments[$WizardArg];
|
|
} else {
|
|
|
|
if ($null -ne $Value -And [string]::IsNullOrEmpty($Value) -eq $FALSE) {
|
|
$InstallerArguments = Add-InstallerArgument `
|
|
-InstallerArguments $InstallerArguments `
|
|
-Key $WizardArg `
|
|
-Value $Value;
|
|
|
|
return @{
|
|
'Value' = $Value;
|
|
'Args' = $InstallerArguments;
|
|
};
|
|
} else {
|
|
return @{
|
|
'Value' = $Default;
|
|
'Args' = $InstallerArguments;
|
|
};
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Value) -eq $FALSE) {
|
|
|
|
$InstallerArguments = Add-InstallerArgument `
|
|
-InstallerArguments $InstallerArguments `
|
|
-Key $WizardArg `
|
|
-Value $Value;
|
|
|
|
return @{
|
|
'Value' = $Value;
|
|
'Args' = $InstallerArguments;
|
|
};
|
|
}
|
|
|
|
return @{
|
|
'Value' = $RetValue;
|
|
'Args' = $InstallerArguments;
|
|
};
|
|
}
|
|
function Get-IcingaAgentInstallCommand()
|
|
{
|
|
param(
|
|
$InstallerArguments,
|
|
[switch]$PrintConsole
|
|
);
|
|
|
|
[string]$Installer = (
|
|
[string]::Format(
|
|
'Start-IcingaAgentInstallWizard {0}',
|
|
([string]::Join(' ', $InstallerArguments))
|
|
)
|
|
);
|
|
|
|
if ($PrintConsole) {
|
|
Write-IcingaConsolePlain '===='
|
|
Write-IcingaConsolePlain $Installer;
|
|
Write-IcingaConsolePlain '===='
|
|
} else {
|
|
return $Installer;
|
|
}
|
|
}
|
|
|
|
function Read-IcingaAgentDebugLogFile()
|
|
{
|
|
$Logfile = Join-Path -Path (Get-IcingaAgentLogDirectory) -ChildPath 'debug.log';
|
|
if ((Test-Path $Logfile) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'Icinga 2 debug logfile not present. Unable to load it';
|
|
return;
|
|
}
|
|
|
|
Get-Content -Path $Logfile -Tail 20 -Wait;
|
|
}
|
|
|
|
function Read-IcingaAgentLogFile()
|
|
{
|
|
$Logfile = Join-Path -Path (Get-IcingaAgentLogDirectory) -ChildPath 'icinga2.log';
|
|
if ((Test-Path $Logfile) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'Icinga 2 logfile not present. Unable to load it';
|
|
return;
|
|
}
|
|
|
|
Get-Content -Path $Logfile -Tail 20 -Wait;
|
|
}
|
|
|
|
function Set-IcingaAcl()
|
|
{
|
|
param(
|
|
[string]$Directory
|
|
);
|
|
|
|
if (-Not (Test-Path $Directory)) {
|
|
throw 'Failed to set Acl for directory. Directory does not exist';
|
|
return;
|
|
}
|
|
|
|
$DirectoryAcl = (Get-Item -Path $Directory).GetAccessControl('Access');
|
|
$DirectoryAccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
|
|
(Get-IcingaServiceUser),
|
|
'Modify',
|
|
'ContainerInherit,ObjectInherit',
|
|
'None',
|
|
'Allow'
|
|
);
|
|
|
|
$DirectoryAcl.SetAccessRule($DirectoryAccessRule);
|
|
Set-Acl -Path $Directory -AclObject $DirectoryAcl;
|
|
Test-IcingaAcl -Directory $Directory -WriteOutput | Out-Null;
|
|
}
|
|
|
|
function Set-IcingaAgentNodeName()
|
|
{
|
|
param(
|
|
$Hostname
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Hostname)) {
|
|
throw 'You have to specify a hostname in order to change the Icinga Agent NodeName';
|
|
}
|
|
|
|
$ConfigDir = Get-IcingaAgentConfigDirectory;
|
|
$ConstantsConf = Join-Path -Path $ConfigDir -ChildPath 'constants.conf';
|
|
|
|
$ConfigContent = Get-Content -Path $ConstantsConf;
|
|
|
|
if ($ConfigContent.Contains('//const NodeName = "localhost"')) {
|
|
$ConfigContent = $ConfigContent.Replace(
|
|
'//const NodeName = "localhost"',
|
|
[string]::Format('const NodeName = "{0}"', $Hostname)
|
|
);
|
|
} else {
|
|
[string]$NewConfigContent = '';
|
|
foreach ($line in $ConfigContent) {
|
|
if ($line.Contains('const NodeName =')) {
|
|
$line = [string]::Format('const NodeName = "{0}"', $Hostname);
|
|
}
|
|
$NewConfigContent = [string]::Format('{0}{1}{2}', $NewConfigContent, $line, "`r`n");
|
|
}
|
|
$ConfigContent = $NewConfigContent;
|
|
}
|
|
|
|
Set-Content -Path $ConstantsConf -Value $ConfigContent;
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Your hostname was successfully changed to "{0}"', $Hostname));
|
|
}
|
|
|
|
function Set-IcingaAgentServicePermission()
|
|
{
|
|
if (Test-IcingaAgentServicePermission -Silent) {
|
|
Write-IcingaConsoleNotice 'The Icinga Service User already has permission to run as service';
|
|
return;
|
|
}
|
|
|
|
$SystemPermissions = New-IcingaTemporaryFile;
|
|
$ServiceUser = Get-IcingaServiceUser;
|
|
$ServiceUserSID = Get-IcingaUserSID $ServiceUser;
|
|
$SystemContent = Get-IcingaAgentServicePermission;
|
|
$NewSystemContent = @();
|
|
|
|
if ([string]::IsNullOrEmpty($ServiceUser)) {
|
|
Write-IcingaTestOutput -Severity 'Failed' -Message 'There is no user assigned to the Icinga 2 service or the service is not yet installed';
|
|
return $FALSE;
|
|
}
|
|
|
|
foreach ($line in $SystemContent) {
|
|
if ($line -like '*SeServiceLogonRight*') {
|
|
$line = [string]::Format('{0},*{1}', $line, $ServiceUserSID);
|
|
}
|
|
|
|
$NewSystemContent += $line;
|
|
}
|
|
|
|
Set-Content -Path "$SystemPermissions.inf" -Value $NewSystemContent;
|
|
|
|
$SystemOutput = Start-IcingaProcess -Executable 'secedit.exe' -Arguments ([string]::Format('/import /cfg "{0}.inf" /db "{0}.sdb"', $SystemPermissions));
|
|
|
|
if ($SystemOutput.ExitCode -ne 0) {
|
|
throw ([string]::Format('Unable to import system permission information: {0}', $SystemOutput.Message));
|
|
return $null;
|
|
}
|
|
|
|
$SystemOutput = Start-IcingaProcess -Executable 'secedit.exe' -Arguments ([string]::Format('/configure /cfg "{0}.inf" /db "{0}.sdb"', $SystemPermissions));
|
|
|
|
if ($SystemOutput.ExitCode -ne 0) {
|
|
throw ([string]::Format('Unable to configure system permission information: {0}', $SystemOutput.Message));
|
|
return $null;
|
|
}
|
|
|
|
Remove-Item $SystemPermissions*;
|
|
|
|
Test-IcingaAgentServicePermission | Out-Null;
|
|
}
|
|
|
|
function Set-IcingaAgentServiceUser()
|
|
{
|
|
param (
|
|
[string]$User,
|
|
[securestring]$Password,
|
|
[string]$Service = 'icinga2',
|
|
[switch]$SetPermission
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($User)) {
|
|
throw 'Please specify a username to modify the service user';
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($User.Contains('\') -eq $FALSE) {
|
|
$User = [string]::Format('.\{0}', $User);
|
|
}
|
|
|
|
$ArgString = 'config {0} obj= "{1}" password= "{2}"';
|
|
if ($null -eq $Password) {
|
|
$ArgString = 'config {0} obj= "{1}"{2}';
|
|
}
|
|
|
|
$Output = Start-IcingaProcess `
|
|
-Executable 'sc.exe' `
|
|
-Arguments ([string]::Format($ArgString, $Service, $User, (ConvertFrom-IcingaSecureString $Password))) `
|
|
-FlushNewLines $TRUE;
|
|
|
|
if ($Output.ExitCode -eq 0) {
|
|
|
|
if ($SetPermission) {
|
|
Set-IcingaUserPermissions;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Service User successfully updated'
|
|
return $TRUE;
|
|
} else {
|
|
Write-IcingaConsoleError ([string]::Format('Failed to update the service user: {0}', $Output.Message));
|
|
return $FALSE;
|
|
}
|
|
}
|
|
|
|
function Set-IcingaUserPermissions()
|
|
{
|
|
Set-IcingaAgentServicePermission | Out-Null;
|
|
Set-IcingaAcl "$Env:ProgramData\icinga2\etc";
|
|
Set-IcingaAcl "$Env:ProgramData\icinga2\var";
|
|
Set-IcingaAcl (Get-IcingaCacheDir);
|
|
}
|
|
|
|
function Test-IcingaAcl()
|
|
{
|
|
param(
|
|
[string]$Directory,
|
|
[switch]$WriteOutput
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Directory) -Or -Not (Test-Path $Directory)) {
|
|
throw 'The specified directory was not found';
|
|
}
|
|
|
|
$FolderACL = Get-Acl $Directory;
|
|
$ServiceUser = Get-IcingaServiceUser;
|
|
$UserFound = $FALSE;
|
|
$HasAccess = $FALSE;
|
|
$ServiceUserSID = Get-IcingaUserSID $ServiceUser;
|
|
|
|
foreach ($user in $FolderACL.Access) {
|
|
# Not only check here for the exact name but also for included strings like NT AU or NT-AU or even further later on
|
|
# As the Get-Acl Cmdlet will translate usernames into the own language, resultng in 'NT AUTHORITY\NetworkService' being translated
|
|
# to 'NT-AUTORITÄT\Netzwerkdienst' for example
|
|
$UserSID = $null;
|
|
try {
|
|
$UserSID = Get-IcingaUserSID $user.IdentityReference;
|
|
} catch {
|
|
$UserSID = $null;
|
|
}
|
|
|
|
if ($ServiceUserSID -eq $UserSID) {
|
|
$UserFound = $TRUE;
|
|
if (($user.FileSystemRights -Like '*Modify*' -And $user.FileSystemRights -Like '*Synchronize*') -Or $user.FileSystemRights -like '*FullControl*') {
|
|
$HasAccess = $TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($WriteOutput) {
|
|
[string]$messageFormat = 'Directory "{0}" {1} by the Icinga Service User "{2}"';
|
|
if ($UserFound) {
|
|
if ($HasAccess) {
|
|
Write-IcingaTestOutput -Severity 'Passed' -Message ([string]::Format($messageFormat, $Directory, 'is accessible and writeable', $ServiceUser));
|
|
} else {
|
|
Write-IcingaTestOutput -Severity 'Failed' -Message ([string]::Format($messageFormat, $Directory, 'is accessible but NOT writeable', $ServiceUser));
|
|
Write-IcingaConsolePlain "\_ Please run the following command to fix this issue: Set-IcingaAcl -Directory '$Directory'";
|
|
}
|
|
} else {
|
|
Write-IcingaTestOutput -Severity 'Failed' -Message ([string]::Format($messageFormat, $Directory, 'is not accessible', $ServiceUser));
|
|
Write-IcingaConsolePlain "\_ Please run the following command to fix this issue: Set-IcingaAcl -Directory '$Directory'";
|
|
}
|
|
}
|
|
|
|
return $UserFound;
|
|
}
|
|
|
|
function Test-IcingaAgent()
|
|
{
|
|
if (Get-Service 'icinga2' -ErrorAction SilentlyContinue) {
|
|
Write-IcingaTestOutput -Severity 'Passed' -Message 'Icinga Agent service is installed';
|
|
Test-IcingaAgentServicePermission | Out-Null;
|
|
Test-IcingaAcl "$Env:ProgramData\icinga2\etc" -WriteOutput | Out-Null;
|
|
Test-IcingaAcl "$Env:ProgramData\icinga2\var" -WriteOutput | Out-Null;
|
|
Test-IcingaAcl (Get-IcingaCacheDir) -WriteOutput | Out-Null;
|
|
Test-IcingaAgentConfig | Out-Null;
|
|
if (Test-IcingaAgentFeatureEnabled -Feature 'debuglog') {
|
|
Write-IcingaTestOutput -Severity 'Warning' -Message 'The debug log of the Icinga Agent is enabled. Please keep in mind to disable it once testing is done, as a huge amount of data is generated'
|
|
} else {
|
|
Write-IcingaTestOutput -Severity 'Passed' -Message 'Icinga Agent debug log is disabled'
|
|
}
|
|
} else {
|
|
Write-IcingaTestOutput -Severity 'Failed' -Message 'Icinga Agent service is not installed';
|
|
}
|
|
}
|
|
|
|
function Test-IcingaAgentConfig()
|
|
{
|
|
param (
|
|
[switch]$WriteStackTrace
|
|
);
|
|
|
|
$Binary = Get-IcingaAgentBinary;
|
|
$ConfigResult = Start-IcingaProcess -Executable $Binary -Arguments 'daemon -C';
|
|
|
|
if ($ConfigResult.ExitCode -eq 0) {
|
|
Write-IcingaTestOutput -Severity 'Passed' -Message 'Icinga Agent configuration is valid';
|
|
return $TRUE;
|
|
} else {
|
|
Write-IcingaTestOutput -Severity 'Failed' -Message 'Icinga Agent configuration contains errors. Run this command for getting a detailed error report: "Test-IcingaAgentConfig -WriteStackTrace | Out-Null"';
|
|
if ($WriteStackTrace) {
|
|
Write-IcingaConsolePlain $ConfigResult.Message;
|
|
}
|
|
return $FALSE;
|
|
}
|
|
}
|
|
|
|
function Test-IcingaAgentFeatureEnabled()
|
|
{
|
|
param(
|
|
[string]$Feature
|
|
);
|
|
|
|
$Features = Get-IcingaAgentFeatures;
|
|
|
|
if ($Features.Enabled -Contains $Feature) {
|
|
return $TRUE;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Test if .NET Framework 4.6.0 or above is installed which is required by
|
|
the Icinga Agent. Returns either true or false - depending on if the
|
|
.NET Framework 4.6.0 or above is installed or not
|
|
.DESCRIPTION
|
|
Test if .NET Framework 4.6.0 or above is installed which is required by
|
|
the Icinga Agent. Returns either true or false - depending on if the
|
|
.NET Framework 4.6.0 or above is installed or not
|
|
.FUNCTIONALITY
|
|
Test if .NET Framework 4.6.0 or above is installed
|
|
.EXAMPLE
|
|
PS>Test-IcingaAgentNETFrameworkDependency;
|
|
.OUTPUTS
|
|
System.Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed
|
|
#>
|
|
|
|
function Test-IcingaAgentNETFrameworkDependency()
|
|
{
|
|
$RegistryContent = Get-ItemProperty -Path 'HKLM:SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' -ErrorAction SilentlyContinue;
|
|
|
|
# We require at least .NET Framework 4.6.0 to be installed on the system
|
|
# Version on Windows 10: 393295
|
|
# Version on any other system: 393297
|
|
# We do only require to check for the Windows 10 version, as the other Windows verions
|
|
# do not cause an issue there then because of how the next versions are iterated
|
|
|
|
if ($null -eq $RegistryContent -Or $RegistryContent.Release -lt 393295) {
|
|
if ($null -eq $RegistryContent) {
|
|
$RegistryContent = @{
|
|
'Version' = 'Unknown'
|
|
};
|
|
}
|
|
Write-IcingaConsoleError `
|
|
-Message 'To install the Icinga Agent you will require .NET Framework 4.6.0 or later to be installed on the system. Current installed version: {0}' `
|
|
-Objects $RegistryContent.Version;
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice `
|
|
-Message 'Found installed .NET Framework version {0}' `
|
|
-Objects $RegistryContent.Version;
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
function Test-IcingaAgentServicePermission()
|
|
{
|
|
param(
|
|
[switch]$Silent = $FALSE
|
|
);
|
|
|
|
$ServiceUser = Get-IcingaServiceUser;
|
|
$ServiceUserSID = Get-IcingaUserSID $ServiceUser;
|
|
$SystemContent = Get-IcingaAgentServicePermission;
|
|
[bool]$FoundSID = $FALSE;
|
|
|
|
if ($ServiceUser -eq 'NT Authority\SYSTEM') {
|
|
return $TRUE;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ServiceUser)) {
|
|
if (-Not $Silent) {
|
|
Write-IcingaTestOutput -Severity 'Failed' -Message 'There is no user assigned to the Icinga 2 service or the service is not yet installed';
|
|
}
|
|
return $FALSE;
|
|
}
|
|
|
|
foreach ($line in $SystemContent) {
|
|
if ($line -like '*SeServiceLogonRight*') {
|
|
$Index = $line.IndexOf('= ') + 2;
|
|
[string]$SIDs = $line.Substring($Index, $line.Length - $Index);
|
|
[array]$SIDArray = $SIDs.Split(',');
|
|
|
|
foreach ($sid in $SIDArray) {
|
|
if ($sid -like "*$ServiceUserSID" -Or $sid -eq $ServiceUser) {
|
|
$FoundSID = $TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ($FoundSID) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (-Not $Silent) {
|
|
if ($FoundSID) {
|
|
Write-IcingaTestOutput -Severity 'Passed' -Message ([string]::Format('The specified user "{0}" is allowed to run as service', $ServiceUser));
|
|
} else {
|
|
Write-IcingaTestOutput -Severity 'Failed' -Message ([string]::Format('The specified user "{0}" is not allowed to run as service', $ServiceUser));
|
|
}
|
|
}
|
|
|
|
return $FoundSID;
|
|
}
|
|
|
|
function Write-IcingaAgentApiConfig()
|
|
{
|
|
param(
|
|
[int]$Port = 5665
|
|
);
|
|
|
|
[string]$ApiConf = '';
|
|
|
|
$ApiConf = [string]::Format('{0}object ApiListener "api" {1}{2}', $ApiConf, '{', "`r`n");
|
|
$ApiConf = [string]::Format('{0} accept_commands = true;{1}', $ApiConf, "`r`n");
|
|
$ApiConf = [string]::Format('{0} accept_config = true;{1}', $ApiConf, "`r`n");
|
|
$ApiConf = [string]::Format('{0} bind_host = "::";{1}', $ApiConf, "`r`n");
|
|
$ApiConf = [string]::Format('{0} bind_port = {1};{2}', $ApiConf, $Port, "`r`n");
|
|
$ApiConf = [string]::Format('{0}{1}{2}{2}', $ApiConf, '}', "`r`n");
|
|
|
|
$ApiConf = $ApiConf.Substring(0, $ApiConf.Length - 4);
|
|
|
|
Set-Content -Path (Join-Path -Path (Get-IcingaAgentConfigDirectory) -ChildPath 'features-available\api.conf') -Value $ApiConf;
|
|
Write-IcingaConsoleNotice 'Api configuration has been written successfully';
|
|
}
|
|
|
|
function Write-IcingaAgentObjectList()
|
|
{
|
|
param(
|
|
[string]$Path
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Path)) {
|
|
throw 'Please specify a path to write the Icinga objects to';
|
|
}
|
|
|
|
$ObjectList = Get-IcingaAgentObjectList;
|
|
|
|
Set-Content -Path $Path -Value $ObjectList;
|
|
}
|
|
|
|
function Write-IcingaAgentZonesConfig()
|
|
{
|
|
param(
|
|
[array]$Endpoints = @(),
|
|
[array]$EndpointConnections = @(),
|
|
[string]$ParentZone = '',
|
|
[array]$GlobalZones = @(),
|
|
[string]$Hostname = ''
|
|
);
|
|
|
|
if ($Endpoints.Count -eq 0) {
|
|
throw 'Please properly specify your endpoint names';
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ParentZone)) {
|
|
throw 'Please specify a parent zone this agent shall connect to / receives connections from';
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Hostname)) {
|
|
throw 'Please specify hostname for this agent configuration';
|
|
}
|
|
|
|
[int]$Index = 0;
|
|
[string]$ZonesConf = '';
|
|
|
|
$ZonesConf = [string]::Format('{0}object Endpoint "{1}" {2}{3}', $ZonesConf, $Hostname, '{', "`r`n");
|
|
$ZonesConf = [string]::Format('{0}{1}{2}{2}', $ZonesConf, '}', "`r`n");
|
|
|
|
foreach ($endpoint in $Endpoints) {
|
|
$ZonesConf = [string]::Format('{0}object Endpoint "{1}" {2}{3}', $ZonesConf, $endpoint, '{', "`r`n");
|
|
if ($EndpointConnections.Count -ne 0) {
|
|
$ConnectionConfig = Get-IPConfigFromString -IPConfig ($EndpointConnections[$Index]);
|
|
$ZonesConf = [string]::Format('{0} host = "{1}";{2}', $ZonesConf, $ConnectionConfig.address, "`r`n");
|
|
if ([string]::IsNullOrEmpty($ConnectionConfig.port) -eq $FALSE) {
|
|
$ZonesConf = [string]::Format('{0} port = "{1}";{2}', $ZonesConf, $ConnectionConfig.port, "`r`n");
|
|
}
|
|
}
|
|
$ZonesConf = [string]::Format('{0}{1}{2}{2}', $ZonesConf, '}', "`r`n");
|
|
$Index += 1;
|
|
}
|
|
|
|
[string]$EndpointString = '';
|
|
foreach ($endpoint in $Endpoints) {
|
|
$EndpointString = [string]::Format(
|
|
'{0}"{1}", ',
|
|
$EndpointString,
|
|
$endpoint
|
|
);
|
|
}
|
|
$EndpointString = $EndpointString.Substring(0, $EndpointString.Length - 2);
|
|
|
|
$ZonesConf = [string]::Format('{0}object Zone "{1}" {2}{3}', $ZonesConf, $ParentZone, '{', "`r`n");
|
|
$ZonesConf = [string]::Format('{0} endpoints = [ {1} ];{2}', $ZonesConf, $EndpointString, "`r`n");
|
|
$ZonesConf = [string]::Format('{0}{1}{2}{2}', $ZonesConf, '}', "`r`n");
|
|
|
|
$ZonesConf = [string]::Format('{0}object Zone "{1}" {2}{3}', $ZonesConf, $Hostname, '{', "`r`n");
|
|
$ZonesConf = [string]::Format('{0} parent = "{1}";{2}', $ZonesConf, $ParentZone, "`r`n");
|
|
$ZonesConf = [string]::Format('{0} endpoints = [ "{1}" ];{2}', $ZonesConf, $Hostname, "`r`n");
|
|
$ZonesConf = [string]::Format('{0}{1}{2}{2}', $ZonesConf, '}', "`r`n");
|
|
|
|
foreach ($zone in $GlobalZones) {
|
|
$ZonesConf = [string]::Format('{0}object Zone "{1}" {2}{3}', $ZonesConf, $zone, '{', "`r`n");
|
|
$ZonesConf = [string]::Format('{0} global = true;{1}', $ZonesConf, "`r`n");
|
|
$ZonesConf = [string]::Format('{0}{1}{2}{2}', $ZonesConf, '}', "`r`n");
|
|
}
|
|
|
|
$ZonesConf = $ZonesConf.Substring(0, $ZonesConf.Length - 4);
|
|
|
|
Set-Content -Path (Join-Path -Path (Get-IcingaAgentConfigDirectory) -ChildPath 'zones.conf') -Value $ZonesConf;
|
|
Write-IcingaConsoleNotice 'Icinga Agent zones.conf has been written successfully';
|
|
}
|
|
|
|
function Write-IcingaTestOutput()
|
|
{
|
|
param(
|
|
[ValidateSet('Passed', 'Warning', 'Failed')]
|
|
$Severity,
|
|
$Message
|
|
);
|
|
|
|
$Color = 'Green';
|
|
|
|
Switch ($Severity) {
|
|
'Passed' {
|
|
$Color = 'Green';
|
|
break;
|
|
};
|
|
'Warning' {
|
|
$Color = 'Yellow';
|
|
break;
|
|
};
|
|
'Failed' {
|
|
$Color = 'Red';
|
|
break;
|
|
};
|
|
}
|
|
|
|
Write-Host '[' -NoNewline;
|
|
Write-Host $Severity -ForegroundColor $Color -NoNewline;
|
|
Write-Host ']:' $Message;
|
|
}
|
|
|
|
function Install-Icinga()
|
|
{
|
|
param (
|
|
[string]$InstallCommand = $null,
|
|
[string]$InstallFile = ''
|
|
);
|
|
|
|
if ($null -eq $global:Icinga) {
|
|
$global:Icinga = @{ };
|
|
}
|
|
|
|
if ($global:Icinga.ContainsKey('InstallWizard') -eq $FALSE) {
|
|
$global:Icinga.Add(
|
|
'InstallWizard', @{
|
|
'AdminShell' = (Test-AdministrativeShell);
|
|
'LastInput' = '';
|
|
'LastNotice' = '';
|
|
'LastError' = '';
|
|
'HeaderPreview' = '';
|
|
'LastParent' = [System.Collections.ArrayList]@();
|
|
'LastValues' = @();
|
|
'Config' = @{ };
|
|
'ConfigSwap' = @{ };
|
|
'ParentConfig' = $null;
|
|
'Menu' = 'Install-Icinga';
|
|
'NextCommand' = '';
|
|
'NextArguments' = $null;
|
|
'HeaderSelection' = $null;
|
|
'DisplayAdvanced' = $FALSE;
|
|
'ShowAdvanced' = $FALSE;
|
|
'ShowHelp' = $FALSE;
|
|
'DeleteValues' = $FALSE;
|
|
'HeaderPrint' = $FALSE;
|
|
'JumpToSummary' = $FALSE;
|
|
'Closing' = $FALSE;
|
|
}
|
|
);
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($InstallFile) -eq $FALSE) {
|
|
$InstallCommand = Read-IcingaFileContent -File $InstallFile;
|
|
}
|
|
|
|
# Use our install command to configure everything
|
|
if ([string]::IsNullOrEmpty($InstallCommand) -eq $FALSE) {
|
|
|
|
Disable-IcingaFrameworkConsoleOutput;
|
|
|
|
# Add our "old" swap internally
|
|
$OldConfigSwap = Get-IcingaPowerShellConfig -Path 'Framework.Config.Swap';
|
|
|
|
[hashtable]$IcingaConfiguration = Convert-IcingaForwindowsManagementConsoleJSONConfig -Config (ConvertFrom-Json -InputObject $InstallCommand);
|
|
|
|
# First run our configuration values
|
|
Invoke-IcingaForWindowsManagementConsoleCustomConfig -IcingaConfiguration $IcingaConfiguration;
|
|
|
|
# In case we use the director, we require to first fetch all basic values from the Self-Service API then
|
|
# require to register the host to fet the remaining content
|
|
if ($IcingaConfiguration.ContainsKey('IfW-DirectorSelfServiceKey') -And $IcingaConfiguration.ContainsKey('IfW-DirectorUrl')) {
|
|
Resolve-IcingaForWindowsManagementConsoleInstallationDirectorTemplate;
|
|
Resolve-IcingaForWindowsManagementConsoleInstallationDirectorTemplate -Register;
|
|
Disable-IcingaFrameworkConsoleOutput;
|
|
} else {
|
|
# Now load all remaining values we haven't set and define the defaults
|
|
Add-IcingaForWindowsInstallationAdvancedEntries;
|
|
}
|
|
|
|
# Now apply our configuration again to ensure the defaults are overwritten again
|
|
# Suite a mess, but we can improve this later
|
|
Invoke-IcingaForWindowsManagementConsoleCustomConfig -IcingaConfiguration $IcingaConfiguration;
|
|
|
|
Enable-IcingaFrameworkConsoleOutput;
|
|
|
|
Start-IcingaForWindowsInstallation -Automated;
|
|
|
|
# Set our "old" swap live again. By doing so, we can still continue our old
|
|
# configuration
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Config.Swap' -Value $OldConfigSwap;
|
|
|
|
return;
|
|
}
|
|
|
|
while ($TRUE) {
|
|
|
|
# Do nothing else anymore in case we are closing the management console
|
|
if ($global:Icinga.InstallWizard.Closing) {
|
|
break;
|
|
}
|
|
|
|
$FrameworkInstalled = Get-IcingaPowerShellConfig -Path 'Framework.Installed';
|
|
|
|
if ($null -eq $FrameworkInstalled) {
|
|
$FrameworkInstalled = $FALSE;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($global:Icinga.InstallWizard.NextCommand) -Or $global:Icinga.InstallWizard.NextCommand -eq 'Install-Icinga') {
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'What do you want to do?' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Installation';
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuInstallWindows';
|
|
'Help' = 'Allows you to install Icinga for Windows with all required components and options.'
|
|
},
|
|
@{
|
|
'Caption' = 'Install Components';
|
|
'Command' = 'Show-IcingaForWindowsMenuInstallComponents';
|
|
'Help' = 'Allows you to install new components for Icinga for Windows from your repositories.';
|
|
},
|
|
@{
|
|
'Caption' = 'Update environment';
|
|
'Command' = 'Show-IcingaForWindowsMenuUpdateComponents';
|
|
'Help' = 'Allows you to modify your current Icinga for Windows installation.';
|
|
},
|
|
@{
|
|
'Caption' = 'Manage environment';
|
|
'Command' = 'Show-IcingaForWindowsMenuManage';
|
|
'Help' = 'Allows you to modify your current Icinga for Windows installation.';
|
|
},
|
|
@{
|
|
'Caption' = 'Remove components';
|
|
'Command' = 'Show-IcingaForWindowsMenuRemoveComponents';
|
|
'Help' = 'Allows you to modify your current Icinga for Windows installation.';
|
|
'Disabled' = (-Not ($global:Icinga.InstallWizard.AdminShell));
|
|
}
|
|
) `
|
|
-DefaultIndex 0;
|
|
} else {
|
|
$NextArguments = $global:Icinga.InstallWizard.NextArguments;
|
|
|
|
if ($global:Icinga.InstallWizard.NextCommand.Contains(':')) {
|
|
$NextArguments = @{
|
|
'Value' = ($global:Icinga.InstallWizard.NextCommand.Split(':')[1]);
|
|
};
|
|
$global:Icinga.InstallWizard.NextCommand = $global:Icinga.InstallWizard.NextCommand.Split(':')[0];
|
|
}
|
|
|
|
try {
|
|
if ($null -ne $NextArguments -And $NextArguments.Count -ne 0) {
|
|
& $global:Icinga.InstallWizard.NextCommand @NextArguments;
|
|
} else {
|
|
& $global:Icinga.InstallWizard.NextCommand;
|
|
}
|
|
} catch {
|
|
$ErrMsg = $_.Exception.Message;
|
|
|
|
$global:Icinga.InstallWizard.LastError = [string]::Format('Failed to enter menu "{0}". Error "{1}', $global:Icinga.InstallWizard.NextCommand, $ErrMsg);
|
|
$global:Icinga.InstallWizard.NextCommand = 'Install-Icinga';
|
|
$global:Icinga.InstallWizard.NextArguments = @{ };
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function Start-IcingaForWindowsInstallation()
|
|
{
|
|
param (
|
|
[switch]$Automated
|
|
);
|
|
|
|
if ((Get-IcingaFrameworkDebugMode) -eq $FALSE) {
|
|
Clear-Host;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Starting Icinga for Windows installation';
|
|
|
|
$ConnectionType = Get-IcingaForWindowsInstallerStepSelection -InstallerStep 'Show-IcingaForWindowsInstallerMenuSelectConnection';
|
|
$HostnameType = Get-IcingaForWindowsInstallerStepSelection -InstallerStep 'Show-IcingaForWindowsInstallerMenuSelectHostname';
|
|
$FirewallType = Get-IcingaForWindowsInstallerStepSelection -InstallerStep 'Show-IcingaForWindowsInstallerMenuSelectOpenWindowsFirewall';
|
|
|
|
# Certificate handler
|
|
$CertificateType = Get-IcingaForWindowsInstallerStepSelection -InstallerStep 'Show-IcingaForWindowsInstallerMenuSelectCertificate';
|
|
$CertificateTicket = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallerMenuEnterIcingaTicket';
|
|
$CertificateCAFile = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallerMenuEnterIcingaCAFile';
|
|
|
|
# Icinga Agent
|
|
$AgentVersion = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallationMenuEnterIcingaAgentVersion';
|
|
$InstallIcingaAgent = Get-IcingaForWindowsInstallerStepSelection -InstallerStep 'Show-IcingaForWindowsInstallerMenuSelectInstallIcingaAgent';
|
|
$AgentInstallDir = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallationMenuEnterIcingaAgentDirectory';
|
|
$ServiceUser = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallationMenuEnterIcingaAgentUser';
|
|
$ServicePassword = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallationMenuEnterIcingaAgentServicePassword';
|
|
|
|
# Icinga for Windows Service
|
|
$InstallPSService = Get-IcingaForWindowsInstallerStepSelection -InstallerStep 'Show-IcingaForWindowsInstallerMenuSelectInstallIcingaForWindowsService';
|
|
$WindowsServiceDir = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallationMenuEnterWindowsServiceDirectory';
|
|
|
|
# Icinga for Windows Plugins
|
|
$InstallPluginChoice = Get-IcingaForWindowsInstallerStepSelection -InstallerStep 'Show-IcingaForWindowsInstallerMenuSelectInstallIcingaPlugins';
|
|
|
|
# Global Zones
|
|
$GlobalZonesType = Get-IcingaForWindowsInstallerStepSelection -InstallerStep 'Show-IcingaForWindowsInstallerMenuSelectGlobalZones';
|
|
$GlobalZonesCustom = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallationMenuEnterCustomGlobalZones';
|
|
|
|
# Icinga Endpoint Configuration
|
|
$IcingaZone = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentZone';
|
|
$IcingaEndpoints = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentNodes';
|
|
$IcingaPort = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallationMenuEnterIcingaPort';
|
|
|
|
# Repository
|
|
$IcingaStableRepo = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallationMenuStableRepository';
|
|
|
|
# JEA Profile
|
|
$InstallJEAProfile = Get-IcingaForWindowsInstallerStepSelection -InstallerStep 'Show-IcingaForWindowsInstallerMenuSelectInstallJEAProfile';
|
|
|
|
$Hostname = '';
|
|
$GlobalZones = @();
|
|
$IcingaParentAddresses = @();
|
|
$ServicePackageSource = ''
|
|
$ServiceSourceGitHub = $FALSE;
|
|
$InstallAgent = $TRUE;
|
|
$InstallService = $TRUE;
|
|
$InstallPlugins = $TRUE;
|
|
$PluginPackageRelease = $FALSE;
|
|
$PluginPackageSnapshot = $FALSE;
|
|
|
|
if ([string]::IsNullOrEmpty($IcingaStableRepo) -eq $FALSE) {
|
|
Add-IcingaRepository -Name 'Icinga Stable' -RemotePath $IcingaStableRepo;
|
|
}
|
|
|
|
foreach ($endpoint in $IcingaEndpoints) {
|
|
$EndpointAddress = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses' -Parent $endpoint;
|
|
|
|
$IcingaParentAddresses += $EndpointAddress;
|
|
}
|
|
|
|
switch ($HostnameType) {
|
|
'0' {
|
|
$Hostname = (Get-IcingaHostname -AutoUseFQDN 1);
|
|
break;
|
|
};
|
|
'1' {
|
|
$Hostname = (Get-IcingaHostname -AutoUseFQDN 1 -LowerCase 1);
|
|
break;
|
|
};
|
|
'2' {
|
|
$Hostname = (Get-IcingaHostname -AutoUseFQDN 1 -UpperCase 1);
|
|
break;
|
|
};
|
|
'3' {
|
|
$Hostname = (Get-IcingaHostname -AutoUseHostname 1);
|
|
break;
|
|
};
|
|
'4' {
|
|
$Hostname = (Get-IcingaHostname -AutoUseHostname 1 -LowerCase 1);
|
|
break;
|
|
};
|
|
'5' {
|
|
$Hostname = (Get-IcingaHostname -AutoUseHostname 1 -UpperCase 1);
|
|
break;
|
|
};
|
|
}
|
|
|
|
switch ($GlobalZonesType) {
|
|
'0' {
|
|
$GlobalZones += 'director-global';
|
|
$GlobalZones += 'global-templates';
|
|
break;
|
|
};
|
|
'1' {
|
|
$GlobalZones += 'director-global';
|
|
break;
|
|
}
|
|
'2' {
|
|
$GlobalZones += 'global-templates';
|
|
break;
|
|
}
|
|
}
|
|
|
|
foreach ($zone in $GlobalZonesCustom) {
|
|
if ([string]::IsNullOrEmpty($zone) -eq $FALSE) {
|
|
if ($GlobalZones -Contains $zone) {
|
|
continue;
|
|
}
|
|
|
|
$GlobalZones += $zone;
|
|
}
|
|
}
|
|
|
|
switch ($InstallIcingaAgent) {
|
|
'0' {
|
|
# Install Icinga Agent from packages.icinga.com
|
|
$InstallAgent = $TRUE;
|
|
break;
|
|
};
|
|
'1' {
|
|
# Do not install Icinga Agent
|
|
$InstallAgent = $FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch ($InstallPSService) {
|
|
'0' {
|
|
# Install Icinga for Windows Service
|
|
$InstallService = $TRUE;
|
|
break;
|
|
};
|
|
'1' {
|
|
# Do not install Icinga for Windows service
|
|
$InstallService = $FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch ($InstallPluginChoice) {
|
|
'0' {
|
|
# Download stable release
|
|
$PluginPackageRelease = $TRUE;
|
|
break;
|
|
};
|
|
'1' {
|
|
# Do not install plugins
|
|
$InstallPlugins = $FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($InstallAgent) {
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Icinga.AgentLocation' -Value $AgentInstallDir;
|
|
Install-IcingaComponent -Name 'agent' -Version $AgentVersion -Confirm -Release;
|
|
Reset-IcingaAgentConfigFile;
|
|
Move-IcingaAgentDefaultConfig;
|
|
Set-IcingaAgentNodeName -Hostname $Hostname;
|
|
Set-IcingaAgentServiceUser -User $ServiceUser -Password (ConvertTo-IcingaSecureString $ServicePassword) -SetPermission | Out-Null;
|
|
Install-IcingaAgentBaseFeatures;
|
|
Write-IcingaAgentApiConfig -Port $IcingaPort;
|
|
}
|
|
|
|
if ((Install-IcingaAgentCertificates -Hostname $Hostname -Endpoint $IcingaParentAddresses[0] -Port $IcingaPort -CACert $CertificateCAFile -Ticket $CertificateTicket) -eq $FALSE) {
|
|
Disable-IcingaAgentFeature 'api';
|
|
Write-IcingaConsoleWarning `
|
|
-Message '{0}{1}{2}{3}{4}' `
|
|
-Objects (
|
|
'Your Icinga Agent API feature has been disabled. Please provide either your ca.crt ',
|
|
'or connect to a parent node for certificate requests. You can run "Install-IcingaAgentCertificates" ',
|
|
'with your configuration to properly create the host certificate and a valid certificate request. ',
|
|
'After this you can enable the API feature by using "Enable-IcingaAgentFeature api" and restart the ',
|
|
'Icinga Agent service "Restart-IcingaService icinga2"'
|
|
);
|
|
}
|
|
|
|
Write-IcingaAgentZonesConfig -Endpoints $IcingaEndpoints -EndpointConnections $IcingaParentAddresses -ParentZone $IcingaZone -GlobalZones $GlobalZones -Hostname $Hostname;
|
|
|
|
if ($InstallService) {
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Icinga.IcingaForWindowsService' -Value $WindowsServiceDir;
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Icinga.ServiceUser' -User $ServiceUser;
|
|
Set-IcingaInternalPowerShellServicePassword -Password (ConvertTo-IcingaSecureString $ServicePassword);
|
|
|
|
Install-IcingaComponent -Name 'service' -Release -Confirm;
|
|
Register-IcingaBackgroundDaemon -Command 'Start-IcingaServiceCheckDaemon';
|
|
}
|
|
|
|
if ($InstallPlugins) {
|
|
Install-IcingaComponent -Name 'plugins' -Release:$PluginPackageRelease -Snapshot:$PluginPackageSnapshot -Confirm;
|
|
}
|
|
|
|
switch ($FirewallType) {
|
|
'0' {
|
|
# Open Windows Firewall
|
|
Enable-IcingaFirewall -IcingaPort $IcingaPort -Force;
|
|
break;
|
|
};
|
|
'1' {
|
|
# Close Windows Firewall
|
|
Disable-IcingaFirewall;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Write-IcingaFrameworkCodeCache;
|
|
Test-IcingaAgent;
|
|
|
|
if ($InstallAgent) {
|
|
Restart-IcingaService 'icinga2';
|
|
}
|
|
|
|
if ($InstallService) {
|
|
Restart-IcingaService 'icingapowershell';
|
|
}
|
|
|
|
switch ($InstallJEAProfile) {
|
|
'0' {
|
|
Install-IcingaJEAProfile;
|
|
break;
|
|
};
|
|
'1' {
|
|
Install-IcingaSecurity;
|
|
break;
|
|
};
|
|
'2' {
|
|
# Do not install JEA profile
|
|
}
|
|
}
|
|
|
|
# Update configuration and clear swap
|
|
$ConfigSwap = Get-IcingaPowerShellConfig -Path 'Framework.Config.Swap';
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Config.Swap' -Value $null;
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Config.Live' -Value $ConfigSwap;
|
|
$global:Icinga.InstallWizard.Config = @{ };
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Installed' -Value $TRUE;
|
|
|
|
if ($Automated -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'Icinga for Windows is installed. Returning to main menu in 5 seconds'
|
|
Start-Sleep -Seconds 5;
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.NextCommand = 'Install-Icinga';
|
|
$global:Icinga.InstallWizard.NextArguments = @{ };
|
|
}
|
|
|
|
function Add-IcingaForWindowsInstallationAdvancedEntries()
|
|
{
|
|
$ConnectionConfiguration = Get-IcingaForWindowsInstallerStepSelection -InstallerStep 'Show-IcingaForWindowsInstallerMenuSelectConnection';
|
|
|
|
$OpenFirewall = '1'; # Do not open firewall
|
|
if ($ConnectionConfiguration -ne '0') {
|
|
$OpenFirewall = '0';
|
|
}
|
|
|
|
Disable-IcingaFrameworkConsoleOutput;
|
|
|
|
Show-IcingaForWindowsInstallationMenuEnterIcingaPort -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallerMenuSelectOpenWindowsFirewall -DefaultInput $OpenFirewall -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallerMenuSelectCertificate -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallerMenuSelectGlobalZones -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallationMenuEnterCustomGlobalZones -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallationMenuEnterIcingaAgentVersion -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallerMenuSelectInstallIcingaAgent -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallationMenuEnterIcingaAgentDirectory -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallationMenuEnterIcingaAgentUser -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallerMenuSelectInstallIcingaPlugins -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallerMenuSelectInstallIcingaForWindowsService -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallationMenuEnterWindowsServiceDirectory -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallationMenuStableRepository -Automated -Advanced;
|
|
Show-IcingaForWindowsInstallerMenuSelectInstallJEAProfile -Automated -Advanced;
|
|
|
|
Enable-IcingaFrameworkConsoleOutput;
|
|
|
|
$global:Icinga.InstallWizard.NextCommand = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
}
|
|
|
|
function Show-IcingaForWindowsInstallationMenuEnterIcingaAgentDirectory()
|
|
{
|
|
param (
|
|
[array]$Value = @( (Join-Path -Path $Env:ProgramFiles -ChildPath 'ICINGA2') ),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Enter the path where to install the Icinga Agent into:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Allows you to override the location on where the Icinga Agent will be installed into';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues @( $Value ) `
|
|
-MandatoryValue `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-AgentDirectory' -Value 'Show-IcingaForWindowsInstallationMenuEnterIcingaAgentDirectory';
|
|
|
|
function Show-IcingaForWindowsInstallationMenuEnterIcingaAgentServicePassword()
|
|
{
|
|
param (
|
|
[array]$Value = @( ),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please enter the password for your service. Not required for system users!' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Allows you to provide a password for a service user account. This is only required for custom users, like a local or domain user. The default user does not require a password and should be left empty in this case';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-PasswordInput `
|
|
-DefaultValues @( $Value ) `
|
|
-MandatoryValue `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-ServicePassword' -Value 'Show-IcingaForWindowsInstallationMenuEnterIcingaAgentServicePassword';
|
|
|
|
function Show-IcingaForWindowsInstallationMenuEnterIcingaAgentUser()
|
|
{
|
|
param (
|
|
[array]$Value = @( 'NT Authority\NetworkService' ),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please define the user the Icinga Agent service should run with:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallationMenuEnterIcingaAgentServicePassword';
|
|
'Help' = 'Allows you to override the default user the Icinga Agent is running with as service. In case a password is required, you can add it in the next step';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues @( $Value ) `
|
|
-MandatoryValue `
|
|
-JumpToSummary:$FALSE `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
|
|
# Remove a defined password in case we are running system services
|
|
[string]$ServiceUser = Get-IcingaForWindowsInstallerValuesFromStep;
|
|
|
|
if ([string]::IsNullOrEmpty($ServiceUser) -eq $FALSE) {
|
|
$ServiceUser = $ServiceUser.ToLower();
|
|
} else {
|
|
$global:Icinga.InstallWizard.NextCommand = 'Show-IcingaForWindowsInstallationMenuEnterIcingaAgentUser';
|
|
return;
|
|
}
|
|
|
|
if ($ServiceUser -eq 'networkservice' -Or $ServiceUser -eq 'nt authority\networkservice' -Or $ServiceUser -eq 'localsystem' -Or $ServiceUser -eq 'nt authority\localservice' -Or $ServiceUser -eq 'localservice') {
|
|
Remove-IcingaForWindowsInstallerConfigEntry -Menu 'Show-IcingaForWindowsInstallationMenuEnterIcingaAgentServicePassword';
|
|
$global:Icinga.InstallWizard.NextCommand = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
$global:Icinga.InstallWizard.NextArguments = @{ };
|
|
} else {
|
|
$global:Icinga.InstallWizard.NextCommand = 'Show-IcingaForWindowsInstallationMenuEnterIcingaAgentServicePassword';
|
|
}
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-AgentUser' -Value 'Show-IcingaForWindowsInstallationMenuEnterIcingaAgentUser';
|
|
|
|
function Show-IcingaForWindowsInstallationMenuEnterIcingaAgentVersion()
|
|
{
|
|
param (
|
|
[array]$Value = @( 'release' ),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please specify the version of the Icinga Agent you want to install:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Allows you to define which Icinga Agent version is installed on this system. The installer will search for the .MSI package for the specified version on the source location. You can either use "release" to install the highest version found, use "snapshot" to install snapshot packages or specify a direct version like "2.12.3"';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues @( $Value ) `
|
|
-MandatoryValue `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-AgentVersion' -Value 'Show-IcingaForWindowsInstallationMenuEnterIcingaAgentVersion';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuSelectInstallIcingaAgent()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = '0',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please select if the Icinga Agent should be installed' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Install Icinga Agent';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Downloads the Icinga Agent from the specified stable repository and installs it';
|
|
},
|
|
@{
|
|
'Caption' = 'Do not install Icinga Agent';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Do not install the Icinga Agent on this system';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-JumpToSummary:$FALSE `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-InstallAgent' -Value 'Show-IcingaForWindowsInstallerMenuSelectInstallIcingaAgent';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuEnterIcingaCAFile()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
$Advanced = $TRUE;
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please enter the path to your ca.crt file. This can be a local, network share or web address:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'To sign certificates locally you can copy the Icinga CA master "ca.crt" file (normally located at "/var/lib/icinga2/ca") to a location you can access from this host. Enter the full path on where you stored the "ca.crt" file. You can provide a local path "C:\users\public\ca.crt", a network share "\\share.example.com\icinga\ca.crt" or a web address "https://example.com/icinga/ca.crt"';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues @( $Value ) `
|
|
-MandatoryValue `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-CAFile' -Value 'Show-IcingaForWindowsInstallerMenuEnterIcingaCAFile';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuEnterIcingaTicket()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
$Advanced = $TRUE;
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please enter your ticket for signing the Icinga certificate:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'The ticket required for signing your local Icinga certificate. You can get the ticket from the Icinga Director for this host or from your Icinga CA master by running "icinga2 pki ticket --cn <hostname as selected before>"';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues @( $Value ) `
|
|
-MandatoryValue `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-Ticket' -Value 'Show-IcingaForWindowsInstallerMenuEnterIcingaTicket';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuSelectCertificate()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = '0',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'How do you want to create the Icinga certificate?' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Sign certificate manually on the Icinga CA master';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'This option will not require you to provide additional details for certificate generation and only require a connection to/from this host. You will have to sign the certificate manually on the Icinga CA master with "icinga2 ca sign <request>"';
|
|
},
|
|
@{
|
|
'Caption' = 'Sign certificate with a ticket';
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuEnterIcingaTicket';
|
|
'Help' = 'By selecting this option, this host will connect to a parent Icinga node and sign the certificate with a ticket you have to provide in the next step';
|
|
},
|
|
@{
|
|
'Caption' = 'Sign certificate with local ca.crt';
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuEnterIcingaCAFile';
|
|
'Help' = 'This will allow you to sign the certificate for this host directly on this machine. For this you will have to store your Icinga ca.crt somewhere accessible to this system. In the next step you are asked to provide the path to the location of your ca.crt';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-JumpToSummary:$FALSE `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
|
|
# Make sure we delete configuration no longer required
|
|
switch (Get-IcingaForWindowsManagementConsoleLastInput) {
|
|
'0' {
|
|
Remove-IcingaForWindowsInstallerConfigEntry -Menu 'Show-IcingaForWindowsInstallerMenuEnterIcingaTicket';
|
|
Remove-IcingaForWindowsInstallerConfigEntry -Menu 'Show-IcingaForWindowsInstallerMenuEnterIcingaCAFile';
|
|
break;
|
|
};
|
|
'1' {
|
|
Remove-IcingaForWindowsInstallerConfigEntry -Menu 'Show-IcingaForWindowsInstallerMenuEnterIcingaCAFile';
|
|
break;
|
|
};
|
|
'2' {
|
|
Remove-IcingaForWindowsInstallerConfigEntry -Menu 'Show-IcingaForWindowsInstallerMenuEnterIcingaTicket';
|
|
break;
|
|
};
|
|
}
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-Certificate' -Value 'Show-IcingaForWindowsInstallerMenuSelectCertificate';
|
|
|
|
function Resolve-IcingaForWindowsManagementConsoleInstallationDirectorTemplate()
|
|
{
|
|
param (
|
|
[switch]$Register = $FALSE
|
|
);
|
|
|
|
$DirectorUrl = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsManagementConsoleInstallationEnterDirectorUrl';
|
|
$SelfServiceKey = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsManagementConsoleInstallationEnterDirectorSelfServiceKey';
|
|
|
|
# Once we run this menu, we require to reset everything to have a proper state
|
|
if ($Register -eq $FALSE) {
|
|
$global:Icinga.InstallWizard.Config = @{ };
|
|
|
|
Add-IcingaForWindowsInstallerConfigEntry -Selection 'c' -Values $DirectorUrl -OverwriteValues -OverwriteMenu 'Show-IcingaForWindowsManagementConsoleInstallationEnterDirectorUrl';
|
|
Add-IcingaForWindowsInstallerConfigEntry -Selection 'c' -Values $SelfServiceKey -OverwriteValues -OverwriteMenu 'Show-IcingaForWindowsManagementConsoleInstallationEnterDirectorSelfServiceKey';
|
|
} else {
|
|
$HostnameType = Get-IcingaForWindowsInstallerStepSelection -InstallerStep 'Show-IcingaForWindowsInstallerMenuSelectHostname';
|
|
$Hostname = '';
|
|
|
|
switch ($HostnameType) {
|
|
'0' {
|
|
$Hostname = (Get-IcingaHostname -AutoUseFQDN 1);
|
|
break;
|
|
};
|
|
'1' {
|
|
$Hostname = (Get-IcingaHostname -AutoUseFQDN 1 -LowerCase 1);
|
|
break;
|
|
};
|
|
'2' {
|
|
$Hostname = (Get-IcingaHostname -AutoUseFQDN 1 -UpperCase 1);
|
|
break;
|
|
};
|
|
'3' {
|
|
$Hostname = (Get-IcingaHostname -AutoUseHostname 1);
|
|
break;
|
|
};
|
|
'4' {
|
|
$Hostname = (Get-IcingaHostname -AutoUseHostname 1 -LowerCase 1);
|
|
break;
|
|
};
|
|
'5' {
|
|
$Hostname = (Get-IcingaHostname -AutoUseHostname 1 -UpperCase 1);
|
|
break;
|
|
};
|
|
}
|
|
|
|
try {
|
|
$SelfServiceKey = Register-IcingaDirectorSelfServiceHost -DirectorUrl $DirectorUrl -ApiKey $SelfServiceKey -Hostname $Hostname;
|
|
} catch {
|
|
Write-IcingaConsoleNotice 'Host seems already to be registered within Icinga Director. Trying local Api key if present'
|
|
$SelfServiceKey = Get-IcingaPowerShellConfig -Path 'IcingaDirector.SelfService.ApiKey';
|
|
|
|
if ([string]::IsNullOrEmpty($SelfServiceKey)) {
|
|
Write-IcingaConsoleNotice 'No local Api key was found and using your provided template key failed. Please ensure the host is not already registered and drop the set Self-Service key within the Icinga Director for this host.'
|
|
}
|
|
}
|
|
Add-IcingaForWindowsInstallerConfigEntry -Selection 'c' -Values $SelfServiceKey -OverwriteValues -OverwriteMenu 'Show-IcingaForWindowsManagementConsoleInstallationEnterDirectorSelfServiceKey';
|
|
}
|
|
|
|
try {
|
|
$DirectorConfig = Get-IcingaDirectorSelfServiceConfig -DirectorUrl $DirectorUrl -ApiKey $SelfServiceKey;
|
|
} catch {
|
|
Set-IcingaForWindowsManagementConsoleMenu 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
$global:Icinga.InstallWizard.LastError = 'Failed to fetch host configuration with the given Director Url and Self-Service key. Please ensure the template key is correct and in case a previous host key was used, that it matches the one configured within the Icinga Director. In case this form was loaded previously with a key, it might be that the host key is no longer valid and requires to be dropped. In addition please ensure that this host can connect to the Icinga Director and the SSL certificate is trusted. Otherwise run "Enable-IcingaUntrustedCertificateValidation" before starting the management console. Otherwise modify the "DirectorSelfServiceKey" configuration element above with the correct key and try again.';
|
|
return;
|
|
}
|
|
|
|
# No we need to identify which host selection is matching our config
|
|
$HostnameSelection = -1;
|
|
$InstallPluginsSelection = -1;
|
|
$InstallServiceSelection = -1;
|
|
$WindowsFirewallSelection = 1;
|
|
|
|
$ServiceUserName = $DirectorConfig.icinga_service_user;
|
|
$AgentPackageSelection = 1; #Always use custom source
|
|
$AgentPackageSource = $DirectorConfig.download_url;
|
|
$AgentVersion = $DirectorConfig.release;
|
|
$IcingaPort = $DirectorConfig.agent_listen_port;
|
|
$GlobalZones = @();
|
|
$IcingaParents = @();
|
|
$IcingaParentAddresses = New-Object PSCustomObject;
|
|
$ParentZone = '';
|
|
$MasterAddress = '';
|
|
|
|
if ($DirectorUrl.ToLower().Contains('https://') -Or $DirectorUrl.ToLower().Contains('http://')) {
|
|
$MasterAddress = $DirectorUrl.Split('/')[2];
|
|
} else {
|
|
$MasterAddress = $DirectorUrl.Split('/')[0];
|
|
}
|
|
|
|
if ($Register) {
|
|
if ($null -ne $DirectorConfig.agent_add_firewall_rule -And $DirectorConfig.agent_add_firewall_rule) {
|
|
# Open Windows Firewall
|
|
$WindowsFirewallSelection = 0;
|
|
}
|
|
|
|
if ($null -ne $DirectorConfig.global_zones) {
|
|
$GlobalZones = $DirectorConfig.global_zones;
|
|
}
|
|
|
|
if ($null -ne $DirectorConfig.parent_endpoints) {
|
|
$IcingaParents = $DirectorConfig.parent_endpoints;
|
|
}
|
|
|
|
if ($null -ne $DirectorConfig.endpoints_config) {
|
|
[int]$Index = 0;
|
|
foreach ($entry in $DirectorConfig.endpoints_config) {
|
|
$IcingaParentAddresses | Add-Member -MemberType NoteProperty -Name ($IcingaParents[$Index]) -Value (($entry.Split(';')[0]));
|
|
$Index += 1;
|
|
}
|
|
}
|
|
|
|
if ($null -ne $DirectorConfig.parent_zone) {
|
|
$ParentZone = $DirectorConfig.parent_zone;
|
|
}
|
|
}
|
|
|
|
if ($DirectorConfig.fetch_agent_fqdn) {
|
|
switch ($DirectorConfig.transform_hostname) {
|
|
'0' {
|
|
# FQDN as it is
|
|
$HostnameSelection = 0;
|
|
break;
|
|
};
|
|
'1' {
|
|
# FQDN to lowercase
|
|
$HostnameSelection = 1;
|
|
break;
|
|
};
|
|
'2' {
|
|
# FQDN to uppercase
|
|
$HostnameSelection = 2;
|
|
break;
|
|
}
|
|
}
|
|
} elseif ($DirectorConfig.fetch_agent_name) {
|
|
switch ($DirectorConfig.transform_hostname) {
|
|
'0' {
|
|
# Hostname as it is
|
|
$HostnameSelection = 3;
|
|
break;
|
|
};
|
|
'1' {
|
|
# Hostname to lowercase
|
|
$HostnameSelection = 4;
|
|
break;
|
|
};
|
|
'2' {
|
|
# Hostname to uppercase
|
|
$HostnameSelection = 5;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($DirectorConfig.install_framework_service -eq 0) {
|
|
# Do not install
|
|
$InstallServiceSelection = 1;
|
|
} else {
|
|
$InstallServiceSelection = 0;
|
|
}
|
|
|
|
if ($DirectorConfig.install_framework_plugins -eq 0) {
|
|
# Do not install
|
|
$InstallPluginsSelection = 1;
|
|
} else {
|
|
# TODO: This is currently not supported. We use the "default" config for installing from GitHub by now
|
|
$InstallPluginsSelection = 0;
|
|
}
|
|
|
|
Disable-IcingaFrameworkConsoleOutput;
|
|
Show-IcingaForWindowsInstallerMenuSelectHostname -DefaultInput $HostnameSelection -Automated;
|
|
Add-IcingaForWindowsInstallationAdvancedEntries;
|
|
Disable-IcingaFrameworkConsoleOutput;
|
|
|
|
Show-IcingaForWindowsInstallerMenuSelectInstallIcingaPlugins -DefaultInput $InstallPluginsSelection -Value @() -Automated;
|
|
Show-IcingaForWindowsInstallerMenuSelectInstallIcingaForWindowsService -DefaultInput $InstallServiceSelection -Value @() -Automated;
|
|
Show-IcingaForWindowsInstallerMenuSelectOpenWindowsFirewall -DefaultInput $WindowsFirewallSelection -Value @() -Automated;
|
|
|
|
if ($Register) {
|
|
Show-IcingaForWindowsInstallationMenuEnterCustomGlobalZones -Value $GlobalZones -Automated;
|
|
Show-IcingaForWindowsInstallerMenuEnterIcingaParentNodes -Value $IcingaParents -Automated;
|
|
Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses -Value $IcingaParentAddresses -Automated;
|
|
Show-IcingaForWindowsInstallerMenuEnterIcingaParentZone -Value $ParentZone -Automated;
|
|
}
|
|
|
|
Show-IcingaForWindowsManagementConsoleInstallationDirectorRegisterHost -Automated;
|
|
|
|
Enable-IcingaFrameworkConsoleOutput;
|
|
Reset-IcingaForWindowsManagementConsoleInstallationDirectorConfigModifyState;
|
|
}
|
|
|
|
function Show-IcingaForWindowsManagementConsoleInstallationEnterDirectorUrl()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please enter the URL pointing to your Icinga Director module:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleInstallationEnterDirectorSelfServiceKey';
|
|
'Help' = 'The Icinga Web 2 url pointing directly to the root of the Icinga Director module. Example: "https://example.com/icingaweb2/director" or "https://icinga.example.com/director"';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues $Value `
|
|
-MandatoryValue `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-DirectorUrl' -Value 'Show-IcingaForWindowsManagementConsoleInstallationEnterDirectorUrl';
|
|
|
|
function Show-IcingaForWindowsManagementConsoleInstallationDirectorRegisterHost()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = '0',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
$Advanced = $TRUE;
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Do you want to register the host right now inside the Icinga Director? This will show missing configurations.' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Do not register host inside Icinga Director';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'If you do not want to modify extended properties for this host and use default values from the Icinga Director, based on the Self-Service API configuration, use this option and complete the installation process afterwards.';
|
|
},
|
|
@{
|
|
'Caption' = 'Register host inside Icinga Director';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'You can select this option to register the host within the Icinga Director right now, unlocking more advanced configurations for this host like "Parent Zone", "Parent Nodes" and "Parent Node Addresses"';
|
|
'Action' = @{
|
|
'Command' = 'Resolve-IcingaForWindowsManagementConsoleInstallationDirectorTemplate';
|
|
'Arguments' = @{
|
|
'-Register' = $TRUE;
|
|
}
|
|
}
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-JumpToSummary:$FALSE `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-DirectorRegisterHost' -Value 'Show-IcingaForWindowsManagementConsoleInstallationDirectorRegisterHost';
|
|
|
|
function Show-IcingaForWindowsManagementConsoleInstallationEnterDirectorSelfServiceKey()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
if ($null -eq $Value -or $Value.Count -eq 0) {
|
|
$LocalApiKey = Get-IcingaPowerShellConfig -Path 'IcingaDirector.SelfService.ApiKey';
|
|
if ([string]::IsNullOrEmpty($LocalApiKey) -eq $FALSE) {
|
|
$Value += $LocalApiKey;
|
|
}
|
|
}
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please enter the Self-Service API key for the Host-Template to use:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'This is the Self-Service API for the host template to use. To get this, you will have to set the host template to be an "Icinga 2 Agent" template inside the Icinga Director. Afterwards you see an "Agent" tab on the top right navigation, providing you with the key. In case you entered this menu for the first time and see a key already present, this means the installer already run once and therefor you will be presented with your host key. If a host is already present within the Icinga Director, you can also use the "Agent" tab to get the key of this host directly to enter here';
|
|
'Action' = @{
|
|
'Command' = 'Resolve-IcingaForWindowsManagementConsoleInstallationDirectorTemplate';
|
|
'Arguments' = @{
|
|
'-Register' = $FALSE;
|
|
}
|
|
}
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues $Value `
|
|
-MandatoryValue `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-DirectorSelfServiceKey' -Value 'Show-IcingaForWindowsManagementConsoleInstallationEnterDirectorSelfServiceKey';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuSelectOpenWindowsFirewall()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = '1',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please select if your Windows Firewall should be opened for the Icinga port:' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Open Windows Firewall for incoming Icinga connections';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'This will open the Windows Firewall for the configured Icinga Port, to allow incoming communication from Icinga parent node(s)';
|
|
},
|
|
@{
|
|
'Caption' = 'Do not open Windows Firewall for incoming Icinga connections';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Do not open the Windows firewall for any incoming Icinga connections. Please note that in case your Icinga Agent is configured for "Connecting from parent system" you will not be able to establish a communication unless the connection type is changed or the port is opened';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-JumpToSummary:$FALSE `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-WindowsFirewall' -Value 'Show-IcingaForWindowsInstallerMenuSelectOpenWindowsFirewall';
|
|
|
|
function Show-IcingaForWindowsInstallationMenuStableRepository()
|
|
{
|
|
param (
|
|
[array]$Value = @( 'https://packages.icinga.com/IcingaForWindows/stable' ),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please enter the path or Url for your stable Icinga repository:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'This is the stable repository from where all packages of Icinga for Windows are downloaded and intstalled from. Defaults to "https://packages.icinga.com/IcingaForWindows/stable"';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues @( $Value ) `
|
|
-MandatoryValue `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-StableRepository' -Value 'Show-IcingaForWindowsInstallationMenuStableRepository';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuSelectInstallJEAProfile()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = '2',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
if ($PSVersionTable.PSVersion -lt '5.0.0.0') {
|
|
return;
|
|
}
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please select if you want to install the JEA profile for the assigned service user or to create a managed user' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Install JEA Profile';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Installs the Icinga for Windows JEA profile for the specified service user';
|
|
},
|
|
@{
|
|
'Caption' = 'Install JEA Profile with managed user "IcingaForWindows"';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Installs the Icinga for Windows JEA profile with a newly created, managed user "IcingaForWindows". This will override your service and service password configuration';
|
|
},
|
|
@{
|
|
'Caption' = 'Do not install JEA Profile';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Do not install the Icinga for Windows JEA profile';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-JumpToSummary:$FALSE `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-InstallJEAProfile' -Value 'Show-IcingaForWindowsInstallerMenuSelectInstallJEAProfile';
|
|
|
|
function Show-IcingaForWindowsInstallerConfigurationSummary()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
[array]$Entries = @();
|
|
[int]$CurrentIndex = 0
|
|
|
|
Enable-IcingaForWindowsInstallationHeaderPrint;
|
|
|
|
while ($TRUE) {
|
|
if ($CurrentIndex -gt $global:Icinga.InstallWizard.Config.Count) {
|
|
break;
|
|
}
|
|
|
|
foreach ($entry in $global:Icinga.InstallWizard.Config.Keys) {
|
|
$ConfigEntry = $global:Icinga.InstallWizard.Config[$entry];
|
|
|
|
if ($ConfigEntry.Index -ne $CurrentIndex) {
|
|
continue;
|
|
}
|
|
|
|
if ($ConfigEntry.Hidden) {
|
|
continue;
|
|
}
|
|
|
|
if ($ConfigEntry.Advanced -And $global:Icinga.InstallWizard.ShowAdvanced -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
$EntryValue = $ConfigEntry.Selection;
|
|
if ($null -ne $ConfigEntry.Values -And $ConfigEntry.Count -ne 0) {
|
|
if ($ConfigEntry.Password) {
|
|
$EntryValue = ConvertFrom-IcingaArrayToString -Array $ConfigEntry.Values -AddQuotes -SecureContent;
|
|
} else {
|
|
$EntryValue = ConvertFrom-IcingaArrayToString -Array $ConfigEntry.Values -AddQuotes;
|
|
}
|
|
}
|
|
|
|
[string]$Caption = ''
|
|
$PrintName = $entry;
|
|
$RealCommand = $entry;
|
|
$ChildElement = '';
|
|
|
|
if ($RealCommand.Contains(':')) {
|
|
$RealCommand = $entry.Split(':')[0];
|
|
$ChildElement = $entry.Split(':')[1];
|
|
}
|
|
|
|
if ($entry.Contains(':')) {
|
|
$PrintName = [string]::Format('{0} for "{1}"', $RealCommand, $ChildElement);
|
|
} else {
|
|
$PrintName = $RealCommand;
|
|
}
|
|
|
|
$PrintName = $PrintName.Replace('IfW-', '');
|
|
|
|
if (Test-Numeric ($ConfigEntry.Selection)) {
|
|
Set-IcingaForWindowsInstallationHeaderSelection -Selection $ConfigEntry.Selection;
|
|
|
|
&$RealCommand;
|
|
|
|
$Caption = ([string]::Format('{0}: {1}', $PrintName, $global:Icinga.InstallWizard.HeaderPreview));
|
|
} else {
|
|
$Caption = ([string]::Format('{0}: {1}', $PrintName, $EntryValue));
|
|
}
|
|
|
|
$Entries += @{
|
|
'Caption' = $Caption;
|
|
'Command' = $entry;
|
|
'Arguments' = @{ '-JumpToSummary' = $TRUE };
|
|
'Help' = ''
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.HeaderPreview = '';
|
|
}
|
|
|
|
$CurrentIndex += 1;
|
|
}
|
|
|
|
Disable-IcingaForWindowsInstallationHeaderPrint;
|
|
Enable-IcingaForWindowsInstallationJumpToSummary;
|
|
|
|
$global:Icinga.InstallWizard.DisplayAdvanced = $TRUE;
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please validate your configuration. Installation starts on continue:' `
|
|
-Entries $Entries `
|
|
-DefaultIndex 'c' `
|
|
-ContinueFunction 'Show-IcingaForWindowsInstallerMenuFinishInstaller' `
|
|
-ConfigElement `
|
|
-Hidden;
|
|
|
|
Disable-IcingaForWindowsInstallationJumpToSummary;
|
|
$global:Icinga.InstallWizard.DisplayAdvanced = $FALSE;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-ConfigurationSummary' -Value 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuContinueConfiguration()
|
|
{
|
|
$SwapConfig = Get-IcingaPowerShellConfig -Path 'Framework.Config.Swap';
|
|
$global:Icinga.InstallWizard.Config = Convert-IcingaForwindowsManagementConsoleJSONConfig -Config $SwapConfig;
|
|
[string]$Menu = Get-IcingaForWindowsInstallerLastParent;
|
|
|
|
# We don't need the last entry, as this will be added anyways because we are
|
|
# starting right from there and it will be added anyway
|
|
Remove-IcingaForWindowsInstallerLastParent;
|
|
|
|
if ($Menu.Contains(':')) {
|
|
$Menu = Get-IcingaForWindowsInstallerLastParent;
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.NextCommand = $Menu;
|
|
}
|
|
|
|
function Show-IcingaForWindowsInstallerMenuFinishInstaller()
|
|
{
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'How you do want to proceed:' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Start installation';
|
|
'Command' = 'Start-IcingaForWindowsInstallation';
|
|
'Help' = 'Apply the just configured configuration and install components as selected';
|
|
'Disabled' = (-Not ($global:Icinga.InstallWizard.AdminShell));
|
|
'Action' = @{
|
|
'Command' = 'Clear-IcingaForWindowsManagementConsolePaginationCache';
|
|
}
|
|
},
|
|
@{
|
|
'Caption' = 'Export answer file';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleInstallationFileExport';
|
|
'Help' = 'Allows you to export a JSON file containing all settings configured during this step and use it on another system';
|
|
},
|
|
@{
|
|
'Caption' = 'Print installation command';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleInstallationConfigString';
|
|
'Help' = 'Allows you to export a simple configuration command you can run on another system. Similar to the "Export answer file" option, but does not require to distribute files';
|
|
},
|
|
@{
|
|
'Caption' = 'Save current configuration and go to main menu';
|
|
'Command' = 'Install-Icinga';
|
|
'Help' = 'Keep the current configuration as "swap" and exit to the main menu';
|
|
'Action' = @{
|
|
'Command' = 'Clear-IcingaForWindowsManagementConsolePaginationCache';
|
|
}
|
|
}
|
|
) `
|
|
-DefaultIndex 0 `
|
|
-Hidden;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-FinishInstaller' -Value 'Show-IcingaForWindowsInstallerMenuFinishInstaller';
|
|
|
|
function Export-IcingaForWindowsManagementConsoleInstallationAnswerFile()
|
|
{
|
|
$FilePath = '';
|
|
$Value = $global:Icinga.InstallWizard.LastValues;
|
|
|
|
if ($null -ne $Value -And $Value.Count -ne 0) {
|
|
$FilePath = $Value[0]
|
|
}
|
|
|
|
if (Test-Path ($FilePath)) {
|
|
Set-Content -Path (Join-Path -Path $FilePath -ChildPath 'IfW_answer.json') -Value (Get-IcingaForWindowsManagementConsoleConfigurationString);
|
|
$global:Icinga.InstallWizard.NextCommand = 'Install-Icinga';
|
|
$global:Icinga.InstallWizard.LastNotice = ([string]::Format('Answer file "IfW_answer.json" successfully exported into "{0}"', $FilePath));
|
|
Clear-IcingaForWindowsManagementConsolePaginationCache;
|
|
} else {
|
|
$global:Icinga.InstallWizard.LastError = ([string]::Format('The provided path to store the answer file is invalid: "{0}"', $FilePath));
|
|
$global:Icinga.InstallWizard.NextCommand = 'Show-IcingaForWindowsManagementConsoleInstallationFileExport';
|
|
}
|
|
}
|
|
|
|
function Show-IcingaForWindowsManagementConsoleInstallationConfigString()
|
|
{
|
|
[string]$ConfigurationString = [string]::Format(
|
|
"{0}Install-Icinga -InstallCommand '{1}'{0}",
|
|
(New-IcingaNewLine),
|
|
(Get-IcingaForWindowsManagementConsoleConfigurationString -Compress)
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Here is your configuration command for Icinga for Windows:' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = '';
|
|
'Command' = 'Install-Icinga';
|
|
'Help' = 'This command provides a list of settings you entered or modified during the process. In case values are not modified, they do not show up here and are left as default. You can run this entire command on a different Windows host to apply the same configuration';
|
|
'Action' = @{
|
|
'Command' = 'Clear-IcingaForWindowsManagementConsolePaginationCache';
|
|
}
|
|
}
|
|
) `
|
|
-AddConfig `
|
|
-DefaultValues @( $ConfigurationString ) `
|
|
-ConfigLimit 1 `
|
|
-DefaultIndex 'c' `
|
|
-ReadOnly `
|
|
-Hidden;
|
|
}
|
|
|
|
function Show-IcingaForWindowsManagementConsoleInstallationFileExport()
|
|
{
|
|
$FilePath = $ENV:USERPROFILE;
|
|
|
|
if ($null -ne $global:Icinga.InstallWizard.LastValues -And $global:Icinga.InstallWizard.LastValues.Count -ne 0) {
|
|
$FilePath = $global:Icinga.InstallWizard.LastValues[0];
|
|
}
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Where do you want to export the answer file to? The filename "IfW_answer.json" is added automatically.' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = '';
|
|
'Command' = 'Export-IcingaForWindowsManagementConsoleInstallationAnswerFile';
|
|
'Help' = 'This will all you to export the answer file with the given configuration. You can install Icinga for Windows with this file by using the command "Install-Icinga -AnswerFile <path to the file>".';
|
|
}
|
|
) `
|
|
-AddConfig `
|
|
-DefaultValues @( $FilePath ) `
|
|
-ConfigLimit 1 `
|
|
-DefaultIndex 'c' `
|
|
-MandatoryValue `
|
|
-Hidden;
|
|
}
|
|
|
|
function Show-IcingaForWindowsInstallerMenuInstallWindows()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = '0',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
if ($null -eq (Get-IcingaPowerShellConfig -Path 'Framework.Config.Swap') -And $null -eq (Get-IcingaPowerShellConfig -Path 'Framework.Config.Live')) {
|
|
Show-IcingaForWindowsInstallerMenuSelectConnection;
|
|
return;
|
|
}
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Choose the configuration type:' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'New configuration';
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuNewConfiguration';
|
|
'Help' = 'Start a new configuration and truncate all information stored on the current swap file. This will only modify your production if you hit "Start installation" at the end';
|
|
},
|
|
@{
|
|
'Caption' = 'Continue configuration';
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuContinueConfiguration';
|
|
'Help' = 'Continue with the previous configuration swap file.';
|
|
'Disabled' = ([bool]($null -eq (Get-IcingaPowerShellConfig -Path 'Framework.Config.Swap')));
|
|
},
|
|
@{
|
|
'Caption' = 'Reconfigure Environment';
|
|
'Command' = 'Invoke-IcingaForWindowsManagementConsoleReconfigureAgent';
|
|
'Help' = 'Load the current configuration of Icinga for Windows to modify it.';
|
|
'Disabled' = ([bool]($null -eq (Get-IcingaPowerShellConfig -Path 'Framework.Config.Live')));
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
function Show-IcingaForWindowsInstallerMenuNewConfiguration()
|
|
{
|
|
$global:Icinga.InstallWizard.Config = @{ };
|
|
Show-IcingaForWindowsInstallerMenuSelectConnection;
|
|
}
|
|
|
|
function Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = $null,
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
if ($Value.Count -ne 0) {
|
|
|
|
while ($TRUE) {
|
|
# Use the installer file/command for automation
|
|
if ($Value[0].GetType().Name.ToLower() -eq 'pscustomobject') {
|
|
|
|
# This is just to handle automated installation by using a file or the install command
|
|
# We use a hashtable here as well, but reduce complexity and remove network checks
|
|
|
|
foreach ($endpoint in $Value[0].PSObject.Properties) {
|
|
Add-IcingaForWindowsInstallerConfigEntry -Selection 'c' -Values $endpoint.Value `
|
|
-OverwriteValues `
|
|
-OverwriteMenu 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses' `
|
|
-OverwriteParent ([string]::Format('Show-IcingaForWindowsInstallerMenuEnterIcingaParentNodes:{0}', $endpoint.Name));
|
|
}
|
|
|
|
return;
|
|
|
|
} elseif ($Value[0].GetType().Name.ToLower() -eq 'hashtable') { # We will be forwarded this from Test-IcingaForWindowsInstallerParentEndpoints
|
|
|
|
$NetworkMap = $Value[0];
|
|
[int]$AddressIndex = 0;
|
|
|
|
foreach ($entry in $NetworkMap.Keys) {
|
|
$EndpointConfig = $NetworkMap[$entry];
|
|
|
|
if ($EndpointConfig.Error -eq $FALSE) {
|
|
$AddressIndex += 1;
|
|
continue;
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.LastError = ([string]::Format('Failed to resolve the address for the following endpoint: {0}', $EndpointConfig.Endpoint));
|
|
|
|
$Address = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses' -Parent $EndpointConfig.Endpoint;
|
|
|
|
if ($null -eq $Address -Or $Address.Count -eq 0) {
|
|
$Address = @( $EndpointConfig.Address );
|
|
}
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header ([string]::Format('Please enter the connection data for endpoint: "{0}"', $EndpointConfig.Endpoint)) `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'break';
|
|
'Help' = 'The address to communicate with your parent Icinga node. It is highly recommended to use an IP address instead of a FQDN';
|
|
}
|
|
) `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues $Address `
|
|
-MandatoryValue `
|
|
-ParentConfig ([string]::Format('Show-IcingaForWindowsInstallerMenuEnterIcingaParentNodes:{0}', $EndpointConfig.Endpoint)) `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
|
|
$NewAddress = $Address;
|
|
$NewValue = $Value;
|
|
|
|
if ((Test-IcingaForWindowsManagementConsoleContinue)) {
|
|
$ParentAddress = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses' -Parent $EndpointConfig.Endpoint;
|
|
$NetworkTest = Convert-IcingaEndpointsToIPv4 -NetworkConfig $ParentAddress;
|
|
$NewAddress = $ParentAddress;
|
|
|
|
if ($NetworkTest.HasErrors -eq $FALSE) {
|
|
Add-IcingaForWindowsInstallerConfigEntry -Selection 'c' -Values ($NetworkTest.Network[0]) -OverwriteValues -OverwriteMenu 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses';
|
|
$AddressIndex += 1;
|
|
$NewValue[0][$entry].Error = $FALSE;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
Set-IcingaForWindowsManagementConsoleMenu -Menu 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses';
|
|
|
|
$NewValue[0][$entry].Address = $NewAddress;
|
|
|
|
$global:Icinga.InstallWizard.NextArguments = @{
|
|
'Value' = $NewValue;
|
|
'DefaultInput' = $DefaultInput;
|
|
'JumpToSummary' = $JumpToSummary;
|
|
'Automated' = $Automated;
|
|
'Advanced' = $Advanced;
|
|
};
|
|
|
|
return;
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.NextCommand = 'Add-IcingaForWindowsInstallationAdvancedEntries';
|
|
return;
|
|
} elseif ($Value[0].GetType().Name.ToLower() -eq 'string') {
|
|
$Address = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses' -Parent $Value[0];
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header ([string]::Format('Please enter the connection data for endpoint: "{0}"', $Value[0])) `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'break';
|
|
'Help' = 'The address to communicate with your parent Icinga node. It is highly recommended to use an IP address instead of a FQDN';
|
|
}
|
|
) `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues $Address `
|
|
-MandatoryValue `
|
|
-ParentConfig ([string]::Format('Show-IcingaForWindowsInstallerMenuEnterIcingaParentNodes:{0}', $Value[0])) `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
|
|
if ((Test-IcingaForWindowsManagementConsoleContinue)) {
|
|
$ParentAddress = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses' -Parent $Value[0];
|
|
$NetworkTest = Convert-IcingaEndpointsToIPv4 -NetworkConfig $ParentAddress;
|
|
|
|
if ($NetworkTest.HasErrors -eq $FALSE) {
|
|
Add-IcingaForWindowsInstallerConfigEntry -Selection 'c' -Values ($NetworkTest.Network[0]) -OverwriteValues -OverwriteMenu 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses';
|
|
$global:Icinga.InstallWizard.NextCommand = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((Test-IcingaForWindowsManagementConsoleExit) -Or (Test-IcingaForWindowsManagementConsoleMenu) -Or (Test-IcingaForWindowsManagementConsolePrevious)) {
|
|
return;
|
|
}
|
|
|
|
if ((Test-IcingaForWindowsManagementConsoleDelete)) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
# Just to ensure we never are "trapped" in a endless loop
|
|
if ($Automated) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.NextCommand = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-ParentAddress' -Value 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuEnterIcingaParentNodes()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
$Endpoints = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentNodes';
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please enter your parent Icinga node name(s):' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Test-IcingaForWindowsInstallerParentEndpoints';
|
|
'Help' = 'These are the object names for your parent Icinga endpoints as defined within the zones.conf. If you are running multiple Icinga instances within the same zone, you require to add both of them';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 2 `
|
|
-DefaultValues $Value `
|
|
-ContinueFirstValue `
|
|
-MandatoryValue `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
|
|
# In case we delete our parent config, ensure we also delete our endpoint addresses
|
|
if (Test-IcingaForWindowsManagementConsoleDelete) {
|
|
foreach ($endpoint in $Endpoints) {
|
|
Remove-IcingaForWindowsInstallerConfigEntry -Menu 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses' -Parent $endpoint;
|
|
}
|
|
}
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-ParentNodes' -Value 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentNodes';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuEnterIcingaParentZone()
|
|
{
|
|
param (
|
|
[array]$Value = @( 'master' ),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please enter your parent Icinga zone:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentNodes';
|
|
'Help' = 'The object name of the zone of the parent Icinga node(s) you want to communicate with, as defined within the zones.conf';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues $Value `
|
|
-MandatoryValue `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-ParentZone' -Value 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentZone';
|
|
|
|
function Show-IcingaForWindowsInstallationMenuEnterIcingaPort()
|
|
{
|
|
param (
|
|
[array]$Value = @( 5665 ),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please enter your parent Icinga communication port:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'This is the port Icinga will use for communicating with all parent nodes and for which the firewall must be opened, depending on your communication configuration. Defaults to 5665';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues @( $Value ) `
|
|
-MandatoryValue `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-Port' -Value 'Show-IcingaForWindowsInstallationMenuEnterIcingaPort';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuSelectConnection()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = '0',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'How do you want to configure your local Icinga Agent?' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Connecting from this system';
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuSelectHostname';
|
|
'Help' = 'Choose this option if your Icinga Agent should only connect to a parent Icinga node. This is the easiest configuration as certificate generation is done automatically.'
|
|
},
|
|
@{
|
|
'Caption' = 'Connecting from parent system';
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuSelectHostname';
|
|
'Help' = 'Choose this option if the Icinga Agent should not or cannot connect to a parent Icinga node and only connections from a Master/Satellite are possible. This will open the Windows firewall for the chosen Icinga protocol port (default 5665). Certificate generation might require additional steps.';
|
|
},
|
|
@{
|
|
'Caption' = 'Connecting from both systems';
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuSelectHostname';
|
|
'Help' = 'Choose this if connections from a parent Icinga node are possible and the Icinga Agent should connect to a parent node. This will open the Windows firewall for the chosen Icinga protocol port (default 5665).';
|
|
},
|
|
@{
|
|
'Caption' = 'Icinga Director Self-Service API';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleInstallationEnterDirectorUrl';
|
|
'Help' = 'Choose this option if you can connect to the Icinga Director from this host. You will be asked for the Icinga Director Url and a Self-Service API key. The entire configuration for this host is then fetched from the Icinga Director.';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-Connection' -Value 'Show-IcingaForWindowsInstallerMenuSelectConnection';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuSelectHostname()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = '1',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'How is your host object named in Icinga?' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = ([string]::Format('"{0}": FQDN (current)', (Get-IcingaHostname -AutoUseFQDN 1)));
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentZone';
|
|
'Help' = 'This will use the current FQDN of your host and not modify the name at all';
|
|
},
|
|
@{
|
|
'Caption' = ([string]::Format('"{0}": FQDN (lowercase)', (Get-IcingaHostname -AutoUseFQDN 1 -LowerCase 1)));
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentZone';
|
|
'Help' = 'This will use the current FQDN of your host and modify all characters to lowercase';
|
|
},
|
|
@{
|
|
'Caption' = ([string]::Format('"{0}": FQDN (uppercase)', (Get-IcingaHostname -AutoUseFQDN 1 -UpperCase 1)));
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentZone';
|
|
'Help' = 'This will use the current FQDN of your host and modify all characters to uppercase';
|
|
},
|
|
@{
|
|
'Caption' = ([string]::Format('"{0}": Hostname (current)', (Get-IcingaHostname -AutoUseHostname 1)));
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentZone';
|
|
'Help' = 'This will use the hostname only without FQDN extension without modification';
|
|
},
|
|
@{
|
|
'Caption' = ([string]::Format('"{0}": Hostname (lowercase)', (Get-IcingaHostname -AutoUseHostname 1 -LowerCase 1)));
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentZone';
|
|
'Help' = 'This will use the hostname only without FQDN extension and modify all characters to lowercase';
|
|
},
|
|
@{
|
|
'Caption' = ([string]::Format('"{0}": Hostname (uppercase)', (Get-IcingaHostname -AutoUseHostname 1 -UpperCase 1)));
|
|
'Command' = 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentZone';
|
|
'Help' = 'This will use the hostname only without FQDN extension and modify all characters to uppercase';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-Hostname' -Value 'Show-IcingaForWindowsInstallerMenuSelectHostname';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuEnterWindowsServicePackageSource()
|
|
{
|
|
param (
|
|
[array]$Value = @( ),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please enter the full path to the Icinga PowerShell Service .zip file:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Allows you to specify a full custom path on where your Icinga service package .zip file is located at. You can specify a local path "C:\icinga\service\icinga-service.zip", a network path "\\example.com\software\icinga\service\icinga-service.zip" or a web path "https://example.com/icinga/windows/service/icinga-service.zip". Please note that only the custom release .zip packages downloaded from "https://github.com/Icinga/icinga-powershell-service/releases" will work. You can get the packages from there and place them on your custom location';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues $Value `
|
|
-ContinueFirstValue `
|
|
-MandatoryValue `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-WindowsServicePackageSource' -Value 'Show-IcingaForWindowsInstallerMenuEnterWindowsServicePackageSource';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuSelectInstallIcingaForWindowsService()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = '0',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please select of you want to install the Icinga for Windows service:' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Install Icinga for Windows Service';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Installs the Icinga for Windows service from the provided stable repository';
|
|
},
|
|
@{
|
|
'Caption' = 'Do not install Icinga for Windows service';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Select this if you do not want to install the Icinga for Windows service';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-JumpToSummary:$FALSE `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-InstallPowerShellService' -Value 'Show-IcingaForWindowsInstallerMenuSelectInstallIcingaForWindowsService';
|
|
|
|
function Show-IcingaForWindowsInstallationMenuEnterWindowsServiceDirectory()
|
|
{
|
|
param (
|
|
[array]$Value = @( (Join-Path -Path $Env:ProgramFiles -ChildPath 'icinga-framework-service') ),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Enter the path where to install the Icinga for Windows service binary into:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'If you want to run a background PowerShell daemon, you will require a binary starting the shell as service. This is the permanent location for the binary, as the Icinga for Windows service is registered with this binary to run PowerShell as background daemon';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues @( $Value ) `
|
|
-MandatoryValue `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-WindowsServiceDirectory' -Value 'Show-IcingaForWindowsInstallationMenuEnterWindowsServiceDirectory';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuEnterPluginsPackageSource()
|
|
{
|
|
param (
|
|
[array]$Value = @( ),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please enter the full path to the Icinga PowerShell Plugins .zip file:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Allows you to specify a full custom path on where your Icinga plugins .zip file is located at. You can specify a local path "C:\icinga\plugins\icinga-powershell-plugins.zip", a network path "\\example.com\software\icinga\plugins\icinga-powershell-plugins.zip" or a web path "https://example.com/icinga/windows/plugins/icinga-powershell-plugins.zip". Please note that only .zip packages downloaded from "https://github.com/icinga/icinga-powershell-plugins/releases" will work. You can get the packages from there and place them on your custom location';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-ConfigLimit 1 `
|
|
-DefaultValues $Value `
|
|
-ContinueFirstValue `
|
|
-MandatoryValue `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-PluginPackageSource' -Value 'Show-IcingaForWindowsInstallerMenuEnterPluginsPackageSource';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuSelectInstallIcingaPlugins()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = '0',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please select where your Icinga plugins are downloaded from:' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Install plugins';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Installs the Icinga Plugins from the defined stable repository';
|
|
},
|
|
@{
|
|
'Caption' = 'Do not install plugins';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Select this if you do not want to install the plugins for the moment';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-JumpToSummary:$FALSE `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-InstallPlugins' -Value 'Show-IcingaForWindowsInstallerMenuSelectInstallIcingaPlugins';
|
|
|
|
function Show-IcingaForWindowsInstallationMenuEnterCustomGlobalZones()
|
|
{
|
|
param (
|
|
[array]$Value = @( '' ),
|
|
[string]$DefaultInput = 'c',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Please add all your global zones you want to add:' `
|
|
-Entries @(
|
|
@{
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'If you have configured custom global zones you require on this Windows host, please add all of them in this list. Default zones like "director-global" and "global-templates" should not be configured here';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-AddConfig `
|
|
-DefaultValues @( $Value ) `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-CustomZones' -Value 'Show-IcingaForWindowsInstallationMenuEnterCustomGlobalZones';
|
|
|
|
function Show-IcingaForWindowsInstallerMenuSelectGlobalZones()
|
|
{
|
|
param (
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = '0',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Which default Icinga global zones do you want to add?' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Add "director-global" and "global-templates" zones';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Adds both global zones, "director-global" and "global-templates" as the default installer would. Depending on your environment these might be mandatory.';
|
|
},
|
|
@{
|
|
'Caption' = 'Add "director-global" zone';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Only add the global zone "director-global" to your configuration which might be required if you are using the Icinga Director, depending on your configuration.';
|
|
},
|
|
@{
|
|
'Caption' = 'Add "global-templates" zone';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Only add the global zone "global-templates" to your configuration';
|
|
},
|
|
@{
|
|
'Caption' = 'Add no default global zone';
|
|
'Command' = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
'Help' = 'Do not add any default global zones to your configuration';
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput `
|
|
-JumpToSummary:$JumpToSummary `
|
|
-ConfigElement `
|
|
-Automated:$Automated `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
Set-Alias -Name 'IfW-GlobalZones' -Value 'Show-IcingaForWindowsInstallerMenuSelectGlobalZones';
|
|
|
|
function Show-IcingaForWindowsMenuManageIcingaAgent()
|
|
{
|
|
$IcingaService = Get-Service 'icinga2' -ErrorAction SilentlyContinue;
|
|
$AdminShell = $global:Icinga.InstallWizard.AdminShell;
|
|
$ServiceStatus = $null;
|
|
|
|
if ($null -ne $IcingaService) {
|
|
$ServiceStatus = $IcingaService.Status;
|
|
}
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Manage Icinga Agent:' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Manage Features';
|
|
'Command' = 'Show-IcingaForWindowsMenuManageIcingaAgentFeatures';
|
|
'Help' = 'Allows you to install Icinga for Windows with all required components and options';
|
|
'Disabled' = ($null -eq $IcingaService -Or (-Not $AdminShell));
|
|
},
|
|
@{
|
|
'Caption' = 'Read Icinga Agent Log File';
|
|
'Command' = 'Show-IcingaForWindowsMenuManageIcingaAgent';
|
|
'Help' = 'Allows to read the Icinga Agent log file in case the "mainlog" feature of the Icinga Agent is enabled';
|
|
'Disabled' = ((-Not $AdminShell) -Or -Not (Test-IcingaAgentFeatureEnabled -Feature 'mainlog'));
|
|
'Action' = @{
|
|
'Command' = 'Start-Process';
|
|
'Arguments' = @{ '-FilePath' = 'powershell.exe'; '-ArgumentList' = "-Command `"&{ icinga { Read-IcingaAgentLogFile; }; }`"" };
|
|
}
|
|
},
|
|
@{
|
|
'Caption' = 'Read Icinga Debug Log File';
|
|
'Command' = 'Show-IcingaForWindowsMenuManageIcingaAgent';
|
|
'Help' = 'Allows to read the Icinga Agent debug log file in case the "debuglog" feature of the Icinga Agent is enabled';
|
|
'Disabled' = ((-Not $AdminShell) -Or -Not (Test-IcingaAgentFeatureEnabled -Feature 'debuglog'));
|
|
'Action' = @{
|
|
'Command' = 'Start-Process';
|
|
'Arguments' = @{ '-FilePath' = 'powershell.exe'; '-ArgumentList' = "-Command `"&{ icinga { Read-IcingaAgentDebugLogFile; }; }`"" };
|
|
}
|
|
},
|
|
@{
|
|
'Caption' = 'Flush API directory (will restart Agent)';
|
|
'Command' = 'Show-IcingaForWindowsMenuManageIcingaAgent';
|
|
'Help' = 'Allows you to flush the Icinga Agent API directory for cleanup. This will restart the Icinga Agent';
|
|
'Disabled' = ($null -eq $IcingaService -Or (-Not $AdminShell));
|
|
'Action' = @{
|
|
'Command' = 'Clear-IcingaAgentApiDirectory';
|
|
'Arguments' = @{ '-Force' = $TRUE };
|
|
}
|
|
},
|
|
@{
|
|
'Caption' = 'Start Icinga Agent';
|
|
'Command' = 'Show-IcingaForWindowsMenuManageIcingaAgent';
|
|
'Help' = 'Allows you to start the Icinga Agent if the service is not running';
|
|
'Disabled' = ($null -eq $IcingaService -Or $ServiceStatus -eq 'Running' -Or (-Not $AdminShell));
|
|
'Action' = @{
|
|
'Command' = 'Start-Service';
|
|
'Arguments' = @{ '-Name' = 'icinga2'; };
|
|
}
|
|
},
|
|
@{
|
|
'Caption' = 'Stop Icinga Agent';
|
|
'Command' = 'Show-IcingaForWindowsMenuManageIcingaAgent';
|
|
'Help' = 'Allows you to stop the Icinga Agent if the service is not running';
|
|
'Disabled' = ($null -eq $IcingaService -Or $ServiceStatus -ne 'Running' -Or (-Not $AdminShell));
|
|
'Action' = @{
|
|
'Command' = 'Stop-Service';
|
|
'Arguments' = @{ '-Name' = 'icinga2'; };
|
|
}
|
|
},
|
|
@{
|
|
'Caption' = 'Restart Icinga Agent';
|
|
'Command' = 'Show-IcingaForWindowsMenuManageIcingaAgent';
|
|
'Help' = 'Allows you to restart the Icinga Agent if the service is installed';
|
|
'Disabled' = ($null -eq $IcingaService -Or (-Not $AdminShell));
|
|
'Action' = @{
|
|
'Command' = 'Restart-Service';
|
|
'Arguments' = @{ '-Name' = 'icinga2'; };
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
function Show-IcingaForWindowsMenuManageIcingaAgentFeatures()
|
|
{
|
|
$Features = Get-IcingaAgentFeatures;
|
|
|
|
[array]$FeatureList = @();
|
|
|
|
foreach ($entry in $Features.Enabled) {
|
|
|
|
if ([string]::IsNullOrEmpty($entry)) {
|
|
continue;
|
|
}
|
|
|
|
[string]$Caption = [string]::Format('{0}: Enabled', $entry);
|
|
|
|
$FeatureList += @{
|
|
'Caption' = $Caption;
|
|
'Command' = 'Show-IcingaForWindowsMenuManageIcingaAgentFeatures';
|
|
'Help' = ([string]::Format('The feature "{0}" is currently enabled. Select this entry to disable it.', $entry));
|
|
'Disabled' = $FALSE;
|
|
'Action' = @{
|
|
'Command' = 'Disable-IcingaAgentFeature';
|
|
'Arguments' = @{
|
|
'-Feature' = $entry;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($entry in $Features.Disabled) {
|
|
|
|
if ([string]::IsNullOrEmpty($entry)) {
|
|
continue;
|
|
}
|
|
|
|
[string]$Caption = [string]::Format('{0}: Disabled', $entry);
|
|
|
|
$FeatureList += @{
|
|
'Caption' = $Caption;
|
|
'Command' = 'Show-IcingaForWindowsMenuManageIcingaAgentFeatures';
|
|
'Help' = ([string]::Format('The feature "{0}" is currently disabled. Select this entry to enable it.', $entry));
|
|
'Disabled' = $FALSE;
|
|
'Action' = @{
|
|
'Command' = 'Enable-IcingaAgentFeature';
|
|
'Arguments' = @{
|
|
'-Feature' = $entry;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Manage Icinga Agent Features. Select an entry and hit enter to Disable/Enable them:' `
|
|
-Entries $FeatureList;
|
|
}
|
|
|
|
function Invoke-IcingaForWindowsManagementConsoleReconfigureAgent()
|
|
{
|
|
$LiveConfig = Get-IcingaPowerShellConfig -Path 'Framework.Config.Live';
|
|
|
|
if ($null -eq $LiveConfig) {
|
|
$global:Icinga.InstallWizard.NextCommand = 'Show-IcingaForWindowsMenuManageIcingaAgent';
|
|
$global:Icinga.InstallWizard.LastError = 'Unable to load any previous live configuration. Reconfiguring not possible.';
|
|
return;
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.Config = Convert-IcingaForwindowsManagementConsoleJSONConfig -Config $LiveConfig;
|
|
$global:Icinga.InstallWizard.NextCommand = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
}
|
|
|
|
function Show-IcingaForWindowsManagementConsoleFrameworkExperimental()
|
|
{
|
|
$ApiChecks = Get-IcingaFrameworkApiChecks;
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Manage Icinga for Windows experimental features. Not recommended for production!' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = ([string]::Format('Forward checks to Api: {0}', (& { if ($ApiChecks) { 'Enabled' } else { 'Disabled' } } )));
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleFrameworkExperimental';
|
|
'Help' = 'In case enabled, all check commands executed by "Exit-IcingaExecutePlugin" are forwarded to an internal REST-Api and executed from within the Icinga for Windows background daemon. Requires the Icinga for Windows background daemon and the modules "icinga-powershell-restapi" and "icinga-powershell-apichecks"';
|
|
'Disabled' = $FALSE;
|
|
'Action' = @{
|
|
'Command' = 'Invoke-IcingaForWindowsMangementConsoleToogleFrameworkApiChecks';
|
|
'Arguments' = @{ };
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
function Show-IcingaForWindowsManagementConsoleManageFramework()
|
|
{
|
|
$FrameworkDebug = Get-IcingaFrameworkDebugMode;
|
|
$IcingaService = Get-Service 'icingapowershell' -ErrorAction SilentlyContinue;
|
|
$AdminShell = $global:Icinga.InstallWizard.AdminShell;
|
|
$ServiceStatus = $null;
|
|
|
|
if ($null -ne $IcingaService) {
|
|
$ServiceStatus = $IcingaService.Status;
|
|
}
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Manage Icinga for Windows:' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Manage background daemons';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleManageBackgroundDaemons';
|
|
'Help' = 'Allows you to manage Icinga for Windows background daemons';
|
|
'Disabled' = ($null -eq (Get-Service 'icingapowershell' -ErrorAction SilentlyContinue));
|
|
},
|
|
@{
|
|
'Caption' = ([string]::Format('Framework Debug Mode: {0}', (& { if ($FrameworkDebug) { 'Enabled' } else { 'Disabled' } } )));
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleManageFramework';
|
|
'Help' = 'Disable or enable the Icinga PowerShell Framework debug mode';
|
|
'Disabled' = $FALSE;
|
|
'Action' = @{
|
|
'Command' = 'Invoke-IcingaForWindowsMangementConsoleToogleFrameworkDebug';
|
|
'Arguments' = @{ };
|
|
}
|
|
},
|
|
@{
|
|
'Caption' = 'Update Framework Code Cache';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleManageFramework';
|
|
'Help' = 'Updates the Icinga PowerShell Framework Code Cache';
|
|
'Action' = @{
|
|
'Command' = 'Write-IcingaFrameworkCodeCache';
|
|
'Arguments' = @{ };
|
|
}
|
|
},
|
|
@{
|
|
'Caption' = 'Allow untrusted certificate communication (this session only)';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleManageFramework';
|
|
'Help' = 'Enables the Icinga untrusted certificate validation, allowing you to communicate with web servers which ships with a self-signed certificate not installed on this system. This applies only to this PowerShell session and is not permanent. Might be helpful in case you want to connect to the Icinga Director and the SSL is not trusted by this host';
|
|
'Disabled' = $FALSE
|
|
'Action' = @{
|
|
'Command' = 'Enable-IcingaUntrustedCertificateValidation';
|
|
'Arguments' = @{ };
|
|
}
|
|
},
|
|
@{
|
|
'Caption' = 'Configure experimental features';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleFrameworkExperimental';
|
|
'Help' = 'Allows you to manage experimental features for Icinga for Windows';
|
|
'Disabled' = $FALSE
|
|
},
|
|
@{
|
|
'Caption' = 'Start Icinga for Windows Service';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleManageFramework';
|
|
'Help' = 'Allows you to start the Icinga for Windows Service if the service is not running';
|
|
'Disabled' = ($null -eq $IcingaService -Or $ServiceStatus -eq 'Running' -Or (-Not $AdminShell));
|
|
'Action' = @{
|
|
'Command' = 'Start-Service';
|
|
'Arguments' = @{ '-Name' = 'icingapowershell'; };
|
|
}
|
|
},
|
|
@{
|
|
'Caption' = 'Stop Icinga for Windows Service';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleManageFramework';
|
|
'Help' = 'Allows you to stop the Icinga for Windows Service if the service is not running';
|
|
'Disabled' = ($null -eq $IcingaService -Or $ServiceStatus -ne 'Running' -Or (-Not $AdminShell));
|
|
'Action' = @{
|
|
'Command' = 'Stop-Service';
|
|
'Arguments' = @{ '-Name' = 'icingapowershell'; };
|
|
}
|
|
},
|
|
@{
|
|
'Caption' = 'Restart Icinga for Windows Service';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleManageFramework';
|
|
'Help' = 'Allows you to restart the Icinga for Windows Service if the service is installed';
|
|
'Disabled' = ($null -eq $IcingaService -Or (-Not $AdminShell));
|
|
'Action' = @{
|
|
'Command' = 'Restart-Service';
|
|
'Arguments' = @{ '-Name' = 'icingapowershell'; };
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
function Invoke-IcingaForWindowsMangementConsoleToogleFrameworkApiChecks()
|
|
{
|
|
if (Get-IcingaFrameworkApiChecks) {
|
|
Disable-IcingaFrameworkApiChecks;
|
|
} else {
|
|
Enable-IcingaFrameworkApiChecks;
|
|
}
|
|
}
|
|
|
|
function Invoke-IcingaForWindowsMangementConsoleToogleFrameworkDebug()
|
|
{
|
|
if (Get-IcingaFrameworkDebugMode) {
|
|
Disable-IcingaFrameworkDebugMode;
|
|
} else {
|
|
Enable-IcingaFrameworkDebugMode;
|
|
}
|
|
}
|
|
|
|
function Show-IcingaForWindowsManagementConsoleManageBackgroundDaemons()
|
|
{
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Manage the Icinga for Windows background daemons:' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Register background daemon';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleRegisterBackgroundDaemons';
|
|
'Help' = 'Allows you to register a new background daemon for Icinga for Windows';
|
|
'Disabled' = $FALSE;
|
|
},
|
|
@{
|
|
'Caption' = 'Unregister background daemon';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleUnregisterBackgroundDaemons';
|
|
'Help' = 'Remove registered Icinga for Windows background daemons';
|
|
'Disabled' = $FALSE;
|
|
}
|
|
);
|
|
}
|
|
|
|
function Show-IcingaForWindowsManagementConsoleRegisterBackgroundDaemons()
|
|
{
|
|
[array]$AvailableDaemons = @();
|
|
$ModuleList = Get-Module 'icinga-powershell-*' -ListAvailable;
|
|
|
|
$AvailableDaemons += @{
|
|
'Caption' = 'Register background daemon "Start-IcingaServiceCheckDaemon"';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleRegisterBackgroundDaemons';
|
|
'Help' = ((Get-Help 'Start-IcingaServiceCheckDaemon' -Full).Description.Text);
|
|
'Disabled' = $FALSE;
|
|
'Action' = @{
|
|
'Command' = 'Show-IcingaWindowsManagementConsoleYesNoDialog';
|
|
'Arguments' = @{
|
|
'-Caption' = 'Register background daemon "Start-IcingaServiceCheckDaemon"';
|
|
'-Command' = 'Register-IcingaBackgroundDaemon';
|
|
'-CmdArguments' = @{
|
|
'-Command' = 'Start-IcingaServiceCheckDaemon';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($module in $ModuleList) {
|
|
|
|
$ModuleInfo = $null;
|
|
|
|
Import-LocalizedData -BaseDirectory (Join-Path -Path (Get-IcingaForWindowsRootPath) -ChildPath $module.Name) -FileName ([string]::Format('{0}.psd1', $module.Name)) -BindingVariable ModuleInfo -ErrorAction SilentlyContinue;
|
|
|
|
if ($null -eq $ModuleInfo -Or $null -eq $ModuleInfo.PrivateData -Or $null -eq $ModuleInfo.PrivateData.Type -Or ([string]::IsNullOrEmpty($ModuleInfo.PrivateData.Type)) -Or $ModuleInfo.PrivateData.Type -ne 'daemon' -Or $null -eq $ModuleInfo.PrivateData.Function -Or ([string]::IsNullOrEmpty($ModuleInfo.PrivateData.Function))) {
|
|
continue;
|
|
}
|
|
|
|
$HelpObject = Get-Help ($ModuleInfo.PrivateData.Function) -Full -ErrorAction SilentlyContinue;
|
|
$HelpText = '';
|
|
$Caption = [string]::Format('Register background daemon "{0}"', ($ModuleInfo.PrivateData.Function));
|
|
|
|
if ($null -ne $HelpObject) {
|
|
$HelpText = $HelpObject.Description.Text;
|
|
}
|
|
|
|
$AvailableDaemons += @{
|
|
'Caption' = $Caption;
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleRegisterBackgroundDaemons';
|
|
'Help' = $HelpText;
|
|
'Disabled' = $FALSE;
|
|
'Action' = @{
|
|
'Command' = 'Show-IcingaWindowsManagementConsoleYesNoDialog';
|
|
'Arguments' = @{
|
|
'-Caption' = $Caption;
|
|
'-Command' = 'Register-IcingaBackgroundDaemon';
|
|
'-CmdArguments' = @{
|
|
'-Command' = $ModuleInfo.PrivateData.Function;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Register Icinga for Windows background daemon:' `
|
|
-Entries $AvailableDaemons;
|
|
}
|
|
|
|
function Show-IcingaForWindowsManagementConsoleUnregisterBackgroundDaemons()
|
|
{
|
|
[array]$RegisteredDaemons = @();
|
|
|
|
$BackgroundDaemons = Get-IcingaBackgroundDaemons;
|
|
|
|
foreach ($daemon in $BackgroundDaemons.Keys) {
|
|
$DaemonValue = $BackgroundDaemons[$daemon];
|
|
$HelpObject = Get-Help $daemon -Full -ErrorAction SilentlyContinue;
|
|
$HelpText = '';
|
|
$Caption = [string]::Format('Unregister background daemon "{0}"', $daemon);
|
|
|
|
if ($null -ne $HelpObject) {
|
|
$HelpText = $HelpObject.Description.Text;
|
|
}
|
|
|
|
$RegisteredDaemons += @{
|
|
'Caption' = $Caption;
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleUnregisterBackgroundDaemons';
|
|
'Help' = $HelpText;
|
|
'Disabled' = $FALSE;
|
|
'Action' = @{
|
|
'Command' = 'Show-IcingaWindowsManagementConsoleYesNoDialog';
|
|
'Arguments' = @{
|
|
'-Caption' = $Caption;
|
|
'-Command' = 'Unregister-IcingaBackgroundDaemon';
|
|
'-CmdArguments' = @{
|
|
'-BackgroundDaemon' = $daemon;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Unregister Icinga for Windows background daemon:' `
|
|
-Entries $RegisteredDaemons;
|
|
}
|
|
|
|
function Show-IcingaForWindowsMenuInstallComponents()
|
|
{
|
|
$IcingaInstallation = Get-IcingaComponentList;
|
|
$CurrentComponents = Get-IcingaInstallation -Release;
|
|
[int]$MaxComponentLength = Get-IcingaMaxTextLength -TextArray $IcingaInstallation.Components.Keys;
|
|
[array]$InstallList = @();
|
|
|
|
foreach ($entry in $IcingaInstallation.Components.Keys) {
|
|
$LatestVersion = $IcingaInstallation.Components[$entry];
|
|
$LockedVersion = Get-IcingaComponentLock -Name $entry;
|
|
$VersionText = $LatestVersion;
|
|
|
|
# Only show not installed components
|
|
if ($CurrentComponents.ContainsKey($entry)) {
|
|
continue;
|
|
}
|
|
|
|
if ($null -ne $LockedVersion) {
|
|
$VersionText = [string]::Format('{0}*', $LockedVersion);
|
|
$LatestVersion = $LockedVersion;
|
|
}
|
|
|
|
$InstallList += @{
|
|
'Caption' = ([string]::Format('{0} [{1}]', (Add-IcingaWhiteSpaceToString -Text $entry -Length $MaxComponentLength), $VersionText));
|
|
'Command' = 'Show-IcingaForWindowsMenuInstallComponents';
|
|
'Help' = ([string]::Format('This will install the component "{0}" with version "{1}"', $entry, $VersionText));
|
|
'Disabled' = $FALSE;
|
|
'Action' = @{
|
|
'Command' = 'Show-IcingaWindowsManagementConsoleYesNoDialog';
|
|
'Arguments' = @{
|
|
'-Caption' = ([string]::Format('Install component "{0}" with version "{1}"', $entry, $VersionText));
|
|
'-Command' = 'Install-IcingaComponent';
|
|
'-CmdArguments' = @{
|
|
'-Name' = $entry;
|
|
'-Version' = $LatestVersion;
|
|
'-Release' = $TRUE;
|
|
'-Confirm' = $TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($InstallList.Count -ne 0) {
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Install Icinga for Windows components. Select an entry to continue:' `
|
|
-Entries $InstallList;
|
|
} else {
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'There are no packages found for installation'
|
|
}
|
|
}
|
|
|
|
function Show-IcingaForWindowsMenuManage()
|
|
{
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Manage Icinga for Windows:' `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'Icinga Agent';
|
|
'Command' = 'Show-IcingaForWindowsMenuManageIcingaAgent';
|
|
'Help' = 'Allows you to manage the installed Icinga Agent';
|
|
'Disabled' = (-Not ([bool](Get-Service 'icinga2' -ErrorAction SilentlyContinue)));
|
|
},
|
|
@{
|
|
'Caption' = 'Icinga PowerShell Framework';
|
|
'Command' = 'Show-IcingaForWindowsManagementConsoleManageFramework';
|
|
'Help' = 'Allows you to modify certain settings for the Icinga PowerShell Framework and to register background daemons';
|
|
}<#,
|
|
@{
|
|
'Caption' = 'Health Check';
|
|
'Command' = '';
|
|
'Help' = 'Check the current health and status information of your installation';
|
|
}#>
|
|
);
|
|
}
|
|
|
|
function Show-IcingaForWindowsMenuRemoveComponents()
|
|
{
|
|
|
|
[array]$UninstallFeatures = @();
|
|
$AgentInstalled = Get-Service -Name 'icinga2' -ErrorAction SilentlyContinue;
|
|
$PowerShellServiceInstalled = Get-Service -Name 'icingapowershell' -ErrorAction SilentlyContinue;
|
|
$IcingaWindowsServiceData = Get-IcingaForWindowsServiceData;
|
|
$ModuleList = Get-Module 'icinga-powershell-*' -ListAvailable;
|
|
|
|
$UninstallFeatures += @{
|
|
'Caption' = 'Uninstall Icinga Agent';
|
|
'Command' = 'Show-IcingaForWindowsMenuRemoveComponents';
|
|
'Help' = 'Will remove the Icinga Agent from this system. Please note that this option will leave content inside "ProgramData", like certificates, alone'
|
|
'Disabled' = ($null -eq $AgentInstalled);
|
|
'Action' = @{
|
|
'Command' = 'Show-IcingaWindowsManagementConsoleYesNoDialog';
|
|
'Arguments' = @{
|
|
'-Caption' = 'Uninstall Icinga Agent';
|
|
'-Command' = 'Uninstall-IcingaComponent';
|
|
'-CmdArguments' = @{
|
|
'-Name' = 'agent';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$UninstallFeatures += @{
|
|
'Caption' = 'Uninstall Icinga Agent (include ProgramData)';
|
|
'Command' = 'Show-IcingaForWindowsMenuRemoveComponents';
|
|
'Help' = 'Will remove the Icinga Agent from this system. Please note that this option will leave content inside "ProgramData", like certificates, alone'
|
|
'Disabled' = (-Not (Test-Path -Path (Join-Path -Path $Env:ProgramData -ChildPath 'icinga2')));
|
|
'Action' = @{
|
|
'Command' = 'Show-IcingaWindowsManagementConsoleYesNoDialog';
|
|
'Arguments' = @{
|
|
'-Caption' = 'Uninstall Icinga Agent (include ProgramData)';
|
|
'-Command' = 'Uninstall-IcingaComponent';
|
|
'-CmdArguments' = @{
|
|
'-Name' = 'agent';
|
|
'-RemovePackageFiles' = $TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$UninstallFeatures += @{
|
|
'Caption' = 'Uninstall Icinga for Windows Service';
|
|
'Command' = 'Show-IcingaForWindowsMenuRemoveComponents';
|
|
'Help' = 'This will remove the icingapowershell service for Icinga for Windows if installed'
|
|
'Disabled' = ($null -eq $PowerShellServiceInstalled);
|
|
'Action' = @{
|
|
'Command' = 'Show-IcingaWindowsManagementConsoleYesNoDialog';
|
|
'Arguments' = @{
|
|
'-Caption' = 'Uninstall Icinga for Windows service';
|
|
'-Command' = 'Uninstall-IcingaComponent';
|
|
'-CmdArguments' = @{
|
|
'-Name' = 'service';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$UninstallFeatures += @{
|
|
'Caption' = 'Uninstall Icinga for Windows Service (include files)';
|
|
'Command' = 'Show-IcingaForWindowsMenuRemoveComponents';
|
|
'Help' = 'This will remove the icingapowershell service for Icinga for Windows if installed and the service binary including the folder, if empty afterwards'
|
|
'Disabled' = (-Not (Test-Path $IcingaWindowsServiceData.Directory));
|
|
'Action' = @{
|
|
'Command' = 'Show-IcingaWindowsManagementConsoleYesNoDialog';
|
|
'Arguments' = @{
|
|
'-Caption' = 'Uninstall Icinga for Windows service (include files)';
|
|
'-Command' = 'Uninstall-IcingaComponent';
|
|
'-CmdArguments' = @{
|
|
'-Name' = 'service';
|
|
'-RemovePackageFiles' = $TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($module in $ModuleList) {
|
|
$ComponentName = $module.Name.Replace('icinga-powershell-', '');
|
|
$Caption = ([string]::Format('Uninstall component "{0}"', $ComponentName));
|
|
|
|
if ($ComponentName -eq 'framework' -Or $ComponentName -eq 'service' -Or $ComponentName -eq 'agent') {
|
|
continue;
|
|
}
|
|
|
|
$UninstallFeatures += @{
|
|
'Caption' = $Caption;
|
|
'Command' = 'Show-IcingaForWindowsMenuRemoveComponents';
|
|
'Help' = ([string]::Format('This will remove the Icinga for Windows component "{0}" from this host', $ComponentName));
|
|
'Disabled' = $FALSE;
|
|
'Action' = @{
|
|
'Command' = 'Show-IcingaWindowsManagementConsoleYesNoDialog';
|
|
'Arguments' = @{
|
|
'-Caption' = $Caption;
|
|
'-Command' = 'Uninstall-IcingaComponent';
|
|
'-CmdArguments' = @{
|
|
'-Name' = $ComponentName;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Uninstall Icinga for Windows components. Select an entry to continue:' `
|
|
-Entries $UninstallFeatures;
|
|
}
|
|
|
|
function Show-IcingaForWindowsMenuUpdateComponents()
|
|
{
|
|
$IcingaInstallation = Get-IcingaInstallation -Release;
|
|
[int]$MaxComponentLength = Get-IcingaMaxTextLength -TextArray $IcingaInstallation.Keys;
|
|
[array]$UpdateList = @();
|
|
|
|
foreach ($entry in $IcingaInstallation.Keys) {
|
|
$Component = $IcingaInstallation[$entry];
|
|
|
|
$LatestVersion = $Component.LatestVersion;
|
|
if ([string]::IsNullOrEmpty($Component.LockedVersion) -eq $FALSE) {
|
|
if ([Version]$Component.CurrentVersion -ge [Version]$Component.LockedVersion) {
|
|
continue;
|
|
}
|
|
$LatestVersion = [string]::Format('{0}*', $Component.LockedVersion);
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($LatestVersion)) {
|
|
continue;
|
|
}
|
|
|
|
$UpdateList += @{
|
|
'Caption' = ([string]::Format('{0} [{1}] => [{2}]', (Add-IcingaWhiteSpaceToString -Text $entry -Length $MaxComponentLength), $Component.CurrentVersion, $LatestVersion));
|
|
'Command' = 'Show-IcingaForWindowsMenuUpdateComponents';
|
|
'Help' = ([string]::Format('This will update the component "{0}" from current version "{1}" to stable version "{2}"', $entry, $Component.CurrentVersion, $LatestVersion));
|
|
'Disabled' = $FALSE;
|
|
'Action' = @{
|
|
'Command' = 'Show-IcingaWindowsManagementConsoleYesNoDialog';
|
|
'Arguments' = @{
|
|
'-Caption' = ([string]::Format('Update component "{0}" from version "{1}" to stable version "{2}"', $entry, $Component.CurrentVersion, $LatestVersion));
|
|
'-Command' = 'Update-Icinga';
|
|
'-CmdArguments' = @{
|
|
'-Name' = $entry;
|
|
'-Release' = $TRUE;
|
|
'-Confirm' = $TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($UpdateList.Count -ne 0) {
|
|
$UpdateList += @{
|
|
'Caption' = 'Update entire environment';
|
|
'Command' = 'Show-IcingaForWindowsMenuUpdateComponents';
|
|
'Help' = 'This will update all components listed above to the mentioned stable version'
|
|
'Disabled' = $FALSE;
|
|
'Action' = @{
|
|
'Command' = 'Show-IcingaWindowsManagementConsoleYesNoDialog';
|
|
'Arguments' = @{
|
|
'-Caption' = 'Update entire Icinga for Windows environment';
|
|
'-Command' = 'Update-Icinga';
|
|
'-CmdArguments' = @{
|
|
'-Release' = $TRUE;
|
|
'-Confirm' = $TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'Updates Icinga for Windows components. Select an entry to continue:' `
|
|
-Entries $UpdateList;
|
|
} else {
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header 'There are no updates pending for your environment'
|
|
}
|
|
}
|
|
|
|
function Test-IcingaForWindowsInstallerParentEndpoints()
|
|
{
|
|
$Selection = Get-IcingaForWindowsInstallerStepSelection -InstallerStep 'Show-IcingaForWindowsInstallerMenuSelectConnection';
|
|
|
|
# Agents connects, therefor validate this setting. 1 only accepts connections from parent
|
|
if ($Selection -ne 1) {
|
|
$Values = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentNodes';
|
|
$NetworkMap = @{ };
|
|
[bool]$HasErrors = $FALSE;
|
|
|
|
foreach ($endpoint in $Values) {
|
|
$Address = Get-IcingaForWindowsInstallerValuesFromStep -InstallerStep 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses' -Parent $endpoint;
|
|
$TestAddress = $Address;
|
|
if ($null -eq $Address -Or $Address.Count -eq 0) {
|
|
$TestAddress = $endpoint;
|
|
}
|
|
|
|
$Resolved = Convert-IcingaEndpointsToIPv4 -NetworkConfig $TestAddress;
|
|
|
|
if ($Resolved.HasErrors) {
|
|
$Address = $endpoint;
|
|
$HasErrors = $TRUE;
|
|
} else {
|
|
$Address = $Resolved.Network[0];
|
|
}
|
|
|
|
$NetworkMap.Add(
|
|
$endpoint,
|
|
@{
|
|
'Endpoint' = $endpoint;
|
|
'Address' = $Address;
|
|
'Error' = $Resolved.HasErrors;
|
|
}
|
|
);
|
|
|
|
Add-IcingaForWindowsInstallerConfigEntry -Selection 'c' -Values $Address -OverwriteValues `
|
|
-OverwriteMenu 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses' `
|
|
-OverwriteParent ([string]::Format('Show-IcingaForWindowsInstallerMenuEnterIcingaParentNodes:{0}', $endpoint));
|
|
}
|
|
|
|
if ($HasErrors) {
|
|
$global:Icinga.InstallWizard.NextCommand = 'Show-IcingaForWindowsInstallerMenuEnterIcingaParentAddresses';
|
|
$global:Icinga.InstallWizard.NextArguments = @{ 'Value' = $NetworkMap };
|
|
return;
|
|
}
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.NextCommand = 'Add-IcingaForWindowsInstallationAdvancedEntries';
|
|
}
|
|
|
|
function Add-IcingaForWindowsInstallerConfigEntry()
|
|
{
|
|
param (
|
|
[string]$Selection = $null,
|
|
[array]$Values = @(),
|
|
[switch]$Hidden = $FALSE,
|
|
[switch]$PasswordInput = $FALSE,
|
|
[switch]$OverwriteValues = $FALSE,
|
|
[string]$OverwriteMenu = '',
|
|
[string]$OverwriteParent = '',
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($OverwriteMenu) -eq $FALSE) {
|
|
$Step = $OverwriteMenu;
|
|
} else {
|
|
$Step = Get-IcingaForWindowsManagementConsoleMenu;
|
|
}
|
|
if ([string]::IsNullOrEmpty($OverwriteParent) -eq $FALSE) {
|
|
$Parent = $OverwriteParent;
|
|
} else {
|
|
$Parent = $global:Icinga.InstallWizard.ParentConfig;
|
|
}
|
|
|
|
$ConfigIndex = $global:Icinga.InstallWizard.Config.Count;
|
|
$ParentEntry = $null;
|
|
|
|
$Parent = Get-IcingaForWindowsManagementConsoleAlias -Command $Parent;
|
|
$Step = Get-IcingaForWindowsManagementConsoleAlias -Command $Step;
|
|
|
|
if ([string]::IsNullOrEmpty($Parent) -eq $FALSE) {
|
|
$ParentEntry = $Parent.Split(':')[1];
|
|
$Parent = $Parent.Split(':')[0];
|
|
$Step = [string]::Format('{0}:{1}', $Step, $ParentEntry);
|
|
}
|
|
|
|
if ($global:Icinga.InstallWizard.Config.ContainsKey($Step) -eq $FALSE) {
|
|
$global:Icinga.InstallWizard.Config.Add(
|
|
$Step,
|
|
@{
|
|
'Selection' = $Selection;
|
|
'Values' = $Values
|
|
'Index' = $ConfigIndex;
|
|
'Parent' = $Parent;
|
|
'ParentEntry' = $ParentEntry;
|
|
'Hidden' = [bool]$Hidden;
|
|
'Password' = [bool]$PasswordInput;
|
|
'Advanced' = [bool]$Advanced;
|
|
'Modified' = ($Advanced -eq $FALSE);
|
|
}
|
|
);
|
|
} else {
|
|
$global:Icinga.InstallWizard.Config[$Step].Selection = $Selection;
|
|
$global:Icinga.InstallWizard.Config[$Step].Values = $Values;
|
|
$global:Icinga.InstallWizard.Config[$Step].Modified = $TRUE;
|
|
}
|
|
|
|
Write-IcingaforWindowsManagementConsoleConfigSwap -Config $global:Icinga.InstallWizard.Config;
|
|
}
|
|
|
|
function Get-IcingaForWindowsManagementConsoleAlias()
|
|
{
|
|
param (
|
|
[string]$Command
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Command)) {
|
|
return '';
|
|
}
|
|
|
|
$ParentEntry = $null;
|
|
|
|
if ($Command.Contains(':')) {
|
|
$KeyValue = $Command.Split(':');
|
|
$Command = $KeyValue[0];
|
|
$ParentEntry = $KeyValue[1];
|
|
}
|
|
|
|
$CommandAlias = Get-Alias -Definition $Command -ErrorAction SilentlyContinue;
|
|
|
|
if ($null -ne $CommandAlias) {
|
|
$Command = $CommandAlias.Name;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ParentEntry) -eq $FALSE) {
|
|
$Command = [string]::Format('{0}:{1}', $Command, $ParentEntry);
|
|
}
|
|
|
|
return $Command;
|
|
}
|
|
|
|
function Clear-IcingaForWindowsInstallerValuesFromStep()
|
|
{
|
|
$Step = Get-IcingaForWindowsManagementConsoleMenu;
|
|
|
|
if ($global:Icinga.InstallWizard.Config.ContainsKey($Step) -eq $FALSE) {
|
|
return;
|
|
}
|
|
|
|
if ($null -eq $global:Icinga.InstallWizard.Config[$Step].Values) {
|
|
return;
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.Config[$Step].Values = @();
|
|
}
|
|
|
|
function Remove-IcingaForWindowsInstallerConfigEntry()
|
|
{
|
|
param (
|
|
[string]$Menu,
|
|
[string]$Parent
|
|
);
|
|
|
|
$Menu = Get-IcingaForWindowsManagementConsoleAlias -Command $Menu;
|
|
|
|
if ([string]::IsNullOrEmpty($Parent) -eq $FALSE) {
|
|
$Menu = [string]::Format('{0}:{1}', $Menu, $Parent);
|
|
}
|
|
|
|
if ($global:Icinga.InstallWizard.Config.ContainsKey($Menu)) {
|
|
$global:Icinga.InstallWizard.Config.Remove($Menu);
|
|
}
|
|
|
|
Write-IcingaforWindowsManagementConsoleConfigSwap -Config $global:Icinga.InstallWizard.Config;
|
|
}
|
|
|
|
function Get-IcingaForWindowsManagementConsoleConfigurationString()
|
|
{
|
|
param (
|
|
[switch]$Compress = $FALSE
|
|
);
|
|
|
|
[hashtable]$Configuration = @{ };
|
|
|
|
foreach ($entry in $Global:Icinga.InstallWizard.Config.Keys) {
|
|
$Value = $Global:Icinga.InstallWizard.Config[$entry];
|
|
|
|
# Only print arguments that contain changes
|
|
if ($Value.Modified -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
$Command = $entry;
|
|
$Parent = $null;
|
|
|
|
# Handle configurations with parent dependencies
|
|
if ($entry.Contains(':')) {
|
|
$KeyValue = $entry.Split(':');
|
|
$Command = $KeyValue[0];
|
|
$Parent = $KeyValue[1];
|
|
}
|
|
|
|
if ($Configuration.ContainsKey($Command) -eq $FALSE) {
|
|
$Configuration.Add($Command, @{ });
|
|
}
|
|
|
|
# No parent exist, just add the values
|
|
if ([string]::IsNullOrEmpty($Parent)) {
|
|
if ($null -ne $Value.Values -And $Value.Values.Count -ne 0) {
|
|
[array]$ConfigValues = @();
|
|
|
|
foreach ($element in $Value.Values) {
|
|
if ([string]::IsNullOrEmpty($element) -eq $FALSE) {
|
|
$ConfigValues += $element;
|
|
}
|
|
}
|
|
|
|
if ($ConfigValues.Count -ne 0) {
|
|
$Configuration[$Command].Add(
|
|
'Values', $ConfigValues
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
# Handle parent references
|
|
[hashtable]$ParentConfig = @{ };
|
|
|
|
if ($Configuration[$Command].ContainsKey('Values')) {
|
|
$ParentConfig = $Configuration[$Command].Values;
|
|
}
|
|
|
|
$ParentConfig.Add(
|
|
$Value.ParentEntry,
|
|
$Value.Values
|
|
);
|
|
|
|
$Configuration[$Command].Values = $ParentConfig;
|
|
}
|
|
|
|
if ($Configuration[$Command].ContainsKey('Selection')) {
|
|
continue;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Value.Selection) -eq $FALSE -And $Value.Selection -ne 'c') {
|
|
$Configuration[$Command].Add(
|
|
'Selection', $Value.Selection
|
|
);
|
|
}
|
|
|
|
if ($Configuration[$Command].Count -eq 0) {
|
|
$Configuration.Remove($Command);
|
|
}
|
|
}
|
|
|
|
return ($Configuration | ConvertTo-Json -Depth 100 -Compress:$Compress);
|
|
}
|
|
|
|
function Add-IcingaForWindowsManagementConsoleLastParent()
|
|
{
|
|
$Menu = Get-IcingaForWindowsManagementConsoleAlias -Command (Get-IcingaForWindowsManagementConsoleMenu);
|
|
|
|
if ($Menu -eq (Get-IcingaForWindowsInstallerLastParent)) {
|
|
return;
|
|
}
|
|
|
|
# Do not add Yes/No Dialog to the list
|
|
if ($Menu -eq 'Show-IcingaWindowsManagementConsoleYesNoDialog') {
|
|
return;
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.LastParent.Add($Menu) | Out-Null;
|
|
}
|
|
|
|
function Invoke-IcingaForWindowsManagementConsoleCustomConfig()
|
|
{
|
|
param (
|
|
[hashtable]$IcingaConfiguration = @{ }
|
|
);
|
|
|
|
foreach ($cmd in $IcingaConfiguration.Keys) {
|
|
$cmdConfig = $IcingaConfiguration[$cmd];
|
|
|
|
if ($cmd.Contains(':')) {
|
|
continue; # skip for now, as more complicated
|
|
}
|
|
|
|
$cmdArguments = @{
|
|
'Automated' = $TRUE;
|
|
}
|
|
|
|
if ($cmdConfig.ContainsKey('Values') -And $null -ne $cmdConfig.Values) {
|
|
$cmdArguments.Add('Value', $cmdConfig.Values)
|
|
}
|
|
if ($cmdConfig.ContainsKey('Selection') -And $null -ne $cmdConfig.Selection) {
|
|
$cmdArguments.Add('DefaultInput', $cmdConfig.Selection)
|
|
}
|
|
|
|
&$cmd @cmdArguments;
|
|
}
|
|
}
|
|
|
|
function Reset-IcingaForWindowsManagementConsoleInstallationDirectorConfigModifyState()
|
|
{
|
|
foreach ($entry in $Global:Icinga.InstallWizard.Config.Keys) {
|
|
|
|
if ($entry -eq 'IfW-DirectorUrl' -Or $entry -eq 'IfW-DirectorSelfServiceKey') {
|
|
continue;
|
|
}
|
|
|
|
$Global:Icinga.InstallWizard.Config[$entry].Modified = $FALSE;
|
|
}
|
|
}
|
|
|
|
function Get-IcingaForWindowsInstallerLastParent()
|
|
{
|
|
if ($global:Icinga.InstallWizard.LastParent.Count -ne 0) {
|
|
$Parent = $global:Icinga.InstallWizard.LastParent[-1];
|
|
return $Parent;
|
|
}
|
|
|
|
return $null;
|
|
}
|
|
|
|
function Get-IcingaInternalPowerShellServicePassword()
|
|
{
|
|
if ($null -eq $global:Icinga -Or $Global:Icinga.ContainsKey('InstallerServicePassword') -eq $FALSE) {
|
|
return $null;
|
|
}
|
|
|
|
return $Global:Icinga.InstallerServicePassword;
|
|
}
|
|
|
|
function Convert-IcingaForwindowsManagementConsoleJSONConfig()
|
|
{
|
|
param (
|
|
$Config
|
|
);
|
|
|
|
[int]$Index = 0;
|
|
$MaxIndex = $Config.PSObject.Properties.Count;
|
|
[string]$Menu = '';
|
|
[hashtable]$ConvertedConfig = @{ };
|
|
|
|
while ($Index -lt $MaxIndex.Count) {
|
|
foreach ($entry in $Config.PSObject.Properties) {
|
|
|
|
if ($index -eq [int]$entry.Value.Index) {
|
|
$ConvertedConfig.Add(
|
|
$entry.Name,
|
|
@{
|
|
'Selection' = $entry.Value.Selection;
|
|
'Values' = $entry.Value.Values;
|
|
'Index' = $index;
|
|
'Parent' = $entry.Value.Parent;
|
|
'ParentEntry' = $entry.Value.ParentEntry;
|
|
'Hidden' = $entry.Value.Hidden;
|
|
'Password' = $entry.Value.Password;
|
|
'Advanced' = $entry.Value.Advanced;
|
|
'Modified' = $entry.Value.Modified;
|
|
}
|
|
);
|
|
|
|
if ($entry.Value.Advanced -eq $FALSE) {
|
|
$global:Icinga.InstallWizard.LastParent.Add($entry.Name) | Out-Null;
|
|
}
|
|
}
|
|
}
|
|
$Index += 1;
|
|
}
|
|
|
|
return $ConvertedConfig;
|
|
}
|
|
|
|
function Get-IcingaForWindowsManagementConsoleMenu()
|
|
{
|
|
if ($null -eq $global:Icinga -Or $null -eq $global:Icinga.InstallWizard) {
|
|
return '';
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($global:Icinga.InstallWizard.Menu) -Or $global:Icinga.InstallWizard.Menu -eq 'break') {
|
|
return '';
|
|
}
|
|
|
|
return (Get-IcingaForWindowsManagementConsoleAlias -Command $global:Icinga.InstallWizard.Menu);
|
|
}
|
|
|
|
function Clear-IcingaForWindowsManagementConsolePaginationCache()
|
|
{
|
|
$global:Icinga.InstallWizard.LastParent.Clear();
|
|
}
|
|
|
|
function Remove-IcingaForWindowsInstallerLastParent()
|
|
{
|
|
if ($global:Icinga.InstallWizard.LastParent.Count -ne 0) {
|
|
$global:Icinga.InstallWizard.LastParent.RemoveAt($global:Icinga.InstallWizard.LastParent.Count - 1);
|
|
}
|
|
}
|
|
|
|
function Set-IcingaForWindowsManagementConsoleMenu()
|
|
{
|
|
param (
|
|
[string]$Menu
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Menu) -Or $Menu -eq 'break') {
|
|
return;
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.Menu = (Get-IcingaForWindowsManagementConsoleAlias -Command $Menu);
|
|
}
|
|
|
|
function Set-IcingaInternalPowerShellServicePassword()
|
|
{
|
|
param (
|
|
[SecureString]$Password = $null
|
|
);
|
|
|
|
if ($null -eq $global:Icinga) {
|
|
$Global:Icinga = @{
|
|
'InstallerServicePassword' = $Password;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ($Global:Icinga.ContainsKey('InstallerServicePassword') -eq $FALSE) {
|
|
$Global:Icinga.Add(
|
|
'InstallerServicePassword',
|
|
$Password
|
|
)
|
|
|
|
return;
|
|
}
|
|
|
|
$Global:Icinga.InstallerServicePassword = $Password;
|
|
}
|
|
|
|
function Show-IcingaForWindowsInstallerMenu()
|
|
{
|
|
param (
|
|
[string]$Header,
|
|
[array]$Entries,
|
|
[array]$DefaultValues = @(),
|
|
[string]$DefaultIndex = $null,
|
|
[string]$ParentConfig = $null,
|
|
[switch]$AddConfig = $FALSE,
|
|
[switch]$PasswordInput = $FALSE,
|
|
[switch]$ContinueFirstValue = $FALSE,
|
|
[switch]$MandatoryValue = $FALSE,
|
|
[int]$ConfigLimit = -1,
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[string]$ContinueFunction = $null,
|
|
[switch]$ConfigElement = $FALSE,
|
|
[switch]$HiddenConfigElement = $FALSE,
|
|
[switch]$ReadOnly = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
if ((Test-IcingaForWindowsInstallationHeaderPrint) -eq $FALSE -And (Get-IcingaFrameworkDebugMode) -eq $FALSE) {
|
|
Clear-Host;
|
|
}
|
|
|
|
$PSCallStack = Get-PSCallStack;
|
|
$LastArguments = $null;
|
|
$LastCommand = $null;
|
|
|
|
if ($PSCallStack.Count -gt 1) {
|
|
$LastCommand = $PSCallStack[1].Command;
|
|
$LastArguments = $PSCallStack[1].InvocationInfo.BoundParameters;
|
|
|
|
# Only keep internal values as long as we are navigating within the same menu
|
|
if ($global:Icinga.InstallWizard.Menu -ne $LastCommand) {
|
|
$global:Icinga.InstallWizard.LastValues = @();
|
|
}
|
|
|
|
# Prevent from adding ourself because of stack calls.
|
|
# This should always be the "real" last command
|
|
if ($LastCommand -ne 'Show-IcingaForWindowsInstallerMenu') {
|
|
$global:Icinga.InstallWizard.Menu = $LastCommand;
|
|
} else {
|
|
$LastCommand = Get-IcingaForWindowsManagementConsoleMenu;
|
|
}
|
|
}
|
|
|
|
$SelectionForCurrentMenu = Get-IcingaForWindowsInstallerStepSelection -InstallerStep (Get-IcingaForWindowsManagementConsoleMenu);
|
|
[bool]$EntryModified = $FALSE;
|
|
[int]$EntryIndex = 0;
|
|
[hashtable]$KnownIndexes = @{ };
|
|
$LastParent = Get-IcingaForWindowsInstallerLastParent;
|
|
[array]$StoredValues = (Get-IcingaForWindowsInstallerValuesFromStep);
|
|
$global:Icinga.InstallWizard.ParentConfig = $ParentConfig;
|
|
$global:Icinga.InstallWizard.LastInput = $null;
|
|
|
|
if ($LastParent -eq (Get-IcingaForWindowsManagementConsoleAlias -Command $LastCommand)) {
|
|
Remove-IcingaForWindowsInstallerLastParent;
|
|
$LastParent = Get-IcingaForWindowsInstallerLastParent;
|
|
}
|
|
|
|
if (Test-IcingaForWindowsInstallationJumpToSummary) {
|
|
$SelectionForCurrentMenu = $null;
|
|
}
|
|
|
|
if ($StoredValues.Count -eq 0 -And $DefaultValues.Count -ne 0) {
|
|
$StoredValues = $DefaultValues;
|
|
}
|
|
|
|
if ($global:Icinga.InstallWizard.DeleteValues) {
|
|
$StoredValues = @();
|
|
$global:Icinga.InstallWizard.DeleteValues = $FALSE;
|
|
}
|
|
|
|
if ((Test-IcingaForWindowsInstallationHeaderPrint) -eq $FALSE) {
|
|
|
|
$ConsoleHeaderLines = @(
|
|
'Icinga for Windows Management Console',
|
|
'Copyright $Copyright',
|
|
'User environment $UserDomain\$Username',
|
|
'Icinga PowerShell Framework $FrameworkVersion'
|
|
);
|
|
|
|
if ($global:Icinga.InstallWizard.AdminShell -eq $FALSE) {
|
|
$ConsoleHeaderLines += '[Warning]: Run this shell as Administrator to unlock all features'
|
|
}
|
|
|
|
$ConsoleHeaderLines += @(
|
|
'This is an experimental feature and might contain bugs',
|
|
'Please provide us with feedback, issues and input at',
|
|
'https://github.com/Icinga/icinga-powershell-framework/issues'
|
|
)
|
|
|
|
Write-IcingaConsoleHeader -HeaderLines $ConsoleHeaderLines;
|
|
|
|
Write-IcingaConsolePlain '';
|
|
Write-IcingaConsolePlain $Header;
|
|
Write-IcingaConsolePlain '';
|
|
}
|
|
|
|
foreach ($entry in $Entries) {
|
|
if ([string]::IsNullOrEmpty($entry.Caption) -eq $FALSE) {
|
|
$Header = ([string]::Format('[{0}] {1}', $EntryIndex, $entry.Caption));
|
|
$FontColor = 'Default';
|
|
|
|
if ((Test-IcingaForWindowsInstallationHeaderPrint) -eq $FALSE) {
|
|
# Highlight the default index in a different color
|
|
if ($DefaultIndex -eq $EntryIndex) {
|
|
$FontColor = 'Cyan';
|
|
}
|
|
|
|
# In case a entry is disabled, highlight it differently
|
|
if ($null -ne $entry.Disabled -And $entry.Disabled -eq $TRUE) {
|
|
$FontColor = 'DarkGray';
|
|
}
|
|
|
|
# Mark our previous selection in another color for better highlighting
|
|
if ($null -ne $SelectionForCurrentMenu -And $SelectionForCurrentMenu -eq $EntryIndex) {
|
|
$FontColor = 'Green';
|
|
}
|
|
|
|
Write-IcingaConsolePlain $Header -ForeColor $FontColor;
|
|
|
|
if ($global:Icinga.InstallWizard.ShowHelp -And ([string]::IsNullOrEmpty($entry.Help)) -eq $FALSE) {
|
|
Write-IcingaConsolePlain '';
|
|
Write-IcingaConsolePlain $entry.Help -ForeColor Magenta;
|
|
Write-IcingaConsolePlain '';
|
|
}
|
|
} else {
|
|
if ((Get-IcingaForWindowsInstallationHeaderSelection) -eq $EntryIndex) {
|
|
$global:Icinga.InstallWizard.HeaderPreview = $entry.Caption;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
$KnownIndexes.Add([string]$EntryIndex, $TRUE);
|
|
$EntryIndex += 1;
|
|
}
|
|
|
|
if ((Test-IcingaForWindowsInstallationHeaderPrint)) {
|
|
return;
|
|
}
|
|
|
|
if ($StoredValues.Count -ne 0) {
|
|
if ($PasswordInput -eq $FALSE) {
|
|
Write-IcingaConsolePlain ([string]::Format(' {0}', (ConvertFrom-IcingaArrayToString -Array $StoredValues -AddQuotes))) -ForeColor Cyan;
|
|
} else {
|
|
Write-IcingaConsolePlain ([string]::Format(' {0}', (ConvertFrom-IcingaArrayToString -Array $StoredValues -AddQuotes -SecureContent))) -ForeColor Cyan;
|
|
}
|
|
}
|
|
|
|
if ($AddConfig) {
|
|
if ($global:Icinga.InstallWizard.ShowHelp -And ([string]::IsNullOrEmpty($Entries[0].Help)) -eq $FALSE) {
|
|
Write-IcingaConsolePlain '';
|
|
Write-IcingaConsolePlain $entry.Help -ForeColor Magenta;
|
|
}
|
|
}
|
|
|
|
$MenuNavigation = '[x] Exit';
|
|
|
|
Write-IcingaConsolePlain '';
|
|
|
|
if ($global:Icinga.InstallWizard.DisplayAdvanced) {
|
|
$MenuNavigation = [string]::Format('{0} [a] Advanced', $MenuNavigation)
|
|
}
|
|
|
|
$MenuNavigation = [string]::Format('{0} [c] Continue', $MenuNavigation)
|
|
|
|
if ($AddConfig -And $ReadOnly -eq $FALSE) {
|
|
$MenuNavigation = [string]::Format('{0} [d] Delete', $MenuNavigation)
|
|
}
|
|
|
|
$MenuNavigation = [string]::Format('{0} [h] Help [m] Main', $MenuNavigation)
|
|
|
|
if ([string]::IsNullOrEmpty($LastParent) -eq $FALSE -Or $global:Icinga.InstallWizard.LastParent.Count -gt 1) {
|
|
$MenuNavigation = [string]::Format('{0} [p] Previous', $MenuNavigation)
|
|
}
|
|
|
|
Write-IcingaConsolePlain $MenuNavigation;
|
|
|
|
$Prompt = 'Input';
|
|
$CountPrompt = ([string]::Format('({0}/{1})', $StoredValues.Count, $ConfigLimit));
|
|
if ($ConfigLimit -eq -1) {
|
|
$CountPrompt = ([string]::Format('({0} values)', $StoredValues.Count));
|
|
}
|
|
|
|
if ($AddConfig) {
|
|
$Prompt = ([string]::Format('Input {0}', $CountPrompt));
|
|
# In case we reached the maximum entries, set c as default input for easier handling
|
|
if (($ConfigLimit -le $StoredValues.Count) -Or ($ContinueFirstValue -eq $TRUE -And $StoredValues.Count -ge 1)) {
|
|
$DefaultIndex = 'c';
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($DefaultIndex) -eq $FALSE) {
|
|
if ((Test-Numeric $DefaultIndex)) {
|
|
$Prompt = [string]::Format('Input (Default {0} and c)', $DefaultIndex);
|
|
} else {
|
|
$Prompt = [string]::Format('Input (Default {0})', $DefaultIndex);
|
|
}
|
|
if ($AddConfig) {
|
|
$Prompt = [string]::Format('{0} {1}', $Prompt, $CountPrompt);
|
|
}
|
|
}
|
|
|
|
Write-IcingaConsolePlain '';
|
|
|
|
if ([string]::IsNullOrEmpty($global:Icinga.InstallWizard.LastError) -eq $FALSE) {
|
|
Write-IcingaConsoleError ($global:Icinga.InstallWizard.LastError);
|
|
$global:Icinga.InstallWizard.LastError = '';
|
|
Write-IcingaConsolePlain '';
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($global:Icinga.InstallWizard.LastNotice) -eq $FALSE) {
|
|
Write-IcingaConsoleNotice ($global:Icinga.InstallWizard.LastNotice);
|
|
$global:Icinga.InstallWizard.LastNotice = '';
|
|
Write-IcingaConsolePlain '';
|
|
}
|
|
|
|
if ($Automated -eq $FALSE) {
|
|
$Result = Read-Host -Prompt $Prompt -AsSecureString:$PasswordInput;
|
|
|
|
# Translate the value back to check what we used for input. We are not going to share
|
|
# the content however
|
|
if ($PasswordInput) {
|
|
$Result = ConvertFrom-IcingaSecureString -SecureString $Result;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Result) -And [string]::IsNullOrEmpty($DefaultIndex) -eq $FALSE) {
|
|
$Result = $DefaultIndex;
|
|
}
|
|
} else {
|
|
if ([string]::IsNullOrEmpty($DefaultIndex) -eq $FALSE) {
|
|
$Result = $DefaultIndex;
|
|
}
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.NextCommand = $LastCommand;
|
|
$global:Icinga.InstallWizard.NextArguments = $LastArguments;
|
|
$global:Icinga.InstallWizard.LastInput = $Result;
|
|
|
|
switch ($Result) {
|
|
'x' {
|
|
Clear-Host;
|
|
$global:Icinga.InstallWizard.Closing = $TRUE;
|
|
return;
|
|
};
|
|
'a' {
|
|
$global:Icinga.InstallWizard.ShowAdvanced = (-Not ($global:Icinga.InstallWizard.ShowAdvanced));
|
|
return;
|
|
};
|
|
'h' {
|
|
$global:Icinga.InstallWizard.ShowHelp = (-Not ($global:Icinga.InstallWizard.ShowHelp));
|
|
|
|
return;
|
|
};
|
|
'm' {
|
|
$global:Icinga.InstallWizard.NextCommand = $null;
|
|
$global:Icinga.InstallWizard.NextArguments = $null;
|
|
|
|
return;
|
|
}
|
|
'p' {
|
|
if ([string]::IsNullOrEmpty($LastParent) -eq $FALSE) {
|
|
Remove-IcingaForWindowsInstallerLastParent;
|
|
|
|
$global:Icinga.InstallWizard.NextCommand = $LastParent;
|
|
$global:Icinga.InstallWizard.NextArguments = $null;
|
|
|
|
return;
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.LastError = 'You cannot move to the previous menu from here.';
|
|
if ($global:Icinga.InstallWizard.LastParent.Count -eq 0) {
|
|
$global:Icinga.InstallWizard.NextCommand = $null;
|
|
$global:Icinga.InstallWizard.NextArguments = $null;
|
|
|
|
return;
|
|
}
|
|
|
|
return;
|
|
};
|
|
'd' {
|
|
if ($ReadOnly -eq $FALSE) {
|
|
$StoredValues = @();
|
|
Clear-IcingaForWindowsInstallerValuesFromStep
|
|
$global:Icinga.InstallWizard.DeleteValues = $TRUE;
|
|
$global:Icinga.InstallWizard.LastValues = @();
|
|
}
|
|
|
|
return;
|
|
};
|
|
'c' {
|
|
if ($MandatoryValue -And $StoredValues.Count -eq 0) {
|
|
$global:Icinga.InstallWizard.LastError = 'You need to add at least one value!';
|
|
|
|
return;
|
|
}
|
|
|
|
if ($AddConfig -eq $FALSE) {
|
|
$Result = $DefaultIndex;
|
|
$global:Icinga.InstallWizard.LastInput = $Result;
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.LastValues = $StoredValues;
|
|
|
|
break;
|
|
};
|
|
default {
|
|
if ($AddConfig) {
|
|
|
|
if ($ConfigLimit -eq -1 -Or $ConfigLimit -gt $StoredValues.Count) {
|
|
if ([string]::IsNullOrEmpty($Result) -eq $FALSE) {
|
|
|
|
$StoredValues += $Result;
|
|
if ($ConfigElement) {
|
|
Add-IcingaForWindowsInstallerConfigEntry -Values $StoredValues -Hidden:$HiddenConfigElement -PasswordInput:$PasswordInput -Advanced:$Advanced;
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.LastValues = $StoredValues;
|
|
} else {
|
|
if ($DefaultValues.Count -ne 0) {
|
|
$global:Icinga.InstallWizard.LastNotice = 'Empty values are not allowed! Resetting to default.';
|
|
} else {
|
|
$global:Icinga.InstallWizard.LastError = 'You cannot add an empty value!';
|
|
}
|
|
}
|
|
} else {
|
|
$global:Icinga.InstallWizard.LastError = [string]::Format('You can only add {0} value(s)', $ConfigLimit);
|
|
}
|
|
|
|
return;
|
|
}
|
|
if ((Test-Numeric $Result) -eq $FALSE -Or $KnownIndexes.ContainsKey([string]$Result) -eq $FALSE) {
|
|
$global:Icinga.InstallWizard.LastError = [string]::Format('Invalid selection has been made: {0}', $Result);
|
|
|
|
return;
|
|
}
|
|
|
|
break;
|
|
};
|
|
}
|
|
|
|
$DisabledMenu = $FALSE;
|
|
$NextMenu = $null;
|
|
$NextArguments = @{ };
|
|
$ActionCmd = $null;
|
|
$ActionArgs = $null;
|
|
|
|
if ([string]::IsNullOrEmpty($Result) -eq $FALSE) {
|
|
if ($Result -eq 'c') {
|
|
if ([string]::IsNullOrEmpty($ContinueFunction) -eq $FALSE) {
|
|
$NextMenu = $ContinueFunction;
|
|
} else {
|
|
$NextMenu = $Entries[0].Command;
|
|
if ($null -ne $Entries[0].Disabled) {
|
|
$DisabledMenu = $Entries[0].Disabled;
|
|
}
|
|
}
|
|
$ActionCmd = $Entries[0].Action.Command;
|
|
$ActionArgs = $Entries[0].Action.Arguments;
|
|
} else {
|
|
$NextMenu = $Entries[$Result].Command;
|
|
if ($null -ne $Entries[$Result].Disabled) {
|
|
$DisabledMenu = $Entries[$Result].Disabled;
|
|
}
|
|
if ($Entries[$Result].ContainsKey('Arguments')) {
|
|
$NextArguments = $Entries[$Result].Arguments;
|
|
}
|
|
$ActionCmd = $Entries[$Result].Action.Command;
|
|
$ActionArgs = $Entries[$Result].Action.Arguments;
|
|
}
|
|
}
|
|
|
|
if ($DisabledMenu) {
|
|
$global:Icinga.InstallWizard.LastNotice = [string]::Format('This menu is not enabled: {0}', $Result);
|
|
|
|
return;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($NextMenu)) {
|
|
$global:Icinga.InstallWizard.LastNotice = [string]::Format('This menu is not yet implemented: {0}', $Result);
|
|
|
|
return;
|
|
}
|
|
|
|
if ($Advanced -eq $FALSE) {
|
|
Add-IcingaForWindowsManagementConsoleLastParent;
|
|
}
|
|
|
|
if ($JumpToSummary) {
|
|
$NextMenu = 'Show-IcingaForWindowsInstallerConfigurationSummary';
|
|
}
|
|
|
|
if ($ConfigElement) {
|
|
Add-IcingaForWindowsInstallerConfigEntry `
|
|
-InstallerStep (Get-IcingaForWindowsManagementConsoleMenu) `
|
|
-Selection $Result `
|
|
-Values $StoredValues `
|
|
-Hidden:$HiddenConfigElement `
|
|
-PasswordInput:$PasswordInput `
|
|
-Advanced:$Advanced;
|
|
}
|
|
|
|
# Reset Help View
|
|
$global:Icinga.InstallWizard.ShowHelp = $FALSE;
|
|
|
|
if ($NextMenu -eq 'break') {
|
|
return;
|
|
}
|
|
|
|
$global:Icinga.InstallWizard.NextCommand = $NextMenu;
|
|
$global:Icinga.InstallWizard.NextArguments = $NextArguments;
|
|
|
|
if ($Automated) {
|
|
return;
|
|
}
|
|
|
|
# In case a action is defined, execute the given action
|
|
if ([string]::IsNullOrEmpty($ActionCmd) -eq $FALSE) {
|
|
if ($null -eq $ActionArgs -Or $ActionArgs.Count -eq 0) {
|
|
$ActionArgs = @{ };
|
|
}
|
|
|
|
& $ActionCmd @ActionArgs | Out-Null;
|
|
}
|
|
}
|
|
|
|
function Get-IcingaForWindowsInstallerStepSelection()
|
|
{
|
|
param (
|
|
[string]$InstallerStep
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($InstallerStep)) {
|
|
$InstallerStep = Get-IcingaForWindowsManagementConsoleMenu;
|
|
} else {
|
|
$InstallerStep = Get-IcingaForWindowsManagementConsoleAlias -Command $InstallerStep;
|
|
}
|
|
|
|
if ($global:Icinga.InstallWizard.Config.ContainsKey($InstallerStep)) {
|
|
return $global:Icinga.InstallWizard.Config[$InstallerStep].Selection;
|
|
}
|
|
|
|
return $null;
|
|
}
|
|
|
|
function Get-IcingaForWindowsInstallerValuesFromStep()
|
|
{
|
|
param (
|
|
[string]$InstallerStep,
|
|
[string]$Parent
|
|
);
|
|
|
|
[array]$Values = @();
|
|
|
|
$Step = Get-IcingaForWindowsManagementConsoleMenu;
|
|
|
|
if ([string]::IsNullOrEmpty($InstallerStep) -eq $FALSE) {
|
|
$Step = Get-IcingaForWindowsManagementConsoleAlias -Command $InstallerStep;
|
|
|
|
if ([string]::IsNullOrEmpty($Parent) -eq $FALSE) {
|
|
$Step = [string]::Format('{0}:{1}', $Step, $Parent);
|
|
}
|
|
}
|
|
|
|
if ($global:Icinga.InstallWizard.Config.ContainsKey($Step) -eq $FALSE) {
|
|
return @();
|
|
}
|
|
|
|
if ($null -eq $global:Icinga.InstallWizard.Config[$Step].Values) {
|
|
return @();
|
|
}
|
|
|
|
return [array]($global:Icinga.InstallWizard.Config[$Step].Values);
|
|
}
|
|
|
|
function Write-IcingaforWindowsManagementConsoleConfigSwap()
|
|
{
|
|
param (
|
|
$Config = @{ }
|
|
);
|
|
|
|
[hashtable]$NewConfig = @{ };
|
|
|
|
# Remove passwords - do not store them inside our local config file
|
|
foreach ($entry in $Config.Keys) {
|
|
$Value = $Config[$entry];
|
|
|
|
$NewConfig.Add($entry, @{ });
|
|
|
|
foreach ($configElement in $Value.Keys) {
|
|
$confValue = $Value[$configElement];
|
|
|
|
if ($Value.Password -eq $TRUE -And $configElement -eq 'Values') {
|
|
$NewConfig[$entry].Add(
|
|
$configElement,
|
|
@( '***' )
|
|
);
|
|
} else {
|
|
$NewConfig[$entry].Add(
|
|
$configElement,
|
|
$confValue
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Config.Swap' -Value $NewConfig;
|
|
}
|
|
|
|
function Test-IcingaForWindowsManagementConsoleContinue()
|
|
{
|
|
if ([string]::IsNullOrEmpty($global:Icinga.InstallWizard.LastInput)) {
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($global:Icinga.InstallWizard.LastInput -eq 'c') {
|
|
return $TRUE;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
function Test-IcingaForWindowsManagementConsoleDelete()
|
|
{
|
|
if ([string]::IsNullOrEmpty($global:Icinga.InstallWizard.LastInput)) {
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($global:Icinga.InstallWizard.LastInput -eq 'd') {
|
|
return $TRUE;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
function Test-IcingaForWindowsManagementConsoleExit()
|
|
{
|
|
if ([string]::IsNullOrEmpty($global:Icinga.InstallWizard.LastInput)) {
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($global:Icinga.InstallWizard.LastInput -eq 'x') {
|
|
return $TRUE;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
function Test-IcingaForWindowsManagementConsoleHelp()
|
|
{
|
|
if ([string]::IsNullOrEmpty($global:Icinga.InstallWizard.LastInput)) {
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($global:Icinga.InstallWizard.LastInput -eq 'h') {
|
|
return $TRUE;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
function Test-IcingaForWindowsManagementConsoleMenu()
|
|
{
|
|
if ([string]::IsNullOrEmpty($global:Icinga.InstallWizard.LastInput)) {
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($global:Icinga.InstallWizard.LastInput -eq 'm') {
|
|
return $TRUE;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
function Test-IcingaForWindowsManagementConsolePrevious()
|
|
{
|
|
if ([string]::IsNullOrEmpty($global:Icinga.InstallWizard.LastInput)) {
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($global:Icinga.InstallWizard.LastInput -eq 'p') {
|
|
return $TRUE;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
function Get-IcingaForWindowsManagementConsoleLastInput()
|
|
{
|
|
return $global:Icinga.InstallWizard.LastInput;
|
|
}
|
|
|
|
function Show-IcingaWindowsManagementConsoleYesNoDialog()
|
|
{
|
|
param (
|
|
[string]$Caption = '',
|
|
[string]$Command = '',
|
|
[hashtable]$CmdArguments = @{ },
|
|
[array]$Value = @(),
|
|
[string]$DefaultInput = '0',
|
|
[switch]$JumpToSummary = $FALSE,
|
|
[switch]$Automated = $FALSE,
|
|
[switch]$Advanced = $FALSE
|
|
);
|
|
|
|
$LastParent = Get-IcingaForWindowsInstallerLastParent;
|
|
|
|
Show-IcingaForWindowsInstallerMenu `
|
|
-Header ([string]::Format('Are you sure you want to perform this action: "{0}"?', $Caption)) `
|
|
-Entries @(
|
|
@{
|
|
'Caption' = 'No';
|
|
'Command' = $LastParent;
|
|
'Help' = 'Do not apply the last action and return without doing anything';
|
|
},
|
|
@{
|
|
'Caption' = 'Yes';
|
|
'Command' = $LastParent;
|
|
'Help' = "Apply the action and confirm it's execution";
|
|
}
|
|
) `
|
|
-DefaultIndex $DefaultInput;
|
|
|
|
if ((Get-IcingaForWindowsManagementConsoleLastInput) -eq '1') {
|
|
if ($null -eq $CmdArguments -Or $CmdArguments.Count -eq 0) {
|
|
& $Command | Out-Null;
|
|
} else {
|
|
& $Command @CmdArguments | Out-Null;
|
|
}
|
|
$global:Icinga.InstallWizard.LastNotice = [string]::Format('Action "{0}" has been executed', $Caption);
|
|
}
|
|
}
|
|
|
|
function Disable-IcingaForWindowsInstallationHeaderPrint()
|
|
{
|
|
$global:Icinga.InstallWizard.HeaderPrint = $FALSE;
|
|
}
|
|
|
|
function Disable-IcingaForWindowsInstallationJumpToSummary()
|
|
{
|
|
$global:Icinga.InstallWizard.JumpToSummary = $FALSE;
|
|
}
|
|
|
|
function Enable-IcingaForWindowsInstallationHeaderPrint()
|
|
{
|
|
$global:Icinga.InstallWizard.HeaderPrint = $TRUE;
|
|
}
|
|
|
|
function Enable-IcingaForWindowsInstallationJumpToSummary()
|
|
{
|
|
$global:Icinga.InstallWizard.JumpToSummary = $TRUE;
|
|
}
|
|
|
|
function Get-IcingaForWindowsInstallationHeaderSelection()
|
|
{
|
|
return $global:Icinga.InstallWizard.HeaderSelection;
|
|
}
|
|
|
|
function Test-IcingaForWindowsInstallationHeaderPrint()
|
|
{
|
|
return $global:Icinga.InstallWizard.HeaderPrint;
|
|
}
|
|
|
|
function Test-IcingaForWindowsInstallationJumpToSummary()
|
|
{
|
|
return $global:Icinga.InstallWizard.JumpToSummary;
|
|
}
|
|
|
|
function Set-IcingaForWindowsInstallationHeaderSelection()
|
|
{
|
|
param (
|
|
[string]$Selection = $null
|
|
);
|
|
|
|
$global:Icinga.InstallWizard.HeaderSelection = $Selection;
|
|
}
|
|
|
|
<#
|
|
# This script will provide 'Enums' we can use for proper
|
|
# error handling and to provide more detailed descriptions
|
|
#
|
|
# Example usage:
|
|
# $IcingaEventLogEnums[2000]
|
|
#>
|
|
if ($null -eq $IcingaEventLogEnums -Or $IcingaEventLogEnums.ContainsKey('Framework') -eq $FALSE) {
|
|
[hashtable]$IcingaEventLogEnums += @{
|
|
'Framework' = @{
|
|
1000 = @{
|
|
'EntryType' = 'Information';
|
|
'Message' = 'Generic debug message issued by the Framework or its components';
|
|
'Details' = 'The Framework or is components can issue generic debug message in case the debug log is enabled. Please ensure to disable it, if not used. You can do so with the command "Disable-IcingaFrameworkDebugMode"';
|
|
'EventId' = 1000;
|
|
};
|
|
1500 = @{
|
|
'EntryType' = 'Error';
|
|
'Message' = 'Failed to securely establish a communication between this server and the client';
|
|
'Details' = 'A client connection could not be established to this server. This issue is mostly caused by using Self-Signed/Icinga 2 Agent certificates for the server and the client not trusting the certificate. To resolve this issue, either use trusted certificates signed by your trusted CA or setup the client to accept untrusted certificates';
|
|
'EventId' = 1500;
|
|
};
|
|
1501 = @{
|
|
'EntryType' = 'Error';
|
|
'Message' = 'Client connection was interrupted because of invalid SSL stream';
|
|
'Details' = 'A client connection was terminated by the Framework because no secure SSL handshake could be established. This issue in general is followed by EventId 1500.';
|
|
'EventId' = 1501;
|
|
};
|
|
1550 = @{
|
|
'EntryType' = 'Error';
|
|
'Message' = 'Unsupported web authentication used';
|
|
'Details' = 'A web client tried to authenticate with an unsupported authorization method.';
|
|
'EventId' = 1550;
|
|
};
|
|
1551 = @{
|
|
'EntryType' = 'Warning';
|
|
'Message' = 'Invalid authentication credentials provided';
|
|
'Details' = 'A web request for a client was rejected because of invalid formated base64 encoded credentials.';
|
|
'EventId' = 1551;
|
|
};
|
|
1552 = @{
|
|
'EntryType' = 'Error';
|
|
'Message' = 'Failed to parse use credentials from base64 encoding';
|
|
'Details' = 'Provided user credentials encoded as base64 could not be converted to domain, user and password objects.';
|
|
'EventId' = 1552;
|
|
};
|
|
1553 = @{
|
|
'EntryType' = 'Error';
|
|
'Message' = 'Failed to query Icinga check over internal REST-Api check handler';
|
|
'Details' = 'A service check could not be executed by using the internal REST-Api check handler. The check either ran into a timeout or could not be processed. Maybe the check was not registered to be allowed for being executed. Further details can be found below.';
|
|
'EventId' = 1553;
|
|
};
|
|
1560 = @{
|
|
'EntryType' = 'Error';
|
|
'Message' = 'Failed to test user login as no Principal Context could be established';
|
|
'Details' = 'A web client trying to authenticate failed as no Principal Context for the provided domain could be established.';
|
|
'EventId' = 1560;
|
|
};
|
|
1561 = @{
|
|
'EntryType' = 'Error';
|
|
'Message' = 'Failed to authenticate user with given credentials';
|
|
'Details' = 'A web client trying to authenticate failed as the provided user credentials could not be verified.';
|
|
'EventId' = 1561;
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
Export-ModuleMember -Variable @( 'IcingaEventLogEnums' );
|
|
|
|
function Register-IcingaEventLog()
|
|
{
|
|
try {
|
|
# Run this in a Try-Catch-Block, as we will run into an exception if it is not
|
|
# present in the Application where it should be once we try to load the
|
|
# Security log. If it is not found in the "public" Event-Log data, the
|
|
# App is not registered
|
|
$Registered = [System.Diagnostics.EventLog]::SourceExists(
|
|
'Icinga for Windows'
|
|
);
|
|
|
|
if ($Registered) {
|
|
return;
|
|
}
|
|
|
|
New-EventLog -LogName Application -Source 'Icinga for Windows';
|
|
} catch {
|
|
Exit-IcingaThrowException -ExceptionType 'Configuration' -ExceptionThrown $IcingaExceptions.Configuration.EventLogNotInstalled -Force;
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Default Cmdlet for printing debug messages to console
|
|
.DESCRIPTION
|
|
Default Cmdlet for printing debug messages to console
|
|
.FUNCTIONALITY
|
|
Default Cmdlet for printing debug messages to console
|
|
.EXAMPLE
|
|
PS>Write-IcingaConsoleDebug -Message 'Test message: {0}' -Objects 'Hello World';
|
|
.PARAMETER Message
|
|
The message to print with {x} placeholdes replaced by content inside the Objects array. Replace x with the
|
|
number of the index from the objects array
|
|
.PARAMETER Objects
|
|
An array of objects being added to a provided message. The index of the array position has to refer to the
|
|
message locations.
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Write-IcingaConsoleDebug()
|
|
{
|
|
param (
|
|
[string]$Message,
|
|
[array]$Objects
|
|
);
|
|
|
|
if ((Get-IcingaFrameworkDebugMode) -eq $FALSE) {
|
|
return;
|
|
}
|
|
|
|
Write-IcingaConsoleOutput `
|
|
-Message $Message `
|
|
-Objects $Objects `
|
|
-ForeColor 'Blue' `
|
|
-Severity 'Debug';
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Default Cmdlet for printing error messages to console
|
|
.DESCRIPTION
|
|
Default Cmdlet for printing error messages to console
|
|
.FUNCTIONALITY
|
|
Default Cmdlet for printing error messages to console
|
|
.EXAMPLE
|
|
PS>Write-IcingaConsoleError -Message 'Test message: {0}' -Objects 'Hello World';
|
|
.PARAMETER Message
|
|
The message to print with {x} placeholdes replaced by content inside the Objects array. Replace x with the
|
|
number of the index from the objects array
|
|
.PARAMETER Objects
|
|
An array of objects being added to a provided message. The index of the array position has to refer to the
|
|
message locations.
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Write-IcingaConsoleError()
|
|
{
|
|
param (
|
|
[string]$Message,
|
|
[array]$Objects
|
|
);
|
|
|
|
Write-IcingaConsoleOutput `
|
|
-Message $Message `
|
|
-Objects $Objects `
|
|
-ForeColor 'Red' `
|
|
-Severity 'Error';
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Default Cmdlet for printing notice messages to console
|
|
.DESCRIPTION
|
|
Default Cmdlet for printing notice messages to console
|
|
.FUNCTIONALITY
|
|
Default Cmdlet for printing notice messages to console
|
|
.EXAMPLE
|
|
PS>Write-IcingaConsoleNotice -Message 'Test message: {0}' -Objects 'Hello World';
|
|
.PARAMETER Message
|
|
The message to print with {x} placeholdes replaced by content inside the Objects array. Replace x with the
|
|
number of the index from the objects array
|
|
.PARAMETER Objects
|
|
An array of objects being added to a provided message. The index of the array position has to refer to the
|
|
message locations.
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Write-IcingaConsoleNotice()
|
|
{
|
|
param (
|
|
[string]$Message,
|
|
[array]$Objects
|
|
);
|
|
|
|
Write-IcingaConsoleOutput `
|
|
-Message $Message `
|
|
-Objects $Objects `
|
|
-ForeColor 'Green' `
|
|
-Severity 'Notice';
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Standardise console output and make handling of object conversion easier into messages
|
|
by using this standard function for displaying severity and log entries
|
|
.DESCRIPTION
|
|
Standardised function to output console messages controlled by the arguments provided
|
|
for coloring, displaying severity and add objects into output messages
|
|
.FUNCTIONALITY
|
|
Standardise console output and make handling of object conversion easier into messages
|
|
by using this standard function for displaying severity and log entries
|
|
.EXAMPLE
|
|
PS>Write-IcingaConsoleOutput -Message 'Test message: {0}' -Objects 'Hello World' -ForeColor 'Green' -Severity 'Test';
|
|
.PARAMETER Message
|
|
The message to print with {x} placeholdes replaced by content inside the Objects array. Replace x with the
|
|
number of the index from the objects array
|
|
.PARAMETER Objects
|
|
An array of objects being added to a provided message. The index of the array position has to refer to the
|
|
message locations.
|
|
.PARAMETER ForeColor
|
|
The color the severity name will be displayed in
|
|
.PARAMETER Severity
|
|
The severity being displayed before the actual message. Leave empty to skip.
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Write-IcingaConsoleOutput()
|
|
{
|
|
param (
|
|
[string]$Message,
|
|
[array]$Objects,
|
|
[ValidateSet('Default', 'Black', 'DarkBlue', 'DarkGreen', 'DarkCyan', 'DarkRed', 'DarkMagenta', 'DarkYellow', 'Gray', 'DarkGray', 'Blue', 'Green', 'Cyan', 'Red', 'Magenta', 'Yellow', 'White')]
|
|
[string]$ForeColor = 'Default',
|
|
[string]$Severity = 'Notice'
|
|
);
|
|
|
|
if ((Test-IcingaFrameworkConsoleOutput) -eq $FALSE) {
|
|
return;
|
|
}
|
|
|
|
# Never write console output in case the Framework is running as daemon
|
|
if ($null -ne $global:IcingaDaemonData -And $null -ne $global:IcingaDaemonData.FrameworkRunningAsDaemon -And $global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $TRUE) {
|
|
return;
|
|
}
|
|
|
|
$OutputMessage = $Message;
|
|
[int]$Index = 0;
|
|
|
|
foreach ($entry in $Objects) {
|
|
|
|
$OutputMessage = $OutputMessage.Replace(
|
|
[string]::Format('{0}{1}{2}', '{', $Index, '}'),
|
|
$entry
|
|
);
|
|
$Index++;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Severity) -eq $FALSE) {
|
|
Write-Host '[' -NoNewline;
|
|
Write-Host $Severity -NoNewline -ForegroundColor $ForeColor;
|
|
Write-Host ']: ' -NoNewline;
|
|
Write-Host $OutputMessage;
|
|
|
|
return;
|
|
}
|
|
|
|
if ($ForeColor -eq 'Default') {
|
|
Write-Host $OutputMessage;
|
|
} else {
|
|
Write-Host $OutputMessage -ForegroundColor $ForeColor;
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Default Cmdlet for printing plain messages to console
|
|
.DESCRIPTION
|
|
Default Cmdlet for printing plain messages to console
|
|
.FUNCTIONALITY
|
|
Default Cmdlet for printing plain messages to console
|
|
.EXAMPLE
|
|
PS>Write-IcingaConsolePlain -Message 'Test message: {0}' -Objects 'Hello World';
|
|
.PARAMETER Message
|
|
The message to print with {x} placeholdes replaced by content inside the Objects array. Replace x with the
|
|
number of the index from the objects array
|
|
.PARAMETER Objects
|
|
An array of objects being added to a provided message. The index of the array position has to refer to the
|
|
message locations.
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Write-IcingaConsolePlain()
|
|
{
|
|
param (
|
|
[string]$Message,
|
|
[array]$Objects,
|
|
[ValidateSet('Default', 'Black', 'DarkBlue', 'DarkGreen', 'DarkCyan', 'DarkRed', 'DarkMagenta', 'DarkYellow', 'Gray', 'DarkGray', 'Blue', 'Green', 'Cyan', 'Red', 'Magenta', 'Yellow', 'White')]
|
|
[string]$ForeColor = 'Default'
|
|
);
|
|
|
|
Write-IcingaConsoleOutput `
|
|
-Message $Message `
|
|
-Objects $Objects `
|
|
-ForeColor $ForeColor `
|
|
-Severity $null;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Default Cmdlet for printing warning messages to console
|
|
.DESCRIPTION
|
|
Default Cmdlet for printing warning messages to console
|
|
.FUNCTIONALITY
|
|
Default Cmdlet for printing warning messages to console
|
|
.EXAMPLE
|
|
PS>Write-IcingaConsoleWarning -Message 'Test message: {0}' -Objects 'Hello World';
|
|
.PARAMETER Message
|
|
The message to print with {x} placeholdes replaced by content inside the Objects array. Replace x with the
|
|
number of the index from the objects array
|
|
.PARAMETER Objects
|
|
An array of objects being added to a provided message. The index of the array position has to refer to the
|
|
message locations.
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Write-IcingaConsoleWarning()
|
|
{
|
|
param (
|
|
[string]$Message,
|
|
[array]$Objects
|
|
);
|
|
|
|
Write-IcingaConsoleOutput `
|
|
-Message $Message `
|
|
-Objects $Objects `
|
|
-ForeColor 'DarkYellow' `
|
|
-Severity 'Warning';
|
|
}
|
|
|
|
function Write-IcingaDebugMessage()
|
|
{
|
|
param(
|
|
[string]$Message,
|
|
[array]$Objects = @()
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Message)) {
|
|
return;
|
|
}
|
|
|
|
if ($null -eq $global:IcingaDaemonData -Or $global:IcingaDaemonData.DebugMode -eq $FALSE) {
|
|
return;
|
|
}
|
|
|
|
[array]$DebugContent = @($Message);
|
|
$DebugContent += $Objects;
|
|
|
|
Write-IcingaEventMessage -EventId 1000 -Namespace 'Framework' -Objects $DebugContent;
|
|
}
|
|
|
|
function Write-IcingaErrorMessage()
|
|
{
|
|
param(
|
|
[int]$EventId = 0,
|
|
[string]$Message = $null
|
|
);
|
|
|
|
if ($EventId -eq 0 -Or [string]::IsNullOrEmpty($Message)) {
|
|
return;
|
|
}
|
|
|
|
Write-EventLog -LogName Application -Source 'Icinga for Windows' -EntryType Error -EventId $EventId -Message $Message;
|
|
}
|
|
|
|
function Write-IcingaEventMessage()
|
|
{
|
|
param (
|
|
[int]$EventId = 0,
|
|
[string]$Namespace = $null,
|
|
[array]$Objects = @()
|
|
);
|
|
|
|
if ($EventId -eq 0 -Or [string]::IsNullOrEmpty($Namespace)) {
|
|
return;
|
|
}
|
|
|
|
[string]$EntryType = $IcingaEventLogEnums[$Namespace][$EventId].EntryType;
|
|
[string]$Message = $IcingaEventLogEnums[$Namespace][$EventId].Message;
|
|
[string]$Details = $IcingaEventLogEnums[$Namespace][$EventId].Details;
|
|
|
|
if ([string]::IsNullOrEmpty($Details)) {
|
|
$Details = '';
|
|
}
|
|
if ([string]::IsNullOrEmpty($Message)) {
|
|
$Message = '';
|
|
}
|
|
|
|
[string]$ObjectDump = '';
|
|
|
|
if ($Objects.Count -eq 0) {
|
|
$ObjectDump = [string]::Format(
|
|
'{0}{0}No additional object details provided.',
|
|
(New-IcingaNewLine)
|
|
);
|
|
}
|
|
|
|
foreach ($entry in $Objects) {
|
|
$ObjectDump = [string]::Format(
|
|
'{0}{1}',
|
|
$ObjectDump,
|
|
($entry | Out-String)
|
|
);
|
|
}
|
|
|
|
[string]$EventLogMessage = [string]::Format(
|
|
'{0}{1}{1}{2}{1}{1}Object dumps if available:{1}{3}',
|
|
$Message,
|
|
(New-IcingaNewLine),
|
|
$Details,
|
|
$ObjectDump
|
|
|
|
);
|
|
|
|
if ($null -eq $EntryType -Or $null -eq $Message) {
|
|
return;
|
|
}
|
|
|
|
[int]$MaxEventLogMessageSize = 30000;
|
|
|
|
if ($EventLogMessage.Length -ge $MaxEventLogMessageSize) {
|
|
while ($EventLogMessage.Length -ge $MaxEventLogMessageSize) {
|
|
$CutMessage = $EventLogMessage.Substring(0, $MaxEventLogMessageSize);
|
|
Write-EventLog -LogName Application `
|
|
-Source 'Icinga for Windows' `
|
|
-EntryType $EntryType `
|
|
-EventId $EventId `
|
|
-Message $CutMessage;
|
|
|
|
$EventLogMessage = $EventLogMessage.Substring($MaxEventLogMessageSize, $EventLogMessage.Length - $MaxEventLogMessageSize);
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($EventLogMessage)) {
|
|
return;
|
|
}
|
|
|
|
Write-EventLog -LogName Application `
|
|
-Source 'Icinga for Windows' `
|
|
-EntryType $EntryType `
|
|
-EventId $EventId `
|
|
-Message $EventLogMessage;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Adds counter instances or single counter objects to an internal cache
|
|
by a given counter name or full path
|
|
.DESCRIPTION
|
|
Adds counter instances or single counter objects to an internal cache
|
|
by a given counter name or full path
|
|
.FUNCTIONALITY
|
|
Adds counter instances or single counter objects to an internal cache
|
|
by a given counter name or full path
|
|
.EXAMPLE
|
|
PS>Add-IcingaPerformanceCounterCache -Counter '\Processor(*)\% processor time' -Instances $CounterInstances;
|
|
.PARAMETER Counter
|
|
The path to the counter to store data for
|
|
.PARAMETER Instances
|
|
The value to store for a specific path to a counter
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Add-IcingaPerformanceCounterCache()
|
|
{
|
|
param (
|
|
$Counter,
|
|
$Instances
|
|
);
|
|
|
|
if ($global:Icinga_PerfCounterCache.ContainsKey($Counter)) {
|
|
$global:Icinga_PerfCounterCache[$Counter] = $Instances;
|
|
} else {
|
|
$global:Icinga_PerfCounterCache.Add(
|
|
$Counter, $Instances
|
|
);
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Fetches stored data for a given performance counter path. Returns
|
|
$null if no values are assigned
|
|
.DESCRIPTION
|
|
Fetches stored data for a given performance counter path. Returns
|
|
$null if no values are assigned
|
|
.FUNCTIONALITY
|
|
Fetches stored data for a given performance counter path. Returns
|
|
$null if no values are assigned
|
|
.EXAMPLE
|
|
PS>Get-IcingaPerformanceCounterCacheItem -Counter '\Processor(*)\% processor time';
|
|
.PARAMETER Counter
|
|
The path to the counter to fetch data for
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaPerformanceCounterCacheItem()
|
|
{
|
|
param (
|
|
$Counter
|
|
);
|
|
|
|
if ($global:Icinga_PerfCounterCache.ContainsKey($Counter)) {
|
|
return $global:Icinga_PerfCounterCache[$Counter];
|
|
}
|
|
|
|
return $null;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Creates counter objects and sub-instances from a given Performance Counter
|
|
Will return either a New-IcingaPerformanceCounterObject or New-IcingaPerformanceCounterResult
|
|
which both contain the same members, allowing for dynmically use of objects
|
|
.DESCRIPTION
|
|
Creates counter objects and sub-instances from a given Performance Counter
|
|
Will return either a New-IcingaPerformanceCounterObject or New-IcingaPerformanceCounterResult
|
|
which both contain the same members, allowing for dynmically use of objects
|
|
.FUNCTIONALITY
|
|
Creates counter objects and sub-instances from a given Performance Counter
|
|
Will return either a New-IcingaPerformanceCounterObject or New-IcingaPerformanceCounterResult
|
|
which both contain the same members, allowing for dynmically use of objects
|
|
.EXAMPLE
|
|
PS>New-IcingaPerformanceCounter -Counter '\Processor(*)\% processor time';
|
|
|
|
FullName Counters
|
|
-------- --------
|
|
\Processor(*)\% processor time {@{FullName=\Processor(2)\% processor time; Category=Processor; Instance=2; Counter=%...
|
|
.EXAMPLE
|
|
PS>New-IcingaPerformanceCounter -Counter '\Processor(*)\% processor time' -SkipWait;
|
|
.PARAMETER Counter
|
|
The path to the Performance Counter to fetch data for
|
|
.PARAMETER SkipWait
|
|
Set this if no sleep is intended for initialising the counter. This can be useful
|
|
if multiple counters are fetched during one call with this function if the sleep
|
|
is done afterwards manually. A sleep is set to 500ms to ensure counter data is
|
|
valid and contains an offset from previous/current values
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function New-IcingaPerformanceCounter()
|
|
{
|
|
param(
|
|
[string]$Counter = '',
|
|
[boolean]$SkipWait = $FALSE
|
|
);
|
|
|
|
# Simply use the counter name, like
|
|
# \Paging File(_total)\% Usage
|
|
if ([string]::IsNullOrEmpty($Counter) -eq $TRUE) {
|
|
return (New-IcingaPerformanceCounterNullObject -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 (New-IcingaPerformanceCounterNullObject -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 New-IcingaPerformanceCounterResult
|
|
# 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
|
|
$CachedCounter = Get-IcingaPerformanceCounterCacheItem -Counter $Counter;
|
|
|
|
if ($null -ne $CachedCounter) {
|
|
return (New-IcingaPerformanceCounterResult -FullName $Counter -PerformanceCounters $CachedCounter);
|
|
}
|
|
|
|
# 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 = New-IcingaPerformanceCounterObject -FullName $NewCounterName -Category $UseCounterCategory -Counter $UseCounterName -Instance $instance -SkipWait $TRUE;
|
|
$AllCountersIntances += $NewCounter;
|
|
}
|
|
} catch {
|
|
# Throw an exception in case our permissions are not enough to fetch performance counter
|
|
Exit-IcingaThrowException -InputString $_.Exception -StringPattern 'System.UnauthorizedAccessException' -ExceptionType 'Permission' -ExceptionThrown $IcingaExceptions.Permission.PerformanceCounter;
|
|
Exit-IcingaThrowException -InputString $_.Exception -StringPattern 'System.InvalidOperationException' -ExceptionType 'Input' -CustomMessage $Counter -ExceptionThrown $IcingaExceptions.Inputs.PerformanceCounter;
|
|
Exit-IcingaThrowException -InputString $_.Exception -StringPattern '' -ExceptionType 'Unhandled';
|
|
# Shouldn't actually get down here anyways
|
|
return (New-IcingaPerformanceCounterNullObject -FullName $Counter -ErrorMessage ([string]::Format('Failed to deserialize instances for counter "{0}". Exception: "{1}".', $Counter, $_.Exception.Message)));
|
|
}
|
|
|
|
# If we load multiple instances, we should add a global wait here instead of a wait for each single instance
|
|
# This will speed up CPU loading for example with plenty of cores avaiable
|
|
if ($SkipWait -eq $FALSE) {
|
|
Start-Sleep -Milliseconds 500;
|
|
}
|
|
|
|
# Add the parent counter including the array of Performance Counters to our
|
|
# caching mechanism and return the New-IcingaPerformanceCounterResult object for usage
|
|
# within the monitoring modules
|
|
Add-IcingaPerformanceCounterCache -Counter $Counter -Instances $AllCountersIntances;
|
|
return (New-IcingaPerformanceCounterResult -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
|
|
$CachedCounter = Get-IcingaPerformanceCounterCacheItem -Counter $Counter;
|
|
|
|
if ($null -ne $CachedCounter) {
|
|
return $CachedCounter;
|
|
}
|
|
|
|
# If the cache is not present yet, create the Performance Counter object,
|
|
# and add it to our cache
|
|
$NewCounter = New-IcingaPerformanceCounterObject -FullName $Counter -Category $UseCounterCategory -Counter $UseCounterName -Instance $UseCounterInstance -SkipWait $SkipWait;
|
|
Add-IcingaPerformanceCounterCache -Counter $Counter -Instances $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 (Get-IcingaPerformanceCounterCacheItem -Counter $Counter);
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Accepts a list of Performance Counters which will all be fetched at once and
|
|
returned as a hashtable object. No additional configuration is required.
|
|
.DESCRIPTION
|
|
Accepts a list of Performance Counters which will all be fetched at once and
|
|
returned as a hashtable object. No additional configuration is required.
|
|
.FUNCTIONALITY
|
|
Accepts a list of Performance Counters which will all be fetched at once and
|
|
returned as a hashtable object. No additional configuration is required.
|
|
.EXAMPLE
|
|
PS>New-IcingaPerformanceCounterArray -CounterArray '\Processor(*)\% processor time', '\Memory\committed bytes';
|
|
|
|
Name Value
|
|
---- -----
|
|
\Processor(*)\% processor time {\Processor(7)\% processor time, \Processor(6)\% processor time, \Processor(0)\% proc...
|
|
\Memory\committed bytes {error, sample, type, value...}
|
|
.PARAMETER CounterArray
|
|
An array of Performance Counters which will all be fetched at once
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Hashtable
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function New-IcingaPerformanceCounterArray()
|
|
{
|
|
param(
|
|
[array]$CounterArray = @()
|
|
)
|
|
|
|
[hashtable]$CounterResult = @{};
|
|
[bool]$RequireSleep = $TRUE;
|
|
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
|
|
$CachedCounter = Get-IcingaPerformanceCounterCacheItem -Counter $Counter;
|
|
|
|
if ($null -ne $CachedCounter) {
|
|
$RequireSleep = $FALSE;
|
|
}
|
|
|
|
$obj = New-IcingaPerformanceCounter -Counter $counter -SkipWait $TRUE;
|
|
if ($CounterResult.ContainsKey($obj.Name()) -eq $FALSE) {
|
|
$CounterResult.Add($obj.Name(), $obj.Value());
|
|
}
|
|
}
|
|
|
|
# TODO: Add a cache for our Performance Counters to only fetch them once
|
|
# for each session to speed up the loading. This cold be something like
|
|
# this:
|
|
# New-IcingaPerformanceCounterCache $CounterResult;
|
|
# Internally we could do something like this
|
|
# $global:Icinga_PerfCounterCache += $CounterResult;
|
|
|
|
# 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 = New-IcingaPerformanceCounter -Counter $counter -SkipWait $TRUE;
|
|
if ($CounterResult.ContainsKey($obj.Name()) -eq $FALSE) {
|
|
$CounterResult.Add($obj.Name(), $obj.Value());
|
|
}
|
|
}
|
|
}
|
|
|
|
return $CounterResult;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Initialises the internal cache storage for Performance Counters
|
|
.DESCRIPTION
|
|
Initialises the internal cache storage for Performance Counters
|
|
.FUNCTIONALITY
|
|
Initialises the internal cache storage for Performance Counters
|
|
.EXAMPLE
|
|
PS>New-IcingaPerformanceCounterCache;
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function New-IcingaPerformanceCounterCache()
|
|
{
|
|
if ($null -eq $global:Icinga_PerfCounterCache) {
|
|
$global:Icinga_PerfCounterCache = (
|
|
[hashtable]::Synchronized(
|
|
@{}
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
This will create a Performance Counter object in case a counter instance
|
|
does not exis, but still returning default members to allow us to smoothly
|
|
execute our code
|
|
.DESCRIPTION
|
|
This will create a Performance Counter object in case a counter instance
|
|
does not exis, but still returning default members to allow us to smoothly
|
|
execute our code
|
|
.FUNCTIONALITY
|
|
This will create a Performance Counter object in case a counter instance
|
|
does not exis, but still returning default members to allow us to smoothly
|
|
execute our code
|
|
.EXAMPLE
|
|
PS>New-IcingaPerformanceCounterNullObject '\Processor(20)\%processor time' -ErrorMessage 'This counter with instance 20 does not exist';
|
|
|
|
FullName ErrorMessage
|
|
-------- ------------
|
|
\Processor(20)\%processor time This counter with instance 20 does not exist
|
|
.PARAMETER FullName
|
|
The full path/name of the Performance Counter which does not exist
|
|
.PARAMETER ErrorMessage
|
|
The error message which is included within the 'error' member of the Performance Counter
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.PSObject
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function New-IcingaPerformanceCounterNullObject()
|
|
{
|
|
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;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Creates a new Performance Counter object based on given input filters.
|
|
Returns a PSObject with custom members to access the data of the counter
|
|
.DESCRIPTION
|
|
Creates a new Performance Counter object based on given input filters.
|
|
Returns a PSObject with custom members to access the data of the counter
|
|
.FUNCTIONALITY
|
|
Creates a new Performance Counter object based on given input filters.
|
|
Returns a PSObject with custom members to access the data of the counter
|
|
.EXAMPLE
|
|
PS>New-IcingaPerformanceCounterObject -FullName '\Processor(*)\% processor time' -Category 'Processor' -Instance '*' -Counter '% processor time';
|
|
|
|
Category : Processor
|
|
Instance : *
|
|
Counter : % processor time
|
|
PerfCounter : System.Diagnostics.PerformanceCounter
|
|
SkipWait : False
|
|
.EXAMPLE
|
|
PS>New-IcingaPerformanceCounterObject -FullName '\Processor(*)\% processor time' -Category 'Processor' -Instance '*' -Counter '% processor time' -SkipWait;
|
|
|
|
Category : Processor
|
|
Instance : *
|
|
Counter : % processor time
|
|
PerfCounter : System.Diagnostics.PerformanceCounter
|
|
SkipWait : True
|
|
.PARAMETER FullName
|
|
The full path to the Performance Counter
|
|
.PARAMETER Category
|
|
The name of the category of the Performance Counter
|
|
.PARAMETER Instance
|
|
The instance of the Performance Counter
|
|
.PARAMETER Counter
|
|
The actual name of the counter to fetch
|
|
.PARAMETER SkipWait
|
|
Set this if no sleep is intended for initialising the counter. This can be useful
|
|
if multiple counters are fetched during one call with this function if the sleep
|
|
is done afterwards manually. A sleep is set to 500ms to ensure counter data is
|
|
valid and contains an offset from previous/current values
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.PSObject
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function New-IcingaPerformanceCounterObject()
|
|
{
|
|
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 {
|
|
|
|
Write-IcingaConsoleDebug `
|
|
-Message 'Creating new Counter for Category "{0}" with Instance "{1}" and Counter "{2}". Full Name "{3}"' `
|
|
-Objects $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', ([math]::Round([decimal]$this.PerfCounter.NextValue(), 6)));
|
|
$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;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Will provide a virtual object, containing an array of Performance Counters.
|
|
The object has the following members:
|
|
* Name
|
|
* Value
|
|
.DESCRIPTION
|
|
Will provide a virtual object, containing an array of Performance Counters.
|
|
The object has the following members:
|
|
* Name
|
|
* Value
|
|
.FUNCTIONALITY
|
|
Will provide a virtual object, containing an array of Performance Counters.
|
|
The object has the following members:
|
|
* Name
|
|
* Value
|
|
.EXAMPLE
|
|
PS>New-IcingaPerformanceCounterResult -FullName '\Processor(*)\% processor time' -PerformanceCounters $PerformanceCounters;
|
|
.PARAMETER FullName
|
|
The full path to the Performance Counter
|
|
.PARAMETER PerformanceCounters
|
|
A list of all instances/counters for the given Performance Counter
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.PSObject
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function New-IcingaPerformanceCounterResult()
|
|
{
|
|
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;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Will use an array of provided Performance Counter and sort the input by
|
|
a given counter category. In this case we can fetch all Processor instances
|
|
and receive values for each core which can then be accessed from a hashtable
|
|
with an eady query. Allows to modify output in addition
|
|
.DESCRIPTION
|
|
Will use an array of provided Performance Counter and sort the input by
|
|
a given counter category. In this case we can fetch all Processor instances
|
|
and receive values for each core which can then be accessed from a hashtable
|
|
with an eady query. Allows to modify output in addition
|
|
.FUNCTIONALITY
|
|
Will use an array of provided Performance Counter and sort the input by
|
|
a given counter category. In this case we can fetch all Processor instances
|
|
and receive values for each core which can then be accessed from a hashtable
|
|
with an eady query. Allows to modify output in addition
|
|
.EXAMPLE
|
|
PS>New-IcingaPerformanceCounterStructure -CounterCategory 'Processor' -PerformanceCounterHash (New-IcingaPerformanceCounterArray '\Processor(*)\% processor time');
|
|
|
|
Name Value
|
|
---- -----
|
|
7 {% processor time}
|
|
3 {% processor time}
|
|
4 {% processor time}
|
|
_Total {% processor time}
|
|
2 {% processor time}
|
|
1 {% processor time}
|
|
0 {% processor time}
|
|
6 {% processor time}
|
|
5 {% processor time}
|
|
.EXAMPLE
|
|
PS>New-IcingaPerformanceCounterStructure -CounterCategory 'Processor' -PerformanceCounterHash (New-IcingaPerformanceCounterArray '\Processor(*)\% processor time') -InstanceNameCleanupArray '_';
|
|
|
|
Name Value
|
|
---- -----
|
|
7 {% processor time}
|
|
Total {}
|
|
3 {% processor time}
|
|
4 {% processor time}
|
|
2 {% processor time}
|
|
1 {% processor time}
|
|
0 {% processor time}
|
|
6 {% processor time}
|
|
5 {% processor time}
|
|
.PARAMETER CounterCategory
|
|
The name of the category the sort algorithm will fetch the instances from for sorting
|
|
.PARAMETER PerformanceCounterHash
|
|
An array of Performance Counter objects provided by 'New-IcingaPerformanceCounterArray' to sort for
|
|
.PARAMETER InstanceNameCleanupArray
|
|
An array which will be used to remove string content from the sorted instances keys. For example '_' will change
|
|
'_Total' to 'Total'. Replacements are done in the order added to this array
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Hashtable
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
function New-IcingaPerformanceCounterStructure()
|
|
{
|
|
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;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Fetches all available Performance Counter caregories on the system by using the
|
|
registry and returns the entire content as array. Allows to filter for certain
|
|
categories only
|
|
.DESCRIPTION
|
|
Fetches all available Performance Counter caregories on the system by using the
|
|
registry and returns the entire content as array. Allows to filter for certain
|
|
categories only
|
|
.FUNCTIONALITY
|
|
Fetches all available Performance Counter caregories on the system by using the
|
|
registry and returns the entire content as array. Allows to filter for certain
|
|
categories only
|
|
.EXAMPLE
|
|
PS>Show-IcingaPerformanceCounterCategories;
|
|
|
|
System
|
|
Memory
|
|
Browser
|
|
Cache
|
|
Process
|
|
Thread
|
|
PhysicalDisk
|
|
...
|
|
.EXAMPLE
|
|
PS>Show-IcingaPerformanceCounterCategories -Filter 'Processor';
|
|
|
|
Processor
|
|
.EXAMPLE
|
|
PS>Show-IcingaPerformanceCounterCategories -Filter 'Processor', 'Memory';
|
|
|
|
Memory
|
|
Processor
|
|
.PARAMETER Filter
|
|
A array of counter categories to filter for. Supports wildcard search
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Array
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Show-IcingaPerformanceCounterCategories()
|
|
{
|
|
param (
|
|
[array]$Filter = @()
|
|
);
|
|
|
|
[array]$Counters = @();
|
|
[array]$FilteredCounters = @();
|
|
# Load our cache if it does exist yet
|
|
$PerfCounterCache = Get-IcingaPerformanceCounterCacheItem 'Icinga:CachedCounterList';
|
|
|
|
# Create a cache for all available performance counter categories on the system
|
|
if ($null -eq $PerfCounterCache -or $PerfCounterCache.Count -eq 0) {
|
|
# Fetch the categories from the registry
|
|
$PerfCounterCache = Get-ItemProperty `
|
|
-Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009' `
|
|
-Name 'counter' | Select-Object -ExpandProperty Counter;
|
|
|
|
# Now lets loop our registry data and fetch only for counter categories
|
|
# Ignore everything else and drop the information
|
|
foreach ($counter in $PerfCounterCache) {
|
|
# 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Set our cache to the current list of categories
|
|
Add-IcingaPerformanceCounterCache -Counter 'Icinga:CachedCounterList' -Instances $Counters;
|
|
$PerfCounterCache = $Counters;
|
|
}
|
|
|
|
# In case we have no filter applied, simply return the entire list
|
|
if ($Filter.Count -eq 0) {
|
|
return $PerfCounterCache;
|
|
}
|
|
|
|
# In case we do, check each counter category against our filter element
|
|
foreach ($counter in $PerfCounterCache) {
|
|
foreach ($element in $Filter) {
|
|
if ($counter -like $element) {
|
|
$FilteredCounters += $counter;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $FilteredCounters;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Prints the description of a Performance Counter if available on the system
|
|
.DESCRIPTION
|
|
Prints the description of a Performance Counter if available on the system
|
|
.FUNCTIONALITY
|
|
Prints the description of a Performance Counter if available on the system
|
|
.EXAMPLE
|
|
PS>Show-IcingaPerformanceCounterHelp '\Processor(*)\% processor time';
|
|
|
|
% Processor Time is the percentage of elapsed time that the processor spends to execute a non-Idle thread. It is calculated by measuring the percentage of time that the processor spends executing the idle thread and then subtracting that value from 100%. (Each processor has an idle thread that consumes cycles when no other threads are ready to run). This counter is the primary indicator of processor activity, and displays the average percentage of busy time observed during the sample interval. It should be noted that the accounting calculation of whether the processor is idle is performed at an internal sampling interval of the system clock (10ms). On todays fast processors, % Processor Time can therefore underestimate the processor utilization as the processor may be spending a lot of time servicing threads between the system clock sampling interval. Workload based timer applications are one example of applications which are more likely to be measured inaccurately as timers are signaled just after the sample is taken.
|
|
.EXAMPLE
|
|
PS>Show-IcingaPerformanceCounterHelp '\Memory\system code total bytes';
|
|
|
|
System Code Total Bytes is the size, in bytes, of the pageable operating system code currently mapped into the system virtual address space. This value is calculated by summing the bytes in Ntoskrnl.exe, Hal.dll, the boot drivers, and file systems loaded by Ntldr/osloader. This counter does not include code that must remain in physical memory and cannot be written to disk. This counter displays the last observed value only; it is not an average.
|
|
.PARAMETER Counter
|
|
The full path to the Performance Counter to lookup.
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
function Show-IcingaPerformanceCounterHelp()
|
|
{
|
|
param (
|
|
[string]$Counter = ''
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Counter)) {
|
|
Write-IcingaConsoleError 'Please enter a Performance Counter';
|
|
return;
|
|
}
|
|
|
|
# Create a Performance Counter array which is easier to access later on and skip possible waits
|
|
$PerfCounter = New-IcingaPerformanceCounterArray -Counter $Counter -SkipWait $TRUE;
|
|
[string]$HelpText = '';
|
|
[string]$ErrorText = '';
|
|
|
|
if ($PerfCounter.ContainsKey($Counter)) {
|
|
# Handle counters without instances, like '\Memory\system code total bytes'
|
|
$HelpText = $PerfCounter[$Counter].help;
|
|
$ErrorText = $PerfCounter[$Counter].error;
|
|
|
|
if ([string]::IsNullOrEmpty($HelpText)) {
|
|
# Handle counters with instances, like '\Processor(*)\% processor time'
|
|
$CounterObject = $PerfCounter[$Counter].GetEnumerator() | Select-Object -First 1;
|
|
$CounterData = $CounterObject.Value;
|
|
$HelpText = $CounterData.help;
|
|
if ([string]::IsNullOrEmpty($ErrorText)) {
|
|
$ErrorText = $CounterData.error;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($HelpText) -eq $FALSE) {
|
|
return $HelpText;
|
|
}
|
|
|
|
Write-IcingaConsoleError `
|
|
-Message 'Help context for the Performance Counter "{0}" could not be loaded or was not found. Error context if available: "{1}"' `
|
|
-Objects $Counter, $ErrorText;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Displays all available instances for a provided Performance Counter
|
|
.DESCRIPTION
|
|
Displays all available instances for a provided Performance Counter
|
|
.FUNCTIONALITY
|
|
Displays all available instances for a provided Performance Counter
|
|
.PARAMETER Counter
|
|
The name of the Performance Counter to fetch data for
|
|
.EXAMPLE
|
|
PS>Show-IcingaPerformanceCounterInstances -Counter '\Processor(*)\% processor time';
|
|
|
|
Name Value
|
|
---- -----
|
|
_Total \Processor(_Total)\% processor time
|
|
0 \Processor(0)\% processor time
|
|
1 \Processor(1)\% processor time
|
|
2 \Processor(2)\% processor time
|
|
3 \Processor(3)\% processor time
|
|
...
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Show-IcingaPerformanceCounterInstances()
|
|
{
|
|
param (
|
|
[string]$Counter
|
|
);
|
|
|
|
[hashtable]$Instances = @{};
|
|
|
|
if ([string]::IsNullOrEmpty($Counter)) {
|
|
Write-IcingaConsoleError 'Please enter a Performance Counter';
|
|
return;
|
|
}
|
|
|
|
$PerfCounter = New-IcingaPerformanceCounter -Counter $Counter -SkipWait $TRUE;
|
|
|
|
foreach ($entry in $PerfCounter.Counters) {
|
|
$Instances.Add(
|
|
$entry.Instance,
|
|
($Counter.Replace('(*)', ([string]::Format('({0})', $entry.Instance))))
|
|
);
|
|
}
|
|
|
|
if ($Instances.Count -eq 0) {
|
|
Write-IcingaConsoleNotice `
|
|
-Message 'No instances were found for Performance Counter "{0}". Please ensure the provided counter has instances and you are using "*" for the instance name.' `
|
|
-Objects $Counter;
|
|
|
|
return;
|
|
}
|
|
|
|
return (
|
|
$Instances.GetEnumerator() | Sort-Object Name
|
|
);
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Prints a list of all available Performance Counters for a specified category
|
|
.DESCRIPTION
|
|
Prints a list of all available Performance Counters for a specified category
|
|
.FUNCTIONALITY
|
|
Prints a list of all available Performance Counters for a specified category
|
|
.EXAMPLE
|
|
PS>Show-IcingaPerformanceCounters -CounterCategory 'Processor';
|
|
|
|
\Processor(*)\dpcs queued/sec
|
|
\Processor(*)\% c1 time
|
|
\Processor(*)\% idle time
|
|
\Processor(*)\c3 transitions/sec
|
|
\Processor(*)\% c2 time
|
|
\Processor(*)\% dpc time
|
|
\Processor(*)\% privileged time
|
|
.PARAMETER CounterCategory
|
|
The name of the category to fetch availble counters for
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Array
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
function Show-IcingaPerformanceCounters()
|
|
{
|
|
param (
|
|
[string]$CounterCategory
|
|
);
|
|
|
|
[hashtable]$counters = @{};
|
|
|
|
if ([string]::IsNullOrEmpty($CounterCategory)) {
|
|
$counters.Add('error', 'Please specify a counter category');
|
|
return $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.Keys;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Test if a certain Performance Counter category exist on the systems and returns
|
|
either true or false depending on the state
|
|
.DESCRIPTION
|
|
Test if a certain Performance Counter category exist on the systems and returns
|
|
either true or false depending on the state
|
|
.FUNCTIONALITY
|
|
Test if a certain Performance Counter category exist on the systems and returns
|
|
either true or false depending on the state
|
|
.EXAMPLE
|
|
PS>Test-IcingaPerformanceCounterCategory -Category 'Processor';
|
|
|
|
True
|
|
.PARAMETER Category
|
|
The name of the category to test for
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Test-IcingaPerformanceCounterCategory()
|
|
{
|
|
param (
|
|
[string]$Category
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Category)) {
|
|
return $FALSE;
|
|
}
|
|
|
|
try {
|
|
$Counter = New-Object System.Diagnostics.PerformanceCounterCategory($Category);
|
|
|
|
if ($null -eq $Counter -Or [string]::IsNullOrEmpty($Counter.CategoryType)) {
|
|
return $FALSE;
|
|
}
|
|
} catch {
|
|
return $FALSE;
|
|
}
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
function Add-IcingaRepository()
|
|
{
|
|
param (
|
|
[string]$Name = $null,
|
|
[string]$RemotePath = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to provide a name for the repository';
|
|
return;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($RemotePath)) {
|
|
Write-IcingaConsoleError 'You have to provide a remote path for the repository';
|
|
return;
|
|
}
|
|
|
|
$CurrentRepositories = Get-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories';
|
|
|
|
if ($null -eq $CurrentRepositories) {
|
|
$CurrentRepositories = New-Object -TypeName PSObject;
|
|
}
|
|
|
|
if (Test-IcingaPowerShellConfigItem -ConfigObject $CurrentRepositories -ConfigKey $Name) {
|
|
Write-IcingaConsoleError 'A repository with the given name "{0}" does already exist.' -Objects $Name;
|
|
return;
|
|
}
|
|
|
|
[array]$RepoCount = $CurrentRepositories.PSObject.Properties.Count;
|
|
|
|
$CurrentRepositories | Add-Member -MemberType NoteProperty -Name $Name -Value (New-Object -TypeName PSObject);
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'LocalPath' -Value $null;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'RemotePath' -Value $RemotePath;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'CloneSource' -Value $null;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'UseSCP' -Value $FALSE;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'Order' -Value $RepoCount.Count;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'Enabled' -Value $True;
|
|
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories' -Value $CurrentRepositories;
|
|
Push-IcingaRepository -Name $Name -Silent;
|
|
|
|
Write-IcingaConsoleNotice 'Remote repository "{0}" was successfully added' -Objects $Name;
|
|
}
|
|
|
|
function Disable-IcingaRepository()
|
|
{
|
|
param (
|
|
[string]$Name = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to provide a name for the repository';
|
|
return;
|
|
}
|
|
|
|
$CurrentRepositories = Get-IcingaPowerShellConfig -Path ([string]::Format('Framework.Repository.Repositories.{0}', $Name));
|
|
|
|
if ($null -eq $CurrentRepositories) {
|
|
Write-IcingaConsoleError 'A repository with the name "{0}" is not configured' -Objects $Name;
|
|
return;
|
|
}
|
|
|
|
if ($CurrentRepositories.Enabled -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'The repository "{0}" is already disabled' -Objects $Name;
|
|
return;
|
|
}
|
|
|
|
Set-IcingaPowerShellConfig -Path ([string]::Format('Framework.Repository.Repositories.{0}.Enabled', $Name)) -Value $FALSE;
|
|
|
|
Write-IcingaConsoleNotice 'The repository "{0}" was successfully disabled' -Objects $Name;
|
|
}
|
|
|
|
function Enable-IcingaRepository()
|
|
{
|
|
param (
|
|
[string]$Name = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to provide a name for the repository';
|
|
return;
|
|
}
|
|
|
|
$CurrentRepositories = Get-IcingaPowerShellConfig -Path ([string]::Format('Framework.Repository.Repositories.{0}', $Name));
|
|
|
|
if ($null -eq $CurrentRepositories) {
|
|
Write-IcingaConsoleError 'A repository with the name "{0}" is not configured' -Objects $Name;
|
|
return;
|
|
}
|
|
|
|
if ($CurrentRepositories.Enabled -eq $TRUE) {
|
|
Write-IcingaConsoleNotice 'The repository "{0}" is already enabled' -Objects $Name;
|
|
return;
|
|
}
|
|
|
|
Set-IcingaPowerShellConfig -Path ([string]::Format('Framework.Repository.Repositories.{0}.Enabled', $Name)) -Value $TRUE;
|
|
|
|
Write-IcingaConsoleNotice 'The repository "{0}" was successfully enabled' -Objects $Name;
|
|
}
|
|
|
|
function Get-IcingaComponentList()
|
|
{
|
|
param (
|
|
[switch]$Snapshot = $FALSE
|
|
);
|
|
|
|
$Repositories = Get-IcingaRepositories -ExcludeDisabled;
|
|
[Version]$LatestVersion = $null;
|
|
[string]$SourcePath = $null;
|
|
[bool]$FoundPackage = $FALSE;
|
|
[array]$Output = @();
|
|
[bool]$FoundPackage = $FALSE;
|
|
|
|
$SearchList = New-Object -TypeName PSObject;
|
|
$SearchList | Add-Member -MemberType NoteProperty -Name 'Repos' -Value @();
|
|
$SearchList | Add-Member -MemberType NoteProperty -Name 'Components' -Value @{ };
|
|
|
|
foreach ($entry in $Repositories) {
|
|
$RepoContent = Read-IcingaRepositoryFile -Name $entry.Name;
|
|
|
|
if ($null -eq $RepoContent) {
|
|
continue;
|
|
}
|
|
|
|
if ((Test-IcingaPowerShellConfigItem -ConfigObject $RepoContent -ConfigKey 'Packages') -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($repoEntry in $RepoContent.Packages.PSObject.Properties.Name) {
|
|
|
|
$RepoData = New-Object -TypeName PSObject;
|
|
$RepoData | Add-Member -MemberType NoteProperty -Name 'Name' -Value $entry.Name;
|
|
$RepoData | Add-Member -MemberType NoteProperty -Name 'RemoteSource' -Value $RepoContent.Info.RemoteSource;
|
|
$RepoData | Add-Member -MemberType NoteProperty -Name 'ComponentName' -Value $repoEntry;
|
|
$RepoData | Add-Member -MemberType NoteProperty -Name 'Packages' -Value @();
|
|
|
|
foreach ($package in $RepoContent.Packages.$repoEntry) {
|
|
|
|
$ComponentData = New-Object -TypeName PSObject;
|
|
$ComponentData | Add-Member -MemberType NoteProperty -Name 'Version' -Value $package.Version;
|
|
$ComponentData | Add-Member -MemberType NoteProperty -Name 'Location' -Value $package.Location;
|
|
$ComponentData | Add-Member -MemberType NoteProperty -Name 'Snapshot' -Value $package.Snapshot;
|
|
|
|
if ($Snapshot -And $package.Snapshot -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
if ($SearchList.Components.ContainsKey($repoEntry) -eq $FALSE) {
|
|
$SearchList.Components.Add($repoEntry, $package.Version);
|
|
}
|
|
|
|
if ([version]($SearchList.Components[$repoEntry]) -lt [version]$package.Version) {
|
|
$SearchList.Components[$repoEntry] = $package.Version;
|
|
}
|
|
|
|
$RepoData.Packages += $ComponentData;
|
|
}
|
|
|
|
$SearchList.Repos += $RepoData;
|
|
}
|
|
}
|
|
|
|
return $SearchList;
|
|
}
|
|
|
|
function Get-IcingaComponentLock()
|
|
{
|
|
param (
|
|
[string]$Name = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to specify the component to get the lock version';
|
|
return;
|
|
}
|
|
|
|
$LockedComponents = Get-IcingaPowerShellConfig -Path 'Framework.Repository.ComponentLock';
|
|
|
|
if ($null -eq $LockedComponents) {
|
|
return $null;
|
|
}
|
|
|
|
if (Test-IcingaPowerShellConfigItem -ConfigObject $LockedComponents -ConfigKey $Name) {
|
|
return $LockedComponents.$Name;
|
|
}
|
|
|
|
return $null;
|
|
}
|
|
|
|
function Get-IcingaForWindowsServiceData()
|
|
{
|
|
$IcingaForWindowsService = Get-IcingaServices -Service 'icingapowershell';
|
|
|
|
[hashtable]$ServiceData = @{
|
|
'Directory' = '';
|
|
'FullPath' = '';
|
|
'User' = '';
|
|
}
|
|
|
|
if ($null -ne $IcingaForWindowsService) {
|
|
$ServicePath = $IcingaForWindowsService.icingapowershell.configuration.ServicePath;
|
|
$ServicePath = $ServicePath.SubString(0, $ServicePath.IndexOf('.exe') + 4);
|
|
$ServicePath = $ServicePath.Replace('"', '');
|
|
$ServiceData.FullPath = $ServicePath;
|
|
$ServiceData.Directory = $ServicePath.Substring(0, $ServicePath.LastIndexOf('\') + 1);
|
|
$ServiceData.User = $IcingaForWindowsService.icingapowershell.configuration.ServiceUser;
|
|
|
|
return $ServiceData;
|
|
}
|
|
|
|
$ServiceData.Directory = (Join-Path -Path $env:ProgramFiles -ChildPath 'icinga-framework-service');
|
|
$ServiceData.User = 'NT Authority\NetworkService';
|
|
|
|
return $ServiceData;
|
|
}
|
|
|
|
function Get-IcingaInstallation()
|
|
{
|
|
param (
|
|
[switch]$Release = $FALSE,
|
|
[switch]$Snapshot = $FALSE
|
|
)
|
|
[hashtable]$InstalledComponents = @{ };
|
|
|
|
$PowerShellModules = Get-Module -ListAvailable;
|
|
|
|
foreach ($entry in $PowerShellModules) {
|
|
$RootPath = (Get-IcingaForWindowsRootPath);
|
|
|
|
if ($entry.Path -NotLike "$RootPath*") {
|
|
continue;
|
|
}
|
|
|
|
if ($entry.Name -Like 'icinga-powershell-*') {
|
|
$ComponentName = $entry.Name.Replace('icinga-powershell-', '');
|
|
$InstallPackage = (Get-IcingaRepositoryPackage -Name $ComponentName -Release:$Release -Snapshot:$Snapshot);
|
|
$LatestVersion = '';
|
|
$CurrentVersion = ([string]((Get-Module -ListAvailable -Name $entry.Name -ErrorAction SilentlyContinue) | Sort-Object Version -Descending | Select-Object Version -First 1).Version);
|
|
|
|
if ($InstallPackage.HasPackage) {
|
|
[string]$LatestVersion = $InstallPackage.Package.Version;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($LatestVersion) -eq $FALSE -And [Version]$LatestVersion -le [Version]$CurrentVersion) {
|
|
$LatestVersion = '';
|
|
}
|
|
|
|
Add-IcingaHashtableItem `
|
|
-Hashtable $InstalledComponents `
|
|
-Key $ComponentName `
|
|
-Value @{
|
|
'Path' = (Join-Path -Path $RootPath -ChildPath $entry.Name);
|
|
'CurrentVersion' = $CurrentVersion;
|
|
'LatestVersion' = $LatestVersion;
|
|
'LockedVersion' = (Get-IcingaComponentLock -Name $ComponentName);
|
|
} | Out-Null;
|
|
}
|
|
}
|
|
|
|
$IcingaForWindowsService = Get-IcingaServices -Service 'icingapowershell';
|
|
|
|
if ($null -ne $IcingaForWindowsService) {
|
|
$ServicePath = Get-IcingaForWindowsServiceData;
|
|
|
|
if ($InstalledComponents.ContainsKey('service')) {
|
|
$InstalledComponents.Remove('service');
|
|
}
|
|
|
|
$InstallPackage = (Get-IcingaRepositoryPackage -Name 'service' -Release:$Release -Snapshot:$Snapshot);
|
|
$LatestVersion = '';
|
|
$CurrentVersion = ([string]((Read-IcingaServicePackage -File $ServicePath.FullPath).ProductVersion));
|
|
|
|
if ($InstallPackage.HasPackage) {
|
|
[string]$LatestVersion = $InstallPackage.Package.Version;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($LatestVersion) -eq $FALSE -And [Version]$LatestVersion -le [Version]$CurrentVersion) {
|
|
$LatestVersion = '';
|
|
}
|
|
|
|
$InstalledComponents.Add(
|
|
'service',
|
|
@{
|
|
'Path' = $ServicePath.Directory;
|
|
'CurrentVersion' = $CurrentVersion;
|
|
'LatestVersion' = $LatestVersion;
|
|
'LockedVersion' = (Get-IcingaComponentLock -Name 'service');
|
|
}
|
|
)
|
|
}
|
|
|
|
$IcingaAgent = Get-IcingaAgentInstallation;
|
|
|
|
if ($InstalledComponents.ContainsKey('agent')) {
|
|
$InstalledComponents.Remove('agent');
|
|
}
|
|
|
|
if ($IcingaAgent.Installed) {
|
|
|
|
$InstallPackage = (Get-IcingaRepositoryPackage -Name 'agent' -Release:$Release -Snapshot:$Snapshot);
|
|
$LatestVersion = '';
|
|
$CurrentVersion = ([string]$IcingaAgent.Version.Full);
|
|
|
|
if ($InstallPackage.HasPackage) {
|
|
$LatestVersion = $InstallPackage.Package.Version;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($LatestVersion) -eq $FALSE -And [Version]$LatestVersion -le [Version]$CurrentVersion) {
|
|
$LatestVersion = '';
|
|
}
|
|
|
|
$InstalledComponents.Add(
|
|
'agent',
|
|
@{
|
|
'Path' = $IcingaAgent.RootDir;
|
|
'CurrentVersion' = $CurrentVersion;
|
|
'LatestVersion' = $LatestVersion;
|
|
'LockedVersion' = (Get-IcingaComponentLock -Name 'agent');
|
|
}
|
|
)
|
|
}
|
|
|
|
return $InstalledComponents;
|
|
}
|
|
|
|
function Get-IcingaRepositories()
|
|
{
|
|
param (
|
|
[switch]$ExcludeDisabled = $FALSE
|
|
);
|
|
|
|
$CurrentRepositories = Get-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories';
|
|
[array]$RepoList = $CurrentRepositories.PSObject.Properties | Sort-Object { $_.Value.Order } -Descending;
|
|
|
|
if ($ExcludeDisabled -eq $FALSE) {
|
|
return $RepoList;
|
|
}
|
|
|
|
[array]$ActiveRepos = @();
|
|
|
|
foreach ($repo in $RepoList) {
|
|
if ($repo.Value.Enabled -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
$ActiveRepos += $repo;
|
|
}
|
|
|
|
return $ActiveRepos;
|
|
}
|
|
|
|
function Get-IcingaRepositoryHash()
|
|
{
|
|
param (
|
|
[string]$Path
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Path) -Or (Test-Path $Path) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'The provided path "{0}" does not exist' -Objects $Path;
|
|
return;
|
|
}
|
|
|
|
$RepositoryFolder = Get-ChildItem -Path $Path -Recurse;
|
|
[array]$FileHashes = @();
|
|
|
|
foreach ($entry in $RepositoryFolder) {
|
|
$FileHashes += (Get-FileHash -Path $entry.FullName -Algorithm SHA256).Hash;
|
|
}
|
|
|
|
$HashAlgorithm = [System.Security.Cryptography.HashAlgorithm]::Create('SHA256');
|
|
$BinaryHash = $HashAlgorithm.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($FileHashes.ToString()))
|
|
|
|
return [System.BitConverter]::ToString($BinaryHash).Replace('-', '');
|
|
}
|
|
|
|
function Get-IcingaRepositoryPackage()
|
|
{
|
|
param (
|
|
[string]$Name,
|
|
[string]$Version = $null,
|
|
[switch]$Release = $FALSE,
|
|
[switch]$Snapshot = $FALSE
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to provide a component name';
|
|
return;
|
|
}
|
|
|
|
$Repositories = Get-IcingaRepositories -ExcludeDisabled;
|
|
[Version]$LatestVersion = $null;
|
|
$InstallPackage = $null;
|
|
$SourceRepo = $null;
|
|
$RepoName = $null;
|
|
[bool]$HasRepo = $FALSE;
|
|
|
|
foreach ($entry in $Repositories) {
|
|
$RepoContent = Read-IcingaRepositoryFile -Name $entry.Name;
|
|
[bool]$FoundPackage = $FALSE;
|
|
|
|
if ($null -eq $RepoContent) {
|
|
continue;
|
|
}
|
|
|
|
if ((Test-IcingaPowerShellConfigItem -ConfigObject $RepoContent -ConfigKey 'Packages') -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
if ((Test-IcingaPowerShellConfigItem -ConfigObject $RepoContent.Packages -ConfigKey $Name) -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($package in $RepoContent.Packages.$Name) {
|
|
|
|
if ($Snapshot -And $package.Snapshot -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
if ($Release -And $package.Snapshot -eq $TRUE) {
|
|
continue;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Version) -And ($null -eq $LatestVersion -Or $LatestVersion -lt $package.Version)) {
|
|
[Version]$LatestVersion = [Version]$package.Version;
|
|
$InstallPackage = $package;
|
|
$HasRepo = $TRUE;
|
|
$SourceRepo = $RepoContent;
|
|
$RepoName = $entry.Name;
|
|
continue;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Version) -eq $FALSE -And [version]$package.Version -eq [version]$Version) {
|
|
$InstallPackage = $package;
|
|
$FoundPackage = $TRUE;
|
|
$HasRepo = $TRUE;
|
|
$SourceRepo = $RepoContent;
|
|
$RepoName = $entry.Name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($FoundPackage) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return @{
|
|
'HasPackage' = $HasRepo;
|
|
'Package' = $InstallPackage;
|
|
'Source' = $SourceRepo;
|
|
'Repository' = $RepoName;
|
|
};
|
|
}
|
|
|
|
function Install-IcingaComponent()
|
|
{
|
|
param (
|
|
[string]$Name = $null,
|
|
[string]$Version = $null,
|
|
[switch]$Release = $FALSE,
|
|
[switch]$Snapshot = $FALSE,
|
|
[switch]$Confirm = $FALSE,
|
|
[switch]$Force = $FALSE
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to provide a component name';
|
|
return;
|
|
}
|
|
|
|
Set-IcingaTLSVersion;
|
|
|
|
if ($Version -eq 'release') {
|
|
$Version = $null;
|
|
}
|
|
|
|
if ($Release -eq $TRUE -And $Snapshot -eq $TRUE) {
|
|
Write-IcingaConsoleError 'You can only select either "Release" or "Snapshot" channel for package installation';
|
|
return;
|
|
}
|
|
|
|
if ($Release -eq $FALSE -And $Snapshot -eq $FALSE) {
|
|
$Release = $TRUE;
|
|
}
|
|
|
|
$LockedVersion = Get-IcingaComponentLock -Name $Name;
|
|
|
|
if ($null -ne $LockedVersion) {
|
|
$Version = $LockedVersion;
|
|
Write-IcingaConsoleNotice 'Component "{0}" is locked to version "{1}"' -Objects $Name, $LockedVersion;
|
|
}
|
|
|
|
$PackageContent = Get-IcingaRepositoryPackage -Name $Name -Version $Version -Release:$Release -Snapshot:$Snapshot;
|
|
$InstallPackage = $PackageContent.Package;
|
|
$SourceRepo = $PackageContent.Source;
|
|
$RepoName = $PackageContent.Repository;
|
|
|
|
if ($PackageContent.HasPackage -eq $FALSE) {
|
|
$SearchVersion = 'release';
|
|
if ([string]::IsNullOrEmpty($Version) -eq $FALSE) {
|
|
$SearchVersion = $Version;
|
|
}
|
|
if ($Release) {
|
|
Write-IcingaConsoleError 'The component "{0}" was not found on stable channel with version "{1}"' -Objects $Name, $SearchVersion;
|
|
return;
|
|
}
|
|
if ($Snapshot) {
|
|
Write-IcingaConsoleError 'The component "{0}" was not found on snapshot channel with version "{1}"' -Objects $Name, $SearchVersion;
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
$FileSource = $InstallPackage.Location;
|
|
|
|
if ($InstallPackage.RelativePath -eq $TRUE) {
|
|
$FileSource = Join-WebPath -Path ($SourceRepo.Info.RemoteSource.Replace('\', '/')) -ChildPath ($InstallPackage.Location.Replace('\', '/'));
|
|
}
|
|
|
|
if ($Confirm -eq $FALSE) {
|
|
if ((Get-IcingaAgentInstallerAnswerInput -Prompt ([string]::Format('Do you want to install component "{0}" from source "{1}" ({2})?', $Name.ToLower(), $RepoName, $FileSource)) -Default 'y').result -ne 1) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
$FileName = $FileSource.SubString($FileSource.LastIndexOf('/') + 1, $FileSource.Length - $FileSource.LastIndexOf('/') - 1);
|
|
$DownloadDirectory = New-IcingaTemporaryDirectory;
|
|
$DownloadDestination = (Join-Path -Path $DownloadDirectory -ChildPath $FileName);
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Downloading "{0}" from "{1}"', $Name.ToLower(), $FileSource));
|
|
|
|
if ((Invoke-IcingaWebRequest -UseBasicParsing -Uri $FileSource -OutFile $DownloadDestination).HasErrors) {
|
|
Write-IcingaConsoleError ([string]::Format('Failed to download "{0}" from "{1}" into "{2}". Starting cleanup process', $Name.ToLower(), $FileSource, $DownloadDestination));
|
|
Start-Sleep -Seconds 2;
|
|
Remove-Item -Path $DownloadDirectory -Recurse -Force;
|
|
|
|
return;
|
|
}
|
|
|
|
$FileHash = (Get-FileHash -Path $DownloadDestination -Algorithm SHA256).Hash;
|
|
|
|
if ([string]::IsNullOrEmpty($InstallPackage.Hash) -eq $FALSE -And (Get-FileHash -Path $DownloadDestination -Algorithm SHA256).Hash -ne $InstallPackage.Hash) {
|
|
Write-IcingaConsoleError ([string]::Format('File validation failed. The stored hash inside the repository "{0}" is not matching the file hash "{1}"', $InstallPackage.Hash, $FileHash));
|
|
return;
|
|
}
|
|
|
|
if ([IO.Path]::GetExtension($FileName) -eq '.zip') {
|
|
<#
|
|
Handles installation of Icinga for Windows packages and Icinga for Windows service
|
|
#>
|
|
|
|
Expand-IcingaZipArchive -Path $DownloadDestination -Destination $DownloadDirectory | Out-Null;
|
|
Start-Sleep -Seconds 2;
|
|
Remove-Item -Path $DownloadDestination -Force;
|
|
|
|
$FolderContent = Get-ChildItem -Path $DownloadDirectory -Recurse -Include '*.psd1';
|
|
|
|
<#
|
|
Handles installation of Icinga for Windows packages
|
|
#>
|
|
if ($null -ne $FolderContent -And $FolderContent.Count -ne 0) {
|
|
$ManifestFile = $null;
|
|
$PackageName = $null;
|
|
$PackageRoot = $null;
|
|
|
|
foreach ($manifest in $FolderContent) {
|
|
$ManifestFile = Read-IcingaPackageManifest -File $manifest.FullName;
|
|
|
|
if ($null -ne $ManifestFile) {
|
|
$PackageName = $manifest.Name.Replace('.psd1', '');
|
|
$PackageRoot = $manifest.FullName.SubString(0, $manifest.FullName.LastIndexOf('\'));
|
|
$PackageRoot = Join-Path -Path $PackageRoot -ChildPath '\*'
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($null -eq $ManifestFile) {
|
|
Write-IcingaConsoleError ([string]::Format('Unable to read manifest for package "{0}". Aborting installation', $Name.ToLower()));
|
|
Start-Sleep -Seconds 2;
|
|
Remove-Item -Path $DownloadDirectory -Recurse -Force;
|
|
return;
|
|
}
|
|
|
|
$ComponentFolder = Join-Path -Path (Get-IcingaForWindowsRootPath) -ChildPath $PackageName;
|
|
$ModuleData = (Get-Module -ListAvailable -Name $PackageName -ErrorAction SilentlyContinue) | Sort-Object Version -Descending | Select-Object Version -First 1;
|
|
[string]$InstallVersion = $null;
|
|
$ServiceStatus = $null;
|
|
$AgentStatus = $null;
|
|
|
|
if ($null -ne $ModuleData) {
|
|
[string]$InstallVersion = $ModuleData.Version;
|
|
}
|
|
|
|
if ($ManifestFile.ModuleVersion -eq $InstallVersion -And $Force -eq $FALSE) {
|
|
Write-IcingaConsoleError ([string]::Format('The package "{0}" with version "{1}" is already installed. Use "-Force" to re-install the component', $Name.ToLower(), $ManifestFile.ModuleVersion));
|
|
Start-Sleep -Seconds 2;
|
|
Remove-Item -Path $DownloadDirectory -Recurse -Force;
|
|
return;
|
|
}
|
|
|
|
# These update steps only apply for the framework
|
|
if ($Name.ToLower() -eq 'framework') {
|
|
$ServiceStatus = (Get-Service 'icingapowershell' -ErrorAction SilentlyContinue).Status;
|
|
$AgentStatus = (Get-Service 'icinga2' -ErrorAction SilentlyContinue).Status;
|
|
|
|
if ($ServiceStatus -eq 'Running') {
|
|
Write-IcingaConsoleNotice 'Stopping Icinga for Windows service';
|
|
Stop-IcingaService 'icingapowershell';
|
|
Start-Sleep -Seconds 1;
|
|
}
|
|
if ($AgentStatus -eq 'Running') {
|
|
Write-IcingaConsoleNotice 'Stopping Icinga Agent service';
|
|
Stop-IcingaService 'icinga2';
|
|
Start-Sleep -Seconds 1;
|
|
}
|
|
}
|
|
|
|
if ((Test-Path $ComponentFolder) -eq $FALSE) {
|
|
[void](New-Item -ItemType Directory -Path $ComponentFolder -Force);
|
|
}
|
|
|
|
$ComponentFileContent = Get-ChildItem -Path $ComponentFolder;
|
|
|
|
foreach ($entry in $ComponentFileContent) {
|
|
if (($entry.Name -eq 'cache' -Or $entry.Name -eq 'config') -And $Name.ToLower() -eq 'framework') {
|
|
continue;
|
|
}
|
|
|
|
[void](Remove-ItemSecure -Path $entry.FullName -Recurse -Force);
|
|
}
|
|
|
|
[void](Copy-ItemSecure -Path $PackageRoot -Destination $ComponentFolder -Recurse -Force);
|
|
|
|
Write-IcingaConsoleNotice 'Installing version "{0}" of component "{1}"' -Objects $ManifestFile.ModuleVersion, $Name.ToLower();
|
|
|
|
Unblock-IcingaPowerShellFiles -Path $ComponentFolder;
|
|
|
|
if ($Name.ToLower() -eq 'framework') {
|
|
if (Test-IcingaFunction 'Write-IcingaFrameworkCodeCache') {
|
|
Write-IcingaFrameworkCodeCache;
|
|
}
|
|
|
|
if ($ServiceStatus -eq 'Running') {
|
|
Write-IcingaConsoleNotice 'Starting Icinga for Windows service';
|
|
Start-IcingaService 'icingapowershell';
|
|
}
|
|
if ($AgentStatus -eq 'Running') {
|
|
Write-IcingaConsoleNotice 'Starting Icinga Agent service';
|
|
Start-IcingaService 'icinga2';
|
|
}
|
|
}
|
|
|
|
Import-Module -Name $ComponentFolder -Force;
|
|
Write-IcingaConsoleNotice 'Installation of component "{0}" with version "{1}" was successful. Open a new PowerShell to apply the changes' -Objects $Name.ToLower(), $ManifestFile.ModuleVersion;
|
|
} else {
|
|
<#
|
|
Handles installation of Icinga for Windows service
|
|
#>
|
|
|
|
$FolderContent = Get-ChildItem -Path $DownloadDirectory -Recurse -Include 'icinga-service.exe';
|
|
|
|
if ($Name.ToLower() -eq 'service') {
|
|
|
|
$ConfigDirectory = Get-IcingaPowerShellConfig -Path 'Framework.Icinga.IcingaForWindowsService';
|
|
$ConfigUser = Get-IcingaPowerShellConfig -Path 'Framework.Icinga.ServiceUser';
|
|
$ServiceData = Get-IcingaForWindowsServiceData;
|
|
$ServiceDirectory = $ServiceData.Directory;
|
|
$ServiceUser = $ServiceData.User;
|
|
|
|
if ([string]::IsNullOrEmpty($ConfigDirectory) -eq $FALSE) {
|
|
$ServiceDirectory = $ConfigDirectory;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ConfigUser) -eq $FALSE) {
|
|
$ServiceUser = $ConfigUser;
|
|
}
|
|
|
|
foreach ($binary in $FolderContent) {
|
|
|
|
if ((Test-IcingaZipBinaryChecksum -Path $binary.FullName) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'The checksum for the given service binary does not match';
|
|
continue;
|
|
}
|
|
|
|
if ((Test-Path $ServiceDirectory) -eq $FALSE) {
|
|
[void](New-Item -ItemType Directory -Path $ServiceDirectory -Force);
|
|
}
|
|
|
|
$UpdateBin = Join-Path -Path $ServiceDirectory -ChildPath 'icinga-service.exe.update';
|
|
$ServiceBin = Join-Path -Path $ServiceDirectory -ChildPath 'icinga-service.exe';
|
|
|
|
# Service is already installed
|
|
if (Test-Path $ServiceBin) {
|
|
$InstalledService = Read-IcingaServicePackage -File $ServiceBin;
|
|
$NewService = Read-IcingaServicePackage -File $binary.FullName;
|
|
|
|
if ($InstalledService.ProductVersion -eq $NewService.ProductVersion -And $null -ne $InstalledService -And $null -ne $NewService -And $Force -eq $FALSE) {
|
|
Write-IcingaConsoleError ([string]::Format('The package "service" with version "{0}" is already installed. Use "-Force" to re-install the component', $InstalledService.ProductVersion));
|
|
Start-Sleep -Seconds 2;
|
|
Remove-Item -Path $DownloadDirectory -Recurse -Force;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Installing component "service" into "{0}"' -Objects $ServiceDirectory;
|
|
|
|
Copy-ItemSecure -Path $binary.FullName -Destination $UpdateBin -Force;
|
|
|
|
[void](Install-IcingaForWindowsService -Path $ServiceBin -User $ServiceUser -Password (Get-IcingaInternalPowerShellServicePassword));
|
|
Set-IcingaInternalPowerShellServicePassword -Password $null;
|
|
Start-Sleep -Seconds 2;
|
|
Remove-Item -Path $DownloadDirectory -Recurse -Force;
|
|
|
|
Write-IcingaConsoleNotice 'Installation of component "service" was successful'
|
|
|
|
return;
|
|
}
|
|
|
|
Write-IcingaConsoleError 'Failed to install component "service". Either the package did not include a service binary or the checksum of the binary did not match';
|
|
Start-Sleep -Seconds 2;
|
|
Remove-Item -Path $DownloadDirectory -Recurse -Force;
|
|
return;
|
|
} else {
|
|
Write-IcingaConsoleError 'There was no manifest file found inside the package';
|
|
Remove-Item -Path $DownloadDirectory -Recurse -Force;
|
|
return;
|
|
}
|
|
}
|
|
} elseif ([IO.Path]::GetExtension($FileName) -eq '.msi') {
|
|
|
|
<#
|
|
Handles installation of Icinga Agent MSI Packages
|
|
#>
|
|
|
|
$IcingaData = Get-IcingaAgentInstallation;
|
|
$InstalledVersion = Get-IcingaAgentVersion;
|
|
$InstallTarget = $IcingaData.RootDir;
|
|
$InstallDir = Get-IcingaPowerShellConfig -Path 'Framework.Icinga.AgentLocation';
|
|
$ConfigUser = Get-IcingaPowerShellConfig -Path 'Framework.Icinga.ServiceUser';
|
|
$ServiceUser = $IcingaData.User;
|
|
|
|
if ([string]::IsNullOrEmpty($InstallDir) -eq $FALSE) {
|
|
if ((Test-Path $InstallDir) -eq $FALSE) {
|
|
[void](New-Item -Path $InstallDir -ItemType Directory -Force);
|
|
}
|
|
$InstallTarget = $InstallDir;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ConfigUser) -eq $FALSE) {
|
|
$ServiceUser = $ConfigUser;
|
|
}
|
|
|
|
[string]$InstallFolderMsg = $InstallTarget;
|
|
|
|
if ([string]::IsNullOrEmpty($InstallTarget) -eq $FALSE) {
|
|
$InstallTarget = [string]::Format(' INSTALL_ROOT="{0}"', $InstallTarget);
|
|
} else {
|
|
$InstallTarget = '';
|
|
if ($IcingaData.Architecture -eq 'x86') {
|
|
$InstallFolderMsg = Join-Path -Path ${env:ProgramFiles(x86)} -ChildPath 'icinga2';
|
|
} else {
|
|
$InstallFolderMsg = Join-Path -Path $env:ProgramFiles -ChildPath 'icinga2';
|
|
}
|
|
}
|
|
|
|
$MSIData = & powershell.exe -Command { Use-Icinga; return Read-IcingaMSIMetadata -File $args[0] } -Args $DownloadDestination;
|
|
|
|
if ($InstalledVersion.Full -eq $MSIData.ProductVersion -And $Force -eq $FALSE) {
|
|
Write-IcingaConsoleError 'The package "agent" with version "{0}" is already installed. Use "-Force" to re-install the component' -Objects $InstalledVersion.Full;
|
|
Remove-Item -Path $DownloadDirectory -Recurse -Force;
|
|
|
|
return;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Installing component "agent" with version "{0}" into "{1}"' -Objects $MSIData.ProductVersion, $InstallFolderMsg;
|
|
|
|
if ($IcingaData.Installed) {
|
|
if ((Uninstall-IcingaAgent) -eq $FALSE) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
$InstallProcess = powershell.exe -Command {
|
|
$IcingaInstaller = $args[0];
|
|
$InstallTarget = $args[1];
|
|
Use-Icinga;
|
|
|
|
$InstallProcess = Start-IcingaProcess -Executable 'MsiExec.exe' -Arguments ([string]::Format('/quiet /i "{0}" {1}', $IcingaInstaller, $InstallTarget)) -FlushNewLines;
|
|
|
|
return $InstallProcess;
|
|
} -Args $DownloadDestination, $InstallTarget;
|
|
|
|
if ($InstallProcess.ExitCode -ne 0) {
|
|
Write-IcingaConsoleError -Message 'Failed to install component "agent": {0}{1}' -Objects $InstallProcess.Message, $InstallProcess.Error;
|
|
return $FALSE;
|
|
}
|
|
|
|
Set-IcingaAgentServiceUser -User $ServiceUser -SetPermission;
|
|
|
|
Write-IcingaConsoleNotice 'Installation of component "agent" with version "{0}" was successful.' -Objects $MSIData.ProductVersion;
|
|
} else {
|
|
Write-IcingaConsoleError ([string]::Format('Unsupported file extension "{0}" found for package "{1}". Aborting installation', ([IO.Path]::GetExtension($FileName)), $Name.ToLower()));
|
|
}
|
|
|
|
Start-Sleep -Seconds 1;
|
|
Remove-Item -Path $DownloadDirectory -Recurse -Force;
|
|
}
|
|
|
|
function Lock-IcingaComponent()
|
|
{
|
|
param (
|
|
[string]$Name = $null,
|
|
[string]$Version = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to specify the component to lock';
|
|
return;
|
|
}
|
|
|
|
$Name = $Name.ToLower();
|
|
if ([string]::IsNullOrEmpty($Version)) {
|
|
if ($Name -eq 'agent') {
|
|
$Version = (Get-IcingaAgentVersion).Full;
|
|
} else {
|
|
$ModuleData = Get-Module -ListAvailable -Name ([string]::Format('icinga-powershell-{0}', $Name)) -ErrorAction SilentlyContinue;
|
|
|
|
if ($null -eq $ModuleData) {
|
|
$ModuleData = Get-Module -ListAvailable -Name "*$Name*" -ErrorAction SilentlyContinue;
|
|
}
|
|
|
|
if ($null -ne $ModuleData) {
|
|
$Version = $ModuleData.Version.ToString();
|
|
$Name = (Read-IcingaPackageManifest -File $ModuleData.Path).ComponentName;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Version)) {
|
|
Write-IcingaConsoleError 'Pinning the current version of component "{0}" is not possible, as it seems to be not installed. Please install the component first or manually specify version with "-Version"';
|
|
return;
|
|
}
|
|
|
|
$LockedComponents = Get-IcingaPowerShellConfig -Path 'Framework.Repository.ComponentLock';
|
|
|
|
if ($null -eq $LockedComponents) {
|
|
$LockedComponents = New-Object -TypeName PSObject;
|
|
}
|
|
|
|
if (Test-IcingaPowerShellConfigItem -ConfigObject $LockedComponents -ConfigKey $Name) {
|
|
$LockedComponents.$Name = $Version;
|
|
} else {
|
|
$LockedComponents | Add-Member -MemberType NoteProperty -Name $Name -Value $Version;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Locking of component "{0}" to version "{1}" successful. You can release the lock with "Unlock-IcingaComponent -Name {2}{0}{2}"' -Objects $Name, $Version, "'";
|
|
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Repository.ComponentLock' -Value $LockedComponents;
|
|
}
|
|
|
|
function New-IcingaRepository()
|
|
{
|
|
param (
|
|
[string]$Name = $null,
|
|
[string]$Path = $null,
|
|
[string]$RemotePath = $null,
|
|
[switch]$Force = $FALSE
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to provide a name for the repository';
|
|
return;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Path) -Or (Test-Path $Path) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'The provided path "{0}" does not exist' -Objects $Path;
|
|
return;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($RemotePath)) {
|
|
Write-IcingaConsoleWarning 'No explicit remote path has been defined. Using local path "{0}" as remote path' -Objects $Path;
|
|
$RemotePath = $Path;
|
|
}
|
|
|
|
$CurrentRepositories = Get-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories';
|
|
|
|
if ($null -eq $CurrentRepositories) {
|
|
$CurrentRepositories = New-Object -TypeName PSObject;
|
|
}
|
|
|
|
if (Test-IcingaPowerShellConfigItem -ConfigObject $CurrentRepositories -ConfigKey $Name) {
|
|
Write-IcingaConsoleError 'A repository with the given name "{0}" does already exist. Use "Update-IcingaRepository -Name {1}{0}{1}" to update it.' -Objects $Name, "'";
|
|
return;
|
|
}
|
|
|
|
$IcingaRepository = New-IcingaRepositoryFile -Path $Path -RemotePath $RemotePath;
|
|
|
|
[array]$ConfigCount = $IcingaRepository.Packages.PSObject.Properties.Count;
|
|
|
|
if ($ConfigCount.Count -eq 0) {
|
|
Write-IcingaConsoleWarning 'Created empty repository at location "{0}"' -Objects $Path;
|
|
}
|
|
[array]$RepoCount = $CurrentRepositories.PSObject.Properties.Count;
|
|
|
|
$CurrentRepositories | Add-Member -MemberType NoteProperty -Name $Name -Value (New-Object -TypeName PSObject);
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'LocalPath' -Value $Path;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'RemotePath' -Value $RemotePath;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'CloneSource' -Value $null;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'UseSCP' -Value $FALSE;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'Order' -Value $RepoCount.Count;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'Enabled' -Value $True;
|
|
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories' -Value $CurrentRepositories;
|
|
}
|
|
|
|
function New-IcingaRepositoryFile()
|
|
{
|
|
param (
|
|
[string]$Path = $null,
|
|
[string]$RemotePath = $null
|
|
);
|
|
|
|
$RepoFile = 'ifw.repo.json';
|
|
$RepoPath = Join-Path -Path $Path -ChildPath $RepoFile;
|
|
|
|
$IcingaRepository = New-Object -TypeName PSObject;
|
|
$IcingaRepository | Add-Member -MemberType NoteProperty -Name 'Info' -Value (New-Object -TypeName PSObject);
|
|
|
|
# Info
|
|
$IcingaRepository.Info | Add-Member -MemberType NoteProperty -Name 'LocalSource' -Value $Path;
|
|
$IcingaRepository.Info | Add-Member -MemberType NoteProperty -Name 'RemoteSource' -Value $RemotePath;
|
|
$IcingaRepository.Info | Add-Member -MemberType NoteProperty -Name 'Created' -Value ((Get-Date).ToUniversalTime().ToString('yyyy\/MM\/dd HH:mm:ss'));
|
|
$IcingaRepository.Info | Add-Member -MemberType NoteProperty -Name 'Updated' -Value $IcingaRepository.Info.Created;
|
|
$IcingaRepository.Info | Add-Member -MemberType NoteProperty -Name 'RepoHash' -Value $null;
|
|
|
|
# Packages
|
|
$IcingaRepository | Add-Member -MemberType NoteProperty -Name 'Packages' -Value (New-Object -TypeName PSObject);
|
|
|
|
$RepositoryFolder = Get-ChildItem -Path $Path -Recurse -Include '*.msi', '*.zip';
|
|
|
|
foreach ($entry in $RepositoryFolder) {
|
|
$RepoFilePath = $entry.FullName.Replace($Path, '');
|
|
$FileHash = Get-FileHash -Path $entry.FullName -Algorithm SHA256;
|
|
$ComponentName = '';
|
|
|
|
$IcingaForWindowsPackage = New-Object -TypeName PSObject;
|
|
$IcingaForWindowsPackage | Add-Member -MemberType NoteProperty -Name 'Hash' -Value $FileHash.Hash;
|
|
$IcingaForWindowsPackage | Add-Member -MemberType NoteProperty -Name 'Location' -Value $RepoFilePath;
|
|
$IcingaForWindowsPackage | Add-Member -MemberType NoteProperty -Name 'RelativePath' -Value $TRUE;
|
|
|
|
if ([IO.Path]::GetExtension($entry.Name) -eq '.zip') {
|
|
$IcingaPackage = Read-IcingaPackageManifest -File $entry.FullName;
|
|
$IcingaService = $null;
|
|
$Version = $null;
|
|
|
|
if ($null -ne $IcingaPackage) {
|
|
$PackageVersion = $IcingaPackage.ModuleVersion;
|
|
$ComponentName = $IcingaPackage.ComponentName;
|
|
} else {
|
|
$IcingaService = Read-IcingaServicePackage -File $entry.FullName;
|
|
}
|
|
if ($null -ne $IcingaService) {
|
|
$PackageVersion = $IcingaService.ProductVersion;
|
|
$ComponentName = $IcingaService.ComponentName;
|
|
}
|
|
|
|
[bool]$IsSnapshot = $FALSE;
|
|
|
|
if ($entry.FullName.ToLower() -like '*\master.zip') {
|
|
$IsSnapshot = $TRUE;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ComponentName) -eq $FALSE) {
|
|
$IcingaForWindowsPackage | Add-Member -MemberType NoteProperty -Name 'Version' -Value $PackageVersion;
|
|
$IcingaForWindowsPackage | Add-Member -MemberType NoteProperty -Name 'Snapshot' -Value $IsSnapshot;
|
|
$IcingaForWindowsPackage | Add-Member -MemberType NoteProperty -Name 'Architecture' -Value 'Multi';
|
|
}
|
|
} elseif ([IO.Path]::GetExtension($entry.Name) -eq '.msi') {
|
|
$IcingaPackage = Read-IcingaMSIMetadata -File $entry.FullName;
|
|
|
|
if ([string]::IsNullOrEmpty($IcingaPackage.ProductName) -eq $FALSE -And $IcingaPackage.ProductName -eq 'Icinga 2') {
|
|
$IcingaForWindowsPackage | Add-Member -MemberType NoteProperty -Name 'Version' -Value $IcingaPackage.ProductVersion;
|
|
$IcingaForWindowsPackage | Add-Member -MemberType NoteProperty -Name 'Snapshot' -Value $IcingaPackage.Snapshot;
|
|
$IcingaForWindowsPackage | Add-Member -MemberType NoteProperty -Name 'Architecture' -Value $IcingaPackage.Architecture;
|
|
$ComponentName = 'agent';
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ComponentName)) {
|
|
continue;
|
|
}
|
|
|
|
if (Test-IcingaPowerShellConfigItem -ConfigObject $IcingaRepository.Packages -ConfigKey $ComponentName) {
|
|
$IcingaRepository.Packages.$ComponentName += $IcingaForWindowsPackage;
|
|
} else {
|
|
$IcingaRepository.Packages | Add-Member -MemberType NoteProperty -Name $ComponentName -Value @();
|
|
$IcingaRepository.Packages.$ComponentName += $IcingaForWindowsPackage;
|
|
}
|
|
|
|
$IcingaRepository.Info.RepoHash = Get-IcingaRepositoryHash -Path $Path;
|
|
}
|
|
|
|
Set-Content -Path $RepoPath -Value (ConvertTo-Json -InputObject $IcingaRepository -Depth 100);
|
|
|
|
return $IcingaRepository;
|
|
}
|
|
|
|
function Pop-IcingaRepository()
|
|
{
|
|
param (
|
|
[string]$Name = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to provide a name for the repository';
|
|
return;
|
|
}
|
|
|
|
$CurrentRepositories = Get-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories';
|
|
|
|
if ($null -eq $CurrentRepositories) {
|
|
Write-IcingaConsoleNotice 'You have no repositories configured yet.';
|
|
return;
|
|
}
|
|
|
|
[array]$RepoList = Get-IcingaRepositories;
|
|
[int]$Index = $RepoList.Count - 1;
|
|
|
|
foreach ($repo in $RepoList) {
|
|
if ($repo.Name -eq $Name) {
|
|
continue;
|
|
}
|
|
|
|
$CurrentRepositories.($repo.Name).Order = [int]$Index;
|
|
$Index -= 1;
|
|
}
|
|
|
|
$CurrentRepositories.$Name.Order = [int]$Index;
|
|
|
|
Write-IcingaConsoleNotice 'The repository "{0}" was put at the bottom of the repository list' -Objects $Name;
|
|
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories' -Value $CurrentRepositories;
|
|
}
|
|
|
|
function Push-IcingaRepository()
|
|
{
|
|
param (
|
|
[string]$Name = $null,
|
|
[switch]$Silent = $FALSE
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
if ($Silent -eq $FALSE) {
|
|
Write-IcingaConsoleError 'You have to provide a name for the repository';
|
|
}
|
|
return;
|
|
}
|
|
|
|
$CurrentRepositories = Get-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories';
|
|
|
|
if ($null -eq $CurrentRepositories) {
|
|
if ($Silent -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'You have no repositories configured yet.';
|
|
}
|
|
return;
|
|
}
|
|
|
|
[array]$RepoList = Get-IcingaRepositories;
|
|
[int]$Index = 0;
|
|
|
|
foreach ($repo in $RepoList) {
|
|
if ($repo.Name -eq $Name) {
|
|
continue;
|
|
}
|
|
|
|
$CurrentRepositories.($repo.Name).Order = [int]$Index;
|
|
$Index += 1;
|
|
}
|
|
|
|
$CurrentRepositories.$Name.Order = [int]$Index;
|
|
|
|
if ($Silent -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'The repository "{0}" was put at the top of the repository list' -Objects $Name;
|
|
}
|
|
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories' -Value $CurrentRepositories;
|
|
}
|
|
|
|
function Read-IcingaMSIMetadata()
|
|
{
|
|
param (
|
|
[string]$File = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($File) -Or (Test-Path $File) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'The provided file "{0}" does not exist' -Objects $File;
|
|
return $null;
|
|
}
|
|
|
|
if ([IO.Path]::GetExtension($File) -ne '.msi') {
|
|
Write-IcingaConsoleError 'This Cmdlet is only supporting files with .msi extension. Extension "{0}" given.' -Objects ([IO.Path]::GetExtension($File));
|
|
return $null;
|
|
}
|
|
|
|
$AgentFile = Get-Item $File;
|
|
$MSIPackageData = @{
|
|
'ProductCode' = '';
|
|
'ProductVersion' = '';
|
|
'ProductName' = '';
|
|
}
|
|
|
|
[array]$MSIObjects = $MSIPackageData.Keys;
|
|
|
|
try {
|
|
$InstallerInstance = New-Object -ComObject 'WindowsInstaller.Installer';
|
|
#$MSIPackage = $InstallerInstance.OpenDatabase($File, 0); # Not Working on Windows 2012 R2
|
|
$MSIPackage = $InstallerInstance.GetType().InvokeMember('OpenDatabase', 'InvokeMethod', $Null, $InstallerInstance, @($File, 0));
|
|
|
|
foreach ($PackageInfo in $MSIObjects) {
|
|
$MSIQuery = [string]::Format(
|
|
"SELECT `Value` FROM `Property` WHERE `Property` = '{0}'",
|
|
$PackageInfo
|
|
);
|
|
#$MSIDb = $MSIPackage.OpenView($MSIQuery); # Not Working on Windows 2012 R2
|
|
$MSIDb = $MSIPackage.GetType().InvokeMember('OpenView', 'InvokeMethod', $Null, $MSIPackage, $MSIQuery);
|
|
|
|
if ($null -eq $MSIDb) {
|
|
continue;
|
|
}
|
|
|
|
#$MSIDb.Execute(); # Not Working on Windows 2012 R2
|
|
$MSIDb.GetType().InvokeMember('Execute', 'InvokeMethod', $Null, $MSIDb, $Null);
|
|
#$MSITable = $MSIDb.Fetch(); # Not Working on Windows 2012 R2
|
|
$MSITable = $MSIDb.GetType().InvokeMember('Fetch' , 'InvokeMethod', $Null, $MSIDb, $Null);
|
|
|
|
if ($null -eq $MSITable) {
|
|
continue;
|
|
}
|
|
|
|
$MSIPackageData[$PackageInfo] = $MSITable.GetType().InvokeMember('StringData', 'GetProperty', $null, $MSITable, 1);
|
|
|
|
#$MSIDb.Close(); # Not Working on Windows 2012 R2
|
|
$MSIDb.GetType().InvokeMember('Close', 'InvokeMethod', $null, $MSIDb, $null);
|
|
[void]([System.Runtime.InteropServices.Marshal]::ReleaseComObject($MSIDb));
|
|
$MSIDb = $null;
|
|
}
|
|
|
|
[void]([System.Runtime.InteropServices.Marshal]::ReleaseComObject($MSIPackage));
|
|
[void]([System.Runtime.InteropServices.Marshal]::ReleaseComObject($InstallerInstance));
|
|
$MSIPackage = $null;
|
|
$InstallerInstance = $null;
|
|
|
|
if ($AgentFile.Name.Contains('x86_64')) {
|
|
$MSIPackageData.Add('Architecture', 'x64')
|
|
} else {
|
|
$MSIPackageData.Add('Architecture', 'x86')
|
|
}
|
|
|
|
[Version]$PackageVersion = $MSIPackageData.ProductVersion;
|
|
if ($PackageVersion.Revision -eq -1) {
|
|
$MSIPackageData.Add('Snapshot', $False);
|
|
} else {
|
|
$MSIPackageData.Add('Snapshot', $True);
|
|
}
|
|
|
|
return $MSIPackageData;
|
|
} catch {
|
|
Write-IcingaConsoleError 'Failed to query MSI package information for package "{0}". Exception: {1}' -Objects $File, $_.Exception.Message;
|
|
}
|
|
|
|
return $null;
|
|
}
|
|
|
|
function Read-IcingaPackageManifest()
|
|
{
|
|
param (
|
|
[string]$File = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($File) -Or (Test-Path $File) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'The provided file "{0}" does not exist' -Objects $File;
|
|
return $null;
|
|
}
|
|
|
|
if ((Test-IcingaAddTypeExist 'System.IO.Compression.FileSystem') -eq $FALSE) {
|
|
Add-Type -Assembly 'System.IO.Compression.FileSystem';
|
|
}
|
|
|
|
if ([IO.Path]::GetExtension($File) -ne '.zip' -And [IO.Path]::GetExtension($File) -ne '.psd1') {
|
|
Write-IcingaConsoleError 'Your Icinga for Windows manifest must be inside a .zip file or directly given on the "-File" argument. Extension "{0}" given.' -Objects ([IO.Path]::GetExtension($File));
|
|
return $null;
|
|
}
|
|
|
|
try {
|
|
$ZipPackage = $null;
|
|
|
|
if ([IO.Path]::GetExtension($File) -eq '.zip') {
|
|
$ZipPackage = [System.IO.Compression.ZipFile]::OpenRead($File);
|
|
$PackageManifest = $null;
|
|
$FileName = $null;
|
|
|
|
foreach ($entry in $ZipPackage.Entries) {
|
|
if ([IO.Path]::GetExtension($entry.FullName) -ne '.psd1') {
|
|
continue;
|
|
}
|
|
|
|
$FileName = $entry.Name.Replace('.psd1', '');
|
|
$FilePath = $entry.FullName.Replace($entry.Name, '');
|
|
$FileStream = $entry.Open();
|
|
$FileReader = [System.IO.StreamReader]::new($FileStream);
|
|
$PackageManifestContent = $FileReader.ReadToEnd();
|
|
$FileReader.Dispose();
|
|
|
|
[ScriptBlock]$PackageScript = [ScriptBlock]::Create('return ' + $PackageManifestContent);
|
|
$PackageManifest = (& $PackageScript);
|
|
|
|
if ($null -eq $PackageManifest -Or $PackageManifest.Count -eq 0) {
|
|
continue;
|
|
}
|
|
|
|
if ($PackageManifest.ContainsKey('PrivateData') -eq $FALSE -Or $PackageManifest.ContainsKey('ModuleVersion') -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
$ZipPackage.Dispose();
|
|
} elseif ([IO.Path]::GetExtension($File) -eq '.psd1') {
|
|
$FileName = (Get-Item -Path $File).Name.Replace('.psd1', '');
|
|
$PackageManifestContent = Get-Content -Path $File -Raw;
|
|
[ScriptBlock]$PackageScript = [ScriptBlock]::Create('return ' + $PackageManifestContent);
|
|
$PackageManifest = (& $PackageScript);
|
|
} else {
|
|
return $null;
|
|
}
|
|
|
|
if ($null -eq $PackageManifest) {
|
|
return $null;
|
|
}
|
|
|
|
$PackageManifest.Add('ComponentName', '');
|
|
|
|
if ([string]::IsNullOrEmpty($FileName) -eq $FALSE) {
|
|
if ($FileName.Contains('icinga-powershell-*')) {
|
|
$PackageManifest.ComponentName = $FileName.Replace('icinga-powershell-', '');
|
|
} else {
|
|
if ($PackageManifest.ContainsKey('PrivateData') -And $PackageManifest.PrivateData.ContainsKey('Name') -And $PackageManifest.PrivateData.ContainsKey('Type')) {
|
|
if ($PackageManifest.PrivateData.Name -eq 'Icinga for Windows' -And $PackageManifest.PrivateData.Type -eq 'framework') {
|
|
$PackageManifest.ComponentName = 'framework';
|
|
} else {
|
|
$PackageManifest.ComponentName = ($PackageManifest.PrivateData.Name -Replace 'Windows' -Replace '\W').ToLower();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $PackageManifest;
|
|
} catch {
|
|
$ExMsg = $_.Exception.Message;
|
|
Write-IcingaConsoleError 'Failed to read package content and/or manifest file: {0}' -Objects $ExMsg;
|
|
} finally {
|
|
if ($null -ne $ZipPackage) {
|
|
$ZipPackage.Dispose();
|
|
}
|
|
}
|
|
|
|
return $null;
|
|
}
|
|
|
|
function Read-IcingaRepositoryFile()
|
|
{
|
|
param (
|
|
[string]$Name = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to provide a name for the repository';
|
|
return $null;
|
|
}
|
|
|
|
$Repository = Get-IcingaPowerShellConfig -Path ([string]::Format('Framework.Repository.Repositories.{0}', $Name));
|
|
|
|
if ($null -eq $Repository) {
|
|
Write-IcingaConsoleError 'A repository with the given name "{0}" does not exist. Use "New-IcingaRepository" or "Sync-IcingaForWindowsRepository" to create a new one.' -Objects $Name;
|
|
return $null;
|
|
}
|
|
|
|
$RepoPath = $null;
|
|
$Content = $null;
|
|
|
|
if ([string]::IsNullOrEmpty($Repository.LocalPath) -eq $FALSE -And (Test-Path -Path $Repository.LocalPath)) {
|
|
$RepoPath = $Repository.LocalPath;
|
|
$Content = Get-Content -Path (Join-Path -Path $RepoPath -ChildPath 'ifw.repo.json') -Raw;
|
|
} elseif ([string]::IsNullOrEmpty($Repository.RemotePath) -eq $FALSE -And (Test-Path -Path $Repository.RemotePath)) {
|
|
$RepoPath = $Repository.RemotePath;
|
|
$WebContent = Get-Content -Path (Join-Path -Path $RepoPath -ChildPath 'ifw.repo.json') -Raw;
|
|
} else {
|
|
try {
|
|
$WebContent = Invoke-WebRequest -UseBasicParsing -Uri $Repository.RemotePath;
|
|
$RepoPath = $Repository.RemotePath;
|
|
} catch {
|
|
# Nothing to do
|
|
}
|
|
|
|
if ($null -eq $WebContent) {
|
|
try {
|
|
$WebContent = Invoke-WebRequest -UseBasicParsing -Uri (Join-WebPath -Path $Repository.RemotePath -ChildPath 'ifw.repo.json');
|
|
} catch {
|
|
Write-IcingaConsoleError 'Failed to read repository file from "{0}" or "{0}/ifw.repo.json". Exception: {1}' -Objects $Repository.RemotePath, $_.Exception.Message;
|
|
return $null;
|
|
}
|
|
$RepoPath = $Repository.RemotePath;
|
|
}
|
|
|
|
if ($null -eq $WebContent) {
|
|
Write-IcingaConsoleError 'Unable to fetch data for repository "{0}" from any configured location' -Objects $Name;
|
|
return $null;
|
|
}
|
|
|
|
if ($WebContent.RawContent.Contains('application/octet-stream')) {
|
|
$Content = [System.Text.Encoding]::UTF8.GetString($WebContent.Content)
|
|
} else {
|
|
$Content = $WebContent.Content;
|
|
}
|
|
}
|
|
|
|
if ($null -eq $Content) {
|
|
Write-IcingaConsoleError 'Unable to fetch data for repository "{0}" from any configured location' -Objects $Name;
|
|
return $null;
|
|
}
|
|
|
|
$RepositoryObject = ConvertFrom-Json -InputObject $Content;
|
|
|
|
return $RepositoryObject;
|
|
}
|
|
|
|
function Read-IcingaServicePackage()
|
|
{
|
|
param (
|
|
[string]$File = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($File) -Or (Test-Path $File) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'The provided file "{0}" does not exist' -Objects $File;
|
|
return $null;
|
|
}
|
|
|
|
if ((Test-IcingaAddTypeExist 'System.IO.Compression.FileSystem') -eq $FALSE) {
|
|
Add-Type -Assembly 'System.IO.Compression.FileSystem';
|
|
}
|
|
|
|
if ([IO.Path]::GetExtension($File) -ne '.zip' -And [IO.Path]::GetExtension($File) -ne '.exe') {
|
|
Write-IcingaConsoleError 'Your service binary must be inside a .zip file or directly given on the "-File" argument. Extension "{0}" given.' -Objects ([IO.Path]::GetExtension($File));
|
|
return $null;
|
|
}
|
|
|
|
[hashtable]$BinaryData = @{
|
|
'CompanyName' = '';
|
|
'FileVersion' = '';
|
|
'ProductVersion' = '';
|
|
'ComponentName' = 'service';
|
|
}
|
|
|
|
try {
|
|
$ZipPackage = $null;
|
|
|
|
if ([IO.Path]::GetExtension($File) -eq '.zip') {
|
|
$ZipPackage = [System.IO.Compression.ZipFile]::OpenRead($File);
|
|
|
|
foreach ($entry in $ZipPackage.Entries) {
|
|
if ([IO.Path]::GetExtension($entry.FullName) -ne '.exe') {
|
|
continue;
|
|
}
|
|
|
|
$ServiceTempDir = New-IcingaTemporaryDirectory;
|
|
$BinaryFile = (Join-Path -Path $ServiceTempDir -ChildPath $entry.Name);
|
|
[System.IO.Compression.ZipFileExtensions]::ExtractToFile(
|
|
$entry,
|
|
(Join-Path -Path $ServiceTempDir -ChildPath $entry.Name),
|
|
$TRUE
|
|
);
|
|
|
|
$ServiceBin = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($BinaryFile);
|
|
|
|
if ($ServiceBin.CompanyName -ne 'Icinga GmbH') {
|
|
Remove-Item -Path $ServiceTempDir -Recurse -Force;
|
|
continue;
|
|
}
|
|
|
|
$BinaryData.CompanyName = $ServiceBin.CompanyName;
|
|
$BinaryData.ProductVersion = ([version]($ServiceBin.ProductVersion)).ToString(3);
|
|
$BinaryData.FileVersion = ([version]($ServiceBin.FileVersion)).ToString(3);
|
|
break;
|
|
}
|
|
|
|
$ZipPackage.Dispose();
|
|
} elseif ([IO.Path]::GetExtension($File) -eq '.exe') {
|
|
$ServiceBin = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($File);
|
|
|
|
if ($ServiceBin.CompanyName -ne 'Icinga GmbH') {
|
|
return $null;
|
|
}
|
|
|
|
$BinaryData.CompanyName = $ServiceBin.CompanyName;
|
|
$BinaryData.ProductVersion = ([version]($ServiceBin.ProductVersion)).ToString(3);
|
|
$BinaryData.FileVersion = ([version]($ServiceBin.FileVersion)).ToString(3);
|
|
} else {
|
|
return $null;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($BinaryData.ProductVersion)) {
|
|
return $null;
|
|
}
|
|
|
|
return $BinaryData;
|
|
} catch {
|
|
$ExMsg = $_.Exception.Message;
|
|
Write-IcingaConsoleError 'Failed to read package content and/or binary file: {0}' -Objects $ExMsg;
|
|
} finally {
|
|
if ($null -ne $ZipPackage) {
|
|
$ZipPackage.Dispose();
|
|
}
|
|
}
|
|
|
|
return $null;
|
|
}
|
|
|
|
function Remove-IcingaRepository()
|
|
{
|
|
param (
|
|
[string]$Name = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to provide a name for the repository to remove';
|
|
return;
|
|
}
|
|
|
|
$CurrentRepositories = Get-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories';
|
|
|
|
if ((Test-IcingaPowerShellConfigItem -ConfigObject $CurrentRepositories -ConfigKey $Name) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'A repository with the name "{0}" is not configured' -Objects $Name;
|
|
return;
|
|
}
|
|
|
|
Push-IcingaRepository -Name $Name -Silent;
|
|
|
|
Remove-IcingaPowerShellConfig -Path (
|
|
[string]::Format(
|
|
'Framework.Repository.Repositories.{0}',
|
|
$Name
|
|
)
|
|
);
|
|
|
|
Write-IcingaConsoleNotice 'The repository with the name "{0}" was successfully removed' -Objects $Name;
|
|
}
|
|
|
|
function Search-IcingaRepository()
|
|
{
|
|
param (
|
|
[string]$Name = $null,
|
|
[string]$Version = $null,
|
|
[switch]$Release = $FALSE,
|
|
[switch]$Snapshot = $FALSE
|
|
);
|
|
|
|
if ($Version -eq 'release') {
|
|
$Version = $null;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to provide a component name';
|
|
return;
|
|
}
|
|
|
|
if ($Release -eq $FALSE -And $Snapshot -eq $FALSE) {
|
|
$Release = $TRUE;
|
|
}
|
|
|
|
$Repositories = Get-IcingaRepositories -ExcludeDisabled;
|
|
[Version]$LatestVersion = $null;
|
|
[string]$SourcePath = $null;
|
|
[bool]$FoundPackage = $FALSE;
|
|
[array]$Output = @();
|
|
[bool]$FoundPackage = $FALSE;
|
|
|
|
$SearchList = New-Object -TypeName PSObject;
|
|
$SearchList | Add-Member -MemberType NoteProperty -Name 'Repos' -Value @();
|
|
|
|
foreach ($entry in $Repositories) {
|
|
$RepoContent = Read-IcingaRepositoryFile -Name $entry.Name;
|
|
|
|
if ($null -eq $RepoContent) {
|
|
continue;
|
|
}
|
|
|
|
if ((Test-IcingaPowerShellConfigItem -ConfigObject $RepoContent -ConfigKey 'Packages') -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($repoEntry in $RepoContent.Packages.PSObject.Properties.Name) {
|
|
|
|
if ($repoEntry -NotLike $Name) {
|
|
continue;
|
|
}
|
|
|
|
$RepoData = New-Object -TypeName PSObject;
|
|
$RepoData | Add-Member -MemberType NoteProperty -Name 'Name' -Value $entry.Name;
|
|
$RepoData | Add-Member -MemberType NoteProperty -Name 'RemoteSource' -Value $RepoContent.Info.RemoteSource;
|
|
$RepoData | Add-Member -MemberType NoteProperty -Name 'ComponentName' -Value $repoEntry;
|
|
$RepoData | Add-Member -MemberType NoteProperty -Name 'Packages' -Value @();
|
|
|
|
foreach ($package in $RepoContent.Packages.$repoEntry) {
|
|
|
|
$ComponentData = New-Object -TypeName PSObject;
|
|
$ComponentData | Add-Member -MemberType NoteProperty -Name 'Version' -Value $package.Version;
|
|
$ComponentData | Add-Member -MemberType NoteProperty -Name 'Location' -Value $package.Location;
|
|
$ComponentData | Add-Member -MemberType NoteProperty -Name 'Snapshot' -Value $package.Snapshot;
|
|
|
|
if ($Snapshot -And $package.Snapshot -eq $TRUE -And [string]::IsNullOrEmpty($Version)) {
|
|
$RepoData.Packages += $ComponentData;
|
|
continue;
|
|
}
|
|
|
|
if ($Snapshot -And $package.Snapshot -eq $TRUE -And [string]::IsNullOrEmpty($Version) -eq $FALSE -And [version]$package.Version -eq [version]$Version) {
|
|
$RepoData.Packages += $ComponentData;
|
|
continue;
|
|
}
|
|
|
|
if ($Release -And [string]::IsNullOrEmpty($Version) -And $package.Snapshot -eq $FALSE) {
|
|
$RepoData.Packages += $ComponentData;
|
|
continue;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Version) -eq $FALSE -And $Release -eq $FALSE -And $Snapshot -eq $FALSE -And $package.Snapshot -eq $FALSE) {
|
|
$RepoData.Packages += $ComponentData;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ($RepoData.Packages.Count -ne 0) {
|
|
$FoundPackage = $TRUE;
|
|
}
|
|
|
|
$SearchList.Repos += $RepoData;
|
|
}
|
|
}
|
|
|
|
if ($FoundPackage -eq $FALSE) {
|
|
$SearchVersion = 'release';
|
|
if ([string]::IsNullOrEmpty($Version) -eq $FALSE) {
|
|
$SearchVersion = $Version;
|
|
}
|
|
if ($Release) {
|
|
Write-IcingaConsoleNotice 'The component "{0}" was not found on stable channel with version "{1}"' -Objects $Name, $SearchVersion;
|
|
}
|
|
if ($Snapshot) {
|
|
Write-IcingaConsoleNotice 'The component "{0}" was not found on snapshot channel with version "{1}"' -Objects $Name, $SearchVersion;
|
|
}
|
|
return;
|
|
}
|
|
|
|
foreach ($repo in $SearchList.Repos) {
|
|
if ($repo.Packages.Count -eq 0) {
|
|
continue;
|
|
}
|
|
|
|
$Output += $repo.Name;
|
|
$Output += '-----------';
|
|
$Output += [string]::Format('Source => {0}', $repo.RemoteSource);
|
|
$Output += '';
|
|
$Output += $repo.ComponentName;
|
|
|
|
[array]$VersionList = $repo.Packages | Sort-Object { $_.Version } -Descending;
|
|
|
|
foreach ($componentData in $VersionList) {
|
|
$Output += [string]::Format('{0} => {1}', $componentData.Version, $componentData.Location);
|
|
}
|
|
$Output += '';
|
|
}
|
|
|
|
Write-Host ($Output | Out-String);
|
|
}
|
|
|
|
function Show-Icinga()
|
|
{
|
|
$IcingaInstallation = Get-IcingaInstallation -Release;
|
|
[array]$Output = @( 'Icinga for Windows environment' );
|
|
[int]$MaxComponentLength = Get-IcingaMaxTextLength -TextArray $IcingaInstallation.Keys;
|
|
[int]$MaxVersionLength = Get-IcingaMaxTextLength -TextArray $IcingaInstallation.Values.CurrentVersion;
|
|
[string]$ComponentHeader = Add-IcingaWhiteSpaceToString -Text 'Component' -Length $MaxComponentLength;
|
|
[string]$ComponentLine = Add-IcingaWhiteSpaceToString -Text '---' -Length $MaxComponentLength;
|
|
$Output += '-----------';
|
|
$Output += '';
|
|
$Output += 'Installed components on this system';
|
|
$Output += '';
|
|
$Output += [string]::Format('{0} {1} Available', $ComponentHeader, ((Add-IcingaWhiteSpaceToString -Text 'Version' -Length $MaxVersionLength)));
|
|
$Output += [string]::Format('{0} {1} ---', $ComponentLine, ((Add-IcingaWhiteSpaceToString -Text '---' -Length $MaxVersionLength)));
|
|
|
|
foreach ($component in $IcingaInstallation.Keys) {
|
|
$Data = $IcingaInstallation[$component];
|
|
$LatestVersion = $Data.LatestVersion;
|
|
$CurrentVersion = $Data.CurrentVersion;
|
|
|
|
if ([string]::IsNullOrEmpty($Data.LockedVersion) -eq $FALSE) {
|
|
if ($Data.LockedVersion -eq $Data.CurrentVersion) {
|
|
$CurrentVersion = [string]::Format('{0}*', $CurrentVersion);
|
|
} else {
|
|
$LatestVersion = [string]::Format('{0}*', $Data.LockedVersion);
|
|
}
|
|
}
|
|
|
|
[string]$ComponentName = Add-IcingaWhiteSpaceToString -Text $component -Length $MaxComponentLength;
|
|
$Output += [string]::Format('{0} {1} {2}', $ComponentName, (Add-IcingaWhiteSpaceToString -Text $CurrentVersion -Length $MaxVersionLength), $LatestVersion);
|
|
}
|
|
|
|
$Output += '';
|
|
$Output += 'Available versions flagged with "*" mean that this component is locked to this version';
|
|
|
|
$IcingaForWindowsService = Get-IcingaForWindowsServiceData;
|
|
$IcingaAgentService = Get-IcingaAgentInstallation;
|
|
$WindowsInformation = Get-IcingaWindowsInformation Win32_OperatingSystem | Select-Object Version, BuildNumber, Caption;
|
|
|
|
$Output += '';
|
|
$Output += 'Environment configuration';
|
|
$Output += '';
|
|
$Output += ([string]::Format('PowerShell Root => {0}', (Get-IcingaForWindowsRootPath)));
|
|
$Output += ([string]::Format('Icinga for Windows Service Path => {0}', $IcingaForWindowsService.Directory));
|
|
$Output += ([string]::Format('Icinga for Windows Service User => {0}', $IcingaForWindowsService.User));
|
|
$Output += ([string]::Format('Icinga Agent Path => {0}', $IcingaAgentService.RootDir));
|
|
$Output += ([string]::Format('Icinga Agent User => {0}', $IcingaAgentService.User));
|
|
$Output += ([string]::Format('PowerShell Version => {0}', $PSVersionTable.PSVersion.ToString()));
|
|
$Output += ([string]::Format('Operating System => {0}', $WindowsInformation.Caption));
|
|
$Output += ([string]::Format('Operating System Version => {0}', $WindowsInformation.Version));
|
|
|
|
$Output += '';
|
|
$Output += (Show-IcingaRepository);
|
|
|
|
Write-Output $Output;
|
|
}
|
|
|
|
function Show-IcingaRepository()
|
|
{
|
|
[hashtable]$Repositories = @{ };
|
|
[array]$RepoSummary = @(
|
|
'List of configured repositories on this system. The list order matches the apply order.',
|
|
''
|
|
);
|
|
[array]$RepoList = Get-IcingaRepositories;
|
|
|
|
foreach ($repo in $RepoList) {
|
|
|
|
$RepoSummary += $repo.Name;
|
|
$RepoSummary += '-----------';
|
|
|
|
[int]$MaxLength = Get-IcingaMaxTextLength -TextArray $repo.Value.PSObject.Properties.Name;
|
|
[array]$RepoData = @();
|
|
|
|
foreach ($repoConfig in $repo.Value.PSObject.Properties) {
|
|
$PrintName = Add-IcingaWhiteSpaceToString -Text $repoConfig.Name -Length $MaxLength;
|
|
$RepoData += [string]::Format('{0} => {1}', $PrintName, $repoConfig.Value);
|
|
}
|
|
|
|
$RepoSummary += $RepoData | Sort-Object;
|
|
$RepoSummary += '';
|
|
}
|
|
|
|
if ($RepoList.Count -eq 0) {
|
|
$RepoSummary += 'No repositories configured';
|
|
}
|
|
|
|
Write-Output $RepoSummary;
|
|
}
|
|
|
|
function Sync-IcingaRepository()
|
|
{
|
|
param (
|
|
[string]$Name = $null,
|
|
[string]$Path = $null,
|
|
[string]$RemotePath = $null,
|
|
[string]$Source = $null,
|
|
[switch]$UseSCP = $FALSE,
|
|
[switch]$Force = $FALSE,
|
|
[switch]$ForceTrust = $FALSE
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to provide a name for the repository';
|
|
return;
|
|
}
|
|
|
|
if ($UseSCP -And $null -eq (Get-Command 'scp' -ErrorAction SilentlyContinue) -And $null -eq (Get-Command 'ssh' -ErrorAction SilentlyContinue)) {
|
|
Write-IcingaConsoleWarning 'You cannot use SCP on this system, as SCP and/or SSH seem not to be installed';
|
|
return;
|
|
}
|
|
|
|
if ($UseSCP -And $Path.Contains(':') -eq $FALSE -And $Path.Contains('@') -eq $FALSE) {
|
|
Write-IcingaConsoleWarning 'You have to add host and username to your "-Path" argument. Example: "icinga@icinga.example.com:/var/www/icingarepo/" ';
|
|
return;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Path) -Or (Test-Path $Path) -eq $FALSE -And $UseSCP -eq $FALSE) {
|
|
Write-IcingaConsoleWarning 'The provided path "{0}" does not exist and will be created' -Objects $Path;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($RemotePath)) {
|
|
Write-IcingaConsoleWarning 'No explicit remote path has been defined. Using local path "{0}" as remote path' -Objects $Path;
|
|
$RemotePath = $Path;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Source)) {
|
|
Write-IcingaConsoleError 'You have to specify a source to sync from';
|
|
return;
|
|
}
|
|
|
|
$CurrentRepositories = Get-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories';
|
|
|
|
if ($null -eq $CurrentRepositories) {
|
|
$CurrentRepositories = New-Object -TypeName PSObject;
|
|
}
|
|
|
|
if ((Test-IcingaPowerShellConfigItem -ConfigObject $CurrentRepositories -ConfigKey $Name) -And $Force -eq $FALSE) {
|
|
Write-IcingaConsoleError 'A repository with the given name "{0}" does already exist. Use "Update-IcingaRepository -Name {1}{0}{1}" to update it.' -Objects $Name, "'";
|
|
return;
|
|
}
|
|
|
|
if ((Test-Path $Path) -eq $FALSE -And $UseSCP -eq $FALSE) {
|
|
$FolderCreated = New-Item -Path $Path -ItemType Directory -Force -ErrorAction SilentlyContinue;
|
|
|
|
if ($null -eq $FolderCreated) {
|
|
Write-IcingaConsoleError 'Unable to create repository folder at location "{0}". Please verify that you have permissions to write into the location and try again or create the folder manually' -Objects $Path;
|
|
return;
|
|
}
|
|
}
|
|
|
|
$RepoFile = $null;
|
|
$SSHAuth = $null;
|
|
$RemovePath = $null;
|
|
|
|
if (Test-Path $Source) {
|
|
$CopySource = Join-Path -Path $Source -ChildPath '\*';
|
|
} else {
|
|
$CopySource = $Source;
|
|
}
|
|
|
|
if ($UseSCP -eq $FALSE) {
|
|
$Path = Join-Path -Path $Path -ChildPath '\';
|
|
$RemovePath = Join-Path -Path $Path -ChildPath '\*';
|
|
} else {
|
|
$SSHIndex = $Path.IndexOf(':');
|
|
$SSHAuth = $Path.Substring(0, $SSHIndex);
|
|
$Path = $Path.Substring($SSHIndex + 1, $Path.Length - $SSHIndex - 1);
|
|
|
|
if ($Path[-1] -eq '/') {
|
|
$RemovePath = [string]::Format('{0}*', $Path);
|
|
} else {
|
|
$RemovePath = [string]::Format('{0}/*', $Path);
|
|
}
|
|
}
|
|
|
|
# All cloning will be done into a local file first
|
|
$TmpDir = New-IcingaTemporaryDirectory;
|
|
$RepoFile = (Join-Path -Path $TmpDir -ChildPath 'ifw.repo.json');
|
|
[bool]$HasNonRelative = $FALSE;
|
|
|
|
if (Test-Path $CopySource) { # Sync source is local path
|
|
$Success = Copy-ItemSecure -Path $CopySource -Destination $TmpDir -Recurse -Force;
|
|
} else { # Sync Source is web path
|
|
$ProgressPreference = "SilentlyContinue";
|
|
try {
|
|
Invoke-WebRequest -USeBasicParsing -Uri $Source -OutFile $RepoFile;
|
|
} catch {
|
|
try {
|
|
Invoke-WebRequest -USeBasicParsing -Uri (Join-WebPath -Path $Source -ChildPath 'ifw.repo.json') -OutFile $RepoFile;
|
|
} catch {
|
|
Write-IcingaConsoleError 'Unable to download repository file from "{0}". Exception: "{1}"' -Objects $Source, $_.Exception.Message;
|
|
$Success = Remove-Item -Path $TmpDir -Recurse -Force;
|
|
return;
|
|
}
|
|
}
|
|
|
|
$RepoContent = Get-Content -Path $RepoFile -Raw;
|
|
$JsonRepo = ConvertFrom-Json -InputObject $RepoContent;
|
|
|
|
foreach ($component in $JsonRepo.Packages.PSObject.Properties.Name) {
|
|
$IfWPackage = $JsonRepo.Packages.$component
|
|
|
|
foreach ($package in $IfWPackage) {
|
|
$DownloadLink = $package.Location;
|
|
$TargetLocation = $TmpDir;
|
|
|
|
if ($package.RelativePath -eq $TRUE) {
|
|
$DownloadLink = Join-WebPath -Path $JsonRepo.Info.RemoteSource -ChildPath $package.Location;
|
|
$TargetLocation = Join-Path -Path $TmpDir -ChildPath $package.Location;
|
|
|
|
[void](
|
|
New-Item `
|
|
-ItemType Directory `
|
|
-Path (
|
|
$TargetLocation.SubString(
|
|
0,
|
|
$TargetLocation.LastIndexOf('\')
|
|
)
|
|
) `
|
|
-Force
|
|
);
|
|
} else {
|
|
$HasNonRelative = $TRUE;
|
|
$FileName = $package.Location.Replace('/', '\');
|
|
$Index = $FileName.LastIndexOf('\');
|
|
$FileName = $FileName.SubString($Index, $FileName.Length - $Index);
|
|
$TargetLocation = Join-Path -Path $TmpDir -ChildPath $component;
|
|
[void](New-Item -ItemType Directory -Path $TargetLocation -Force);
|
|
$TargetLocation = Join-Path -Path $TargetLocation -ChildPath $FileName;
|
|
}
|
|
|
|
try {
|
|
Write-IcingaConsoleNotice 'Syncing repository component "{0}" as file "{1}" into temp directory' -Objects $component, $package.Location;
|
|
Invoke-WebRequest -USeBasicParsing -Uri $DownloadLink -OutFile $TargetLocation;
|
|
} catch {
|
|
Write-IcingaConsoleError 'Failed to download repository component "{0}". Exception: "{1}"' -Objects $DownloadLink, $_.Exception.Message;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[string]$CopySource = [string]::Format('{0}\*', $TmpDir);
|
|
|
|
if ((Test-Path $RepoFile) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'The files from this repository were cloned but no repository file was found. Deleting temporary files';
|
|
$Success = Remove-Item -Path $TmpDir -Recurse -Force;
|
|
return;
|
|
}
|
|
|
|
$RepoContent = Get-Content -Path $RepoFile -Raw;
|
|
$JsonRepo = ConvertFrom-Json -InputObject $RepoContent;
|
|
|
|
if ($null -eq $JsonRepo) {
|
|
Write-IcingaConsoleError 'The repository file was found but it is either damaged or empty. Deleting temporary files';
|
|
$Success = Remove-Item -Path $TmpDir -Recurse -Force;
|
|
return;
|
|
}
|
|
|
|
$EnableRepo = $TRUE;
|
|
|
|
if ($ForceTrust -eq $FALSE -And $UseSCP -eq $FALSE) {
|
|
if ($null -eq $JsonRepo.Info.RepoHash -Or [string]::IsNullOrEmpty($JsonRepo.Info.RepoHash)) {
|
|
Write-IcingaConsoleWarning 'The cloned repository file hash cannot be verified, as it is not present inside the repository file. The repository will be added, but disabled for security reasons. Review the content first and ensure you trust the source before enabling it.';
|
|
$EnableRepo = $FALSE;
|
|
} elseif ($JsonRepo.Info.RepoHash -ne (Get-IcingaRepositoryHash -Path $TmpDir)) {
|
|
$Success = Remove-Item -Path $TmpDir -Recurse -Force;
|
|
Write-IcingaConsoleError 'The repository hash for the cloned repository is not matching the file hash of the files inside. Removing repository data';
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ($HasNonRelative) {
|
|
[void](New-IcingaRepositoryFile -Path $TmpDir -RemotePath $RemotePath);
|
|
$RepoContent = Get-Content -Path $RepoFile -Raw;
|
|
$JsonRepo = ConvertFrom-Json -InputObject $RepoContent;
|
|
Start-Sleep -Seconds 2;
|
|
}
|
|
|
|
$JsonRepo.Info.RepoHash = Get-IcingaRepositoryHash -Path $TmpDir;
|
|
$JsonRepo.Info.LocalSource = $Path;
|
|
$JsonRepo.Info.RemoteSource = $RemotePath;
|
|
$JsonRepo.Info.Updated = ((Get-Date).ToUniversalTime().ToString('yyyy\/MM\/dd HH:mm:ss'));
|
|
|
|
Set-Content -Path $RepoFile -Value (ConvertTo-Json -InputObject $JsonRepo -Depth 100);
|
|
|
|
if ($UseSCP -eq $FALSE) { # Windows target
|
|
$Success = Remove-Item -Path $RemovePath -Recurse -Force;
|
|
$Success = Copy-ItemSecure -Path $CopySource -Destination $Path -Recurse -Force;
|
|
|
|
if ($Success -eq $FALSE) {
|
|
Write-IcingaConsoleError 'Unable to sync repository from location "{0}" to destination "{1}". Please verify that you have permissions to write into the location and try again or create the folder manually' -Objects $TmpDir, $Path;
|
|
$Success = Remove-Item -Path $TmpDir -Recurse -Force;
|
|
return;
|
|
}
|
|
} else { # Linux target
|
|
Write-IcingaConsoleNotice 'Creating directory over SSH for host and user "{0}" and path "{1}"' -Objects $SSHAuth, $Path;
|
|
|
|
$Result = Start-IcingaProcess -Executable 'ssh' -Arguments ([string]::Format('{0} mkdir -p "{1}"', $SSHAuth, $Path));
|
|
if ($Result.ExitCode -ne 0) {
|
|
# TODO: Add link to setup docs
|
|
Write-IcingaConsoleError 'SSH Error on directory creation: {0}' -Objects $Result.Error;
|
|
$Success = Remove-Item -Path $TmpDir -Recurse -Force;
|
|
return;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Removing old repository files from "{0}"' -Objects $Path;
|
|
|
|
$Result = Start-IcingaProcess -Executable 'ssh' -Arguments ([string]::Format('{0} rm -Rf "{1}"', $SSHAuth, $RemovePath));
|
|
|
|
if ($Result.ExitCode -ne 0) {
|
|
Write-IcingaConsoleError 'SSH Error on removing old repository data: {0}' -Objects $Result.Error;
|
|
$Success = Remove-Item -Path $TmpDir -Recurse -Force;
|
|
return;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Syncing new repository files to "{0}"' -Objects $Path;
|
|
|
|
$Result = Start-IcingaProcess -Executable 'scp' -Arguments ([string]::Format('-r "{0}" "{1}:{2}"', $CopySource, $SSHAuth, $Path));
|
|
|
|
if ($Result.ExitCode -ne 0) {
|
|
Write-IcingaConsoleError 'SCP Error while copying repository files: {0}' -Objects $Result.Error;
|
|
$Success = Remove-Item -Path $TmpDir -Recurse -Force;
|
|
return;
|
|
}
|
|
}
|
|
|
|
$Success = Remove-Item -Path $TmpDir -Recurse -Force;
|
|
|
|
if ((Test-IcingaPowerShellConfigItem -ConfigObject $CurrentRepositories -ConfigKey $Name) -And $Force -eq $TRUE) {
|
|
$CurrentRepositories.$Name.Enabled = $EnableRepo;
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories' -Value $CurrentRepositories;
|
|
Write-IcingaConsoleNotice 'Re-syncing of repository "{0}" was successful' -Objects $Name;
|
|
return;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'The repository was synced successfully. Use "Update-IcingaRepository" to sync possible changes from the source repository.';
|
|
|
|
[array]$RepoCount = $CurrentRepositories.PSObject.Properties.Count;
|
|
|
|
$CurrentRepositories | Add-Member -MemberType NoteProperty -Name $Name -Value (New-Object -TypeName PSObject);
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'LocalPath' -Value $Path;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'RemotePath' -Value $RemotePath;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'CloneSource' -Value $Source;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'UseSCP' -Value ([bool]$UseSCP);
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'Order' -Value $RepoCount.Count;
|
|
$CurrentRepositories.$Name | Add-Member -MemberType NoteProperty -Name 'Enabled' -Value $EnableRepo;
|
|
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories' -Value $CurrentRepositories;
|
|
|
|
return;
|
|
}
|
|
|
|
function Uninstall-IcingaComponent()
|
|
{
|
|
param (
|
|
[string]$Name = '',
|
|
[switch]$RemovePackageFiles = $FALSE
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to specify a component name to uninstall';
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($Name.ToLower() -eq 'agent') {
|
|
return Uninstall-IcingaAgent -RemoveDataFolder:$RemovePackageFiles;
|
|
}
|
|
|
|
if ($Name.ToLower() -eq 'service') {
|
|
return; Uninstall-IcingaForWindowsService -RemoveFiles:$RemovePackageFiles;
|
|
}
|
|
|
|
$ModuleBase = Get-IcingaForWindowsRootPath;
|
|
$UninstallComponent = [string]::Format('icinga-powershell-{0}', $Name);
|
|
$UninstallPath = Join-Path -Path $ModuleBase -ChildPath $UninstallComponent;
|
|
|
|
if ((Test-Path $UninstallPath) -eq $FALSE) {
|
|
Write-IcingaConsoleNotice -Message 'The Icinga for Windows component "{0}" at "{1}" could not ne found.' -Objects $UninstallComponent, $UninstallPath;
|
|
return $FALSE;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice -Message 'Uninstalling Icinga for Windows component "{0}" from "{1}"' -Objects $UninstallComponent, $UninstallPath;
|
|
if (Remove-ItemSecure -Path $UninstallPath -Recurse -Force) {
|
|
Write-IcingaConsoleNotice -Message 'Successfully removed Icinga for Windows component "{0}" from "{1}"' -Objects $UninstallComponent, $UninstallPath;
|
|
if ($UninstallComponent -ne 'icinga-powershell-framework') {
|
|
Remove-Module $UninstallComponent -Force -ErrorAction SilentlyContinue;
|
|
}
|
|
return $TRUE;
|
|
} else {
|
|
Write-IcingaConsoleError -Message 'Unable to uninstall Icinga for Windows component "{0}" from "{1}"' -Objects $UninstallComponent, $UninstallPath;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
function Unlock-IcingaComponent()
|
|
{
|
|
param (
|
|
[string]$Name = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
Write-IcingaConsoleError 'You have to specify the component to unlock';
|
|
return;
|
|
}
|
|
|
|
$LockedComponents = Get-IcingaPowerShellConfig -Path 'Framework.Repository.ComponentLock';
|
|
|
|
if ($null -eq $LockedComponents) {
|
|
Write-IcingaConsoleNotice 'You have currently no components which are locked configured';
|
|
return;
|
|
}
|
|
|
|
if (Test-IcingaPowerShellConfigItem -ConfigObject $LockedComponents -ConfigKey $Name) {
|
|
Remove-IcingaPowerShellConfig -Path ([string]::Format('Framework.Repository.ComponentLock.{0}', $Name));
|
|
Write-IcingaConsoleNotice 'Unlocking of component "{0}" was successful.' -Objects $Name;
|
|
} else {
|
|
Write-IcingaConsoleNotice 'The component "{0}" is not locked on this system' -Objects $Name;
|
|
}
|
|
}
|
|
|
|
function Update-Icinga()
|
|
{
|
|
param (
|
|
[string]$Name = $null,
|
|
[switch]$Release = $FALSE,
|
|
[switch]$Snapshot = $FALSE,
|
|
[switch]$Confirm = $FALSE,
|
|
[switch]$Force = $FALSE
|
|
);
|
|
|
|
if ($Release -eq $FALSE -And $Snapshot -eq $FALSE) {
|
|
$Release = $TRUE;
|
|
}
|
|
|
|
$CurrentInstallation = Get-IcingaInstallation -Release:$Release -Snapshot:$Snapshot;
|
|
|
|
foreach ($entry in $CurrentInstallation.Keys) {
|
|
$Component = $CurrentInstallation[$entry];
|
|
|
|
if ([string]::IsNullOrEmpty($Name) -eq $FALSE -And $Name -ne $entry) {
|
|
continue;
|
|
}
|
|
|
|
$NewVersion = $Component.LatestVersion;
|
|
|
|
if ([string]::IsNullOrEmpty($NewVersion)) {
|
|
Write-IcingaConsoleNotice 'No update package found for component "{0}"' -Objects $entry;
|
|
continue;
|
|
}
|
|
|
|
$LockedVersion = Get-IcingaComponentLock -Name $entry;
|
|
|
|
if ($null -ne $LockedVersion) {
|
|
$NewVersion = $LockedVersion;
|
|
}
|
|
|
|
if ([Version]$NewVersion -le [Version]$Component.CurrentVersion -And $Force -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'The installed version "{0}" of component "{1}" is identical or lower than the new version "{2}". Use "-Force" to install anyway' -Objects $Component.CurrentVersion, $entry, $NewVersion;
|
|
continue;
|
|
}
|
|
|
|
Install-IcingaComponent -Name $entry -Version $NewVersion -Release:$Release -Snapshot:$Snapshot -Confirm:$Confirm -Force:$Force
|
|
}
|
|
}
|
|
|
|
function Update-IcingaRepository()
|
|
{
|
|
param (
|
|
[string]$Name = $null,
|
|
[string]$Path = $null,
|
|
[string]$RemotePath = $null,
|
|
[switch]$CreateNew = $FALSE,
|
|
[switch]$ForceTrust = $FALSE
|
|
);
|
|
|
|
$CurrentRepositories = Get-IcingaPowerShellConfig -Path 'Framework.Repository.Repositories';
|
|
|
|
[array]$ConfigCount = $CurrentRepositories.PSObject.Properties.Count;
|
|
|
|
if (($null -eq $CurrentRepositories -Or $ConfigCount.Count -eq 0) -And $CreateNew -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'There are no repositories configured yet. You can create a custom repository with "New-IcingaRepository" or clone an existing one with "Sync-IcingaForWindowsRepository"';
|
|
return;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Name) -eq $FALSE) {
|
|
if ((Test-IcingaPowerShellConfigItem -ConfigObject $CurrentRepositories -ConfigKey $Name) -eq $FALSE -And $CreateNew -eq $FALSE) {
|
|
Write-IcingaConsoleError 'A repository with the given name "{0}" does not exist. Use "New-IcingaRepository" or "Sync-IcingaForWindowsRepository" to create a new one.' -Objects $Name;
|
|
return;
|
|
}
|
|
}
|
|
|
|
foreach ($definedRepo in $CurrentRepositories.PSObject.Properties) {
|
|
|
|
if ([string]::IsNullOrEmpty($Name) -eq $FALSE -And $definedRepo.Name.ToLower() -ne $Name.ToLower()) {
|
|
continue;
|
|
}
|
|
|
|
if ($definedRepo.Value.Enabled -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'Skipping disabled repository "{0}"' -Objects $definedRepo.Name;
|
|
continue;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($definedRepo.Value.CloneSource) -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($definedRepo.Value.LocalPath)) {
|
|
continue;
|
|
}
|
|
|
|
if ((Test-Path $definedRepo.Value.LocalPath) -eq $FALSE) {
|
|
if ($CreateNew) {
|
|
return $null;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
$Path = Join-Path -Path $definedRepo.Value.LocalPath -ChildPath '\';
|
|
|
|
if ($CreateNew -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'Updating Icinga for Windows repository "{0}"' -Objects $definedRepo.Name;
|
|
}
|
|
|
|
$IcingaRepository = New-IcingaRepositoryFile -Path $Path -RemotePath $RemotePath;
|
|
|
|
if ($CreateNew) {
|
|
return $IcingaRepository;
|
|
}
|
|
}
|
|
|
|
# Always sync repositories at the end, in case we updated a local repository and cloned it to somewhere else
|
|
foreach ($definedRepo in $CurrentRepositories.PSObject.Properties) {
|
|
|
|
if ([string]::IsNullOrEmpty($Name) -eq $FALSE -And $definedRepo.Name.ToLower() -ne $Name.ToLower()) {
|
|
continue;
|
|
}
|
|
|
|
if ($definedRepo.Value.Enabled -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($definedRepo.Value.LocalPath)) {
|
|
continue;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Syncing repository "{0}"' -Objects $definedRepo.Name;
|
|
|
|
if ([string]::IsNullOrEmpty($definedRepo.Value.CloneSource) -eq $FALSE) {
|
|
Sync-IcingaRepository `
|
|
-Name $definedRepo.Name `
|
|
-Path $definedRepo.Value.LocalPath `
|
|
-RemotePath $definedRepo.Value.RemotePath `
|
|
-Source $definedRepo.Value.CloneSource `
|
|
-UseSCP:$definedRepo.Value.UseSCP `
|
|
-Force `
|
|
-ForceTrust:$ForceTrust;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'All Icinga for Windows repositories were successfully updated';
|
|
}
|
|
|
|
function New-IcingaThreadHash()
|
|
{
|
|
param(
|
|
[ScriptBlock]$ShellScript,
|
|
[array]$Arguments
|
|
);
|
|
|
|
[string]$ScriptString = '';
|
|
[string]$ArgString = ($Arguments | Out-String);
|
|
if ($null -ne $ShellScript) {
|
|
$ScriptString = $ShellScript.ToString();
|
|
}
|
|
return (Get-StringSha1 -Content ($ScriptString + $ArgString + (Get-Date -Format "MM-dd-yyyy-HH-mm-ffff")));
|
|
}
|
|
|
|
function New-IcingaThreadInstance()
|
|
{
|
|
param(
|
|
[string]$Name,
|
|
$ThreadPool,
|
|
[ScriptBlock]$ScriptBlock,
|
|
[array]$Arguments,
|
|
[Switch]$Start
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
$Name = New-IcingaThreadHash -ShellScript $ScriptBlock -Arguments $Arguments;
|
|
}
|
|
|
|
Write-IcingaDebugMessage -Message (
|
|
[string]::Format(
|
|
'Creating new thread instance {0}{1}Arguments:{1}{2}',
|
|
$Name,
|
|
"`r`n",
|
|
($Arguments | Out-String)
|
|
)
|
|
);
|
|
|
|
$Shell = [PowerShell]::Create();
|
|
$Shell.RunspacePool = $ThreadPool;
|
|
[void]$Shell.AddScript($ScriptBlock);
|
|
foreach ($argument in $Arguments) {
|
|
[void]$Shell.AddArgument($argument);
|
|
}
|
|
|
|
$Thread = New-Object PSObject;
|
|
Add-Member -InputObject $Thread -MemberType NoteProperty -Name Shell -Value $Shell;
|
|
if ($Start) {
|
|
Add-Member -InputObject $Thread -MemberType NoteProperty -Name Handle -Value ($Shell.BeginInvoke());
|
|
Add-Member -InputObject $Thread -MemberType NoteProperty -Name Started -Value $TRUE;
|
|
} else {
|
|
Add-Member -InputObject $Thread -MemberType NoteProperty -Name Handle -Value $null;
|
|
Add-Member -InputObject $Thread -MemberType NoteProperty -Name Started -Value $FALSE;
|
|
}
|
|
|
|
if ($global:IcingaDaemonData.IcingaThreads.ContainsKey($Name) -eq $FALSE) {
|
|
$global:IcingaDaemonData.IcingaThreads.Add($Name, $Thread);
|
|
} else {
|
|
$global:IcingaDaemonData.IcingaThreads.Add(
|
|
(New-IcingaThreadHash -ShellScript $ScriptBlock -Arguments $Arguments),
|
|
$Thread
|
|
);
|
|
}
|
|
}
|
|
|
|
function New-IcingaThreadPool()
|
|
{
|
|
param(
|
|
[int]$MinInstances = 1,
|
|
[int]$MaxInstances = 5
|
|
);
|
|
|
|
$Runspaces = [RunspaceFactory]::CreateRunspacePool(
|
|
$MinInstances,
|
|
$MaxInstances,
|
|
[System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault(),
|
|
$host
|
|
)
|
|
|
|
$Runspaces.Open();
|
|
|
|
return $Runspaces;
|
|
}
|
|
|
|
function Remove-IcingaThread()
|
|
{
|
|
param(
|
|
[string]$Thread
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Thread)) {
|
|
return;
|
|
}
|
|
|
|
Stop-IcingaThread -Thread $Thread;
|
|
|
|
if ($global:IcingaDaemonData.IcingaThreads.ContainsKey($Thread)) {
|
|
$global:IcingaDaemonData.IcingaThreads[$Thread].Shell.Dispose();
|
|
$global:IcingaDaemonData.IcingaThreads.Remove($Thread);
|
|
}
|
|
}
|
|
|
|
function Restart-IcingaThread()
|
|
{
|
|
param(
|
|
[string]$Thread
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Thread)) {
|
|
return;
|
|
}
|
|
|
|
Stop-IcingaThread $Thread;
|
|
Start-IcingaThread $Thread;
|
|
}
|
|
|
|
function Start-IcingaThread()
|
|
{
|
|
param(
|
|
[string]$Thread
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Thread)) {
|
|
return;
|
|
}
|
|
|
|
if ($global:IcingaDaemonData.IcingaThreads.ContainsKey($Thread)) {
|
|
if ($global:IcingaDaemonData.IcingaThreads[$Thread].Started -eq $FALSE) {
|
|
$global:IcingaDaemonData.IcingaThreads[$Thread].Handle = $global:IcingaDaemonData.IcingaThreads[$Thread].Shell.BeginInvoke();
|
|
$global:IcingaDaemonData.IcingaThreads[$Thread].Started = $TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
function Stop-IcingaThread()
|
|
{
|
|
param(
|
|
[string]$Thread
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Thread)) {
|
|
return;
|
|
}
|
|
|
|
if ($global:IcingaDaemonData.IcingaThreads.ContainsKey($Thread)) {
|
|
if ($global:IcingaDaemonData.IcingaThreads[$Thread].Started -eq $TRUE) {
|
|
$global:IcingaDaemonData.IcingaThreads[$Thread].Shell.Stop();
|
|
$global:IcingaDaemonData.IcingaThreads[$Thread].Handle = $null;
|
|
$global:IcingaDaemonData.IcingaThreads[$Thread].Started = $FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
function Test-IcingaThread()
|
|
{
|
|
param(
|
|
[string]$Thread
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Thread)) {
|
|
return $FALSE;
|
|
}
|
|
|
|
return $global:IcingaDaemonData.IcingaThreads.ContainsKey($Thread);
|
|
}
|
|
|
|
function Add-IcingaArrayListItem()
|
|
{
|
|
param (
|
|
[System.Collections.ArrayList]$Array,
|
|
$Element
|
|
);
|
|
|
|
if ($null -eq $Array -Or $null -eq $Element) {
|
|
return;
|
|
}
|
|
|
|
$Array.Add($Element) | Out-Null;
|
|
}
|
|
|
|
function Add-IcingaHashtableItem()
|
|
{
|
|
param(
|
|
$Hashtable,
|
|
$Key,
|
|
$Value,
|
|
[switch]$Override
|
|
);
|
|
|
|
if ($null -eq $Hashtable) {
|
|
return $FALSE;
|
|
}
|
|
|
|
if ($Hashtable.ContainsKey($Key) -eq $FALSE) {
|
|
$Hashtable.Add($Key, $Value);
|
|
return $TRUE;
|
|
} else {
|
|
if ($Override) {
|
|
$Hashtable.Remove($Key);
|
|
$Hashtable.Add($Key, $Value);
|
|
return $TRUE;
|
|
}
|
|
}
|
|
return $FALSE;
|
|
}
|
|
|
|
function Add-IcingaWhiteSpaceToString()
|
|
{
|
|
param (
|
|
[string]$Text = '',
|
|
[int]$Length = 0
|
|
);
|
|
|
|
[int]$LengthOffset = $Length - $Text.Length;
|
|
|
|
while ($LengthOffset -gt 0) {
|
|
$Text += ' ';
|
|
$LengthOffset -= 1;
|
|
}
|
|
|
|
return $Text;
|
|
}
|
|
|
|
function Add-PSCustomObjectMember()
|
|
{
|
|
param (
|
|
$Object,
|
|
$Key,
|
|
$Value
|
|
);
|
|
|
|
if ($null -eq $Object) {
|
|
return $Object;
|
|
}
|
|
|
|
$Object | Add-Member -MemberType NoteProperty -Name $Key -Value $Value;
|
|
|
|
return $Object;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Compare-IcingaUnixTimeWithDateTime compares a DateTime-Object with the current DateTime and returns the offset between these values as Integer
|
|
.DESCRIPTION
|
|
Compare-IcingaUnixTimeWithDateTime compares a DateTime-Object with the current DateTime and returns the offset between these values as Integer
|
|
.PARAMETER DateTime
|
|
DateTime object you want to compare with the Universal Time
|
|
.INPUTS
|
|
System.DateTime
|
|
.OUTPUTS
|
|
System.Int64
|
|
#>
|
|
function Compare-IcingaUnixTimeWithDateTime() {
|
|
param (
|
|
[datetime]$DateTime
|
|
);
|
|
|
|
# This is when the computer starts counting time
|
|
$UnixEpochStart = (New-Object DateTime 1970, 1, 1, 0, 0, 0, ([DateTimeKind]::Utc));
|
|
# We convert the creation and current time to seconds
|
|
$CreationTime = [long][System.Math]::Floor((($DateTime.ToUniversalTime() - $UnixEpochStart).Ticks / [timespan]::TicksPerSecond));
|
|
$CurrentTime = Get-IcingaUnixTime;
|
|
|
|
# To find out, from the snapshot creation time to the current time, how many seconds are,
|
|
# you have to subtract from the (Current Time in s) the (Creation Time in s)
|
|
return ($CurrentTime - $CreationTime);
|
|
}
|
|
|
|
function Convert-Bytes()
|
|
{
|
|
param(
|
|
[string]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
# Ensure we always use proper formatting of values
|
|
$Value = $Value.Replace(',', '.');
|
|
|
|
If (($Value -Match "(^[\d\.]*) ?(B|KB|MB|GB|TB|PT|KiB|MiB|GiB|TiB|PiB)") -eq $FALSE) {
|
|
$Value = [string]::Format('{0}B', $Value);
|
|
}
|
|
|
|
If (($Value -Match "(^[\d\.]*) ?(B|KB|MB|GB|TB|PT|KiB|MiB|GiB|TiB|PiB)")) {
|
|
[single]$CurrentValue = $Matches[1];
|
|
[string]$CurrentUnit = $Matches[2];
|
|
|
|
switch ($CurrentUnit) {
|
|
{ 'KiB', 'MiB', 'GiB', 'TiB', 'PiB' -contains $_ } { $CurrentValue = ConvertTo-ByteIEC $CurrentValue $CurrentUnit; $boolOption = $true; }
|
|
{ 'KB', 'MB', 'GB', 'TB', 'PB' -contains $_ } { $CurrentValue = ConvertTo-ByteSI $CurrentValue $CurrentUnit; $boolOption = $true; }
|
|
}
|
|
|
|
switch ($Unit) {
|
|
{ 'B' -contains $_ } { $FinalValue = $CurrentValue; $boolOption = $true; }
|
|
{ 'KB' -contains $_ } { $FinalValue = ConvertTo-Kilobyte $CurrentValue -Unit B; $boolOption = $true; }
|
|
{ 'MB' -contains $_ } { $FinalValue = ConvertTo-Megabyte $CurrentValue -Unit B; $boolOption = $true; }
|
|
{ 'GB' -contains $_ } { $FinalValue = ConvertTo-Gigabyte $CurrentValue -Unit B; $boolOption = $true; }
|
|
{ 'TB' -contains $_ } { $FinalValue = ConvertTo-Terabyte $CurrentValue -Unit B; $boolOption = $true; }
|
|
{ 'PB' -contains $_ } { $FinalValue = ConvertTo-Petabyte $CurrentValue -Unit B; $boolOption = $true; }
|
|
{ 'KiB' -contains $_ } { $FinalValue = ConvertTo-Kibibyte $CurrentValue -Unit B; $boolOption = $true; }
|
|
{ 'MiB' -contains $_ } { $FinalValue = ConvertTo-Mebibyte $CurrentValue -Unit B; $boolOption = $true; }
|
|
{ 'GiB' -contains $_ } { $FinalValue = ConvertTo-Gibibyte $CurrentValue -Unit B; $boolOption = $true; }
|
|
{ 'TiB' -contains $_ } { $FinalValue = ConvertTo-Tebibyte $CurrentValue -Unit B; $boolOption = $true; }
|
|
{ 'PiB' -contains $_ } { $FinalValue = ConvertTo-Petabyte $CurrentValue -Unit B; $boolOption = $true; }
|
|
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
return @{'value' = ([decimal]$FinalValue); 'pastunit' = $CurrentUnit; 'endunit' = $Unit };
|
|
}
|
|
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
|
|
function Convert-IcingaCheckArgumentToPSObject()
|
|
{
|
|
param (
|
|
$Parameter = $null
|
|
);
|
|
|
|
$ParamValue = New-Object -TypeName PSObject;
|
|
|
|
if ($null -eq $parameter) {
|
|
return $ParamValue;
|
|
}
|
|
|
|
$ParamValue | Add-Member -MemberType NoteProperty -Name 'type' -Value (New-Object -TypeName PSObject);
|
|
$ParamValue | Add-Member -MemberType NoteProperty -Name 'Description' -Value (New-Object -TypeName PSObject);
|
|
$ParamValue | Add-Member -MemberType NoteProperty -Name 'Attributes' -Value (New-Object -TypeName PSObject);
|
|
$ParamValue | Add-Member -MemberType NoteProperty -Name 'position' -Value $Parameter.position;
|
|
$ParamValue | Add-Member -MemberType NoteProperty -Name 'Name' -Value $Parameter.name;
|
|
$ParamValue | Add-Member -MemberType NoteProperty -Name 'required' -Value $Parameter.required;
|
|
$ParamValue.type | Add-Member -MemberType NoteProperty -Name 'name' -Value $Parameter.type.name;
|
|
$ParamValue.Description | Add-Member -MemberType NoteProperty -Name 'Text' -Value $Parameter.Description.Text;
|
|
$ParamValue.Attributes | Add-Member -MemberType NoteProperty -Name 'ValidValues' -Value $null;
|
|
|
|
return $ParamValue;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Converts Icinga Network configuration from FQDN to IP
|
|
.DESCRIPTION
|
|
This Cmdlet will convert a given Icinga Endpoint configuration based
|
|
on a FQDN to a IPv4 based configuration and returns nothing of the
|
|
FQDN could not be resolved
|
|
.FUNCTIONALITY
|
|
Converts Icinga Network configuration from FQDN to IP
|
|
.EXAMPLE
|
|
PS>Convert-IcingaEndpointsToIPv4 -NetworkConfig @( '[icinga2.example.com]:5665' );
|
|
.PARAMETER NetworkConfig
|
|
An array of Icinga endpoint or single network configuration, like '[icinga2.example.com]:5665'
|
|
which will be converted to IP based configuration
|
|
.INPUTS
|
|
System.Array
|
|
.OUTPUTS
|
|
System.Hashtable
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
function Convert-IcingaEndpointsToIPv4()
|
|
{
|
|
param (
|
|
[array]$NetworkConfig
|
|
);
|
|
|
|
[array]$ResolvedNetwork = @();
|
|
[array]$UnresolvedNetwork = @();
|
|
[bool]$HasUnresolved = $FALSE;
|
|
[string]$Domain = $ENV:UserDNSDomain;
|
|
|
|
foreach ($entry in $NetworkConfig) {
|
|
$Network = Get-IPConfigFromString -IPConfig $entry;
|
|
try {
|
|
$ResolvedIP = [System.Net.Dns]::GetHostAddresses($Network.address);
|
|
$ResolvedNetwork += $entry.Replace($Network.address, $ResolvedIP);
|
|
} catch {
|
|
# Once we failed in first place, try to lookup the "FQDN" with our host domain
|
|
# we are in. Might resolve some issues if our DNS is not knowing the plain
|
|
# hostname and untable to resolve it
|
|
try {
|
|
$ResolvedIP = [System.Net.Dns]::GetHostAddresses(
|
|
[string]::Format(
|
|
'{0}.{1}',
|
|
$Network.address,
|
|
$Domain
|
|
)
|
|
);
|
|
$ResolvedNetwork += $entry.Replace($Network.address, $ResolvedIP);
|
|
} catch {
|
|
$UnresolvedNetwork += $Network.address;
|
|
$HasUnresolved = $TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return @{
|
|
'Network' = $ResolvedNetwork;
|
|
'HasErrors' = $HasUnresolved;
|
|
'Unresolved' = $UnresolvedNetwork;
|
|
};
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Converts any kind of Icinga threshold with provided units
|
|
to the lowest base of the unit which makes sense. It does
|
|
support the Icinga plugin language, like ~:30, @10:40, 15:30,
|
|
...
|
|
|
|
The conversion does currently support the following units:
|
|
|
|
Size: B, KB, MB, GB, TB, PT, KiB, MiB, GiB, TiB, PiB
|
|
Time: ms, s, m, h, d w, M, y
|
|
.DESCRIPTION
|
|
Converts any kind of Icinga threshold with provided units
|
|
to the lowest base of the unit. It does support the Icinga
|
|
plugin language, like ~:30, @10:40, 15:30, ...
|
|
|
|
The conversion does currently support the following units:
|
|
|
|
Size: B, KB, MB, GB, TB, PT, KiB, MiB, GiB, TiB, PiB
|
|
Time: ms, s, m, h, d w, M, y
|
|
.FUNCTIONALITY
|
|
Converts values with units to the lowest unit of this category.
|
|
Accepts Icinga Thresholds.
|
|
.EXAMPLE
|
|
PS>Convert-IcingaPluginThresholds -Threshold '20d';
|
|
|
|
Name Value
|
|
---- -----
|
|
Value 1728000
|
|
Unit s
|
|
.EXAMPLE
|
|
PS>Convert-IcingaPluginThresholds -Threshold '5GB';
|
|
|
|
Name Value
|
|
---- -----
|
|
Value 5000000000
|
|
Unit B
|
|
.EXAMPLE
|
|
PS>Convert-IcingaPluginThresholds -Threshold '10MB:20MB';
|
|
|
|
Name Value
|
|
---- -----
|
|
Value 10000000:20000000
|
|
Unit B
|
|
.EXAMPLE
|
|
PS>Convert-IcingaPluginThresholds -Threshold '10m:1h';
|
|
|
|
Name Value
|
|
---- -----
|
|
Value 600:3600
|
|
Unit s
|
|
.EXAMPLE
|
|
PS>Convert-IcingaPluginThresholds -Threshold '@10m:1h';
|
|
|
|
Name Value
|
|
---- -----
|
|
Value @600:3600
|
|
Unit s
|
|
.EXAMPLE
|
|
Convert-IcingaPluginThresholds -Threshold '~:1M';
|
|
|
|
Name Value
|
|
---- -----
|
|
Value ~:2592000
|
|
Unit s
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Hashtable
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Convert-IcingaPluginThresholds()
|
|
{
|
|
param (
|
|
[string]$Threshold = $null
|
|
);
|
|
|
|
[hashtable]$RetValue = @{
|
|
'Unit' = '';
|
|
'Value' = $null;
|
|
};
|
|
|
|
if ($null -eq $Threshold) {
|
|
return $RetValue;
|
|
}
|
|
|
|
# Always ensure we are using correct digits
|
|
$Threshold = $Threshold.Replace(',', '.');
|
|
|
|
[array]$Content = @();
|
|
|
|
if ($Threshold.Contains(':')) {
|
|
# If we have more than one ':' inside our string, lets check if this is a date time value
|
|
# In case it is convert it properly to a FileTime we can work with later on
|
|
if ([Regex]::Matches($Threshold, ":").Count -gt 1) {
|
|
try {
|
|
$DateTimeValue = [DateTime]::ParseExact($Threshold, 'yyyy\/MM\/dd HH:mm:ss', $null);
|
|
$RetValue.Value = $DateTimeValue.ToFileTime();
|
|
$RetValue.Unit = 's';
|
|
} catch {
|
|
$RetValue.Value = $Threshold;
|
|
}
|
|
|
|
return $RetValue;
|
|
}
|
|
|
|
$Content = $Threshold.Split(':');
|
|
} else {
|
|
$Content += $Threshold;
|
|
}
|
|
|
|
[array]$ConvertedValue = @();
|
|
|
|
foreach ($ThresholdValue in $Content) {
|
|
|
|
[bool]$HasTilde = $FALSE;
|
|
[bool]$HasAt = $FALSE;
|
|
[bool]$Negate = $FALSE;
|
|
$Value = '';
|
|
$WorkUnit = '';
|
|
|
|
if ($ThresholdValue.Contains('~')) {
|
|
$ThresholdValue = $ThresholdValue.Replace('~', '');
|
|
$HasTilde = $TRUE;
|
|
} elseif ($ThresholdValue.Contains('@')) {
|
|
$HasAt = $TRUE;
|
|
$ThresholdValue = $ThresholdValue.Replace('@', '');
|
|
}
|
|
|
|
if ($ThresholdValue[0] -eq '-' -And $ThresholdValue.Length -ge 1) {
|
|
$Negate = $TRUE;
|
|
$ThresholdValue = $ThresholdValue.Substring(1, $ThresholdValue.Length - 1);
|
|
}
|
|
|
|
If (($ThresholdValue -Match "(^[\d\.]*) ?(B|KB|MB|GB|TB|PT|KiB|MiB|GiB|TiB|PiB)")) {
|
|
$WorkUnit = 'B';
|
|
if ([string]::IsNullOrEmpty($RetValue.Unit) -eq $FALSE -And $RetValue.Unit -ne $WorkUnit) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.MultipleUnitUsage -Force;
|
|
}
|
|
$Value = (Convert-Bytes -Value $ThresholdValue -Unit $WorkUnit).Value;
|
|
$RetValue.Unit = $WorkUnit;
|
|
} elseif (($ThresholdValue -Match "(^[\d\.]*) ?(ms|s|m|h|d|w|M|y)")) {
|
|
$WorkUnit = 's';
|
|
if ([string]::IsNullOrEmpty($RetValue.Unit) -eq $FALSE -And $RetValue.Unit -ne $WorkUnit) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.MultipleUnitUsage -Force;
|
|
}
|
|
$Value = (ConvertTo-Seconds -Value $ThresholdValue);
|
|
$RetValue.Unit = $WorkUnit;
|
|
} elseif (($ThresholdValue -Match "(^[\d\.]*) ?(%)")) {
|
|
$WorkUnit = '%';
|
|
$Value = ([string]$ThresholdValue).Replace(' ', '').Replace('%', '');
|
|
$RetValue.Unit = $WorkUnit;
|
|
} else {
|
|
# Load all other units/values generically
|
|
[string]$StrNumeric = '';
|
|
[bool]$FirstChar = $TRUE;
|
|
[bool]$Delimiter = $FALSE;
|
|
foreach ($entry in ([string]($ThresholdValue)).ToCharArray()) {
|
|
if ((Test-Numeric $entry) -Or ($entry -eq '.' -And $Delimiter -eq $FALSE)) {
|
|
$StrNumeric += $entry;
|
|
$FirstChar = $FALSE;
|
|
if ($entry -eq '.') {
|
|
$Delimiter = $TRUE;
|
|
}
|
|
} else {
|
|
if ([string]::IsNullOrEmpty($RetValue.Unit) -And $FirstChar -eq $FALSE) {
|
|
$RetValue.Unit = $entry;
|
|
} else {
|
|
$StrNumeric = '';
|
|
$RetValue.Unit = '';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ([string]::IsNullOrEmpty($StrNumeric)) {
|
|
$Value = $ThresholdValue;
|
|
} else {
|
|
$Value = [decimal]$StrNumeric;
|
|
}
|
|
}
|
|
|
|
if ((Test-Numeric $Value) -And $Negate) {
|
|
$Value = $Value * -1;
|
|
} elseif ($Negate) {
|
|
$Value = [string]::Format('-{0}', $Value);
|
|
}
|
|
|
|
if ($HasTilde) {
|
|
$ConvertedValue += [string]::Format('~{0}', $Value);
|
|
} elseif ($HasAt) {
|
|
$ConvertedValue += [string]::Format('@{0}', $Value);
|
|
} else {
|
|
$ConvertedValue += $Value;
|
|
}
|
|
}
|
|
|
|
[string]$Value = [string]::Join(':', $ConvertedValue);
|
|
|
|
if ([string]::IsNullOrEmpty($Value) -eq $FALSE -And $Value.Contains(':') -eq $FALSE) {
|
|
if ((Test-Numeric $Value)) {
|
|
$RetValue.Value = [decimal]$Value;
|
|
return $RetValue;
|
|
}
|
|
}
|
|
|
|
# Always ensure we are using correct digits
|
|
$Value = ([string]$Value).Replace(',', '.');
|
|
$RetValue.Value = $Value;
|
|
|
|
return $RetValue;
|
|
}
|
|
|
|
function Convert-IcingaPluginValueToString()
|
|
{
|
|
param (
|
|
$Value,
|
|
[string]$Unit = '',
|
|
[string]$OriginalUnit = ''
|
|
);
|
|
|
|
$AdjustedValue = $Value;
|
|
|
|
if ([string]::IsNullOrEmpty($OriginalUnit)) {
|
|
$OriginalUnit = $Unit;
|
|
}
|
|
|
|
try {
|
|
$AdjustedValue = ([math]::Round([decimal]$Value, 6))
|
|
} catch {
|
|
$AdjustedValue = $Value;
|
|
}
|
|
|
|
if ($Unit -eq '%' -Or [string]::IsNullOrEmpty($Unit)) {
|
|
return ([string]::Format('{0}{1}', ([string]$AdjustedValue).Replace(',', '.'), $Unit));
|
|
}
|
|
|
|
switch ($OriginalUnit) {
|
|
{ ($_ -eq "Kbit") -or ($_ -eq "Mbit") -or ($_ -eq "Gbit") -or ($_ -eq "Tbit") -or ($_ -eq "Pbit") -or ($_ -eq "Ebit") -or ($_ -eq "Zbit") -or ($_ -eq "Ybit") } {
|
|
$TransferSpeed = Get-IcingaNetworkInterfaceUnits -Value $Value;
|
|
return ([string]::Format('{0}{1}', $TransferSpeed.LinkSpeed, $TransferSpeed.Unit)).Replace(',', '.');
|
|
};
|
|
{ ($_ -eq "B") -or ($_ -eq "KiB") -or ($_ -eq "MiB") -or ($_ -eq "GiB") -or ($_ -eq "TiB") -or ($_ -eq "PiB") -or ($_ -eq "EiB") -or ($_ -eq "ZiB") -or ($_ -eq "YiB") } {
|
|
return (ConvertTo-BytesNextUnit -Value $Value -Unit $Unit -Units @('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB')).Replace(',', '.');
|
|
};
|
|
{ ($_ -eq "KB") -or ($_ -eq "MB") -or ($_ -eq "GB") -or ($_ -eq "TB") -or ($_ -eq "PB") -or ($_ -eq "EB") -or ($_ -eq "ZB") -or ($_ -eq "YB") } {
|
|
return (ConvertTo-BytesNextUnit -Value $Value -Unit $Unit -Units @('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB')).Replace(',', '.');
|
|
};
|
|
's' {
|
|
return (ConvertFrom-TimeSpan -Seconds $AdjustedValue).Replace(',', '.')
|
|
};
|
|
}
|
|
|
|
return ([string]::Format('{0}{1}', ([string]$AdjustedValue).Replace(',', '.'), $Unit));
|
|
}
|
|
|
|
function ConvertFrom-IcingaArrayToString()
|
|
{
|
|
param (
|
|
[array]$Array = @(),
|
|
[switch]$AddQuotes = $FALSE,
|
|
[switch]$SecureContent = $FALSE
|
|
);
|
|
|
|
if ($null -eq $Array -Or $Array.Count -eq 0) {
|
|
if ($AddQuotes) {
|
|
return '""';
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
[array]$NewArray = @();
|
|
|
|
if ($AddQuotes) {
|
|
foreach ($entry in $Array) {
|
|
if ($SecureContent) {
|
|
$entry = '***';
|
|
}
|
|
$NewArray += ([string]::Format('"{0}"', $entry));
|
|
}
|
|
} else {
|
|
if ($SecureContent) {
|
|
foreach ($entry in $Array) {
|
|
$NewArray += '***';
|
|
}
|
|
} else {
|
|
$NewArray = $Array;
|
|
}
|
|
}
|
|
|
|
return ([string]::Join(', ', $NewArray));
|
|
}
|
|
|
|
function ConvertFrom-IcingaSecureString()
|
|
{
|
|
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;
|
|
}
|
|
|
|
function ConvertFrom-JsonUTF8()
|
|
{
|
|
[CmdletBinding()]
|
|
param (
|
|
[parameter(Mandatory = $TRUE, ValueFromPipeline = $TRUE)]
|
|
$InputObject = $null
|
|
);
|
|
|
|
# We need to properly encode our String to UTF8
|
|
$ContentBytes = [System.Text.Encoding]::Default.GetBytes($InputObject);
|
|
$UTF8String = [System.Text.Encoding]::UTF8.GetString($ContentBytes);
|
|
|
|
# Return the correct encoded JSON
|
|
return (ConvertFrom-Json -InputObject $UTF8String);
|
|
}
|
|
|
|
function ConvertFrom-Percent()
|
|
{
|
|
param (
|
|
$Value = $null,
|
|
$Percent = $null,
|
|
[int]$Digits = 0
|
|
);
|
|
|
|
if ($null -eq $Value -Or $null -eq $Percent) {
|
|
return 0;
|
|
}
|
|
|
|
return ([math]::Round(($Value / 100 * $Percent), $Digits));
|
|
}
|
|
|
|
function ConvertFrom-TimeSpan()
|
|
{
|
|
param (
|
|
$Seconds = 0
|
|
);
|
|
|
|
if (([string]$Seconds).Contains(',') -Or (Test-Numeric $Seconds)) {
|
|
[decimal]$Seconds = [decimal]([string]$Seconds).Replace(',', '.');
|
|
}
|
|
|
|
$Sign = '';
|
|
if ($Seconds -lt 0) {
|
|
$Seconds = [math]::Abs($Seconds);
|
|
$Sign = '-';
|
|
}
|
|
|
|
if ((Test-Numeric $Seconds) -eq $FALSE) {
|
|
return $Seconds;
|
|
}
|
|
|
|
$TimeSpan = [TimeSpan]::FromSeconds($Seconds);
|
|
|
|
if ($TimeSpan.TotalDays -ge 1.0) {
|
|
return (
|
|
[string]::Format(
|
|
'{0}{1}d',
|
|
$Sign,
|
|
([math]::Round($TimeSpan.TotalDays, 2))
|
|
)
|
|
);
|
|
}
|
|
if ($TimeSpan.TotalHours -ge 1.0) {
|
|
return (
|
|
[string]::Format(
|
|
'{0}{1}h',
|
|
$Sign,
|
|
([math]::Round($TimeSpan.TotalHours, 2))
|
|
)
|
|
);
|
|
}
|
|
if ($TimeSpan.TotalMinutes -ge 1.0) {
|
|
return (
|
|
[string]::Format(
|
|
'{0}{1}m',
|
|
$Sign,
|
|
([math]::Round($TimeSpan.TotalMinutes, 2))
|
|
)
|
|
);
|
|
}
|
|
if ($TimeSpan.TotalSeconds -ge 1.0) {
|
|
return (
|
|
[string]::Format(
|
|
'{0}{1}s',
|
|
$Sign,
|
|
([math]::Round($TimeSpan.TotalSeconds, 2))
|
|
)
|
|
);
|
|
}
|
|
if ($TimeSpan.TotalMilliseconds -ge 1.0) {
|
|
return (
|
|
[string]::Format(
|
|
'{0}{1}ms',
|
|
$Sign,
|
|
$TimeSpan.TotalMilliseconds
|
|
)
|
|
);
|
|
}
|
|
|
|
if ($Seconds -lt 0.001) {
|
|
return ([string]::Format('{0}{1}us', $Sign, ([math]::Ceiling([decimal]($Seconds*[math]::Pow(10, 6))))));
|
|
}
|
|
|
|
return ([string]::Format('{0}s', $Seconds));
|
|
}
|
|
|
|
function ConvertTo-BytesNextUnit()
|
|
{
|
|
param (
|
|
[string]$Value = $null,
|
|
[string]$Unit = $null,
|
|
[array]$Units = @('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB')
|
|
);
|
|
|
|
[string]$UnitValue = [string]::Format('{0}{1}', $Value, $Unit);
|
|
|
|
while ($TRUE) {
|
|
$Unit = Get-IcingaNextUnitIteration -Unit $Unit -Units $Units;
|
|
[decimal]$NewValue = (Convert-Bytes -Value $UnitValue -Unit $Unit).Value;
|
|
if ($NewValue -ge 1.0) {
|
|
if ($Unit -eq $RetUnit) {
|
|
break;
|
|
}
|
|
$RetValue = [math]::Round([decimal]$NewValue, 2);
|
|
$RetUnit = $Unit;
|
|
} else {
|
|
if ([string]::IsNullOrEmpty($RetUnit)) {
|
|
$RetValue = $Value;
|
|
$RetUnit = 'B';
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ([string]::Format('{0}{1}', $RetValue, $RetUnit));
|
|
}
|
|
|
|
function ConvertTo-ByteIEC()
|
|
{
|
|
param(
|
|
[single]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
switch ($Unit) {
|
|
{ 'B', 'Byte' -contains $_ } { $result = $Value; $boolOption = $true; }
|
|
{ 'KiB', 'Kibibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 10)); $boolOption = $true; }
|
|
{ 'MiB', 'Mebibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 20)); $boolOption = $true; }
|
|
{ 'GiB', 'Gibibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 30)); $boolOption = $true; }
|
|
{ 'TiB', 'Tebibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 40)); $boolOption = $true; }
|
|
{ 'PiB', 'Pebibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 50)); $boolOption = $true; }
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
function ConvertTo-Kibibyte()
|
|
{
|
|
param(
|
|
[single]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
switch ($Unit) {
|
|
{ 'B', 'Byte' -contains $_ } { $result = ($Value / [math]::Pow(2, 10)); $boolOption = $true; }
|
|
{ 'KiB', 'Kibibyte' -contains $_ } { $result = $Value; $boolOption = $true; }
|
|
{ 'MiB', 'Mebibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 10)); $boolOption = $true; }
|
|
{ 'GiB', 'Gibibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 20)); $boolOption = $true; }
|
|
{ 'TiB', 'Tebibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 30)); $boolOption = $true; }
|
|
{ 'PiB', 'Pebibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 40)); $boolOption = $true; }
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
function ConvertTo-Mebibyte()
|
|
{
|
|
param(
|
|
[single]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
switch ($Unit) {
|
|
{ 'B', 'Byte' -contains $_ } { $result = ($Value / [math]::Pow(2, 20)); $boolOption = $true; }
|
|
{ 'KiB', 'Kibibyte' -contains $_ } { $result = ($Value / [math]::Pow(2, 10)); $boolOption = $true; }
|
|
{ 'MiB', 'Mebibyte' -contains $_ } { $result = $Value; $boolOption = $true; }
|
|
{ 'GiB', 'Gibibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 10)); $boolOption = $true; }
|
|
{ 'TiB', 'Tebibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 20)); $boolOption = $true; }
|
|
{ 'PiB', 'Pebibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 30)); $boolOption = $true; }
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
function ConvertTo-Gibibyte()
|
|
{
|
|
param(
|
|
[single]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
switch ($Unit) {
|
|
{ 'B', 'Byte' -contains $_ } { $result = ($Value / [math]::Pow(2, 30)); $boolOption = $true; }
|
|
{ 'KiB', 'Kibibyte' -contains $_ } { $result = ($Value / [math]::Pow(2, 20)); $boolOption = $true; }
|
|
{ 'MiB', 'Mebibyte' -contains $_ } { $result = ($Value / [math]::Pow(2, 10)); $boolOption = $true; }
|
|
{ 'GiB', 'Gibibyte' -contains $_ } { $result = $Value; $boolOption = $true; }
|
|
{ 'TiB', 'Tebibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 10)); $boolOption = $true; }
|
|
{ 'PiB', 'Pebibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 20)); $boolOption = $true; }
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
function ConvertTo-Tebibyte()
|
|
{
|
|
param(
|
|
[single]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
switch ($Unit) {
|
|
{ 'B', 'Byte' -contains $_ } { $result = ($Value / [math]::Pow(2, 40)); $boolOption = $true; }
|
|
{ 'KiB', 'Kibibyte' -contains $_ } { $result = ($Value / [math]::Pow(2, 30)); $boolOption = $true; }
|
|
{ 'MiB', 'Mebibyte' -contains $_ } { $result = ($Value / [math]::Pow(2, 20)); $boolOption = $true; }
|
|
{ 'GiB', 'Gibibyte' -contains $_ } { $result = ($Value / [math]::Pow(2, 10)); $boolOption = $true; }
|
|
{ 'TiB', 'Tebibyte' -contains $_ } { $result = $Value; $boolOption = $true; }
|
|
{ 'PiB', 'Pebibyte' -contains $_ } { $result = ($Value * [math]::Pow(2, 10)); $boolOption = $true; }
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
function ConvertTo-Pebibyte()
|
|
{
|
|
param(
|
|
[single]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
switch ($Unit) {
|
|
{ 'B', 'Byte' -contains $_ } { $result = ($Value / [math]::Pow(2, 50)); $boolOption = $true; }
|
|
{ 'KiB', 'Kibibyte' -contains $_ } { $result = ($Value / [math]::Pow(2, 40)); $boolOption = $true; }
|
|
{ 'MiB', 'Mebibyte' -contains $_ } { $result = ($Value / [math]::Pow(2, 30)); $boolOption = $true; }
|
|
{ 'GiB', 'Gibibyte' -contains $_ } { $result = ($Value / [math]::Pow(2, 20)); $boolOption = $true; }
|
|
{ 'TiB', 'Tebibyte' -contains $_ } { $result = ($Value / [math]::Pow(2, 10)); $boolOption = $true; }
|
|
{ 'PiB', 'Pebibyte' -contains $_ } { $result = $Value; $boolOption = $true; }
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Converts unit sizes to byte.
|
|
.DESCRIPTION
|
|
This module converts a given unit size to byte.
|
|
e.g Kilobyte to Byte.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.EXAMPLE
|
|
PS> ConvertTo-Byte -Unit TB 200
|
|
200000000000000
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function ConvertTo-ByteSI()
|
|
{
|
|
param(
|
|
[single]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
switch ($Unit) {
|
|
{ 'B', 'Byte' -contains $_ } { $result = $Value; $boolOption = $true; }
|
|
{ 'KB', 'Kilobyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 3)); $boolOption = $true; }
|
|
{ 'MB', 'Megabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 6)); $boolOption = $true; }
|
|
{ 'GB', 'Gigabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 9)); $boolOption = $true; }
|
|
{ 'TB', 'Terabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 12)); $boolOption = $true; }
|
|
{ 'PB', 'Petabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 15)); $boolOption = $true; }
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Converts unit sizes to Kilobyte.
|
|
.DESCRIPTION
|
|
This module converts a given unit size to Kilobyte.
|
|
e.g byte to Kilobyte.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.EXAMPLE
|
|
PS> ConvertTo-Kilobyte -Unit TB 200
|
|
200000000000
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function ConvertTo-Kilobyte()
|
|
{
|
|
param(
|
|
[single]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
switch ($Unit) {
|
|
{ 'B', 'Byte' -contains $_ } { $result = ($Value / [math]::Pow(10, 3)); $boolOption = $true; }
|
|
{ 'KB', 'Kilobyte' -contains $_ } { $result = $Value; $boolOption = $true; }
|
|
{ 'MB', 'Megabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 3)); $boolOption = $true; }
|
|
{ 'GB', 'Gigabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 6)); $boolOption = $true; }
|
|
{ 'TB', 'Terabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 9)); $boolOption = $true; }
|
|
{ 'PB', 'Petabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 12)); $boolOption = $true; }
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Converts unit sizes to Megabyte.
|
|
.DESCRIPTION
|
|
This module converts a given unit size to Megabyte.
|
|
e.g byte to Megabyte.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.EXAMPLE
|
|
PS> ConvertTo-Kilobyte -Unit TB 200
|
|
200000000
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function ConvertTo-Megabyte()
|
|
{
|
|
param(
|
|
[single]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
switch ($Unit) {
|
|
{ 'B', 'Byte' -contains $_ } { $result = ($Value / [math]::Pow(10, 6)); $boolOption = $true; }
|
|
{ 'KB', 'Kilobyte' -contains $_ } { $result = ($Value / [math]::Pow(10, 3)); $boolOption = $true; }
|
|
{ 'MB', 'Megabyte' -contains $_ } { $result = $Value; $boolOption = $true; }
|
|
{ 'GB', 'Gigabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 3)); $boolOption = $true; }
|
|
{ 'TB', 'Terabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 6)); $boolOption = $true; }
|
|
{ 'PB', 'Petabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 9)); $boolOption = $true; }
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Converts unit sizes to Gigabyte.
|
|
.DESCRIPTION
|
|
This module converts a given unit size to Gigabyte.
|
|
e.g byte to Gigabyte.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.EXAMPLE
|
|
PS> ConvertTo-Gigabyte -Unit TB 200
|
|
200000
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function ConvertTo-Gigabyte()
|
|
{
|
|
param(
|
|
[single]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
switch ($Unit) {
|
|
{ 'B', 'Byte' -contains $_ } { $result = ($Value / [math]::Pow(10, 9)); $boolOption = $true; }
|
|
{ 'KB', 'Kilobyte' -contains $_ } { $result = ($Value / [math]::Pow(10, 6)); $boolOption = $true; }
|
|
{ 'MB', 'Megabyte' -contains $_ } { $result = ($Value / [math]::Pow(10, 3)); $boolOption = $true; }
|
|
{ 'GB', 'Gigabyte' -contains $_ } { $result = $Value; $boolOption = $true; }
|
|
{ 'TB', 'Terabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 3)); $boolOption = $true; }
|
|
{ 'PB', 'Petabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 6)); $boolOption = $true; }
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Converts unit sizes to Terabyte.
|
|
.DESCRIPTION
|
|
This module converts a given unit size to Terabyte.
|
|
e.g byte to Terabyte.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.EXAMPLE
|
|
PS> ConvertTo-Terabyte -Unit GB 2000000
|
|
2000
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function ConvertTo-Terabyte()
|
|
{
|
|
param(
|
|
[single]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
switch ($Unit) {
|
|
{ 'B', 'Byte' -contains $_ } { $result = ($Value / [math]::Pow(10, 12)); $boolOption = $true; }
|
|
{ 'KB', 'Kilobyte' -contains $_ } { $result = ($Value / [math]::Pow(10, 9)); $boolOption = $true; }
|
|
{ 'MB', 'Megabyte' -contains $_ } { $result = ($Value / [math]::Pow(10, 6)); $boolOption = $true; }
|
|
{ 'GB', 'Gigabyte' -contains $_ } { $result = ($Value / [math]::Pow(10, 3)); $boolOption = $true; }
|
|
{ 'TB', 'Terabyte' -contains $_ } { $result = $Value; $boolOption = $true; }
|
|
{ 'PB', 'Petabyte' -contains $_ } { $result = ($Value * [math]::Pow(10, 3)); $boolOption = $true; }
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Converts unit sizes to Petabyte.
|
|
.DESCRIPTION
|
|
This module converts a given unit size to Petabyte.
|
|
e.g byte to Petabyte.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.EXAMPLE
|
|
PS> ConvertTo-Petabyte -Unit GB 2000000
|
|
2
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function ConvertTo-Petabyte()
|
|
{
|
|
param(
|
|
[single]$Value,
|
|
[string]$Unit
|
|
);
|
|
|
|
switch ($Unit) {
|
|
{ 'B', 'Byte' -contains $_ } { $result = ($Value / [math]::Pow(10, 15)); $boolOption = $true; }
|
|
{ 'KB', 'Kilobyte' -contains $_ } { $result = ($Value / [math]::Pow(10, 12)); $boolOption = $true; }
|
|
{ 'MB', 'Megabyte' -contains $_ } { $result = ($Value / [math]::Pow(10, 9)); $boolOption = $true; }
|
|
{ 'GB', 'Gigabyte' -contains $_ } { $result = ($Value / [math]::Pow(10, 6)); $boolOption = $true; }
|
|
{ 'TB', 'Terabyte' -contains $_ } { $result = ($Value / [math]::Pow(10, 3)); $boolOption = $true; }
|
|
{ 'PB', 'Petabyte' -contains $_ } { $result = $Value; $boolOption = $true; }
|
|
default {
|
|
if (-Not $boolOption) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.ConversionUnitMissing -Force;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Used to convert both IPv4 addresses and IPv6 addresses to binary.
|
|
.DESCRIPTION
|
|
ConvertTo-IcingaIPBinaryString returns a binary string based on the given IPv4 address or IPv6 address.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.FUNCTIONALITY
|
|
This module is intended to be used to convert an IPv4 address or IPv6 address to binary string.
|
|
.PARAMETER IP
|
|
Used to specify an IPv4 address or IPv6 address.
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.String
|
|
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function ConvertTo-IcingaIPBinaryString()
|
|
{
|
|
param (
|
|
$IP
|
|
);
|
|
|
|
if ($IP -like '*.*') {
|
|
$IP = ConvertTo-IcingaIPv4BinaryString -IP $IP;
|
|
} elseif ($IP -like '*:*') {
|
|
$IP = ConvertTo-IcingaIPv6BinaryString -IP $IP;
|
|
} else {
|
|
return 'Invalid IP was provided!';
|
|
}
|
|
|
|
return $IP;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Used to convert an IPv4 address to binary.
|
|
.DESCRIPTION
|
|
ConvertTo-IcingaIPv6 returns a binary string based on the given IPv4 address.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.FUNCTIONALITY
|
|
This module is intended to be used to convert an IPv4 address to binary string. Its recommended to use ConvertTo-IcingaIPBinaryString as a smart function instead.
|
|
.PARAMETER IP
|
|
Used to specify an IPv4 address.
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.String
|
|
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function ConvertTo-IcingaIPv4BinaryString()
|
|
{
|
|
param(
|
|
[string]$IP
|
|
);
|
|
|
|
try {
|
|
$IP = $IP -split '\.' | ForEach-Object {
|
|
[System.Convert]::ToString($_, 2).PadLeft(8, '0');
|
|
}
|
|
$IP = $IP -join '';
|
|
$IP = $IP -replace '\s', '';
|
|
} catch {
|
|
# Todo: Should we handle errors? It might happen due to faulty routes or unhandled route config
|
|
# we throw errors which should have no effect at all
|
|
return $null;
|
|
}
|
|
|
|
return @{
|
|
'value' = $IP;
|
|
'name' = 'IPv4'
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Used to convert an IPv6 address to binary.
|
|
.DESCRIPTION
|
|
ConvertTo-IcingaIPv6 returns a binary string based on the given IPv6 address.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.FUNCTIONALITY
|
|
This module is intended to be used to convert an IPv6 address to binary string. Its recommended to use ConvertTo-IcingaIPBinaryString as a smart function instead.
|
|
.PARAMETER IP
|
|
Used to specify an IPv6 address.
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.String
|
|
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function ConvertTo-IcingaIPv6BinaryString()
|
|
{
|
|
param(
|
|
[string]$IP
|
|
);
|
|
[string]$IP = Expand-IcingaIPv6String $IP;
|
|
[array]$IPArr = $IP.Split(':');
|
|
|
|
$IPArr = $IPArr.ToCharArray();
|
|
$IP = $IPArr | ForEach-Object {
|
|
[System.Convert]::ToString("0x$_", 2).PadLeft(4, '0');
|
|
}
|
|
$IP = $IP -join '';
|
|
$IP = $IP -replace '\s', '';
|
|
|
|
return @{
|
|
'value' = $IP;
|
|
'name' = 'IPv6'
|
|
}
|
|
}
|
|
|
|
<#
|
|
# Helper class allowing to easily convert strings into SecureStrings
|
|
# and vice-versa
|
|
#>
|
|
function ConvertTo-IcingaSecureString()
|
|
{
|
|
param (
|
|
[string]$String
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($String)) {
|
|
return $null;
|
|
}
|
|
|
|
return (ConvertTo-SecureString -AsPlainText $string -Force);
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Helper function to convert values to integer if possible
|
|
.DESCRIPTION
|
|
Converts an input value to integer if possible in any way. Otherwise it will return the object unmodified
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.FUNCTIONALITY
|
|
Converts an input value to integer if possible in any way. Otherwise it will return the object unmodified
|
|
.PARAMETER Value
|
|
Any value/object is analysed and if possible converted to an integer
|
|
.INPUTS
|
|
System.Object
|
|
.OUTPUTS
|
|
System.Integer
|
|
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function ConvertTo-Integer()
|
|
{
|
|
param (
|
|
$Value,
|
|
[switch]$NullAsEmpty
|
|
);
|
|
|
|
if ($null -eq $Value) {
|
|
if ($NullAsEmpty) {
|
|
return '';
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Value)) {
|
|
if ($NullAsEmpty) {
|
|
return '';
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
if ((Test-Numeric $Value)) {
|
|
return $Value;
|
|
}
|
|
|
|
$Type = $value.GetType().Name;
|
|
|
|
if ($Type -eq 'GpoBoolean' -Or $Type -eq 'Boolean' -Or $Type -eq 'SwitchParameter') {
|
|
return [int]$Value;
|
|
}
|
|
|
|
if ($Type -eq 'String') {
|
|
if ($Value.ToLower() -eq 'true' -Or $Value.ToLower() -eq 'yes' -Or $Value.ToLower() -eq 'y') {
|
|
return 1;
|
|
}
|
|
if ($Value.ToLower() -eq 'false' -Or $Value.ToLower() -eq 'no' -Or $Value.ToLower() -eq 'n') {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return $Value;
|
|
}
|
|
|
|
function ConvertTo-JsonUTF8Bytes()
|
|
{
|
|
[CmdletBinding()]
|
|
param (
|
|
[parameter(Mandatory = $TRUE, ValueFromPipeline = $TRUE)]
|
|
$InputObject = $null,
|
|
[int]$Depth = 10,
|
|
[switch]$Compress = $FALSE
|
|
);
|
|
|
|
$JsonBody = ConvertTo-Json -InputObject $InputObject -Depth 100 -Compress;
|
|
$UTF8Bytes = ([System.Text.Encoding]::UTF8.GetBytes($JsonBody));
|
|
|
|
# Do not remove the "," as we require to force our PowerShell to handle our return value
|
|
# as proper collection
|
|
return , $UTF8Bytes;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Converts unit to seconds.
|
|
.DESCRIPTION
|
|
This module converts a given time unit to seconds.
|
|
e.g hours to seconds.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
|
|
.PARAMETER Value
|
|
Specify unit to be converted to seconds. Allowed units: ms, s, m, h, d, w, M, y
|
|
ms = miliseconds; s = seconds; m = minutes; h = hours; d = days; w = weeks; M = months; y = years;
|
|
|
|
Like 20d for 20 days.
|
|
.EXAMPLE
|
|
PS> ConvertTo-Seconds 30d
|
|
2592000
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function ConvertTo-Seconds()
|
|
{
|
|
param(
|
|
[string]$Value
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Value)) {
|
|
return $Value;
|
|
}
|
|
|
|
[string]$NumberPart = '';
|
|
[string]$UnitPart = '';
|
|
[bool]$Negate = $FALSE;
|
|
[bool]$hasUnit = $FALSE;
|
|
|
|
foreach ($char in $Value.ToCharArray()) {
|
|
if ((Test-Numeric $char)) {
|
|
$NumberPart += $char;
|
|
} else {
|
|
if ($char -eq '-') {
|
|
$Negate = $TRUE;
|
|
} elseif ($char -eq '.' -Or $char -eq ',') {
|
|
$NumberPart += '.';
|
|
} else {
|
|
$UnitPart += $char;
|
|
$hasUnit = $TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (-Not $hasUnit -Or (Test-Numeric $NumberPart) -eq $FALSE) {
|
|
return $Value;
|
|
}
|
|
|
|
[single]$ValueSplitted = $NumberPart;
|
|
$result = 0;
|
|
|
|
if ($Negate) {
|
|
$ValueSplitted *= -1;
|
|
}
|
|
|
|
[string]$errorMsg = (
|
|
[string]::Format('Invalid unit type "{0}" specified for convertion. Allowed units: ms, s, m, h, d, w, M, y', $UnitPart)
|
|
);
|
|
|
|
if ($UnitPart -Match 'ms') {
|
|
$result = ($ValueSplitted / [math]::Pow(10, 3));
|
|
} else {
|
|
if ($UnitPart.Length -gt 1) {
|
|
return $Value;
|
|
}
|
|
|
|
switch ([int][char]$UnitPart) {
|
|
{ 115 -contains $_ } { $result = $ValueSplitted; break; } # s
|
|
{ 109 -contains $_ } { $result = $ValueSplitted * 60; break; } # m
|
|
{ 104 -contains $_ } { $result = $ValueSplitted * 3600; break; } # h
|
|
{ 100 -contains $_ } { $result = $ValueSplitted * 86400; break; } # d
|
|
{ 119 -contains $_ } { $result = $ValueSplitted * 604800; break; } # w
|
|
{ 77 -contains $_ } { $result = $ValueSplitted * 2592000; break; } # M
|
|
{ 121 -contains $_ } { $result = $ValueSplitted * 31536000; break; } # y
|
|
default {
|
|
Throw $errorMsg;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
function ConvertTo-SecondsFromIcingaThresholds()
|
|
{
|
|
param(
|
|
[string]$Threshold
|
|
);
|
|
|
|
[array]$Content = $Threshold.Split(':');
|
|
[array]$NewContent = @();
|
|
|
|
foreach ($entry in $Content) {
|
|
$NewContent += (Get-IcingaThresholdsAsSeconds -Value $entry)
|
|
}
|
|
|
|
[string]$Value = [string]::Join(':', $NewContent);
|
|
|
|
if ([string]::IsNullOrEmpty($Value) -eq $FALSE -And $Value.Contains(':') -eq $FALSE) {
|
|
return [convert]::ToDouble($Value);
|
|
}
|
|
|
|
return $Value;
|
|
}
|
|
|
|
function Get-IcingaThresholdsAsSeconds()
|
|
{
|
|
param(
|
|
[string]$Value
|
|
);
|
|
|
|
if ($Value.Contains('~')) {
|
|
$Value = $Value.Replace('~', '');
|
|
return [string]::Format('~{0}', (ConvertTo-Seconds $Value));
|
|
} elseif ($Value.Contains('@')) {
|
|
$Value = $Value.Replace('@', '');
|
|
return [string]::Format('@{0}', (ConvertTo-Seconds $Value));
|
|
}
|
|
|
|
return (ConvertTo-Seconds $Value);
|
|
}
|
|
|
|
Export-ModuleMember -Function @( 'ConvertTo-Seconds', 'ConvertTo-SecondsFromIcingaThresholds' );
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Used to Expand an IPv6 address.
|
|
.DESCRIPTION
|
|
Expand-IcingaIPv6String returns the expanded version of an IPv6 address.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.FUNCTIONALITY
|
|
This module is intended to be used to expand an IPv6 address.
|
|
.EXAMPLE
|
|
PS> Expand-IcingaIPv6String ffe8::71:ab:
|
|
FFE8:0000:0000:0000:0000:0071:00AB:0000
|
|
.PARAMETER IP
|
|
Used to specify an IPv6 address.
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.String
|
|
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function Expand-IcingaIPv6String()
|
|
{
|
|
param (
|
|
[String]$IP
|
|
);
|
|
|
|
$Counter = 0;
|
|
$RelV = -1;
|
|
|
|
for ($Index = 0; $Index -lt $IP.Length; $Index++) {
|
|
if ($IP[$Index] -eq ':') {
|
|
$Counter++;
|
|
if (($Index - 1) -ge 0 -and $IP[$Index - 1] -eq ':') {
|
|
$RelV = $Index;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($RelV -lt 0 -and $Counter -ne 7) {
|
|
Write-IcingaConsoleError "Invalid IP was provided!";
|
|
return $null;
|
|
}
|
|
|
|
if ($Counter -lt 7) {
|
|
$IP = $IP.Substring(0, $RelV) + (':'*(7 - $Counter)) + $IP.Substring($RelV);
|
|
}
|
|
|
|
$Result = @();
|
|
|
|
foreach ($SIP in $IP -split ':') {
|
|
$Value = 0;
|
|
[int]::TryParse(
|
|
$SIP,
|
|
[System.Globalization.NumberStyles]::HexNumber,
|
|
[System.Globalization.CultureInfo]::InvariantCulture,
|
|
[Ref]$Value
|
|
) | Out-Null;
|
|
$Result += ('{0:X4}' -f $Value);
|
|
}
|
|
$Result = $Result -join ':';
|
|
|
|
return $Result;
|
|
}
|
|
|
|
function Format-IcingaDigitCount()
|
|
{
|
|
param(
|
|
[string]$Value,
|
|
[int]$Digits,
|
|
[string]$Symbol = 0
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Value)) {
|
|
return $Value;
|
|
}
|
|
|
|
$CurrentLength = $Value.Length;
|
|
if ($CurrentLength -ge $Digits) {
|
|
return $Value;
|
|
}
|
|
|
|
while ($Value.Length -lt $Digits) {
|
|
$Value = [string]::Format('{0}{1}', $Symbol, $Value);
|
|
}
|
|
|
|
return $Value;
|
|
}
|
|
|
|
function Format-IcingaPerfDataLabel()
|
|
{
|
|
param(
|
|
$PerfData
|
|
);
|
|
|
|
$Output = ((($PerfData) -Replace ' ', '_') -Replace '[\W]', '');
|
|
|
|
while ($Output.Contains('__')) {
|
|
$Output = $Output.Replace('__', '_');
|
|
}
|
|
# Remove all special characters and spaces on label names
|
|
return $Output;
|
|
}
|
|
|
|
function Format-IcingaPerfDataValue()
|
|
{
|
|
param(
|
|
$PerfValue
|
|
);
|
|
|
|
if ((Test-Numeric $PerfValue) -eq $FALSE) {
|
|
return $PerfValue;
|
|
}
|
|
|
|
# Convert our value to a string and replace ',' with a '.' to allow Icinga to parse the output
|
|
# In addition, round every output to 6 digits
|
|
return (([string]([math]::round([decimal]$PerfValue, 6))).Replace(',', '.'));
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Exports command as JSON for icinga director
|
|
|
|
.DESCRIPTION
|
|
Get-IcingaCheckCommandConfig returns a JSON-file of one or all 'Invoke-IcingaCheck'-Commands, which can be imported via Icinga-Director
|
|
When no single command is specified all commands will be exported, and vice versa.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
|
|
.FUNCTIONALITY
|
|
This module is intended to be used to export one or all PowerShell-Modules with the namespace 'Invoke-IcingaCheck'.
|
|
The JSON-Export, which will be generated through this module is structured like an Icinga-Director-JSON-Export, so it can be imported via the Icinga-Director the same way.
|
|
|
|
.EXAMPLE
|
|
PS>Get-IcingaCheckCommandConfig
|
|
Check Command JSON for the following commands:
|
|
- 'Invoke-IcingaCheckBiosSerial'
|
|
- 'Invoke-IcingaCheckCPU'
|
|
- 'Invoke-IcingaCheckProcessCount'
|
|
- 'Invoke-IcingaCheckService'
|
|
- 'Invoke-IcingaCheckUpdates'
|
|
- 'Invoke-IcingaCheckUptime'
|
|
- 'Invoke-IcingaCheckUsedPartitionSpace'
|
|
- 'Invoke-IcingaCheckUsers'
|
|
############################################################
|
|
|
|
.EXAMPLE
|
|
Get-IcingaCheckCommandConfig -OutDirectory 'C:\Users\icinga\config-exports'
|
|
The following commands have been exported:
|
|
- 'Invoke-IcingaCheckBiosSerial'
|
|
- 'Invoke-IcingaCheckCPU'
|
|
- 'Invoke-IcingaCheckProcessCount'
|
|
- 'Invoke-IcingaCheckService'
|
|
- 'Invoke-IcingaCheckUpdates'
|
|
- 'Invoke-IcingaCheckUptime'
|
|
- 'Invoke-IcingaCheckUsedPartitionSpace'
|
|
- 'Invoke-IcingaCheckUsers'
|
|
JSON export created in 'C:\Users\icinga\config-exports\PowerShell_CheckCommands_09-13-2019-10-55-1989.json'
|
|
|
|
.EXAMPLE
|
|
Get-IcingaCheckCommandConfig Invoke-IcingaCheckBiosSerial, Invoke-IcingaCheckCPU -OutDirectory 'C:\Users\icinga\config-exports'
|
|
The following commands have been exported:
|
|
- 'Invoke-IcingaCheckBiosSerial'
|
|
- 'Invoke-IcingaCheckCPU'
|
|
JSON export created in 'C:\Users\icinga\config-exports\PowerShell_CheckCommands_09-13-2019-10-58-5342.json'
|
|
|
|
.PARAMETER CheckName
|
|
Used to specify an array of commands which should be exported.
|
|
Separated with ','
|
|
|
|
.PARAMETER FileName
|
|
Define a custom file name for the exported `.json`/`.conf` file
|
|
|
|
.PARAMETER IcingaConfig
|
|
Will switch the configuration generator to write plain Icinga 2 `.conf`
|
|
files instead of Icinga Director Basket `.json` files
|
|
|
|
.INPUTS
|
|
System.Array
|
|
|
|
.OUTPUTS
|
|
System.String
|
|
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
|
|
.NOTES
|
|
#>
|
|
|
|
function Get-IcingaCheckCommandConfig()
|
|
{
|
|
param(
|
|
[array]$CheckName,
|
|
[string]$OutDirectory = '',
|
|
[string]$Filename,
|
|
[switch]$IcingaConfig
|
|
);
|
|
|
|
[array]$BlacklistedArguments = @(
|
|
'ThresholdInterval'
|
|
);
|
|
|
|
# Check whether all Checks will be exported or just the ones specified
|
|
if ([string]::IsNullOrEmpty($CheckName) -eq $true) {
|
|
$CheckName = (Get-Command Invoke-IcingaCheck*).Name
|
|
}
|
|
|
|
[int]$FieldID = 2; # Starts at '2', because '0' and '1' are reserved for 'Verbose' and 'NoPerfData'
|
|
[hashtable]$Basket = @{ };
|
|
|
|
# Define basic hashtable structure by adding fields: "Datafield", "DataList", "Command"
|
|
$Basket.Add('Datafield', @{ });
|
|
$Basket.Add('DataList', @{ });
|
|
$Basket.Add('Command', @{ });
|
|
|
|
# At first generate a base Check-Command we can use as import source for all other commands
|
|
$Basket.Command.Add(
|
|
'PowerShell Base',
|
|
@{
|
|
'arguments' = @{ };
|
|
'command' = 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe';
|
|
'disabled' = $FALSE;
|
|
'fields' = @();
|
|
'imports' = @();
|
|
'is_string' = $NULL;
|
|
'methods_execute' = 'PluginCheck';
|
|
'object_name' = 'PowerShell Base';
|
|
'object_type' = 'object';
|
|
'timeout' = '180';
|
|
'vars' = @{ };
|
|
'zone' = $NULL;
|
|
}
|
|
);
|
|
|
|
$ThresholdIntervalArg = New-Object -TypeName PSObject;
|
|
$ThresholdIntervalArg | Add-Member -MemberType NoteProperty -Name 'type' -Value (New-Object -TypeName PSObject);
|
|
$ThresholdIntervalArg | Add-Member -MemberType NoteProperty -Name 'Description' -Value (New-Object -TypeName PSObject);
|
|
$ThresholdIntervalArg | Add-Member -MemberType NoteProperty -Name 'position' -Value 99;
|
|
$ThresholdIntervalArg | Add-Member -MemberType NoteProperty -Name 'Name' -Value 'ThresholdInterval';
|
|
$ThresholdIntervalArg | Add-Member -MemberType NoteProperty -Name 'required' -Value $FALSE;
|
|
$ThresholdIntervalArg.type | Add-Member -MemberType NoteProperty -Name 'name' -Value 'String';
|
|
$ThresholdIntervalArg.Description | Add-Member -MemberType NoteProperty -Name 'Text' -Value 'Change the value your defined threshold checks against from the current value to a collected time threshold of the Icinga for Windows daemon, as described here: https://icinga.com/docs/icinga-for-windows/latest/doc/service/10-Register-Service-Checks/ An example for this argument would be 1m or 15m which will use the average of 1m or 15m for monitoring.';
|
|
|
|
# Loop through ${CheckName}, to get information on every command specified/all commands.
|
|
foreach ($check in $CheckName) {
|
|
|
|
# Get necessary syntax-information and more through cmdlet "Get-Help"
|
|
$Data = (Get-Help $check);
|
|
$ParameterList = (Get-Command -Name $check).Parameters;
|
|
$CheckParamList = @( $ThresholdIntervalArg );
|
|
$PluginNameSpace = $Data.Name.Replace('Invoke-', '');
|
|
|
|
foreach ($entry in $Data.parameters.parameter) {
|
|
foreach ($BlackListArg in $BlacklistedArguments) {
|
|
if ($BlackListArg.ToLower() -eq $entry.Name.ToLower()) {
|
|
Write-IcingaConsoleError -Message 'The argument "{0}" for check command "{1}" is not allowed, as this is reserved as Framework constant argument and can not be used.' -Objects $BlackListArg, $check;
|
|
return;
|
|
}
|
|
}
|
|
$CheckParamList += (Convert-IcingaCheckArgumentToPSObject -Parameter $entry);
|
|
}
|
|
|
|
foreach ($arg in $ParameterList.Keys) {
|
|
foreach ($entry in $CheckParamList) {
|
|
if ($entry.Name -eq $arg) {
|
|
$entry.Attributes.ValidValues = $ParameterList[$arg].Attributes.ValidValues;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Add command Structure
|
|
$Basket.Command.Add(
|
|
$Data.Name, @{
|
|
'arguments' = @{
|
|
# Set the Command handling for every check command
|
|
'-C' = @{
|
|
'value' = [string]::Format('try {{ Use-Icinga -Minimal; }} catch {{ Write-Output {1}The Icinga PowerShell Framework is either not installed on the system or not configured properly. Please check https://icinga.com/docs/windows for further details{1}; Write-Output {1}Error:{1} $$($$_.Exception.Message)Components:`r`n$$( Get-Module -ListAvailable {1}icinga-powershell-*{1} )`r`n{1}Module-Path:{1}`r`n$$($$Env:PSModulePath); exit 3; }}; Exit-IcingaExecutePlugin -Command {1}{0}{1} ', $Data.Name, "'");
|
|
'order' = '0';
|
|
}
|
|
}
|
|
'fields' = @();
|
|
'imports' = @( 'PowerShell Base' );
|
|
'object_name' = $Data.Name;
|
|
'object_type' = 'object';
|
|
'vars' = @{};
|
|
}
|
|
);
|
|
|
|
# Loop through parameters of a given command
|
|
foreach ($parameter in $CheckParamList) {
|
|
|
|
$IsDataList = $FALSE;
|
|
|
|
# IsNumeric-Check on position to determine the order-value
|
|
If (Test-Numeric($parameter.position) -eq $TRUE) {
|
|
[string]$Order = [int]$parameter.position + 1;
|
|
} else {
|
|
[string]$Order = 99
|
|
}
|
|
|
|
$IcingaCustomVariable = [string]::Format('${0}_{1}_{2}$', $PluginNameSpace, (Get-Culture).TextInfo.ToTitleCase($parameter.type.name), $parameter.Name);
|
|
|
|
if ($IcingaCustomVariable.Length -gt 66) {
|
|
Write-IcingaConsoleError 'The argument "{0}" for the plugin "{1}" is too long. The maximum size of generated custom variables is 64 digits. Current argument size: "{2}", Name: "{3}"' -Objects $parameter.Name, $check, ($IcingaCustomVariable.Length - 2), $IcingaCustomVariable.Replace('$', '');
|
|
return;
|
|
}
|
|
|
|
# Todo: Should we improve this? Actually the handling would be identical, we just need to assign
|
|
# the proper field for this
|
|
if ($IcingaCustomVariable -like '*_Int32_Verbose$' -Or $IcingaCustomVariable -like '*_Int_Verbose$' -Or $IcingaCustomVariable -like '*_Object_Verbose$') {
|
|
$IcingaCustomVariable = [string]::Format('${0}_Int_Verbose$', $PluginNameSpace);
|
|
}
|
|
|
|
# Add arguments to a given command
|
|
if ($parameter.type.name -eq 'SwitchParameter') {
|
|
$Basket.Command[$Data.Name].arguments.Add(
|
|
[string]::Format('-{0}', $parameter.Name), @{
|
|
'set_if' = $IcingaCustomVariable;
|
|
'set_if_format' = 'string';
|
|
'order' = $Order;
|
|
}
|
|
);
|
|
|
|
$Basket.Command[$Data.Name].vars.Add($IcingaCustomVariable.Replace('$', ''), $FALSE);
|
|
|
|
} elseif ($parameter.type.name -eq 'Array') {
|
|
# Conditional whether type of parameter is array
|
|
$Basket.Command[$Data.Name].arguments.Add(
|
|
[string]::Format('-{0}', $parameter.Name), @{
|
|
'value' = @{
|
|
'type' = 'Function';
|
|
'body' = [string]::Format(
|
|
'var arr = macro("{0}");{1} if (len(arr) == 0) {2}{1} return "@()";{1} {3}{1} return arr.map({1} x => if (typeof(x) == String) {2}{1} var argLen = len(x);{1} if (argLen != 0 && x.substr(0,1) == "{4}" && x.substr(argLen - 1, argLen) == "{4}") {2}{1} x;{1} {3} else {2}{1} "{4}" + x + "{4}";{1} {3}{1} {3} else {2}{1} x;{1} {3}{1} ).join(",");',
|
|
$IcingaCustomVariable,
|
|
"`r`n",
|
|
'{',
|
|
'}',
|
|
"'"
|
|
);
|
|
}
|
|
'order' = $Order;
|
|
}
|
|
);
|
|
} elseif ($parameter.type.name -eq 'SecureString') {
|
|
# Convert out input string as SecureString
|
|
$Basket.Command[$Data.Name].arguments.Add(
|
|
[string]::Format('-{0}', $parameter.Name), @{
|
|
'value' = (
|
|
[string]::Format(
|
|
"(ConvertTo-IcingaSecureString '{0}')",
|
|
$IcingaCustomVariable
|
|
)
|
|
)
|
|
'order' = $Order;
|
|
}
|
|
);
|
|
} else {
|
|
# Default to Object
|
|
$Basket.Command[$Data.Name].arguments.Add(
|
|
[string]::Format('-{0}', $parameter.Name), @{
|
|
'value' = $IcingaCustomVariable;
|
|
'order' = $Order;
|
|
}
|
|
);
|
|
}
|
|
|
|
# Determine wether a parameter is required based on given syntax-information
|
|
if ($parameter.required -eq $TRUE) {
|
|
$Required = 'y';
|
|
} else {
|
|
$Required = 'n';
|
|
}
|
|
|
|
$IcingaCustomVariable = [string]::Format('{0}_{1}_{2}', $PluginNameSpace, (Get-Culture).TextInfo.ToTitleCase($parameter.type.name), $parameter.Name);
|
|
|
|
# Todo: Should we improve this? Actually the handling would be identical, we just need to assign
|
|
# the proper field for this
|
|
if ($IcingaCustomVariable -like '*_Int32_Verbose' -Or $IcingaCustomVariable -like '*_Int_Verbose' -Or $IcingaCustomVariable -like '*_Object_Verbose') {
|
|
$IcingaCustomVariable = [string]::Format('{0}_Int_Verbose', $PluginNameSpace);
|
|
}
|
|
|
|
[bool]$ArgumentKnown = $FALSE;
|
|
|
|
foreach ($argument in $Basket.Datafield.Keys) {
|
|
if ($Basket.Datafield[$argument].varname -eq $IcingaCustomVariable) {
|
|
$ArgumentKnown = $TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($ArgumentKnown) {
|
|
continue;
|
|
}
|
|
|
|
$DataListName = [string]::Format('{0} {1}', $PluginNameSpace, $parameter.Name);
|
|
|
|
if ($null -ne $parameter.Attributes.ValidValues) {
|
|
$IcingaDataType = 'Datalist';
|
|
Add-PowerShellDataList -Name $DataListName -Basket $Basket -Arguments $parameter.Attributes.ValidValues;
|
|
$IsDataList = $TRUE;
|
|
} elseif ($parameter.type.name -eq 'SwitchParameter') {
|
|
$IcingaDataType = 'Boolean';
|
|
} elseif ($parameter.type.name -eq 'Object') {
|
|
$IcingaDataType = 'String';
|
|
} elseif ($parameter.type.name -eq 'Array') {
|
|
$IcingaDataType = 'Array';
|
|
} elseif ($parameter.type.name -eq 'Int' -Or $parameter.type.name -eq 'Int32') {
|
|
$IcingaDataType = 'Number';
|
|
} else {
|
|
$IcingaDataType = 'String';
|
|
}
|
|
|
|
$IcingaDataType = [string]::Format('Icinga\Module\Director\DataType\DataType{0}', $IcingaDataType)
|
|
|
|
if ($Basket.Datafield.Values.varname -ne $IcingaCustomVariable) {
|
|
$Basket.Datafield.Add(
|
|
[string]$FieldID, @{
|
|
'varname' = $IcingaCustomVariable;
|
|
'caption' = $parameter.Name;
|
|
'description' = $parameter.Description.Text;
|
|
'datatype' = $IcingaDataType;
|
|
'format' = $NULL;
|
|
'originalId' = [string]$FieldID;
|
|
}
|
|
);
|
|
|
|
if ($IsDataList) {
|
|
[string]$DataListDataType = 'string';
|
|
|
|
if ($parameter.type.name -eq 'Array') {
|
|
$DataListDataType = 'array';
|
|
}
|
|
|
|
$Basket.Datafield[[string]$FieldID].Add(
|
|
'settings', @{
|
|
'datalist' = $DataListName;
|
|
'data_type' = $DataListDataType;
|
|
'behavior' = 'strict';
|
|
}
|
|
);
|
|
} else {
|
|
$CustomVarVisibility = 'visible';
|
|
|
|
if ($parameter.type.name -eq 'SecureString') {
|
|
$CustomVarVisibility = 'hidden';
|
|
}
|
|
|
|
$Basket.Datafield[[string]$FieldID].Add(
|
|
'settings', @{
|
|
'visibility' = $CustomVarVisibility;
|
|
}
|
|
);
|
|
}
|
|
|
|
# Increment FieldID, so unique datafields are added.
|
|
[int]$FieldID = [int]$FieldID + 1;
|
|
}
|
|
|
|
# Increment FieldNumeration, so unique fields for a given command are added.
|
|
[int]$FieldNumeration = [int]$FieldNumeration + 1;
|
|
}
|
|
}
|
|
|
|
foreach ($check in $CheckName) {
|
|
[int]$FieldNumeration = 0;
|
|
|
|
$Data = (Get-Help $check)
|
|
$PluginNameSpace = $Data.Name.Replace('Invoke-', '');
|
|
$CheckParamList = @( $ThresholdIntervalArg );
|
|
|
|
foreach ($entry in $Data.parameters.parameter) {
|
|
$CheckParamList += (Convert-IcingaCheckArgumentToPSObject -Parameter $entry);;
|
|
}
|
|
|
|
foreach ($parameter in $CheckParamList) {
|
|
$IcingaCustomVariable = [string]::Format('{0}_{1}_{2}', $PluginNameSpace, (Get-Culture).TextInfo.ToTitleCase($parameter.type.name), $parameter.Name);
|
|
|
|
# Todo: Should we improve this? Actually the handling would be identical, we just need to assign
|
|
# the proper field for this
|
|
if ($IcingaCustomVariable -like '*_Int32_Verbose' -Or $IcingaCustomVariable -like '*_Int_Verbose' -Or $IcingaCustomVariable -like '*_Object_Verbose') {
|
|
$IcingaCustomVariable = [string]::Format('{0}_Int_Verbose', $PluginNameSpace);
|
|
}
|
|
|
|
foreach ($DataFieldID in $Basket.Datafield.Keys) {
|
|
[string]$varname = $Basket.Datafield[$DataFieldID].varname;
|
|
if ([string]$varname -eq [string]$IcingaCustomVariable) {
|
|
$Basket.Command[$Data.Name].fields += @{
|
|
'datafield_id' = [int]$DataFieldID;
|
|
'is_required' = $Required;
|
|
'var_filter' = $NULL;
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[string]$FileType = '.json';
|
|
if ($IcingaConfig) {
|
|
$FileType = '.conf';
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Filename)) {
|
|
$TimeStamp = (Get-Date -Format "MM-dd-yyyy-HH-mm-ffff");
|
|
$FileName = [string]::Format("PowerShell_CheckCommands_{0}{1}", $TimeStamp, $FileType);
|
|
} else {
|
|
if ($Filename.Contains($FileType) -eq $FALSE) {
|
|
$Filename = [string]::Format('{0}{1}', $Filename, $FileType);
|
|
}
|
|
}
|
|
|
|
# Generate JSON Output from Hashtable
|
|
$output = ConvertTo-Json -Depth 100 $Basket -Compress;
|
|
|
|
# Determine whether json output via powershell or in file (based on param -OutDirectory)
|
|
if ([string]::IsNullOrEmpty($OutDirectory) -eq $false) {
|
|
$ConfigDirectory = $OutDirectory;
|
|
$OutDirectory = (Join-Path -Path $OutDirectory -ChildPath $FileName);
|
|
if ((Test-Path($OutDirectory)) -eq $false) {
|
|
New-Item -Path $OutDirectory -ItemType File -Force | Out-Null;
|
|
}
|
|
|
|
if ((Test-Path($OutDirectory)) -eq $false) {
|
|
throw 'Failed to create specified directory. Please try again or use a different target location.';
|
|
}
|
|
|
|
if ($IcingaConfig) {
|
|
Write-IcingaPlainConfigurationFiles -Content $Basket -OutDirectory $ConfigDirectory -FileName $FileName;
|
|
} else {
|
|
Set-Content -Path $OutDirectory -Value $output;
|
|
}
|
|
|
|
# Output-Text
|
|
Write-IcingaConsoleNotice "The following commands have been exported:"
|
|
foreach ($check in $CheckName) {
|
|
Write-IcingaConsoleNotice "- '$check'";
|
|
}
|
|
Write-IcingaConsoleNotice "JSON export created in '${OutDirectory}'"
|
|
Write-IcingaConsoleWarning 'By using this generated check command configuration you will require the Icinga PowerShell Framework 1.4.0 or later to be installed on ALL monitored machines!';
|
|
return;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice "Check Command JSON for the following commands:"
|
|
foreach ($check in $CheckName) {
|
|
Write-IcingaConsoleNotice "- '$check'"
|
|
}
|
|
Write-IcingaConsoleWarning 'By using this generated check command configuration you will require the Icinga PowerShell Framework 1.4.0 or later to be installed on ALL monitored machines!';
|
|
Write-IcingaConsoleNotice '############################################################';
|
|
|
|
return $output;
|
|
}
|
|
|
|
function Write-IcingaPlainConfigurationFiles()
|
|
{
|
|
param (
|
|
$Content,
|
|
$OutDirectory,
|
|
$FileName
|
|
);
|
|
|
|
$ConfigDirectory = $OutDirectory;
|
|
$OutDirectory = (Join-Path -Path $OutDirectory -ChildPath $FileName);
|
|
|
|
$IcingaConfig = '';
|
|
|
|
foreach ($entry in $Content.Command.Keys) {
|
|
$CheckCommand = $Content.Command[$entry];
|
|
|
|
# Skip PowerShell base, this is written at the end in a separate file
|
|
if ($CheckCommand.object_name -eq 'PowerShell Base') {
|
|
continue;
|
|
}
|
|
|
|
# Create the CheckCommand object
|
|
$IcingaConfig += [string]::Format('object CheckCommand "{0}" {{{1}', $CheckCommand.object_name, (New-IcingaNewLine));
|
|
|
|
# Import all defined import templates
|
|
foreach ($import in $CheckCommand.imports) {
|
|
$IcingaConfig += [string]::Format(' import "{0}"{1}', $import, (New-IcingaNewLine));
|
|
}
|
|
$IcingaConfig += New-IcingaNewLine;
|
|
|
|
if ($CheckCommand.arguments.Count -ne 0) {
|
|
# Arguments for the configuration
|
|
$IcingaConfig += ' arguments += {'
|
|
$IcingaConfig += New-IcingaNewLine;
|
|
|
|
foreach ($argument in $CheckCommand.arguments.Keys) {
|
|
$CheckArgument = $CheckCommand.arguments[$argument];
|
|
|
|
# Each single argument, like "-Verbosity" = {
|
|
$IcingaConfig += [string]::Format(' "{0}" = {{{1}', $argument, (New-IcingaNewLine));
|
|
|
|
foreach ($argconfig in $CheckArgument.Keys) {
|
|
$Value = '';
|
|
|
|
if ($argconfig -eq 'set_if_format') {
|
|
continue;
|
|
}
|
|
|
|
# Order is numeric -> no "" required
|
|
if ($argconfig -eq 'order') {
|
|
$StringFormater = ' {0} = {1}{2}';
|
|
} else {
|
|
# All other entries should be handled as strings and contain ""
|
|
$StringFormater =' {0} = "{1}"{2}'
|
|
}
|
|
|
|
# In case it is a hashtable, this is most likely a DSL function
|
|
# We have to render it differently to also match the intends
|
|
if ($CheckArgument[$argconfig] -is [Hashtable]) {
|
|
$Value = $CheckArgument[$argconfig].body;
|
|
$DSLArray = $Value.Split("`r`n");
|
|
$Value = '';
|
|
foreach ($item in $DSLArray) {
|
|
if ([string]::IsNullOrEmpty($item)) {
|
|
continue;
|
|
}
|
|
$Value += [string]::Format(' {0}{1}', $item, (New-IcingaNewLine));
|
|
}
|
|
$Value = $Value.Substring(0, $Value.Length - 2);
|
|
$StringFormater =' {0} = {{{{{2}{1}{2} }}}}{2}'
|
|
} else {
|
|
# All other values besides DSL
|
|
$Value = $CheckArgument[$argconfig];
|
|
}
|
|
|
|
# Read description from our variables
|
|
if ($argconfig -eq 'value') {
|
|
foreach ($item in $Content.DataField.Keys) {
|
|
$DataField = $Content.DataField[$item];
|
|
|
|
if ($Value.Contains($DataField.varname)) {
|
|
if ([string]::IsNullOrEmpty($DataField.description)) {
|
|
break;
|
|
}
|
|
$Description = $DataField.description.Replace("`r`n", ' ');
|
|
$Description = $Description.Replace("\", '\\');
|
|
$Description = $Description.Replace("`n", ' ');
|
|
$Description = $Description.Replace("`r", ' ');
|
|
$Description = $Description.Replace('"', "'");
|
|
$IcingaConfig += [string]::Format(' description = "{0}"{1}', $Description, (New-IcingaNewLine));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Write the argument to your CheckCommand
|
|
$IcingaConfig += [string]::Format($StringFormater, $argconfig, $Value, (New-IcingaNewLine));
|
|
}
|
|
|
|
# Close this specific argument
|
|
$IcingaConfig += ' }'
|
|
$IcingaConfig += New-IcingaNewLine;
|
|
}
|
|
|
|
$IcingaConfig = $IcingaConfig.Substring(0, $IcingaConfig.Length - 2);
|
|
|
|
# Close all arguments content
|
|
$IcingaConfig += New-IcingaNewLine;
|
|
$IcingaConfig += ' }'
|
|
}
|
|
|
|
# In case we pre-define custom variables, we should add them here
|
|
if ($CheckCommand.vars.Count -ne 0) {
|
|
$IcingaConfig += New-IcingaNewLine;
|
|
|
|
foreach ($var in $CheckCommand.vars.Keys) {
|
|
[string]$Value = $CheckCommand.vars[$var];
|
|
$IcingaConfig += [string]::Format(' vars.{0} = {1}{2}', $var, $Value.ToLower(), (New-IcingaNewLine));
|
|
}
|
|
} else {
|
|
$IcingaConfig += New-IcingaNewLine;
|
|
}
|
|
|
|
# Close the CheckCommand object
|
|
$IcingaConfig += '}';
|
|
if ($Content.Command.Count -gt 2) {
|
|
$IcingaConfig += New-IcingaNewLine;
|
|
$IcingaConfig += New-IcingaNewLine;
|
|
}
|
|
}
|
|
|
|
# Write the PowerShell Base command to a separate file for Icinga 2 configuration
|
|
[string]$PowerShellBase = [string]::Format('object CheckCommand "PowerShell Base" {{{0}', (New-IcingaNewLine));
|
|
$PowerShellBase += [string]::Format(' import "plugin-check-command"{0}', (New-IcingaNewLine));
|
|
$PowerShellBase += [string]::Format(' command = [{0}', (New-IcingaNewLine));
|
|
$PowerShellBase += [string]::Format(' "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"{0}', (New-IcingaNewLine));
|
|
$PowerShellBase += [string]::Format(' ]{0}', (New-IcingaNewLine));
|
|
$PowerShellBase += [string]::Format(' timeout = 3m{0}', (New-IcingaNewLine));
|
|
$PowerShellBase += '}';
|
|
|
|
Set-Content -Path (Join-Path -Path $ConfigDirectory -ChildPath 'PowerShell_Base.conf') -Value $PowerShellBase;
|
|
Set-Content -Path $OutDirectory -Value $IcingaConfig;
|
|
}
|
|
|
|
function Add-PowerShellDataList()
|
|
{
|
|
param(
|
|
$Name,
|
|
$Basket,
|
|
$Arguments
|
|
);
|
|
|
|
$Basket.DataList.Add(
|
|
$Name, @{
|
|
'list_name' = $Name;
|
|
'owner' = $env:username;
|
|
'originalId' = '2';
|
|
'entries' = @();
|
|
}
|
|
);
|
|
|
|
foreach ($entry in $Arguments) {
|
|
if ([string]::IsNullOrEmpty($entry)) {
|
|
Write-IcingaConsoleWarning `
|
|
-Message 'The plugin argument "{0}" contains the illegal ValidateSet $null which will not be rendered. Please remove it from the arguments list of "{1}"' `
|
|
-Objects $Name, $Arguments;
|
|
|
|
continue;
|
|
}
|
|
$Basket.DataList[$Name]['entries'] += @{
|
|
'entry_name' = $entry;
|
|
'entry_value' = $entry;
|
|
'format' = 'string';
|
|
'allowed_roles' = $NULL;
|
|
};
|
|
}
|
|
}
|
|
|
|
function Get-IcingaHashtableItem()
|
|
{
|
|
param(
|
|
$Hashtable,
|
|
$Key,
|
|
$NullValue = $null
|
|
);
|
|
|
|
if ($null -eq $Hashtable) {
|
|
return $NullValue;
|
|
}
|
|
|
|
if ($Hashtable.ContainsKey($Key) -eq $FALSE) {
|
|
return $NullValue;
|
|
}
|
|
|
|
return $Hashtable[$Key];
|
|
}
|
|
|
|
function Get-IcingaMaxTextLength()
|
|
{
|
|
param (
|
|
[array]$TextArray = ''
|
|
);
|
|
|
|
[int]$MaxLength = 0;
|
|
|
|
foreach ($text in $TextArray) {
|
|
if ($MaxLength -lt $text.Length) {
|
|
$MaxLength = $text.Length;
|
|
}
|
|
}
|
|
|
|
return $MaxLength;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Returns interface ip address, which will be used for the host object within the icinga director.
|
|
.DESCRIPTION
|
|
Get-IcingaNetworkInterface returns the ip address of the interface, which will be used for the host object within the icinga director.
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.FUNCTIONALITY
|
|
This module is intended to be used to determine the interface ip address, during kickstart wizard, but will also function standalone.
|
|
.EXAMPLE
|
|
PS> Get-IcingaNetworkInterface 'icinga.com'
|
|
192.168.243.88
|
|
.EXAMPLE
|
|
PS> Get-IcingaNetworkInterface '8.8.8.8'
|
|
192.168.243.88
|
|
.PARAMETER IP
|
|
Used to specify either an IPv4, IPv6 address or an FQDN.
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.String
|
|
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function Get-IcingaNetworkInterface()
|
|
{
|
|
param(
|
|
[string]$IP
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($IP)) {
|
|
Write-IcingaConsoleError 'Please specify a valid IP-Address or FQDN';
|
|
return $null;
|
|
}
|
|
|
|
# Ensure that we can still process on older Windows system where
|
|
# Get-NetRoute ist not available
|
|
if ((Test-IcingaFunction 'Get-NetRoute') -eq $FALSE) {
|
|
Write-IcingaConsoleWarning 'Your Windows system does not support "Get-NetRoute". A fallback solution is used to fetch the IP of the first Network Interface routing through 0.0.0.0'
|
|
return (Get-IcingaNetworkRoute).Interface;
|
|
}
|
|
|
|
try {
|
|
[array]$IP = ([System.Net.Dns]::GetHostAddresses($IP)).IPAddressToString;
|
|
} catch {
|
|
Write-IcingaConsoleError 'Invalid IP was provided!';
|
|
return $null;
|
|
}
|
|
|
|
$IPBinStringMaster = ConvertTo-IcingaIPBinaryString -IP $IP;
|
|
|
|
[hashtable]$InterfaceData=@{};
|
|
|
|
$InterfaceInfo = Get-NetRoute;
|
|
$Counter = 0;
|
|
|
|
foreach ( $Info in $InterfaceInfo ) {
|
|
$Counter++;
|
|
|
|
$Divide = $Info.DestinationPrefix;
|
|
$IP, $Mask = $Divide.Split('/');
|
|
|
|
foreach ($destinationIP in $IPBinStringMaster) {
|
|
[string]$Key = '';
|
|
[string]$MaskKey = '';
|
|
<# IPv4 #>
|
|
if ($destinationIP.name -eq 'IPv4') {
|
|
if ($IP -like '*.*') {
|
|
if ([int]$Mask -lt 10) {
|
|
$MaskKey = [string]::Format('00{0}', $Mask);
|
|
} else {
|
|
$MaskKey = [string]::Format('0{0}', $Mask);
|
|
}
|
|
}
|
|
}
|
|
<# IPv6 #>
|
|
if ($destinationIP.name -eq 'IPv6') {
|
|
if ($IP -like '*:*') {
|
|
if ([int]$Mask -lt 10) {
|
|
$MaskKey = [string]::Format('00{0}', $Mask);
|
|
} elseif ([int]$Mask -lt 100) {
|
|
$MaskKey = [string]::Format('0{0}', $Mask);
|
|
} else {
|
|
$MaskKey = $Mask;
|
|
}
|
|
}
|
|
}
|
|
|
|
$Key = [string]::Format('{0}-{1}', $MaskKey, $Counter);
|
|
|
|
if ($InterfaceData.ContainsKey($Key)) {
|
|
continue;
|
|
}
|
|
|
|
$InterfaceData.Add(
|
|
$Key, @{
|
|
'Binary IP String' = (ConvertTo-IcingaIPBinaryString -IP $IP).value;
|
|
'Mask' = $Mask;
|
|
'Interface' = $Info.ifIndex;
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
$InterfaceDataOrdered = $InterfaceData.GetEnumerator() | Sort-Object -Property Name -Descending;
|
|
$ExternalInterfaces = @{};
|
|
|
|
foreach ( $Route in $InterfaceDataOrdered ) {
|
|
foreach ($destinationIP in $IPBinStringMaster) {
|
|
[string]$RegexPattern = [string]::Format("^.{{{0}}}", $Route.Value.Mask);
|
|
[string]$ToBeMatched = $Route.Value."Binary IP String";
|
|
if ($null -eq $ToBeMatched) {
|
|
continue;
|
|
}
|
|
|
|
$Match1=[regex]::Matches($ToBeMatched, $RegexPattern).Value;
|
|
$Match2=[regex]::Matches($destinationIP.Value, $RegexPattern).Value;
|
|
|
|
If ($Match1 -like $Match2) {
|
|
$ExternalInterface = ((Get-NetIPAddress -InterfaceIndex $Route.Value.Interface -AddressFamily $destinationIP.Name -ErrorAction SilentlyContinue).IPAddress);
|
|
|
|
# If no interface was found -> skip this entry
|
|
if ($null -eq $ExternalInterface) {
|
|
continue;
|
|
}
|
|
|
|
if ($ExternalInterfaces.ContainsKey($ExternalInterface)) {
|
|
$ExternalInterfaces[$ExternalInterface].count += 1;
|
|
} else {
|
|
$ExternalInterfaces.Add(
|
|
$ExternalInterface,
|
|
@{
|
|
'count' = 1
|
|
}
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($ExternalInterfaces.Count -eq 0) {
|
|
foreach ($destinationIP in $IPBinStringMaster) {
|
|
$ExternalInterface = ((Get-NetIPAddress -InterfaceIndex (Get-NetRoute | Where-Object -Property DestinationPrefix -Like '0.0.0.0/0')[0].IfIndex -AddressFamily $destinationIP.name).IPAddress).split('%')[0];
|
|
if ($ExternalInterfaces.ContainsKey($ExternalInterface)) {
|
|
$ExternalInterfaces[$ExternalInterface].count += 1;
|
|
} else {
|
|
$ExternalInterfaces.Add(
|
|
$ExternalInterface,
|
|
@{
|
|
'count' = 1
|
|
}
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
$InternalCount = 0;
|
|
[array]$UseInterface = @();
|
|
foreach ($interface in $ExternalInterfaces.Keys) {
|
|
$currentCount = $ExternalInterfaces[$interface].count;
|
|
if ($currentCount -gt $InternalCount) {
|
|
$InternalCount = $currentCount;
|
|
$UseInterface += $interface;
|
|
}
|
|
}
|
|
|
|
# In case we found multiple interfaces, fallback to our
|
|
# 'route print' function and return this interface instead
|
|
if ($UseInterface.Count -ne 1) {
|
|
return (Get-IcingaNetworkRoute).Interface;
|
|
}
|
|
|
|
return $UseInterface[0];
|
|
}
|
|
|
|
function Get-IcingaNetworkInterfaceUnits()
|
|
{
|
|
param (
|
|
[long]$Value
|
|
);
|
|
|
|
[hashtable]$InterfaceData = @{
|
|
'RawValue' = $Value;
|
|
'LinkSpeed' = 0;
|
|
'Unit' = 'Mbit'
|
|
};
|
|
|
|
[decimal]$result = ($Value / [Math]::Pow(10, 6));
|
|
|
|
if ($result -ge 1000) {
|
|
$InterfaceData.LinkSpeed = [decimal]($result / 1000);
|
|
$InterfaceData.Unit = 'Gbit';
|
|
} else {
|
|
$InterfaceData.LinkSpeed = $result;
|
|
$InterfaceData.Unit = 'Mbit';
|
|
}
|
|
|
|
return $InterfaceData;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Fetch the used interface for our Windows System
|
|
.DESCRIPTION
|
|
Newer Windows systems provide a Cmdlet 'Get-NetRoute' for fetching the
|
|
network route configurations. Older systems however do not provide this
|
|
and to ensure some sort of backwards compatibility, we will have a look
|
|
on our route configuration and return the first valid interface found
|
|
.FUNCTIONALITY
|
|
This Cmdlet will return first valid IP for our interface
|
|
.EXAMPLE
|
|
PS>Get-IcingaNetworkRoute
|
|
.OUTPUTS
|
|
System.Array
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function Get-IcingaNetworkRoute()
|
|
{
|
|
$RouteConfig = (&route print | Where-Object {
|
|
$_.TrimStart() -Like "0.0.0.0*";
|
|
}).Split() | Where-Object {
|
|
return $_;
|
|
};
|
|
|
|
$Interface = @{
|
|
'Destination' = $RouteConfig[0];
|
|
'Netmask' = $RouteConfig[1];
|
|
'Gateway' = $RouteConfig[2];
|
|
'Interface' = $RouteConfig[3];
|
|
'Metric' = $RouteConfig[4];
|
|
}
|
|
|
|
return $Interface;
|
|
}
|
|
|
|
function Get-IcingaNextUnitIteration()
|
|
{
|
|
param (
|
|
[string]$Unit = '',
|
|
[array]$Units = @()
|
|
);
|
|
|
|
[bool]$Found = $FALSE;
|
|
|
|
foreach ($entry in $Units) {
|
|
if ($Found) {
|
|
return $entry;
|
|
}
|
|
if ($entry -eq $Unit) {
|
|
$Found = $TRUE;
|
|
}
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
function Get-IcingaPSObjectProperties()
|
|
{
|
|
param(
|
|
$Object = $null,
|
|
[array]$Include = @(),
|
|
[array]$Exclude = @()
|
|
);
|
|
|
|
[hashtable]$RetValue = @{};
|
|
|
|
if ($null -eq $Object) {
|
|
return $RetValue;
|
|
}
|
|
|
|
foreach ($property in $Object.PSObject.Properties) {
|
|
[string]$DataType = $property.TypeNameOfValue;
|
|
|
|
if ($Include.Count -ne 0 -And -Not ($Include -Contains $property.Name)) {
|
|
continue;
|
|
}
|
|
|
|
if ($Exclude.Count -ne 0 -And $Exclude -Contains $property.Name) {
|
|
continue;
|
|
}
|
|
|
|
if ($DataType.Contains('string') -or $DataType.Contains('int') -Or $DataType.Contains('bool')) {
|
|
$RetValue.Add(
|
|
$property.Name,
|
|
$property.Value
|
|
);
|
|
} else {
|
|
try {
|
|
$RetValue.Add(
|
|
$property.Name,
|
|
(Get-IcingaPSObjectProperties -Object $property.Value)
|
|
);
|
|
} catch {
|
|
$RetValue.Add(
|
|
$property.Name,
|
|
([string]$property.Value)
|
|
);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return $RetValue;
|
|
}
|
|
|
|
function Get-IcingaServices()
|
|
{
|
|
param (
|
|
[array]$Service,
|
|
[array]$Exclude = @()
|
|
);
|
|
|
|
$ServiceInformation = Get-Service -Name $Service -ErrorAction SilentlyContinue;
|
|
$ServiceWmiInfo = $null;
|
|
|
|
if ($Service.Count -eq 0) {
|
|
$ServiceWmiInfo = Get-IcingaWindowsInformation Win32_Service;
|
|
} else {
|
|
$ServiceWmiInfo = Get-IcingaWindowsInformation Win32_Service | Where-Object { $Service -Contains $_.Name } | Select-Object StartName, Name, ExitCode, StartMode, PathName;
|
|
}
|
|
|
|
if ($null -eq $ServiceInformation) {
|
|
return $null;
|
|
}
|
|
|
|
[hashtable]$ServiceData = @{ };
|
|
|
|
foreach ($service in $ServiceInformation) {
|
|
|
|
[array]$DependentServices = $null;
|
|
[array]$DependingServices = $null;
|
|
$ServiceExitCode = 0;
|
|
[string]$ServiceUser = '';
|
|
[string]$ServicePath = '';
|
|
[int]$StartModeId = 5;
|
|
[string]$StartMode = 'Unknown';
|
|
|
|
if ($Exclude -contains $service.ServiceName) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($wmiService in $ServiceWmiInfo) {
|
|
if ($wmiService.Name -eq $service.ServiceName) {
|
|
$ServiceUser = $wmiService.StartName;
|
|
$ServicePath = $wmiService.PathName;
|
|
$ServiceExitCode = $wmiService.ExitCode;
|
|
if ([string]::IsNullOrEmpty($wmiService.StartMode) -eq $FALSE) {
|
|
$StartModeId = ([int]$IcingaEnums.ServiceWmiStartupType[$wmiService.StartMode]);
|
|
$StartMode = $IcingaEnums.ServiceStartupTypeName[$StartModeId];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
#Dependent / Child
|
|
foreach ($dependency in $service.DependentServices) {
|
|
if ($null -eq $DependentServices) {
|
|
$DependentServices = @();
|
|
}
|
|
$DependentServices += $dependency.Name;
|
|
}
|
|
|
|
#Depends / Parent
|
|
foreach ($dependency in $service.ServicesDependedOn) {
|
|
if ($null -eq $DependingServices) {
|
|
$DependingServices = @();
|
|
}
|
|
$DependingServices += $dependency.Name;
|
|
}
|
|
|
|
$ServiceData.Add(
|
|
$service.Name, @{
|
|
'metadata' = @{
|
|
'DisplayName' = $service.DisplayName;
|
|
'ServiceName' = $service.ServiceName;
|
|
'Site' = $service.Site;
|
|
'Container' = $service.Container;
|
|
'ServiceHandle' = $service.ServiceHandle;
|
|
'Dependent' = $DependentServices;
|
|
'Depends' = $DependingServices;
|
|
};
|
|
'configuration' = @{
|
|
'CanPauseAndContinue' = $service.CanPauseAndContinue;
|
|
'CanShutdown' = $service.CanShutdown;
|
|
'CanStop' = $service.CanStop;
|
|
'Status' = @{
|
|
'raw' = [int]$service.Status;
|
|
'value' = $service.Status;
|
|
};
|
|
'ServiceType' = @{
|
|
'raw' = [int]$service.ServiceType;
|
|
'value' = $service.ServiceType;
|
|
};
|
|
'ServiceHandle' = $service.ServiceHandle;
|
|
'StartType' = @{
|
|
'raw' = $StartModeId;
|
|
'value' = $StartMode;
|
|
};
|
|
'ServiceUser' = $ServiceUser;
|
|
'ServicePath' = $ServicePath;
|
|
'ExitCode' = $ServiceExitCode;
|
|
}
|
|
}
|
|
);
|
|
}
|
|
return $ServiceData;
|
|
}
|
|
|
|
function Get-IcingaUnixTime()
|
|
{
|
|
param(
|
|
[switch]$Milliseconds = $FALSE
|
|
);
|
|
|
|
if ($Milliseconds) {
|
|
return ([int64](([DateTime]::UtcNow) - (Get-Date '1/1/1970')).TotalMilliseconds / 1000);
|
|
}
|
|
|
|
return [int][double]::Parse(
|
|
(Get-Date -UFormat %s -Date (Get-Date).ToUniversalTime())
|
|
);
|
|
}
|
|
|
|
function Get-IcingaUserSID()
|
|
{
|
|
param(
|
|
[string]$User
|
|
);
|
|
|
|
if ($User -eq 'LocalSystem') {
|
|
$User = 'NT Authority\SYSTEM';
|
|
}
|
|
|
|
$UserData = Split-IcingaUserDomain -User $User;
|
|
|
|
try {
|
|
$NTUser = New-Object System.Security.Principal.NTAccount($UserData.Domain, $UserData.User);
|
|
$SecurityData = $NTUser.Translate([System.Security.Principal.SecurityIdentifier]);
|
|
} catch {
|
|
throw $_.Exception;
|
|
}
|
|
|
|
if ($null -eq $SecurityData) {
|
|
throw 'Failed to fetch user information from system';
|
|
}
|
|
|
|
return $SecurityData.Value;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Compares two numeric input values and returns the lower or higher value
|
|
.DESCRIPTION
|
|
Compares two numeric numbers and returns either the higher or lower value
|
|
depending on the configuration of the argument
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.FUNCTIONALITY
|
|
Compares two numeric input values and returns the lower or higher value
|
|
.PARAMETER Value
|
|
The input value to check for
|
|
.PARAMETER Compare
|
|
The value to compare against
|
|
.PARAMETER Minimum
|
|
Configures the command to return the lower number of both inputs
|
|
.PARAMETER Maximum
|
|
Configures the command to return the higher number of both inputs
|
|
.EXAMPLE
|
|
PS> Get-IcingaValue -Value 10 -Compare 12 -Minimum;
|
|
.EXAMPLE
|
|
PS> Get-IcingaValue -Value 10 -Compare 12 -Maximum;
|
|
.INPUTS
|
|
System.Integer
|
|
.OUTPUTS
|
|
System.Integer
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function Get-IcingaValue()
|
|
{
|
|
param(
|
|
$Value,
|
|
$Compare,
|
|
[switch]$Minimum = $FALSE,
|
|
[switch]$Maximum = $FALSE
|
|
);
|
|
|
|
# If none of both is set, return the current value
|
|
if (-Not $Minimum -And -Not $Maximum) {
|
|
return $Value;
|
|
}
|
|
|
|
# Return the lower value
|
|
if ($Minimum) {
|
|
# If the value is greater or equal the compared value, return the compared one
|
|
if ($Value -ge $Compare) {
|
|
return $Compare;
|
|
}
|
|
|
|
# Otherwise return the value itself
|
|
return $Value;
|
|
}
|
|
|
|
# Return the higher value
|
|
if ($Maximum) {
|
|
# If the value is greater or equal the compared one, return the value
|
|
if ($Value -ge $Compare) {
|
|
return $Value;
|
|
}
|
|
|
|
# Otherwise return the compared value
|
|
return $Compare;
|
|
}
|
|
|
|
# Shouldnt happen anyway
|
|
return $Value;
|
|
}
|
|
|
|
function Get-IPConfigFromString()
|
|
{
|
|
param(
|
|
[string]$IPConfig
|
|
);
|
|
|
|
if ($IPConfig.Contains(':') -and ($IPConfig.Contains('[') -eq $FALSE -And $IPConfig.Contains(']') -eq $FALSE)) {
|
|
throw 'Invalid IP-Address format. For IPv6 and/or port configuration, the syntax must be like [ip]:port';
|
|
}
|
|
|
|
if ($IPConfig.Contains('[') -eq $FALSE) {
|
|
return @{
|
|
'address' = $IPConfig;
|
|
'port' = $null
|
|
};
|
|
}
|
|
|
|
if ($IPConfig.Contains('[') -eq $FALSE -or $IPConfig.Contains(']') -eq $FALSE) {
|
|
throw 'Invalid IP-Address format. It must match the following [ip]:port';
|
|
}
|
|
|
|
$StartBracket = $IPConfig.IndexOf('[') + 1;
|
|
$EndBracket = $IPConfig.IndexOf(']') - 1;
|
|
$PortDelimeter = $IPConfig.LastIndexOf(':') + 1;
|
|
|
|
$Port = '';
|
|
$IP = $IPConfig.Substring($StartBracket, $EndBracket);
|
|
|
|
if ($PortDelimeter -ne 0 -And $PortDelimeter -ge $EndBracket) {
|
|
$Port = $IPConfig.Substring($PortDelimeter, $IPConfig.Length - $PortDelimeter);
|
|
}
|
|
|
|
return @{
|
|
'address' = $IP;
|
|
'port' = $Port
|
|
};
|
|
}
|
|
|
|
function Get-StringSha1()
|
|
{
|
|
param (
|
|
[string]$Content
|
|
);
|
|
|
|
$CryptoAlgorithm = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider;
|
|
$ContentHash = [System.Text.Encoding]::UTF8.GetBytes($Content);
|
|
$ContentBytes = $CryptoAlgorithm.ComputeHash($ContentHash);
|
|
$OutputHash = '';
|
|
|
|
foreach ($byte in $ContentBytes) {
|
|
$OutputHash += $byte.ToString()
|
|
}
|
|
|
|
return $OutputHash;
|
|
}
|
|
|
|
function Get-UnitPrefixIEC()
|
|
{
|
|
param(
|
|
[single]$Value
|
|
);
|
|
|
|
If ( $Value / [math]::Pow(2, 50) -ge 1 ) {
|
|
return 'PiB'
|
|
} elseif ( $Value / [math]::Pow(2, 40) -ge 1 ) {
|
|
return 'TiB'
|
|
} elseif ( $Value / [math]::Pow(2, 30) -ge 1 ) {
|
|
return 'GiB'
|
|
} elseif ( $Value / [math]::Pow(2, 20) -ge 1 ) {
|
|
return 'MiB'
|
|
} elseif ( $Value / [math]::Pow(2, 10) -ge 1 ) {
|
|
return 'KiB'
|
|
} else {
|
|
return 'B'
|
|
}
|
|
}
|
|
|
|
|
|
function Get-UnitPrefixSI()
|
|
{
|
|
param(
|
|
[single]$Value
|
|
);
|
|
|
|
If ( $Value / [math]::Pow(10, 15) -ge 1 ) {
|
|
return 'PB'
|
|
} elseif ( $Value / [math]::Pow(10, 12) -ge 1 ) {
|
|
return 'TB'
|
|
} elseif ( $Value / [math]::Pow(10, 9) -ge 1 ) {
|
|
return 'GB'
|
|
} elseif ( $Value / [math]::Pow(10, 6) -ge 1 ) {
|
|
return 'MB'
|
|
} elseif ( $Value / [math]::Pow(10, 3) -ge 1 ) {
|
|
return 'KB'
|
|
} else {
|
|
return 'B'
|
|
}
|
|
}
|
|
|
|
function Join-WebPath()
|
|
{
|
|
param(
|
|
[string]$Path,
|
|
[string]$ChildPath
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Path) -Or [string]::IsNullOrEmpty($ChildPath)) {
|
|
return $Path;
|
|
}
|
|
|
|
[int]$Length = $Path.Length;
|
|
[int]$Slash = $Path.LastIndexOf('/') + 1;
|
|
|
|
if ($Length -eq $Slash) {
|
|
$Path = $Path.Substring(0, $Path.Length - 1);
|
|
}
|
|
|
|
if ($ChildPath[0] -eq '/') {
|
|
return ([string]::Format('{0}{1}', $Path, $ChildPath));
|
|
}
|
|
|
|
return ([string]::Format('{0}/{1}', $Path, $ChildPath));
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Creates a basic auth header for web requests in case the Get-Credential
|
|
method is not supported or working properly
|
|
.DESCRIPTION
|
|
Creates a basic auth header for web requests in case the Get-Credential
|
|
method is not supported or working properly
|
|
.FUNCTIONALITY
|
|
Creates a hashtable with a basic authorization header as Base64 encoded
|
|
.EXAMPLE
|
|
PS>New-IcingaBasicAuthHeader -Username 'example_user' -Password $SecurePasswordString;
|
|
.EXAMPLE
|
|
PS>New-IcingaBasicAuthHeader -Username 'example_user' -Password (Read-Host -Prompt 'Please enter your password' -AsSecureString);
|
|
.EXAMPLE
|
|
PS>New-IcingaBasicAuthHeader -Username 'example_user' -Password (ConvertTo-IcingaSecureString 'my_secret_password');
|
|
.PARAMETER Username
|
|
The user we will use to authenticate for
|
|
.PARAMETER Password
|
|
The password for the user provided as SecureString
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Hashtable
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function New-IcingaBasicAuthHeader()
|
|
{
|
|
param(
|
|
[string]$Username = $null,
|
|
[SecureString]$Password = $null
|
|
);
|
|
|
|
if ($null -eq $Password -or [string]::IsNullOrEmpty($Username)) {
|
|
Write-IcingaConsoleWarning 'Please specify your username and password to continue';
|
|
return @{};
|
|
}
|
|
|
|
$Credentials = [System.Convert]::ToBase64String(
|
|
[System.Text.Encoding]::ASCII.GetBytes(
|
|
[string]::Format(
|
|
'{0}:{1}',
|
|
$Username,
|
|
(ConvertFrom-IcingaSecureString $Password)
|
|
)
|
|
)
|
|
);
|
|
|
|
return @{
|
|
'Authorization' = [string]::Format('Basic {0}', $Credentials)
|
|
};
|
|
}
|
|
|
|
function New-IcingaCheckCommand()
|
|
{
|
|
param(
|
|
[string]$Name = '',
|
|
[array]$Arguments = @(
|
|
'Warning',
|
|
'Critical',
|
|
'[switch]NoPerfData',
|
|
'[int]Verbose'
|
|
)
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name) -eq $TRUE) {
|
|
throw 'Please specify a command name';
|
|
}
|
|
|
|
if ($Name -match 'Invoke' -or $Name -match 'IcingaCheck') {
|
|
throw 'Please specify a command name only without PowerShell Cmdlet naming';
|
|
}
|
|
|
|
[string]$CommandName = [string]::Format(
|
|
'Invoke-IcingaCheck{0}',
|
|
(Get-Culture).TextInfo.ToTitleCase($Name.ToLower())
|
|
);
|
|
|
|
[string]$CommandFile = [string]::Format(
|
|
'icinga-powershell-{0}.psm1',
|
|
$Name.ToLower()
|
|
);
|
|
[string]$PSDFile = [string]::Format(
|
|
'icinga-powershell-{0}.psd1',
|
|
$Name.ToLower()
|
|
);
|
|
|
|
[string]$ModuleFolder = Join-Path -Path (Get-IcingaFrameworkRootPath) -ChildPath (
|
|
[string]::Format('icinga-powershell-{0}', $Name.ToLower())
|
|
);
|
|
[string]$ScriptFile = Join-Path -Path $ModuleFolder -ChildPath $CommandFile;
|
|
[string]$PSDFile = Join-Path -Path $ModuleFolder -ChildPath $PSDFile;
|
|
|
|
if ((Test-Path $ModuleFolder) -eq $TRUE) {
|
|
throw 'This module folder does already exist.';
|
|
}
|
|
|
|
if ((Test-Path $ScriptFile) -eq $TRUE) {
|
|
throw 'This check command does already exist.';
|
|
}
|
|
|
|
New-Item -Path $ModuleFolder -ItemType Directory | Out-Null;
|
|
|
|
Add-Content -Path $ScriptFile -Value '';
|
|
Add-Content -Path $ScriptFile -Value "function $CommandName()";
|
|
Add-Content -Path $ScriptFile -Value "{";
|
|
|
|
if ($Arguments.Count -ne 0) {
|
|
Add-Content -Path $ScriptFile -Value " param(";
|
|
[int]$index = $Arguments.Count - 1;
|
|
foreach ($argument in $Arguments) {
|
|
|
|
if ($argument.Contains('$') -eq $FALSE) {
|
|
if ($argument.Contains(']') -eq $TRUE) {
|
|
$splittedArguments = $argument.Split(']');
|
|
$argument = [string]::Format('{0}]${1}', $splittedArguments[0], $splittedArguments[1]);
|
|
} else {
|
|
$argument = [string]::Format('${0}', $argument);
|
|
}
|
|
}
|
|
|
|
if ($index -ne 0) {
|
|
[string]$content = [string]::Format('{0},', $argument);
|
|
} else {
|
|
[string]$content = [string]::Format('{0}', $argument);
|
|
}
|
|
Add-Content -Path $ScriptFile -Value " $content";
|
|
|
|
$index -= 1;
|
|
}
|
|
Add-Content -Path $ScriptFile -Value " );";
|
|
}
|
|
|
|
Add-Content -Path $ScriptFile -Value "";
|
|
Add-Content -Path $ScriptFile -Value ' <# Icinga Basic Check-Plugin Template. Below you will find an example structure. #>';
|
|
Add-Content -Path $ScriptFile -Value ([string]::Format(' $CheckPackage = New-IcingaCheckPackage -Name {0}New Package{0} -OperatorAnd -Verbose $Verbose;', "'"));
|
|
Add-Content -Path $ScriptFile -Value ([string]::Format(' $IcingaCheck = New-IcingaCheck -Name {0}New Check{0} -Value 10 -Unit {0}%{0}', "'"));
|
|
Add-Content -Path $ScriptFile -Value ([string]::Format(' $IcingaCheck.WarnOutOfRange($Warning).CritOutOfRange($Critical) | Out-Null;', "'"));
|
|
Add-Content -Path $ScriptFile -Value ([string]::Format(' $CheckPackage.AddCheck($IcingaCheck);', "'"));
|
|
Add-Content -Path $ScriptFile -Value "";
|
|
Add-Content -Path $ScriptFile -Value ([string]::Format(' return (New-IcingaCheckresult -Check $CheckPackage -NoPerfData $NoPerfData -Compile);', "'"));
|
|
|
|
Add-Content -Path $ScriptFile -Value "}";
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('The Check-Command "{0}" was successfully added.', $CommandName));
|
|
|
|
# Try to open the default Editor for the new Cmdlet
|
|
$DefaultEditor = (Get-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.psm1\OpenWithList' -Name a).a;
|
|
$DefaultEditor = $DefaultEditor.Replace('.exe', '');
|
|
|
|
New-ModuleManifest `
|
|
-Path $PSDFile `
|
|
-ModuleToProcess $CommandFile `
|
|
-RequiredModules @('icinga-powershell-framework') `
|
|
-FunctionsToExport @('*') `
|
|
-CmdletsToExport @('*') `
|
|
-VariablesToExport '*' | Out-Null;
|
|
|
|
Unblock-IcingaPowerShellFiles -Path $ModuleFolder;
|
|
|
|
Import-Module $ScriptFile -Global;
|
|
|
|
if ([string]::IsNullOrEmpty($DefaultEditor) -eq $FALSE -And ($null -eq (Get-Command $DefaultEditor -ErrorAction SilentlyContinue)) -And ((Test-Path $DefaultEditor) -eq $FALSE)) {
|
|
Write-IcingaConsoleWarning 'No default editor for .psm1 files found. Specify a default editor to automatically open the newly generated check plugin.';
|
|
return;
|
|
}
|
|
|
|
& $DefaultEditor "$ScriptFile";
|
|
}
|
|
|
|
function New-IcingaNewLine()
|
|
{
|
|
return "`r`n";
|
|
}
|
|
|
|
function New-IcingaTemporaryDirectory()
|
|
{
|
|
[string]$TmpDirectory = '';
|
|
[string]$DirectoryPath = '';
|
|
|
|
while ($TRUE) {
|
|
$TmpDirectory = [string]::Format('tmp_icinga{0}.d', (Get-Random));
|
|
$DirectoryPath = Join-Path $Env:TMP -ChildPath $TmpDirectory;
|
|
|
|
if ((Test-Path $DirectoryPath) -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (New-Item -Path $DirectoryPath -ItemType Directory);
|
|
}
|
|
|
|
function New-IcingaTemporaryFile()
|
|
{
|
|
[string]$TmpFile = '';
|
|
[string]$FilePath = '';
|
|
|
|
while ($TRUE) {
|
|
$TmpFile = [string]::Format('tmp_icinga{0}.tmp', (Get-Random));
|
|
$FilePath = Join-Path $Env:TMP -ChildPath $TmpFile;
|
|
|
|
if ((Test-Path $FilePath) -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (New-Item -Path $FilePath -ItemType File);
|
|
}
|
|
|
|
function New-StringTree()
|
|
{
|
|
param(
|
|
[int]$Spacing
|
|
)
|
|
|
|
if ($Spacing -eq 0) {
|
|
return '';
|
|
}
|
|
|
|
[string]$spaces = '\_ ';
|
|
|
|
while ($Spacing -gt 1) {
|
|
$Spacing -= 1;
|
|
$spaces = ' ' + $spaces;
|
|
}
|
|
|
|
return $spaces;
|
|
}
|
|
|
|
function Pop-IcingaArrayListItem()
|
|
{
|
|
param(
|
|
[System.Collections.ArrayList]$Array
|
|
);
|
|
|
|
if ($null -eq $Array) {
|
|
return $null;
|
|
}
|
|
|
|
if ($Array.Count -eq 0) {
|
|
return $null;
|
|
}
|
|
|
|
$Content = $Array[0];
|
|
$Array.RemoveAt(0);
|
|
|
|
return $Content;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Reads content of a file in read-only mode, ensuring no data corruption is happening
|
|
.DESCRIPTION
|
|
Reads content of a file in read-only mode, ensuring no data corruption is happening
|
|
.FUNCTIONALITY
|
|
Reads content of a file in read-only mode, ensuring no data corruption is happening
|
|
.EXAMPLE
|
|
PS>Read-IcingaFileContent -File 'config.json';
|
|
.OUTPUTS
|
|
System.Object
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Read-IcingaFileContent()
|
|
{
|
|
param (
|
|
[string]$File
|
|
);
|
|
|
|
if ((Test-Path $File) -eq $FALSE) {
|
|
return $null;
|
|
}
|
|
|
|
[System.IO.FileStream]$FileStream = [System.IO.File]::Open(
|
|
$File,
|
|
[System.IO.FileMode]::Open,
|
|
[System.IO.FileAccess]::Read,
|
|
[System.IO.FileShare]::Read
|
|
);
|
|
|
|
$ReadArray = New-Object Byte[] $FileStream.Length;
|
|
$UTF8Encoding = New-Object System.Text.UTF8Encoding $TRUE;
|
|
$FileContent = '';
|
|
|
|
while ($FileStream.Read($ReadArray, 0 , $ReadArray.Length)) {
|
|
$FileContent = [System.String]::Concat($FileContent, $UTF8Encoding.GetString($ReadArray));
|
|
}
|
|
|
|
$FileStream.Dispose();
|
|
|
|
return $FileContent;
|
|
}
|
|
|
|
function Remove-IcingaDirectorSelfServiceKey()
|
|
{
|
|
$Path = 'IcingaDirector.SelfService.ApiKey';
|
|
$Value = Get-IcingaPowerShellConfig $Path;
|
|
if ($null -ne $Value) {
|
|
Remove-IcingaPowerShellConfig 'IcingaDirector.SelfService.ApiKey';
|
|
$Value = Get-IcingaPowerShellConfig $Path;
|
|
if ($null -eq $Value) {
|
|
Write-IcingaConsoleNotice 'Icinga Director Self-Service Api key was successfully removed. Please dont forget to drop it within the Icinga Director as well';
|
|
}
|
|
} else {
|
|
Write-IcingaConsoleWarning 'There is no Self-Service Api key configured on this system';
|
|
}
|
|
}
|
|
|
|
function Remove-IcingaHashtableItem()
|
|
{
|
|
param(
|
|
$Hashtable,
|
|
$Key
|
|
);
|
|
|
|
if ($null -eq $Hashtable) {
|
|
return;
|
|
}
|
|
|
|
if ($Hashtable.ContainsKey($Key)) {
|
|
$Hashtable.Remove($Key);
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Sets nummeric values to be negative
|
|
.DESCRIPTION
|
|
This module sets a numeric value to be negative.
|
|
e.g 12 to -12
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.EXAMPLE
|
|
PS> Set-NumericNegative 32
|
|
-32
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
|
|
function Set-NumericNegative()
|
|
{
|
|
param(
|
|
$Value
|
|
);
|
|
|
|
$Value = $Value * -1;
|
|
|
|
return $Value;
|
|
}
|
|
function Show-IcingaDirecorSelfServiceKey()
|
|
{
|
|
$Path = 'IcingaDirector.SelfService.ApiKey';
|
|
$Value = Get-IcingaPowerShellConfig $Path;
|
|
|
|
if ($null -ne $Value) {
|
|
Write-IcingaConsoleNotice ([string]::Format('Self-Service Key: "{0}"', $Value));
|
|
} else {
|
|
Write-IcingaConsoleWarning 'There is no Self-Service Api key configured on this system';
|
|
}
|
|
}
|
|
|
|
function Show-IcingaEventLogAnalysis()
|
|
{
|
|
param (
|
|
[string]$LogName = 'Application'
|
|
);
|
|
|
|
Write-IcingaConsoleNotice 'Analysing EventLog "{0}"...' -Objects $LogName;
|
|
|
|
Start-IcingaTimer 'EventLog Analyser';
|
|
|
|
try {
|
|
[array]$BasicLogArray = Get-WinEvent -ListLog $LogName -ErrorAction Stop;
|
|
$BasicLogData = $BasicLogArray[0];
|
|
} catch {
|
|
Write-IcingaConsoleError 'Failed to fetch data for EventLog "{0}". Probably this log does not exist.' -Objects $LogName;
|
|
return;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Logging Mode: {0}' -Objects $BasicLogData.LogMode;
|
|
Write-IcingaConsoleNotice 'Maximum Size: {0} GB' -Objects ([math]::Round((Convert-Bytes -Value $BasicLogData.MaximumSizeInBytes -Unit 'GB').value, 2));
|
|
Write-IcingaConsoleNotice 'Current Entries: {0}' -Objects $BasicLogData.RecordCount;
|
|
|
|
[hashtable]$LogAnalysis = @{
|
|
'Day' = @{
|
|
'Entries' = @{ };
|
|
'Count' = 0;
|
|
'Average' = 0;
|
|
'Maximum' = 0;
|
|
};
|
|
'Hour' = @{
|
|
'Entries' = @{ };
|
|
'Count' = 0;
|
|
'Average' = 0;
|
|
'Maximum' = 0;
|
|
};
|
|
'Minute' = @{
|
|
'Entries' = @{ };
|
|
'Count' = 0;
|
|
'Average' = 0;
|
|
'Maximum' = 0;
|
|
};
|
|
};
|
|
|
|
$LogData = Get-WinEvent -LogName $LogName;
|
|
[string]$NewestEntry = $null;
|
|
[string]$OldestEntry = $null;
|
|
|
|
foreach ($entry in $LogData) {
|
|
[string]$DayOfLogging = $entry.TimeCreated.ToString('yyyy\/MM\/dd');
|
|
[string]$HourOfLogging = $entry.TimeCreated.ToString('yyyy\/MM\/dd-HH');
|
|
[string]$MinuteOfLogging = $entry.TimeCreated.ToString('yyyy\/MM\/dd-HH-mm');
|
|
|
|
$OldestEntry = $entry.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss');
|
|
|
|
if ([string]::IsNullOrEmpty($NewestEntry)) {
|
|
$NewestEntry = $OldestEntry;
|
|
}
|
|
|
|
if ($LogAnalysis.Day.Entries.ContainsKey($DayOfLogging) -eq $FALSE) {
|
|
$LogAnalysis.Day.Entries.Add($DayOfLogging, 0);
|
|
}
|
|
|
|
if ($LogAnalysis.Hour.Entries.ContainsKey($HourOfLogging) -eq $FALSE) {
|
|
$LogAnalysis.Hour.Entries.Add($HourOfLogging, 0);
|
|
}
|
|
|
|
if ($LogAnalysis.Minute.Entries.ContainsKey($MinuteOfLogging) -eq $FALSE) {
|
|
$LogAnalysis.Minute.Entries.Add($MinuteOfLogging, 0);
|
|
}
|
|
|
|
$LogAnalysis.Day.Entries[$DayOfLogging] += 1;
|
|
$LogAnalysis.Hour.Entries[$HourOfLogging] += 1;
|
|
$LogAnalysis.Minute.Entries[$MinuteOfLogging] += 1;
|
|
|
|
$LogAnalysis.Day.Count += 1;
|
|
$LogAnalysis.Hour.Count += 1;
|
|
$LogAnalysis.Minute.Count += 1;
|
|
|
|
$LogAnalysis.Day.Average = [math]::Ceiling($LogAnalysis.Day.Count / $LogAnalysis.Day.Entries.Count);
|
|
$LogAnalysis.Hour.Average = [math]::Ceiling($LogAnalysis.Hour.Count / $LogAnalysis.Hour.Entries.Count);
|
|
$LogAnalysis.Minute.Average = [math]::Ceiling($LogAnalysis.Minute.Count / $LogAnalysis.Minute.Entries.Count);
|
|
}
|
|
|
|
foreach ($value in $LogAnalysis.Day.Entries.Values) {
|
|
$LogAnalysis.Day.Maximum = Get-IcingaValue -Value $value -Compare $LogAnalysis.Day.Maximum -Maximum;
|
|
}
|
|
foreach ($value in $LogAnalysis.Hour.Entries.Values) {
|
|
$LogAnalysis.Hour.Maximum = Get-IcingaValue -Value $value -Compare $LogAnalysis.Hour.Maximum -Maximum;
|
|
}
|
|
foreach ($value in $LogAnalysis.Minute.Entries.Values) {
|
|
$LogAnalysis.Minute.Maximum = Get-IcingaValue -Value $value -Compare $LogAnalysis.Minute.Maximum -Maximum;
|
|
}
|
|
Stop-IcingaTimer 'EventLog Analyser';
|
|
|
|
Write-IcingaConsoleNotice 'Average Logs per Day: {0}' -Objects $LogAnalysis.Day.Average;
|
|
Write-IcingaConsoleNotice 'Average Logs per Hour: {0}' -Objects $LogAnalysis.Hour.Average;
|
|
Write-IcingaConsoleNotice 'Average Logs per Minute: {0}' -Objects $LogAnalysis.Minute.Average;
|
|
Write-IcingaConsoleNotice 'Maximum Logs per Day: {0}' -Objects $LogAnalysis.Day.Maximum;
|
|
Write-IcingaConsoleNotice 'Maximum Logs per Hour: {0}' -Objects $LogAnalysis.Hour.Maximum;
|
|
Write-IcingaConsoleNotice 'Maximum Logs per Minute: {0}' -Objects $LogAnalysis.Minute.Maximum;
|
|
Write-IcingaConsoleNotice 'Newest entry timestamp: {0}' -Objects $NewestEntry;
|
|
Write-IcingaConsoleNotice 'Oldest entry timestamp: {0}' -Objects $OldestEntry;
|
|
Write-IcingaConsoleNotice 'Analysing Time: {0}s' -Objects ([math]::Round((Get-IcingaTimer 'EventLog Analyser').Elapsed.TotalSeconds, 2));
|
|
}
|
|
|
|
function Split-IcingaCheckCommandArgs()
|
|
{
|
|
[array]$arguments = @();
|
|
foreach ($arg in $args) {
|
|
$arguments += $arg;
|
|
}
|
|
|
|
return $arguments;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Splits a username containing a domain into a hashtable to easily use both values independently.
|
|
If no domain is specified the hostname will used as "local domain"
|
|
.DESCRIPTION
|
|
Splits a username containing a domain into a hashtable to easily use both values independently.
|
|
If no domain is specified the hostname will used as "local domain"
|
|
.PARAMETER User
|
|
A user object either containing only the user or domain information
|
|
.EXAMPLE
|
|
PS>Split-IcingaUserDomain -User 'icinga';
|
|
|
|
Name Value
|
|
---- -----
|
|
User icinga
|
|
Domain icinga-win
|
|
.EXAMPLE
|
|
PS>Split-IcingaUserDomain -User 'ICINGADOMAIN\icinga';
|
|
|
|
Name Value
|
|
---- -----
|
|
User icinga
|
|
Domain ICINGADOMAIN
|
|
.EXAMPLE
|
|
PS>Split-IcingaUserDomain -User 'icinga@ICINGADOMAIN';
|
|
|
|
Name Value
|
|
---- -----
|
|
User icinga
|
|
Domain ICINGADOMAIN
|
|
.EXAMPLE
|
|
PS>Split-IcingaUserDomain -User '.\icinga';
|
|
|
|
Name Value
|
|
---- -----
|
|
User icinga
|
|
Domain icinga-win
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Hashtable
|
|
#>
|
|
|
|
function Split-IcingaUserDomain()
|
|
{
|
|
param (
|
|
$User
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($User)) {
|
|
Write-IcingaConsoleError 'Please enter a valid username';
|
|
return '';
|
|
}
|
|
|
|
[array]$UserData = @();
|
|
|
|
if ($User.Contains('\')) {
|
|
$UserData = $User.Split('\');
|
|
} elseif ($User.Contains('@')) {
|
|
[array]$Split = $User.Split('@');
|
|
$UserData = @(
|
|
$Split[1],
|
|
$Split[0]
|
|
);
|
|
} else {
|
|
$UserData = @(
|
|
(Get-IcingaNetbiosName),
|
|
$User
|
|
);
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($UserData[0]) -Or $UserData[0] -eq '.' -Or $UserData[0] -eq 'BUILTIN') {
|
|
$UserData[0] = (Get-IcingaNetbiosName);
|
|
}
|
|
|
|
return @{
|
|
'Domain' = $UserData[0];
|
|
'User' = $UserData[1];
|
|
};
|
|
}
|
|
|
|
function Start-IcingaProcess()
|
|
{
|
|
param(
|
|
[string]$Executable,
|
|
[string]$Arguments,
|
|
[switch]$FlushNewLines
|
|
);
|
|
|
|
$processData = New-Object System.Diagnostics.ProcessStartInfo;
|
|
$processData.FileName = $Executable;
|
|
$processData.RedirectStandardError = $true;
|
|
$processData.RedirectStandardOutput = $true;
|
|
$processData.UseShellExecute = $false;
|
|
$processData.Arguments = $Arguments;
|
|
|
|
$process = New-Object System.Diagnostics.Process;
|
|
$process.StartInfo = $processData;
|
|
$process.Start() | Out-Null;
|
|
|
|
$stdout = $process.StandardOutput.ReadToEnd();
|
|
$stderr = $process.StandardError.ReadToEnd();
|
|
$process.WaitForExit();
|
|
|
|
if ($flushNewLines) {
|
|
$stdout = $stdout.Replace("`n", '').Replace("`r", '');
|
|
$stderr = $stderr.Replace("`n", '').Replace("`r", '');
|
|
} else {
|
|
if ($stdout.Contains("`n")) {
|
|
$stdout = $stdout.Substring(0, $stdout.LastIndexOf("`n"));
|
|
}
|
|
}
|
|
return @{
|
|
'Message' = $stdout;
|
|
'Error' = $stderr;
|
|
'ExitCode' = $process.ExitCode;
|
|
};
|
|
}
|
|
|
|
function Test-AdministrativeShell()
|
|
{
|
|
$WindowsPrincipcal = New-Object System.Security.Principal.WindowsPrincipal(
|
|
[System.Security.Principal.WindowsIdentity]::GetCurrent()
|
|
);
|
|
|
|
if ($WindowsPrincipcal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
|
return $TRUE;
|
|
}
|
|
return $FALSE;
|
|
}
|
|
|
|
function Test-IcingaAddTypeExist()
|
|
{
|
|
param (
|
|
[string]$Type = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Type)) {
|
|
return $FALSE;
|
|
}
|
|
|
|
foreach ($entry in [System.AppDomain]::CurrentDomain.GetAssemblies()) {
|
|
if ($entry.GetTypes() -Match $Type) {
|
|
return $TRUE;
|
|
}
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Tests for binary operators with -band if a specific Value contains binary
|
|
operators within a Compare array. In addition you can use a Namespace
|
|
argument to provide a hashtable in which your key values are included to
|
|
reduce the amount of code to write
|
|
.DESCRIPTION
|
|
Tests for binary operators with -band if a specific Value contains binary
|
|
operators within a Compare array. In addition you can use a Namespace
|
|
argument to provide a hashtable in which your key values are included to
|
|
reduce the amount of code to write
|
|
.EXAMPLE
|
|
PS>Test-IcingaBinaryOperator -Value Ok -Compare EmptyClass, InvalidNameSpace, PermissionError, Ok -Namespace $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo;
|
|
True
|
|
.EXAMPLE
|
|
PS>Test-IcingaBinaryOperator -Value 2 -Compare 1,4,8,16,32,64,128,256;
|
|
False
|
|
.PARAMETER Value
|
|
The value to check if it is included within the compare argument. This can either be
|
|
the name of the key for a Namespace or a numeric value
|
|
.PARAMETER Compare
|
|
An array of values to compare for and check if the value matches with the -band operator
|
|
The array can either contain the key names of your Namespace, numeric values or both cominbed
|
|
.PARAMETER Namespace
|
|
A hashtable object containing values you want to compare for. By providing a hashtable here
|
|
you can use the key names for each value on the Value and Compare argument
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Test-IcingaBinaryOperator()
|
|
{
|
|
param (
|
|
$Value = $null,
|
|
[array]$Compare = @(),
|
|
[hashtable]$Namespace = $null
|
|
);
|
|
|
|
[long]$BinaryValue = 0;
|
|
|
|
foreach ($entry in $Compare) {
|
|
if ($null -ne $Namespace) {
|
|
if ($Namespace.ContainsKey($entry)) {
|
|
$BinaryValue += $Namespace[$entry];
|
|
} else {
|
|
if (Test-Numeric $entry) {
|
|
$BinaryValue += $entry;
|
|
}
|
|
}
|
|
} else {
|
|
$BinaryValue += $entry;
|
|
}
|
|
}
|
|
|
|
if ($null -ne $Value -and (Test-Numeric $Value)) {
|
|
if (($Value -band $BinaryValue) -eq $Value) {
|
|
return $TRUE;
|
|
}
|
|
}
|
|
|
|
if ($null -ne $Namespace -and $Namespace.ContainsKey($Value)) {
|
|
if (($Namespace[$Value] -band $BinaryValue) -eq $Namespace[$Value]) {
|
|
return $TRUE;
|
|
}
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
function Test-IcingaDecimal()
|
|
{
|
|
param (
|
|
$Value = $null
|
|
);
|
|
|
|
[hashtable]$RetValue = @{
|
|
'Value' = $Value;
|
|
'Decimal' = $FALSE;
|
|
};
|
|
|
|
if ($null -eq $Value -Or [string]::IsNullOrEmpty($Value)) {
|
|
return $RetValue;
|
|
}
|
|
|
|
$TmpValue = ([string]$Value).Replace(',', '.');
|
|
|
|
if ((Test-Numeric $TmpValue) -eq $FALSE) {
|
|
return $RetValue;
|
|
}
|
|
|
|
$RetValue.Value = [decimal]$TmpValue;
|
|
$RetValue.Decimal = $TRUE;
|
|
|
|
return $RetValue;
|
|
}
|
|
|
|
function Test-IcingaFunction()
|
|
{
|
|
param(
|
|
[string]$Name
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Name)) {
|
|
return $FALSE;
|
|
}
|
|
|
|
if (Get-Command $Name -ErrorAction SilentlyContinue) {
|
|
return $TRUE;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Tests whether a value is numeric
|
|
.DESCRIPTION
|
|
This module tests whether a value is numeric
|
|
|
|
More Information on https://github.com/Icinga/icinga-powershell-framework
|
|
.EXAMPLE
|
|
PS> Test-Numeric 32
|
|
True
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
function Test-Numeric ($number) {
|
|
return $number -Match "^-?[0-9]\d*(\.\d+)?$";
|
|
}
|
|
|
|
function Test-PSCustomObjectMember()
|
|
{
|
|
param(
|
|
$PSObject,
|
|
$Name
|
|
);
|
|
|
|
if ($null -eq $PSObject) {
|
|
return $FALSE;
|
|
}
|
|
|
|
return ([bool]($PSObject.PSobject.Properties.Name -eq $Name));
|
|
}
|
|
|
|
function Write-IcingaConsoleHeader()
|
|
{
|
|
param (
|
|
[array]$HeaderLines = @()
|
|
);
|
|
|
|
[array]$ParsedHeaders = @();
|
|
[int]$MaxHeaderLength = 0;
|
|
[int]$TableHeaderCount = 0;
|
|
[array]$TableHeader = @();
|
|
|
|
Import-LocalizedData `
|
|
-BaseDirectory (Get-IcingaFrameworkRootPath) `
|
|
-FileName 'icinga-powershell-framework.psd1' `
|
|
-BindingVariable IcingaFrameworkData;
|
|
|
|
foreach ($line in $HeaderLines) {
|
|
$line = $line.Replace('$FrameworkVersion', $IcingaFrameworkData.PrivateData.Version);
|
|
$line = $line.Replace('$Copyright', $IcingaFrameworkData.Copyright);
|
|
$line = $line.Replace('$UserDomain', $env:USERDOMAIN);
|
|
$line = $line.Replace('$Username', $env:USERNAME);
|
|
|
|
$ParsedHeaders += $line;
|
|
}
|
|
|
|
foreach ($line in $ParsedHeaders) {
|
|
if ($MaxHeaderLength -lt $line.Length) {
|
|
$MaxHeaderLength = $line.Length
|
|
}
|
|
}
|
|
|
|
$TableHeaderCount = $MaxHeaderLength + 6;
|
|
|
|
while ($TableHeaderCount -ne 0) {
|
|
$TableHeader += '*';
|
|
$TableHeaderCount -= 1;
|
|
}
|
|
|
|
$TableHeaderCount = $MaxHeaderLength + 6;
|
|
|
|
Write-IcingaConsolePlain ([string]::Join('', $TableHeader));
|
|
|
|
foreach ($line in $ParsedHeaders) {
|
|
[array]$LeftSpacing = @();
|
|
[array]$RightSpacing = @();
|
|
|
|
if ($line.Length -lt $MaxHeaderLength) {
|
|
$Spacing = [math]::floor(($MaxHeaderLength - $line.Length) / 2);
|
|
|
|
while ($Spacing -gt 0) {
|
|
$LeftSpacing += ' ';
|
|
$RightSpacing += ' ';
|
|
$Spacing -= 1;
|
|
}
|
|
|
|
if ($TableHeaderCount -gt ($line.Length + $LeftSpacing.Count + $RightSpacing.Count + 6)) {
|
|
[int]$RightOffset = $TableHeaderCount - ($line.Length + $LeftSpacing.Count + $RightSpacing.Count + 6)
|
|
while ($RightOffset -gt 0) {
|
|
$RightSpacing += ' ';
|
|
$RightOffset -= 1;
|
|
}
|
|
}
|
|
}
|
|
Write-IcingaConsolePlain -Message '**{1} {0} {2}**' -Objects $line, ([string]::Join('', $LeftSpacing)), ([string]::Join('', $RightSpacing));
|
|
}
|
|
|
|
Write-IcingaConsolePlain ([string]::Join('', $TableHeader));
|
|
}
|
|
|
|
function Get-IcingaBackgroundDaemons()
|
|
{
|
|
$Daemons = Get-IcingaPowerShellConfig -Path 'BackgroundDaemon.EnabledDaemons';
|
|
|
|
if ($null -eq $Daemons) {
|
|
return $null;
|
|
}
|
|
|
|
[hashtable]$Output = @{};
|
|
|
|
foreach ($daemon in $Daemons.PSObject.Properties) {
|
|
$Arguments = @{ };
|
|
|
|
foreach ($argument in $daemon.Value.Arguments.PSObject.Properties) {
|
|
$Arguments.Add($argument.Name, $argument.Value);
|
|
}
|
|
|
|
$Output.Add($daemon.Name, $Arguments);
|
|
}
|
|
|
|
return $Output;
|
|
}
|
|
|
|
function Register-IcingaBackgroundDaemon()
|
|
{
|
|
param(
|
|
[string]$Command,
|
|
[hashtable]$Arguments
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Command)) {
|
|
throw 'Please specify a Cmdlet to run as Background Daemon';
|
|
}
|
|
|
|
if (-Not (Test-IcingaFunction $Command)) {
|
|
throw ([string]::Format('The Cmdlet "{0}" is not available in your session. Please restart the session and try again or verify your input', $Command));
|
|
}
|
|
|
|
$Path = [string]::Format('BackgroundDaemon.EnabledDaemons.{0}', $Command);
|
|
|
|
Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.Command', $Path)) -Value $Command;
|
|
Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.Arguments', $Path)) -Value $Arguments;
|
|
|
|
Write-IcingaConsoleNotice ([string]::Format('Background daemon Cmdlet "{0}" has been configured', $Command));
|
|
}
|
|
|
|
function Start-IcingaPowerShellDaemon()
|
|
{
|
|
param(
|
|
[switch]$RunAsService
|
|
);
|
|
|
|
$ScriptBlock = {
|
|
param($IcingaDaemonData);
|
|
|
|
Use-Icinga -LibOnly -Daemon;
|
|
|
|
try {
|
|
$EnabledDaemons = Get-IcingaBackgroundDaemons;
|
|
|
|
foreach ($daemon in $EnabledDaemons.Keys) {
|
|
if (-Not (Test-IcingaFunction $daemon)) {
|
|
continue;
|
|
}
|
|
|
|
$daemonArgs = $EnabledDaemons[$daemon];
|
|
&$daemon @daemonArgs;
|
|
}
|
|
} catch {
|
|
# Todo: Add exception handling
|
|
}
|
|
|
|
while ($TRUE) {
|
|
Start-Sleep -Seconds 1;
|
|
}
|
|
};
|
|
|
|
$global:IcingaDaemonData.FrameworkRunningAsDaemon = $TRUE;
|
|
$global:IcingaDaemonData.Add('BackgroundDaemon', [hashtable]::Synchronized(@{}));
|
|
# Todo: Add config for active background tasks. Set it to 20 for the moment
|
|
$global:IcingaDaemonData.IcingaThreadPool.Add('BackgroundPool', (New-IcingaThreadPool -MaxInstances 20));
|
|
$global:IcingaDaemonData.Add('Config', (Read-IcingaPowerShellConfig));
|
|
|
|
New-IcingaThreadInstance -Name "Icinga_PowerShell_Background_Daemon" -ThreadPool $IcingaDaemonData.IcingaThreadPool.BackgroundPool -ScriptBlock $ScriptBlock -Arguments @( $global:IcingaDaemonData ) -Start;
|
|
|
|
if ($RunAsService) {
|
|
while ($TRUE) {
|
|
Start-Sleep -Seconds 100;
|
|
}
|
|
}
|
|
}
|
|
|
|
function Unregister-IcingaBackgroundDaemon()
|
|
{
|
|
param(
|
|
[string]$BackgroundDaemon,
|
|
[hashtable]$Arguments
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($BackgroundDaemon)) {
|
|
throw 'Please specify a Cmdlet to remove from running as Background Daemon';
|
|
}
|
|
|
|
$Path = [string]::Format('BackgroundDaemon.EnabledDaemons.{0}', $BackgroundDaemon);
|
|
|
|
Remove-IcingaPowerShellConfig -Path $Path;
|
|
|
|
Write-IcingaConsoleNotice 'Background daemon has been removed';
|
|
}
|
|
|
|
function Get-IcingaRegisteredServiceChecks()
|
|
{
|
|
$Services = Get-IcingaPowerShellConfig -Path 'BackgroundDaemon.RegisteredServices';
|
|
[hashtable]$Output = @{};
|
|
|
|
foreach ($service in $Services.PSObject.Properties) {
|
|
$Content = @{
|
|
'Id' = $service.Name;
|
|
'CheckCommand' = $service.Value.CheckCommand;
|
|
'Arguments' = $service.Value.Arguments;
|
|
'Interval' = $service.Value.Interval;
|
|
'TimeIndexes' = $service.Value.TimeIndexes;
|
|
};
|
|
|
|
$Output.Add($service.Name, $Content);
|
|
}
|
|
|
|
return $Output;
|
|
}
|
|
|
|
function Register-IcingaServiceCheck()
|
|
{
|
|
param(
|
|
[string]$CheckCommand,
|
|
[hashtable]$Arguments,
|
|
[int]$Interval = 60,
|
|
[array]$TimeIndexes = @()
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($CheckCommand)) {
|
|
throw 'Please specify a CheckCommand';
|
|
}
|
|
|
|
$Hash = Get-StringSha1 ([string]::Format('{0} {1}', $CheckCommand, ($Arguments | Out-String)));
|
|
$Path = [string]::Format('BackgroundDaemon.RegisteredServices.{0}', $Hash);
|
|
|
|
Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.CheckCommand', $Path)) -Value $CheckCommand;
|
|
Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.Arguments', $Path)) -Value $Arguments;
|
|
Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.Interval', $Path)) -Value $Interval;
|
|
Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.TimeIndexes', $Path)) -Value $TimeIndexes;
|
|
|
|
Write-IcingaConsoleNotice 'Icinga Service Check has been configured';
|
|
}
|
|
|
|
function Set-IcingaRegisteredServiceCheckConfig()
|
|
{
|
|
param(
|
|
[string]$ServiceId,
|
|
[hashtable]$Arguments = $null,
|
|
$Interval = $null,
|
|
[array]$TimeIndexes = $null
|
|
);
|
|
|
|
$Services = Get-IcingaRegisteredServiceChecks;
|
|
|
|
if ($Services.ContainsKey($ServiceId) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'Service Id was not found';
|
|
return;
|
|
}
|
|
|
|
[bool]$Modified = $FALSE;
|
|
$Path = [string]::Format('BackgroundDaemon.RegisteredServices.{0}', $ServiceId);
|
|
|
|
if ($null -ne $Arguments) {
|
|
Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.Arguments', $Path)) -Value $Arguments;
|
|
$Modified = $TRUE;
|
|
}
|
|
if ($null -ne $Interval) {
|
|
Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.Interval', $Path)) -Value $Interval;
|
|
$Modified = $TRUE;
|
|
}
|
|
if ($null -ne $TimeIndexes) {
|
|
Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.TimeIndexes', $Path)) -Value $TimeIndexes;
|
|
$Modified = $TRUE;
|
|
}
|
|
|
|
if ($Modified) {
|
|
Write-IcingaConsoleNotice 'Service configuration was successfully updated';
|
|
} else {
|
|
Write-IcingaConsoleWarning 'No arguments were specified to update the service configuration';
|
|
}
|
|
}
|
|
|
|
function Show-IcingaRegisteredServiceChecks()
|
|
{
|
|
$Services = Get-IcingaRegisteredServiceChecks;
|
|
|
|
foreach ($service in $Services.Keys) {
|
|
Write-IcingaConsoleNotice ([string]::Format('Service Id: {0}', $service));
|
|
Write-IcingaConsoleNotice (
|
|
$Services[$service] | Out-String
|
|
);
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
A background daemon executing registered service checks in the background to fetch
|
|
metrics for certain checks over time. Time frames are configurable individual
|
|
.DESCRIPTION
|
|
This background daemon will execute checks registered with "Register-IcingaServiceCheck"
|
|
for the given time interval and store the collected metrics for a defined period of time
|
|
inside a JSON file. Check values collected by this daemon are then automatically added
|
|
to regular check executions for additional performance metrics.
|
|
|
|
Example: Register-IcingaServiceCheck -CheckCommand 'Invoke-IcingaCheckCPU' -Interval 30 -TimeIndexes 1,3,5,15;
|
|
|
|
This will execute the CPU check every 30 seconds and calculate the average of 1, 3, 5 and 15 minutes
|
|
|
|
More Information on
|
|
https://icinga.com/docs/icinga-for-windows/latest/doc/service/02-Register-Daemons/
|
|
https://icinga.com/docs/icinga-for-windows/latest/doc/service/10-Register-Service-Checks/
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
.NOTES
|
|
#>
|
|
|
|
function Start-IcingaServiceCheckDaemon()
|
|
{
|
|
$ScriptBlock = {
|
|
param($IcingaDaemonData);
|
|
|
|
Use-Icinga -LibOnly -Daemon;
|
|
|
|
$IcingaDaemonData.IcingaThreadPool.Add('ServiceCheckPool', (New-IcingaThreadPool -MaxInstances (Get-IcingaConfigTreeCount -Path 'BackgroundDaemon.RegisteredServices')));
|
|
|
|
while ($TRUE) {
|
|
|
|
$RegisteredServices = Get-IcingaRegisteredServiceChecks;
|
|
|
|
foreach ($service in $RegisteredServices.Keys) {
|
|
[string]$ThreadName = [string]::Format('Icinga_Background_Service_Check_{0}', $service);
|
|
if ((Test-IcingaThread $ThreadName)) {
|
|
continue;
|
|
}
|
|
|
|
[hashtable]$ServiceArgs = @{ };
|
|
|
|
if ($null -ne $RegisteredServices[$service].Arguments) {
|
|
foreach ($property in $RegisteredServices[$service].Arguments.PSObject.Properties) {
|
|
if ($ServiceArgs.ContainsKey($property.Name)) {
|
|
continue;
|
|
}
|
|
|
|
$ServiceArgs.Add($property.Name, $property.Value)
|
|
}
|
|
}
|
|
|
|
Start-IcingaServiceCheckTask -CheckId $service -CheckCommand $RegisteredServices[$service].CheckCommand -Arguments $ServiceArgs -Interval $RegisteredServices[$service].Interval -TimeIndexes $RegisteredServices[$service].TimeIndexes;
|
|
}
|
|
Start-Sleep -Seconds 1;
|
|
}
|
|
};
|
|
|
|
New-IcingaThreadInstance -Name "Icinga_PowerShell_ServiceCheck_Scheduler" -ThreadPool $IcingaDaemonData.IcingaThreadPool.BackgroundPool -ScriptBlock $ScriptBlock -Arguments @( $global:IcingaDaemonData ) -Start;
|
|
}
|
|
|
|
function Start-IcingaServiceCheckTask()
|
|
{
|
|
param(
|
|
$CheckId,
|
|
$CheckCommand,
|
|
$Arguments,
|
|
$Interval,
|
|
$TimeIndexes
|
|
);
|
|
|
|
[string]$ThreadName = [string]::Format('Icinga_Background_Service_Check_{0}', $CheckId);
|
|
|
|
$ScriptBlock = {
|
|
param($IcingaDaemonData, $CheckCommand, $Arguments, $Interval, $TimeIndexes, $CheckId);
|
|
|
|
Use-Icinga -LibOnly -Daemon;
|
|
$PassedTime = 0;
|
|
$SortedResult = $null;
|
|
$PerfCache = @{ };
|
|
$AverageCalc = @{ };
|
|
[int]$MaxTime = 0;
|
|
|
|
# Initialise some global variables we use to actually store check result data from
|
|
# plugins properly. This is doable from each thread instance as this part isn't
|
|
# shared between daemons
|
|
New-IcingaCheckSchedulerEnvironment;
|
|
|
|
foreach ($index in $TimeIndexes) {
|
|
# Only allow numeric index values
|
|
if ((Test-Numeric $index) -eq $FALSE) {
|
|
continue;
|
|
}
|
|
if ($AverageCalc.ContainsKey([string]$index) -eq $FALSE) {
|
|
$AverageCalc.Add(
|
|
[string]$index,
|
|
@{
|
|
'Interval' = ([int]$index);
|
|
'Time' = ([int]$index * 60);
|
|
'Sum' = 0;
|
|
'Count' = 0;
|
|
}
|
|
);
|
|
}
|
|
if ($MaxTime -le [int]$index) {
|
|
$MaxTime = [int]$index;
|
|
}
|
|
}
|
|
|
|
[int]$MaxTimeInSeconds = $MaxTime * 60;
|
|
|
|
if (-Not ($global:Icinga.CheckData.ContainsKey($CheckCommand))) {
|
|
$global:Icinga.CheckData.Add($CheckCommand, @{ });
|
|
$global:Icinga.CheckData[$CheckCommand].Add('results', @{ });
|
|
$global:Icinga.CheckData[$CheckCommand].Add('average', @{ });
|
|
}
|
|
|
|
$LoadedCacheData = Get-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult_store' -KeyName $CheckCommand;
|
|
|
|
if ($null -ne $LoadedCacheData) {
|
|
foreach ($entry in $LoadedCacheData.PSObject.Properties) {
|
|
$global:Icinga.CheckData[$CheckCommand]['results'].Add(
|
|
$entry.name,
|
|
@{ }
|
|
);
|
|
foreach ($item in $entry.Value.PSObject.Properties) {
|
|
$global:Icinga.CheckData[$CheckCommand]['results'][$entry.name].Add(
|
|
$item.Name,
|
|
$item.Value
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
while ($TRUE) {
|
|
if ($PassedTime -ge $Interval) {
|
|
try {
|
|
& $CheckCommand @Arguments | Out-Null;
|
|
} catch {
|
|
# Just for debugging. Not required in production or usable at all
|
|
$ErrMsg = $_.Exception.Message;
|
|
Write-IcingaConsoleError $ErrMsg;
|
|
}
|
|
|
|
try {
|
|
$UnixTime = Get-IcingaUnixTime;
|
|
|
|
foreach ($result in $global:Icinga.CheckData[$CheckCommand]['results'].Keys) {
|
|
[string]$HashIndex = $result;
|
|
$SortedResult = $global:Icinga.CheckData[$CheckCommand]['results'][$HashIndex].GetEnumerator() | Sort-Object name -Descending;
|
|
Add-IcingaHashtableItem -Hashtable $PerfCache -Key $HashIndex -Value @{ } | Out-Null;
|
|
|
|
foreach ($timeEntry in $SortedResult) {
|
|
|
|
if ((Test-Numeric $timeEntry.Value) -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($calc in $AverageCalc.Keys) {
|
|
if (($UnixTime - $AverageCalc[$calc].Time) -le [int]$timeEntry.Key) {
|
|
$AverageCalc[$calc].Sum += $timeEntry.Value;
|
|
$AverageCalc[$calc].Count += 1;
|
|
}
|
|
}
|
|
if (($UnixTime - $MaxTimeInSeconds) -le [int]$timeEntry.Key) {
|
|
Add-IcingaHashtableItem -Hashtable $PerfCache[$HashIndex] -Key ([string]$timeEntry.Key) -Value ([string]$timeEntry.Value) | Out-Null;
|
|
}
|
|
}
|
|
|
|
foreach ($calc in $AverageCalc.Keys) {
|
|
if ($AverageCalc[$calc].Count -ne 0) {
|
|
$AverageValue = ($AverageCalc[$calc].Sum / $AverageCalc[$calc].Count);
|
|
[string]$MetricName = Format-IcingaPerfDataLabel (
|
|
[string]::Format('{0}_{1}', $HashIndex, $AverageCalc[$calc].Interval)
|
|
);
|
|
|
|
Add-IcingaHashtableItem `
|
|
-Hashtable $global:Icinga.CheckData[$CheckCommand]['average'] `
|
|
-Key $MetricName -Value $AverageValue -Override | Out-Null;
|
|
}
|
|
|
|
$AverageCalc[$calc].Sum = 0;
|
|
$AverageCalc[$calc].Count = 0;
|
|
}
|
|
}
|
|
|
|
# Flush data we no longer require in our cache to free memory
|
|
[array]$CheckStores = $global:Icinga.CheckData[$CheckCommand]['results'].Keys;
|
|
|
|
foreach ($CheckStore in $CheckStores) {
|
|
[string]$CheckKey = $CheckStore;
|
|
[array]$CheckTimeStamps = $global:Icinga.CheckData[$CheckCommand]['results'][$CheckKey].Keys;
|
|
|
|
foreach ($TimeSample in $CheckTimeStamps) {
|
|
if (($UnixTime - $MaxTimeInSeconds) -gt [int]$TimeSample) {
|
|
Remove-IcingaHashtableItem -Hashtable $global:Icinga.CheckData[$CheckCommand]['results'][$CheckKey] -Key ([string]$TimeSample);
|
|
}
|
|
}
|
|
}
|
|
|
|
Set-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult' -KeyName $CheckCommand -Value $global:Icinga.CheckData[$CheckCommand]['average'];
|
|
# Write collected metrics to disk in case we reload the daemon. We will load them back into the module after reload then
|
|
Set-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult_store' -KeyName $CheckCommand -Value $PerfCache;
|
|
} catch {
|
|
# Just for debugging. Not required in production or usable at all
|
|
$ErrMsg = $_.Exception.Message;
|
|
Write-IcingaConsoleError 'Failed to handle check result processing: {0}' -Objects $ErrMsg;
|
|
}
|
|
|
|
# Cleanup the error stack and remove not required data
|
|
$Error.Clear();
|
|
|
|
# Always ensure our check data is cleared regardless of possible
|
|
# exceptions which might occur
|
|
Get-IcingaCheckSchedulerPerfData | Out-Null;
|
|
Get-IcingaCheckSchedulerPluginOutput | Out-Null;
|
|
|
|
$PassedTime = 0;
|
|
$SortedResult.Clear();
|
|
$PerfCache.Clear();
|
|
}
|
|
|
|
$PassedTime += 1;
|
|
Start-Sleep -Seconds 1;
|
|
# Force PowerShell to call the garbage collector to free memory
|
|
[System.GC]::Collect();
|
|
}
|
|
};
|
|
|
|
New-IcingaThreadInstance -Name $ThreadName -ThreadPool $IcingaDaemonData.IcingaThreadPool.ServiceCheckPool -ScriptBlock $ScriptBlock -Arguments @( $global:IcingaDaemonData, $CheckCommand, $Arguments, $Interval, $TimeIndexes, $CheckId ) -Start;
|
|
}
|
|
|
|
function Unregister-IcingaServiceCheck()
|
|
{
|
|
param(
|
|
[string]$ServiceId
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($ServiceId)) {
|
|
throw 'Please specify a Service Id';
|
|
}
|
|
|
|
$Path = [string]::Format('BackgroundDaemon.RegisteredServices.{0}', $ServiceId);
|
|
|
|
Remove-IcingaPowerShellConfig -Path $Path;
|
|
|
|
Write-IcingaConsolePlain 'Icinga Service Check has been configured';
|
|
}
|
|
|
|
function Get-IcingaHelpThresholds()
|
|
{
|
|
param (
|
|
$Value,
|
|
$Warning,
|
|
$Critical
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($Value) -eq $FALSE) {
|
|
$ExampleCheck = New-IcingaCheck -Name 'Example' -Value $Value;
|
|
$ExampleCheck.WarnOutOfRange($Warning).CritOutOfRange($Critical) | Out-Null;
|
|
|
|
return (New-IcingaCheckResult -Check $ExampleCheck -Compile);
|
|
}
|
|
|
|
Write-IcingaConsolePlain
|
|
'
|
|
Icinga is providing a basic handling for thresholds to make it easier to check if certain values of metrics should rise an event or not.
|
|
By default, you are always fine to specify simple numeric values for thresholds throughout the entire Check-Plugins.
|
|
|
|
#####################
|
|
|
|
-Warning 60
|
|
-Critical 90
|
|
|
|
This example will always raise an event, in case the value is below 0. On the other hand, it will raise
|
|
Warning, if the value is above 60 and
|
|
Critical, if the value is above 90.
|
|
|
|
Example: Get-IcingaHelpThresholds -Value 40 -Warning 60 -Critical 90; #This will return Ok
|
|
Get-IcingaHelpThresholds -Value 70 -Warning 60 -Critical 90; #This will return Warning
|
|
|
|
There is however a smart way available, to check for ranges of metric values which are explained below.
|
|
|
|
#####################
|
|
|
|
Between Range
|
|
-Warning "30:50"
|
|
|
|
This configuration will check if a value is within the specified range. In this example it would return Ok, whenver the
|
|
value is >= 30 and <= 50
|
|
|
|
Example: Get-IcingaHelpThresholds -Value 40 -Warning "30:50" -Critical "10:70"; #This will return Ok
|
|
Get-IcingaHelpThresholds -Value 20 -Warning "30:50" -Critical "10:70"; #This will return Warning
|
|
Get-IcingaHelpThresholds -Value 5 -Warning "30:50" -Critical "10:70"; #This will return Critical
|
|
|
|
#####################
|
|
|
|
Outside Range
|
|
-Warning "@40:70"
|
|
|
|
The exact opposite of the between range. Simply write an @ before your range and it will return Ok only, if the value is
|
|
outside the range. In this case, it will only return Ok if the value is <= 40 and >= 70
|
|
|
|
Example: Get-IcingaHelpThresholds -Value 10 -Warning "@20:90" -Critical "@40:60"; #This will return Ok
|
|
Get-IcingaHelpThresholds -Value 20 -Warning "@20:90" -Critical "@40:60"; #This will return Warning
|
|
Get-IcingaHelpThresholds -Value 50 -Warning "@20:90" -Critical "@40:60"; #This will return Critical
|
|
|
|
#####################
|
|
|
|
Above value
|
|
-Warning "50:"
|
|
|
|
A threshold followed by a : will always return Ok in case the value is above the configured start value. In this case it will
|
|
always return Ok as long as the value itself is above 50
|
|
|
|
Example: Get-IcingaHelpThresholds -Value 100 -Warning "90:" -Critical "50:"; #This will return Ok
|
|
Get-IcingaHelpThresholds -Value 60 -Warning "90:" -Critical "50:"; #This will return Warning
|
|
Get-IcingaHelpThresholds -Value 10 -Warning "90:" -Critical "50:"; #This will return Critical
|
|
|
|
#####################
|
|
|
|
Below value
|
|
-Warning "~:40"
|
|
|
|
Like the above value, you can also configure a threshold to require to be lower then a certain value. In this example, every value
|
|
below 40 will return Ok
|
|
|
|
Example: Get-IcingaHelpThresholds -Value 20 -Warning "~:40" -Critical "~:70"; #This will return Ok
|
|
Get-IcingaHelpThresholds -Value 60 -Warning "~:40" -Critical "~:70"; #This will return Warning
|
|
Get-IcingaHelpThresholds -Value 90 -Warning "~:40" -Critical "~:70"; #This will return Critical
|
|
|
|
#####################
|
|
|
|
You can play around yourself with this by using this Cmdlet with different values and -Warning / -Critical thresholds:
|
|
|
|
Get-IcingaHelpThresholds -Value <value> -Warning <warning> -Critical <critical>;
|
|
';
|
|
}
|
|
|
|
<#
|
|
# 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]$IcingaExitCode = @{
|
|
Ok = 0;
|
|
Warning = 1;
|
|
Critical = 2;
|
|
Unknown = 3;
|
|
};
|
|
|
|
[hashtable]$IcingaExitCodeText = @{
|
|
0 = '[OK]';
|
|
1 = '[WARNING]';
|
|
2 = '[CRITICAL]';
|
|
3 = '[UNKNOWN]';
|
|
};
|
|
|
|
[hashtable]$IcingaExitCodeColor = @{
|
|
0 = 'Green';
|
|
1 = 'Yellow';
|
|
2 = 'Red';
|
|
3 = 'Magenta';
|
|
};
|
|
|
|
[hashtable]$IcingaMeasurementUnits = @{
|
|
's' = 'seconds';
|
|
'ms' = 'milliseconds';
|
|
'us' = 'microseconds';
|
|
'%' = 'percent';
|
|
'B' = 'bytes';
|
|
'KB' = 'Kilobytes';
|
|
'MB' = 'Megabytes';
|
|
'GB' = 'Gigabytes';
|
|
'TB' = 'Terabytes';
|
|
'c' = 'counter';
|
|
'Kbit' = 'Kilobit';
|
|
'Mbit' = 'Megabit';
|
|
'Gbit' = 'Gigabit';
|
|
'Tbit' = 'Terabit';
|
|
'Pbit' = 'Petabit';
|
|
'Ebit' = 'Exabit';
|
|
'Zbit' = 'Zettabit';
|
|
'Ybit' = 'Yottabit';
|
|
};
|
|
|
|
<##################################################################################################
|
|
################# Service Enums ##################################################################
|
|
##################################################################################################>
|
|
|
|
[hashtable]$ServiceStartupTypeName = @{
|
|
0 = 'Boot';
|
|
1 = 'System';
|
|
2 = 'Automatic';
|
|
3 = 'Manual';
|
|
4 = 'Disabled';
|
|
5 = 'Unknown'; # Custom
|
|
}
|
|
|
|
[hashtable]$ServiceWmiStartupType = @{
|
|
'Boot' = 0;
|
|
'System' = 1;
|
|
'Auto' = 2;
|
|
'Manual' = 3;
|
|
'Disabled' = 4;
|
|
'Unknown' = 5; # Custom
|
|
}
|
|
|
|
<#
|
|
# Once we defined a new enum hashtable above, simply add it to this list
|
|
# to make it available within the entire module.
|
|
#
|
|
# Example usage:
|
|
# $IcingaEnums.IcingaExitCode.Ok
|
|
#>
|
|
if ($null -eq $IcingaEnums) {
|
|
[hashtable]$IcingaEnums = @{
|
|
IcingaExitCode = $IcingaExitCode;
|
|
IcingaExitCodeText = $IcingaExitCodeText;
|
|
IcingaExitCodeColor = $IcingaExitCodeColor;
|
|
IcingaMeasurementUnits = $IcingaMeasurementUnits;
|
|
#services
|
|
ServiceStartupTypeName = $ServiceStartupTypeName;
|
|
ServiceWmiStartupType = $ServiceWmiStartupType;
|
|
}
|
|
}
|
|
|
|
Export-ModuleMember -Variable @( 'IcingaEnums' );
|
|
|
|
[hashtable]$TestIcingaWindowsInfo = @{
|
|
'Ok' = 1;
|
|
'EmptyClass' = 2;
|
|
'PermissionError' = 4;
|
|
'ObjectNotFound' = 8;
|
|
'InvalidNameSpace' = 16;
|
|
'UnhandledException' = 32;
|
|
'NotSpecified' = 64;
|
|
'CimNotInstalled' = 128;
|
|
}
|
|
|
|
[hashtable]$TestIcingaWindowsInfoText = @{
|
|
1 = 'Everything is fine.';
|
|
2 = 'No class specified to check';
|
|
4 = 'Unable to query data using the given WMI-Class. You are either missing permissions or the service is not running properly';
|
|
8 = 'The specified WMI Class could not be found in the specified NameSpace.';
|
|
16 = 'No namespace with the specified name could be found on this system.';
|
|
32 = 'Windows unhandled exception is thrown. Please enable frame DebugMode for information.';
|
|
64 = 'Either the service has been stopped or you are not authorized to access the service.';
|
|
128 = 'The Cmdlet Get-CimClass is not available on your system.';
|
|
}
|
|
|
|
[hashtable]$TestIcingaWindowsInfoExceptionType = @{
|
|
1 = 'OK';
|
|
2 = 'EmptyClass';
|
|
4 = 'PermissionError';
|
|
8 = 'ObjectNotFound';
|
|
16 = 'InvalidNameSpace';
|
|
32 = 'UnhandledException';
|
|
64 = 'NotSpecified';
|
|
128 = 'CimNotInstalled';
|
|
}
|
|
|
|
[hashtable]$TestIcingaWindowsInfoEnums = @{
|
|
TestIcingaWindowsInfo = $TestIcingaWindowsInfo;
|
|
TestIcingaWindowsInfoText = $TestIcingaWindowsInfoText;
|
|
TestIcingaWindowsInfoExceptionType = $TestIcingaWindowsInfoExceptionType;
|
|
}
|
|
|
|
Export-ModuleMember -Variable @( 'TestIcingaWindowsInfoEnums' );
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Tests if a provided command is available on the system and exists
|
|
the shell with an Unknown error and a message. Required to properly
|
|
handle Icinga checks and possible error displaying inside Icinga Web 2
|
|
.DESCRIPTION
|
|
Tests if a provided command is available on the system and exists
|
|
the shell with an Unknown error and a message. Required to properly
|
|
handle Icinga checks and possible error displaying inside Icinga Web 2
|
|
.FUNCTIONALITY
|
|
Tests if a provided command is available on the system and exists
|
|
the shell with an Unknown error and a message. Required to properly
|
|
handle Icinga checks and possible error displaying inside Icinga Web 2
|
|
.EXAMPLE
|
|
PS>Exit-IcingaPluginNotInstalled -Command 'Invoke-IcingaCheckCPU';
|
|
.PARAMETER Command
|
|
The name of the check command to test for
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Exit-IcingaPluginNotInstalled()
|
|
{
|
|
param (
|
|
[string]$Command
|
|
);
|
|
|
|
$PowerShellModule = Get-Module 'icinga-powershell-*' -ListAvailable |
|
|
ForEach-Object {
|
|
foreach ($cmd in $_.ExportedCommands.Values) {
|
|
if ($Command.ToLower() -eq $cmd.Name.ToLower()) {
|
|
return $cmd.Path;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($PowerShellModule) -eq $FALSE) {
|
|
try {
|
|
Import-Module $PowerShellModule -ErrorAction Stop;
|
|
} catch {
|
|
$ExMsg = $_.Exception.Message;
|
|
Exit-IcingaThrowException -CustomMessage 'Module not loaded' -ExceptionType 'Configuration' -ExceptionThrown $ExMsg -Force;
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Command)) {
|
|
Exit-IcingaThrowException -CustomMessage 'Null-Command' -ExceptionType 'Configuration' -ExceptionThrown $IcingaExceptions.Configuration.PluginNotAssigned -Force;
|
|
}
|
|
|
|
if ($null -eq (Get-Command $Command -ErrorAction SilentlyContinue)) {
|
|
Exit-IcingaThrowException -CustomMessage $Command -ExceptionType 'Configuration' -ExceptionThrown $IcingaExceptions.Configuration.PluginNotInstalled -Force;
|
|
}
|
|
}
|
|
|
|
function Exit-IcingaThrowCritical()
|
|
{
|
|
param (
|
|
[string]$Message = '',
|
|
[string]$FilterString = $null,
|
|
[string]$SearchString = $null,
|
|
[switch]$Force = $FALSE
|
|
);
|
|
|
|
if ($Force -eq $FALSE) {
|
|
if ([string]::IsNullOrEmpty($FilterString) -Or [string]::IsNullOrEmpty($SearchString)) {
|
|
return;
|
|
}
|
|
|
|
if ($FilterString -NotLike "*$SearchString*") {
|
|
return;
|
|
}
|
|
}
|
|
|
|
[string]$OutputMessage = [string]::Format(
|
|
'[CRITICAL] {0}',
|
|
$Message
|
|
);
|
|
|
|
Set-IcingaInternalPluginExitCode -ExitCode $IcingaEnums.IcingaExitCode.Critical;
|
|
Set-IcingaInternalPluginException -PluginException $OutputMessage;
|
|
|
|
if ($null -eq $global:IcingaDaemonData -Or $global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE) {
|
|
Write-IcingaConsolePlain $OutputMessage;
|
|
exit $IcingaEnums.IcingaExitCode.Critical;
|
|
}
|
|
}
|
|
|
|
function Exit-IcingaThrowException()
|
|
{
|
|
param(
|
|
[string]$InputString,
|
|
[string]$StringPattern,
|
|
[string]$CustomMessage,
|
|
$ExceptionThrown,
|
|
[ValidateSet('Permission', 'Input', 'Configuration', 'Connection', 'Unhandled', 'Custom')]
|
|
[string]$ExceptionType = 'Unhandled',
|
|
[hashtable]$ExceptionList = @{ },
|
|
[string]$KnowledgeBaseId,
|
|
[switch]$Force
|
|
);
|
|
|
|
if ($Force -eq $FALSE) {
|
|
if ($null -eq $InputString -Or [string]::IsNullOrEmpty($InputString)) {
|
|
return;
|
|
}
|
|
|
|
if (-Not $InputString.Contains($StringPattern)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ($null -eq $ExceptionList -Or $ExceptionList.Count -eq 0) {
|
|
$ExceptionList = $IcingaExceptions;
|
|
}
|
|
|
|
$ExceptionMessageLib = $null;
|
|
$ExceptionTypeString = '';
|
|
|
|
switch ($ExceptionType) {
|
|
'Permission' {
|
|
$ExceptionTypeString = 'Permission';
|
|
$ExceptionMessageLib = $ExceptionList.Permission;
|
|
};
|
|
'Input' {
|
|
$ExceptionTypeString = 'Invalid Input';
|
|
$ExceptionMessageLib = $ExceptionList.Inputs;
|
|
};
|
|
'Configuration' {
|
|
$ExceptionTypeString = 'Invalid Configuration';
|
|
$ExceptionMessageLib = $ExceptionList.Configuration;
|
|
};
|
|
'Connection' {
|
|
$ExceptionTypeString = 'Connection error';
|
|
$ExceptionMessageLib = $ExceptionList.Connection;
|
|
};
|
|
'Unhandled' {
|
|
$ExceptionTypeString = 'Unhandled';
|
|
};
|
|
'Custom' {
|
|
$ExceptionTypeString = 'Custom';
|
|
};
|
|
}
|
|
|
|
[string]$ExceptionName = '';
|
|
[string]$ExceptionIWKB = $KnowledgeBaseId;
|
|
|
|
if ($null -ne $ExceptionMessageLib) {
|
|
foreach ($definedError in $ExceptionMessageLib.Keys) {
|
|
if ($ExceptionMessageLib.$definedError -eq $ExceptionThrown) {
|
|
$ExceptionName = $definedError;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ($null -eq $ExceptionMessageLib -Or [string]::IsNullOrEmpty($ExceptionName)) {
|
|
$ExceptionName = [string]::Format('{0} Exception', $ExceptionTypeString);
|
|
if ([string]::IsNullOrEmpty($InputString)) {
|
|
$InputString = $ExceptionThrown;
|
|
}
|
|
$ExceptionThrown = [string]::Format(
|
|
'{0} exception occured:{1}{2}',
|
|
$ExceptionTypeString,
|
|
"`r`n",
|
|
$InputString
|
|
);
|
|
}
|
|
|
|
if ($ExceptionThrown -is [hashtable]) {
|
|
$ExceptionIWKB = $ExceptionThrown.IWKB;
|
|
$ExceptionThrown = $ExceptionThrown.Message;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ExceptionIWKB) -eq $FALSE) {
|
|
$ExceptionIWKB = [string]::Format(
|
|
'{0}{0}Further details can be found on the Icinga for Windows Knowledge base: https://icinga.com/docs/windows/latest/doc/knowledgebase/{1}',
|
|
(New-IcingaNewLine),
|
|
$ExceptionIWKB
|
|
);
|
|
}
|
|
|
|
$OutputMessage = '{0}: Icinga {6} Error was thrown: {4}: {5}{2}{2}{3}{1}';
|
|
if ([string]::IsNullOrEmpty($CustomMessage) -eq $TRUE) {
|
|
$OutputMessage = '{0}: Icinga {6} Error was thrown: {4}{2}{2}{3}{5}{1}';
|
|
}
|
|
|
|
$OutputMessage = [string]::Format(
|
|
$OutputMessage,
|
|
$IcingaEnums.IcingaExitCodeText.($IcingaEnums.IcingaExitCode.Unknown),
|
|
$ExceptionIWKB,
|
|
(New-IcingaNewLine),
|
|
$ExceptionThrown,
|
|
$ExceptionName,
|
|
$CustomMessage,
|
|
$ExceptionTypeString
|
|
);
|
|
|
|
Set-IcingaInternalPluginExitCode -ExitCode $IcingaEnums.IcingaExitCode.Unknown;
|
|
Set-IcingaInternalPluginException -PluginException $OutputMessage;
|
|
|
|
if ($null -eq $global:IcingaDaemonData -Or $global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE) {
|
|
Write-IcingaConsolePlain $OutputMessage;
|
|
exit $IcingaEnums.IcingaExitCode.Unknown;
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
This function returns the HRESULT unique value thrown by the last exception
|
|
.DESCRIPTION
|
|
This function returns the HRESULT unique value thrown by the last exception
|
|
.OUTPUTS
|
|
System.String
|
|
#>
|
|
function Get-IcingaLastExceptionId()
|
|
{
|
|
if ([string]::IsNullOrEmpty($Error)) {
|
|
return '';
|
|
}
|
|
|
|
[string]$ExceptionId = ([string]($Error.FullyQualifiedErrorId)).Split(',')[0].Split(' ')[1];
|
|
$Error.Clear();
|
|
|
|
return $ExceptionId;
|
|
}
|
|
|
|
<#
|
|
# 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]$Permission = @{
|
|
PerformanceCounter = 'A Plugin failed to fetch Performance Counter information. This may be caused when the used Service User is not permitted to access these information. To fix this, please add the User the Icinga Agent is running on into the "Performance Monitor Users" group and restart the service.';
|
|
CacheFolder = "A plugin failed to write new data into the configured cache directory. Please update the permissions of this folder to allow write access for the user the Icinga Service is running with or use another folder as cache directory.";
|
|
CimInstance = @{
|
|
'Message' = 'The user you are running this command as does not have permission to access the requested Cim-Object. To fix this, please add the user the Agent is running with to the "Remote Management Users" groups and grant access to the WMI branch for the Class/Namespace mentioned above and add the permission "Remote enable".';
|
|
'IWKB' = 'IWKB000001';
|
|
}
|
|
WMIObject = @{
|
|
'Message' = 'The user you are running this command as does not have permission to access the requested Wmi-Object. To fix this, please add the user the Agent is running with to the "Remote Management Users" groups and grant access to the WMI branch for the Class/Namespace mentioned above and add the permission "Remote enable".';
|
|
'IWKB' = 'IWKB000001';
|
|
}
|
|
WindowsUpdate = @{
|
|
'Message' = 'The user you are running this command as does not have permission to access the Windows Update ComObject "Microsoft.Update.Session".';
|
|
'IWKB' = 'IWKB000006';
|
|
}
|
|
};
|
|
|
|
[hashtable]$Inputs = @{
|
|
PerformanceCounter = 'A plugin failed to fetch Performance Counter information. Please ensure the counter is written properly and available on your system.';
|
|
EventLogLogName = 'Failed to fetch EventLog information. Please specify a valid LogName.';
|
|
EventLog = 'Failed to fetch EventLog information. Please check your inputs for EntryTypes and other categories and try again.';
|
|
ConversionUnitMissing = 'Unable to parse input value. You have to add an unit to your input value. Example: "10GB". Allowed units are: "B, KB, MB, GB, TB, PB, KiB, MiB, GiB, TiB, PiB".';
|
|
MultipleUnitUsage = 'Failed to convert your Icinga threshold units as you were trying to convert values with a different type of unit category. This feature only supports the conversion of one unit category. For example you can not convert 20MB:10d in the same call, as size and time units are not compatible.';
|
|
CimClassNameUnknown = 'The provided class name you try to fetch with Get-CimInstance is not known on this system.';
|
|
WmiObjectClassUnknown = 'The provided class name you try to fetch with Get-WmiObject is not known on this system.';
|
|
MSSQLCredentialHandling = 'The connection to MSSQL was not possible because your login credential was not correct.';
|
|
MSSQLCommandMissing = 'Failed to build a SQL query'
|
|
};
|
|
|
|
[hashtable]$Configuration = @{
|
|
PluginArgumentConflict = 'Your plugin argument configuration is causing a conflict. Mostly this error is caused by missmatching configurations by enabling multiple switch arguments which are resulting in a conflicting configuration for the plugin.';
|
|
PluginArgumentMissing = 'Your plugin argument configuration is missing mandatory arguments. This error is caused when mandatory or required arguments are missing from a plugin call and the operation is unable to process without them.';
|
|
PluginNotInstalled = 'The plugin assigned to this service check seems not to be installed on this machine. Please review your service check configuration for spelling errors and check if the plugin is installed and executable on this machine by PowerShell.';
|
|
PluginNotAssigned = 'Your check for this service could not be processed because it seems like no valid Cmdlet was assigned to the check command. Please review your check command to ensure that a valid Cmdlet is assigned and executed by a PowerShell call.';
|
|
EventLogNotInstalled = 'Your Icinga PowerShell Framework has been executed by an unprivileged user before it was properly installed. The Windows EventLog application could not be registered because the current user has insufficient permissions. Please log into the machine and run "Use-Icinga" once from an administrative shell to complete the setup process. Once done this error should vanish.';
|
|
PerfCounterCategoryMissing = 'The specified Performance Counter category was not found on this system. This could either be a configuration error on your local Windows machine or a wrong usage of the plugin. Please check on different Windows machines if this issue persis. In case it only occurs on certain machines it is likely that the counter is simply not present and the plugin can not be processed.';
|
|
}
|
|
|
|
[hashtable]$Connection = @{
|
|
MSSQLConnectionError = 'Could not open a connection to SQL Server. This failure may be caused by the fact that under the default settings SQL Server does not allow remote connections or the host is unreachable.';
|
|
}
|
|
|
|
<#
|
|
# Once we defined a new enum hashtable above, simply add it to this list
|
|
# to make it available within the entire module.
|
|
#
|
|
# Example usage:
|
|
# $IcingaException.Inputs.PerformanceCounter
|
|
#>
|
|
|
|
if ($null -eq $IcingaExceptions) {
|
|
[hashtable]$IcingaExceptions = @{
|
|
Permission = $Permission;
|
|
Inputs = $Inputs;
|
|
Configuration = $Configuration;
|
|
Connection = $Connection;
|
|
}
|
|
}
|
|
|
|
Export-ModuleMember -Variable @( 'IcingaExceptions' );
|
|
|
|
function Compare-IcingaPluginThresholds()
|
|
{
|
|
param (
|
|
[string]$Threshold = $null,
|
|
$InputValue = $null,
|
|
$BaseValue = $null,
|
|
[switch]$Matches = $FALSE,
|
|
[switch]$NotMatches = $FALSE,
|
|
[switch]$DateTime = $FALSE,
|
|
[string]$Unit = '',
|
|
$ThresholdCache = $null,
|
|
[string]$CheckName = '',
|
|
[hashtable]$Translation = @{ },
|
|
$Minium = $null,
|
|
$Maximum = $null,
|
|
[switch]$IsBetween = $FALSE,
|
|
[switch]$IsLowerEqual = $FALSE,
|
|
[switch]$IsGreaterEqual = $FALSE,
|
|
[string]$TimeInterval = $null
|
|
);
|
|
|
|
# Fix possible numeric value comparison issues
|
|
$TestInput = Test-IcingaDecimal $InputValue;
|
|
$BaseInput = Test-IcingaDecimal $BaseValue;
|
|
|
|
if ($TestInput.Decimal) {
|
|
[decimal]$InputValue = [decimal]$TestInput.Value;
|
|
}
|
|
if ($BaseInput.Decimal) {
|
|
[decimal]$BaseValue = [decimal]$BaseInput.Value;
|
|
}
|
|
|
|
$IcingaThresholds = New-Object -TypeName PSObject;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'Value' -Value $InputValue;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'BaseValue' -Value $BaseValue;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'RawValue' -Value $InputValue;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'Unit' -Value $Unit;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'OriginalUnit' -Value $Unit;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'PerfUnit' -Value $Unit;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'IcingaThreshold' -Value $Threshold;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'RawThreshold' -Value $Threshold;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'CompareValue' -Value $null;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'MinRangeValue' -Value $null;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'MaxRangeValue' -Value $null;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'PercentValue' -Value '';
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'TimeSpan' -Value '';
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'InRange' -Value $TRUE;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'Message' -Value '';
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'Range' -Value '';
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'FullMessage' -Value (
|
|
[string]::Format('{0}', (ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $Unit -Value $InputValue)))
|
|
);
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'HeaderValue' -Value $IcingaThresholds.FullMessage;
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'ErrorMessage' -Value '';
|
|
$IcingaThresholds | Add-Member -MemberType NoteProperty -Name 'HasError' -Value $FALSE;
|
|
|
|
# In case we are using % values, we should set the BaseValue always to 100
|
|
if ($Unit -eq '%' -And $null -eq $BaseValue) {
|
|
$BaseValue = 100;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($TimeInterval) -eq $FALSE -And $null -ne $ThresholdCache) {
|
|
$TimeSeconds = ConvertTo-Seconds $TimeInterval;
|
|
$MinuteInterval = ([TimeSpan]::FromSeconds($TimeSeconds)).Minutes;
|
|
$CheckPerfDataLabel = [string]::Format('{0}_{1}', (Format-IcingaPerfDataLabel $CheckName), $MinuteInterval);
|
|
|
|
if ($null -ne $ThresholdCache.$CheckPerfDataLabel) {
|
|
$InputValue = $ThresholdCache.$CheckPerfDataLabel;
|
|
$InputValue = [math]::round([decimal]$InputValue, 6);
|
|
$IcingaThresholds.TimeSpan = $MinuteInterval;
|
|
} else {
|
|
$IcingaThresholds.HasError = $TRUE;
|
|
$IcingaThresholds.ErrorMessage = [string]::Format(
|
|
'The provided time interval "{0}" which translates to "{1}m" in your "-ThresholdInterval" argument does not exist',
|
|
$TimeInterval,
|
|
$MinuteInterval
|
|
);
|
|
|
|
return $IcingaThresholds;
|
|
}
|
|
} <#else {
|
|
# The symbol splitting our threshold from the time index value
|
|
# Examples:
|
|
# @20:40#15m
|
|
# ~:40#15m
|
|
# 40#15m
|
|
$TimeIndexSeparator = '#';
|
|
|
|
# In case we found a ~ not starting at the beginning, we should load the
|
|
# time index values created by our background daemon
|
|
# Allows us to specify something like "40:50#15"
|
|
if ($Threshold.Contains($TimeIndexSeparator) -And $null -ne $ThresholdCache) {
|
|
[int]$LastIndex = $Threshold.LastIndexOf($TimeIndexSeparator);
|
|
if ($LastIndex -ne 0) {
|
|
$TmpValue = $Threshold;
|
|
$Threshold = $TmpValue.Substring(0, $LastIndex);
|
|
$TimeIndex = $TmpValue.Substring($LastIndex + 1, $TmpValue.Length - $LastIndex - 1);
|
|
$TimeSeconds = ConvertTo-Seconds $TimeIndex;
|
|
$MinuteInterval = ([TimeSpan]::FromSeconds($TimeSeconds)).Minutes;
|
|
|
|
$CheckPerfDataLabel = [string]::Format('{0}_{1}', (Format-IcingaPerfDataLabel $CheckName), $MinuteInterval);
|
|
|
|
if ($null -ne $ThresholdCache.$CheckPerfDataLabel) {
|
|
$InputValue = $ThresholdCache.$CheckPerfDataLabel;
|
|
$InputValue = [math]::round([decimal]$InputValue, 6);
|
|
$IcingaThresholds.TimeSpan = $MinuteInterval;
|
|
} else {
|
|
$IcingaThresholds.HasError = $TRUE;
|
|
$IcingaThresholds.ErrorMessage = [string]::Format(
|
|
'The provided time interval "{0}{1}" which translates to "{2}m" in your "-ThresholdInterval" argument does not exist',
|
|
$TimeIndexSeparator,
|
|
$TimeIndex,
|
|
$MinuteInterval
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}#>
|
|
|
|
[bool]$UseDynamicPercentage = $FALSE;
|
|
[hashtable]$ConvertedThreshold = Convert-IcingaPluginThresholds -Threshold $Threshold;
|
|
$Minimum = (Convert-IcingaPluginThresholds -Threshold $Minimum).Value;
|
|
$Maximum = (Convert-IcingaPluginThresholds -Threshold $Maximum).Value;
|
|
[string]$ThresholdValue = $ConvertedThreshold.Value;
|
|
$IcingaThresholds.Unit = $ConvertedThreshold.Unit;
|
|
$IcingaThresholds.IcingaThreshold = $ThresholdValue;
|
|
$TempValue = (Convert-IcingaPluginThresholds -Threshold ([string]::Format('{0}{1}', $InputValue, $Unit)));
|
|
$InputValue = $TempValue.Value;
|
|
$TmpUnit = $TempValue.Unit;
|
|
$TestInput = Test-IcingaDecimal $InputValue;
|
|
|
|
if ($TestInput.Decimal) {
|
|
[decimal]$InputValue = [decimal]$TestInput.Value;
|
|
}
|
|
|
|
$IcingaThresholds.RawValue = $InputValue;
|
|
$TempValue = (Convert-IcingaPluginThresholds -Threshold ([string]::Format('{0}{1}', $BaseValue, $Unit)));
|
|
$BaseValue = $TempValue.Value;
|
|
$Unit = $TmpUnit;
|
|
$IcingaThresholds.PerfUnit = $Unit;
|
|
$IcingaThresholds.BaseValue = $BaseValue;
|
|
|
|
if ([string]::IsNullOrEmpty($IcingaThresholds.Unit)) {
|
|
$IcingaThresholds.Unit = $Unit;
|
|
}
|
|
|
|
# Calculate % value from base value of set
|
|
if ([string]::IsNullOrEmpty($BaseValue) -eq $FALSE -And $BaseValue -ne 0 -And $IcingaThresholds.Unit -eq '%') {
|
|
$InputValue = $InputValue / $BaseValue * 100;
|
|
$UseDynamicPercentage = $TRUE;
|
|
} elseif (([string]::IsNullOrEmpty($BaseValue) -eq $TRUE -Or $BaseValue -eq 0) -And $IcingaThresholds.Unit -eq '%') {
|
|
$IcingaThresholds.HasError = $TRUE;
|
|
$IcingaThresholds.ErrorMessage = 'This argument does not support the % unit';
|
|
|
|
return $IcingaThresholds;
|
|
}
|
|
|
|
# Always override our InputValue, case we might have change it
|
|
$IcingaThresholds.Value = $InputValue;
|
|
|
|
# If we simply provide a numeric number, we always check Value > Threshold or Value < 0
|
|
if ($Matches) {
|
|
# Checks if the InputValue Matches the Threshold
|
|
if ($InputValue -Like $ThresholdValue) {
|
|
$IcingaThresholds.InRange = $FALSE;
|
|
$IcingaThresholds.Message = 'is matching threshold';
|
|
$IcingaThresholds.Range = [string]::Format(
|
|
'{0}',
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
}
|
|
} elseif ($NotMatches) {
|
|
# Checks if the InputValue not Matches the Threshold
|
|
if ($InputValue -NotLike $ThresholdValue) {
|
|
$IcingaThresholds.InRange = $FALSE;
|
|
$IcingaThresholds.Message = 'is not matching threshold';
|
|
$IcingaThresholds.Range = [string]::Format(
|
|
'{0}',
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
}
|
|
} elseif ($DateTime) {
|
|
# Checks if the InputValue Is Inside our time value
|
|
|
|
try {
|
|
$DateTimeValue = 0;
|
|
[decimal]$TimeThreshold = 0;
|
|
$CurrentDate = $global:Icinga.CurrentDate;
|
|
$IcingaThresholds.Unit = '';
|
|
|
|
if ([string]::IsNullOrEmpty($InputValue) -eq $FALSE) {
|
|
$DateTimeValue = [DateTime]::FromFileTime($InputValue);
|
|
$IcingaThresholds.Value = $DateTimeValue.ToString('yyyy\/MM\/dd HH:mm:ss');
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ThresholdValue) -eq $FALSE) {
|
|
$TimeThreshold = (ConvertTo-Seconds -Value $Threshold);
|
|
$CurrentDate = $CurrentDate.AddSeconds($TimeThreshold);
|
|
$IcingaThresholds.IcingaThreshold = $CurrentDate.ToFileTimeUtc();
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($ThresholdValue) -eq $FALSE -And ($DateTimeValue -eq 0 -Or $DateTimeValue -lt $CurrentDate)) {
|
|
$IcingaThresholds.InRange = $FALSE;
|
|
$IcingaThresholds.Message = 'is lower than';
|
|
$IcingaThresholds.Range = [string]::Format(
|
|
'{0} ({1}{2})',
|
|
((Get-Date).ToString('yyyy\/MM\/dd HH:mm:ss')),
|
|
( $( if ($TimeThreshold -ge 0) { '+'; } else { ''; } )),
|
|
$Threshold
|
|
);
|
|
}
|
|
} catch {
|
|
$IcingaThresholds.ErrorMessage = [string]::Format(
|
|
'Invalid date time specified. Your InputValue "{0}" seems not be a valid date time or your provided Threshold "{1}" cannot be converted to seconds. Exception: {2}',
|
|
$InputValue,
|
|
$ThresholdValue,
|
|
$_.Exception.Message
|
|
);
|
|
$IcingaThresholds.HasError = $TRUE;
|
|
|
|
return $IcingaThresholds;
|
|
}
|
|
} elseif ($IsBetween) {
|
|
if ($InputValue -gt $Minium -And $InputValue -lt $Maximum) {
|
|
$IcingaThresholds.InRange = $FALSE;
|
|
$IcingaThresholds.Message = 'is inside range';
|
|
$IcingaThresholds.Range = [string]::Format(
|
|
'{0} and {1}',
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $Minium -OriginalUnit $IcingaThresholds.OriginalUnit)),
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $Maximum -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
}
|
|
|
|
if ($IcingaThresholds.Unit -eq '%') {
|
|
$IcingaThresholds.RawThreshold = [string]::Format(
|
|
'{0}% ({2}) {1}% ({3})',
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $Minium),
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $Maximum),
|
|
(Convert-IcingaPluginValueToString -Unit $Unit -Value $Minium -OriginalUnit $IcingaThresholds.OriginalUnit),
|
|
(Convert-IcingaPluginValueToString -Unit $Unit -Value $Maximum -OriginalUnit $IcingaThresholds.OriginalUnit)
|
|
);
|
|
$IcingaThresholds.PercentValue = [string]::Format(
|
|
'@{0}:{1}',
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $Minium),
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $Maximum)
|
|
);
|
|
}
|
|
} elseif ($IsLowerEqual) {
|
|
if ($InputValue -le $ThresholdValue) {
|
|
$IcingaThresholds.InRange = $FALSE;
|
|
$IcingaThresholds.Message = 'is lower equal than threshold';
|
|
$IcingaThresholds.Range = [string]::Format(
|
|
'{0}',
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
}
|
|
|
|
if ($IcingaThresholds.Unit -eq '%') {
|
|
$IcingaThresholds.RawThreshold = [string]::Format(
|
|
'{0}% ({1})',
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $ThresholdValue),
|
|
(Convert-IcingaPluginValueToString -Unit $Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit)
|
|
);
|
|
$IcingaThresholds.PercentValue = [string]::Format(
|
|
'{0}:',
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $ThresholdValue)
|
|
);
|
|
}
|
|
} elseif ($IsGreaterEqual) {
|
|
if ($InputValue -ge $ThresholdValue) {
|
|
$IcingaThresholds.InRange = $FALSE;
|
|
$IcingaThresholds.Message = 'is greater equal than threshold';
|
|
$IcingaThresholds.Range = [string]::Format(
|
|
'{0}',
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
}
|
|
|
|
if ($IcingaThresholds.Unit -eq '%') {
|
|
$IcingaThresholds.RawThreshold = [string]::Format(
|
|
'{0}% ({1})',
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $ThresholdValue),
|
|
(Convert-IcingaPluginValueToString -Unit $Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit)
|
|
);
|
|
|
|
$IcingaThresholds.PercentValue = [string]::Format(
|
|
'~:{0}',
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $ThresholdValue)
|
|
);
|
|
}
|
|
} else {
|
|
if ((Test-Numeric $ThresholdValue)) {
|
|
if ($InputValue -gt $ThresholdValue -Or $InputValue -lt 0) {
|
|
$IcingaThresholds.InRange = $FALSE;
|
|
$IcingaThresholds.Message = 'is greater than threshold';
|
|
$IcingaThresholds.Range = [string]::Format('{0}', (Convert-IcingaPluginValueToString -Unit $Unit -Value $ThresholdValue -OriginalUnit $IcingaThresholds.OriginalUnit));
|
|
}
|
|
|
|
$IcingaThresholds.CompareValue = [decimal]$ThresholdValue;
|
|
|
|
if ($IcingaThresholds.Unit -eq '%') {
|
|
$IcingaThresholds.RawThreshold = [string]::Format('{0}% ({1})', $ThresholdValue, (Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $ThresholdValue) -OriginalUnit $IcingaThresholds.OriginalUnit));
|
|
|
|
$IcingaThresholds.PercentValue = [string]::Format(
|
|
'{0}',
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $ThresholdValue)
|
|
);
|
|
}
|
|
} else {
|
|
# Transform our provided thresholds to split everything into single objects
|
|
[array]$thresholds = $ThresholdValue.Split(':');
|
|
[string]$rangeMin = $thresholds[0];
|
|
[string]$rangeMax = $thresholds[1];
|
|
[bool]$IsNegating = $rangeMin.Contains('@');
|
|
[string]$rangeMin = $rangeMin.Replace('@', '');
|
|
|
|
if ((Test-Numeric ($rangeMin.Replace('@', '').Replace('~', '')))) {
|
|
$IcingaThresholds.MinRangeValue = [decimal]($rangeMin.Replace('@', '').Replace('~', ''));
|
|
[decimal]$rangeMin = [decimal]$rangeMin;
|
|
}
|
|
if ((Test-Numeric $rangeMax)) {
|
|
$IcingaThresholds.MaxRangeValue = [decimal]$rangeMax;
|
|
[decimal]$rangeMax = [decimal]$rangeMax;
|
|
}
|
|
|
|
if ($IsNegating -eq $FALSE -And (Test-Numeric $rangeMin) -And (Test-Numeric $rangeMax)) {
|
|
# Handles: 30:40
|
|
# Error on: < 30 or > 40
|
|
# Ok on: between {30 .. 40}
|
|
|
|
if ($InputValue -lt $rangeMin -Or $InputValue -gt $rangeMax) {
|
|
$IcingaThresholds.InRange = $FALSE;
|
|
$IcingaThresholds.Message = 'is outside range';
|
|
$IcingaThresholds.Range = [string]::Format(
|
|
'{0} and {1}',
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $rangeMin -OriginalUnit $IcingaThresholds.OriginalUnit)),
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $rangeMax -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
}
|
|
|
|
if ($IcingaThresholds.Unit -eq '%') {
|
|
$IcingaThresholds.RawThreshold = [string]::Format(
|
|
'{0}% ({2}) and {1}% ({3})',
|
|
$rangeMin,
|
|
$rangeMax,
|
|
(Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMin -OriginalUnit $IcingaThresholds.OriginalUnit)),
|
|
(Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMax -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
|
|
$IcingaThresholds.PercentValue = [string]::Format(
|
|
'{0}:{1}',
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $rangeMin),
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $rangeMax)
|
|
);
|
|
}
|
|
} elseif ((Test-Numeric $rangeMin) -And [string]::IsNullOrEmpty($rangeMax) -eq $TRUE) {
|
|
# Handles: 20:
|
|
# Error on: 20:
|
|
# Ok on: between 20 .. ∞
|
|
|
|
if ($InputValue -lt $rangeMin) {
|
|
$IcingaThresholds.InRange = $FALSE;
|
|
$IcingaThresholds.Message = 'is lower than threshold';
|
|
$IcingaThresholds.Range = [string]::Format(
|
|
'{0}',
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $rangeMin -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
}
|
|
|
|
if ($IcingaThresholds.Unit -eq '%') {
|
|
$IcingaThresholds.RawThreshold = [string]::Format(
|
|
'{0}% ({1})',
|
|
$rangeMin,
|
|
(Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMin -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
|
|
$IcingaThresholds.PercentValue = [string]::Format(
|
|
'{0}:',
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $rangeMin)
|
|
);
|
|
}
|
|
} elseif ($rangeMin -eq '~' -And (Test-Numeric $rangeMax)) {
|
|
# Handles: ~:20
|
|
# Error on: > 20
|
|
# Ok on: between -∞ .. 20
|
|
|
|
if ($InputValue -gt $rangeMax) {
|
|
$IcingaThresholds.InRange = $FALSE;
|
|
$IcingaThresholds.Message = 'is greater than threshold';
|
|
$IcingaThresholds.Range = [string]::Format(
|
|
'{0}',
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $rangeMax -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
}
|
|
|
|
if ($IcingaThresholds.Unit -eq '%') {
|
|
$IcingaThresholds.RawThreshold = [string]::Format(
|
|
'{0}% ({1})',
|
|
$rangeMax,
|
|
(Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMax -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
|
|
$IcingaThresholds.PercentValue = [string]::Format(
|
|
'~:{0}',
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $rangeMax)
|
|
);
|
|
}
|
|
} elseif ($IsNegating -And (Test-Numeric $rangeMin) -And (Test-Numeric $rangeMax)) {
|
|
# Handles: @30:40
|
|
# Error on: ≥ 30 and ≤ 40
|
|
# Ok on: -∞ .. 29 and 41 .. ∞
|
|
|
|
if ($InputValue -ge $rangeMin -And $InputValue -le $rangeMax) {
|
|
$IcingaThresholds.InRange = $FALSE;
|
|
$IcingaThresholds.Message = 'is inside range';
|
|
$IcingaThresholds.Range = [string]::Format(
|
|
'{0} and {1}',
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $rangeMin -OriginalUnit $IcingaThresholds.OriginalUnit)),
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $rangeMax -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
}
|
|
|
|
if ($IcingaThresholds.Unit -eq '%') {
|
|
$IcingaThresholds.RawThreshold = [string]::Format(
|
|
'{0}% ({2}) {1}% ({3})',
|
|
$rangeMin,
|
|
$rangeMax,
|
|
(Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMin -OriginalUnit $IcingaThresholds.OriginalUnit)),
|
|
(Convert-IcingaPluginValueToString -Unit $Unit -Value (ConvertFrom-Percent -Value $BaseValue -Percent $rangeMax -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
|
|
$IcingaThresholds.PercentValue = [string]::Format(
|
|
'@{0}:{1}',
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $rangeMin),
|
|
(ConvertFrom-Percent -Value $BaseValue -Percent $rangeMax)
|
|
);
|
|
}
|
|
} else {
|
|
if ([string]::IsNullOrEmpty($Threshold) -eq $FALSE) {
|
|
# Unhandled
|
|
$IcingaThresholds.ErrorMessage = [string]::Format(
|
|
'Invalid range specified for threshold: InputValue "{0}" and Threshold {1}',
|
|
$InputValue,
|
|
$Threshold
|
|
);
|
|
$IcingaThresholds.HasError = $TRUE;
|
|
|
|
return $IcingaThresholds;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$PluginOutputMessage = New-Object -TypeName 'System.Text.StringBuilder';
|
|
|
|
[string]$PluginCurrentValue = [string]::Format(
|
|
'{0}',
|
|
(ConvertTo-IcingaPluginOutputTranslation -Translation $Translation -Value (Convert-IcingaPluginValueToString -Unit $IcingaThresholds.Unit -Value $IcingaThresholds.Value -OriginalUnit $IcingaThresholds.OriginalUnit))
|
|
);
|
|
|
|
[string]$PluginThresholdValue = $IcingaThresholds.Range;
|
|
|
|
if ($UseDynamicPercentage -And $Unit -ne '%') {
|
|
$IcingaThresholds.IcingaThreshold = $IcingaThresholds.PercentValue;
|
|
$PluginCurrentValue = [string]::Format('{0}% ({1})', ([string]([math]::Round($IcingaThresholds.Value, 2))).Replace(',', '.'), (Convert-IcingaPluginValueToString -Unit $Unit -Value $IcingaThresholds.RawValue -OriginalUnit $IcingaThresholds.OriginalUnit));
|
|
$PluginThresholdValue = $IcingaThresholds.RawThreshold;
|
|
}
|
|
|
|
$IcingaThresholds.HeaderValue = $PluginCurrentValue;
|
|
$PluginOutputMessage.Append($PluginCurrentValue) | Out-Null;
|
|
|
|
if ([string]::IsNullOrEmpty($IcingaThresholds.Message) -eq $FALSE) {
|
|
$PluginOutputMessage.Append(' ') | Out-Null;
|
|
$PluginOutputMessage.Append($IcingaThresholds.Message.Replace(',', '.')) | Out-Null;
|
|
|
|
if ([string]::IsNullOrEmpty($PluginThresholdValue) -eq $FALSE) {
|
|
$PluginOutputMessage.Append(' ') | Out-Null;
|
|
$PluginOutputMessage.Append(([string]$PluginThresholdValue).Replace(',', '.')) | Out-Null;
|
|
}
|
|
}
|
|
|
|
# Lets build our full message for adding on the value
|
|
$IcingaThresholds.FullMessage = $PluginOutputMessage.ToString();
|
|
|
|
return $IcingaThresholds;
|
|
}
|
|
|
|
function ConvertTo-IcingaPluginOutputTranslation()
|
|
{
|
|
param (
|
|
$Value = $null,
|
|
[hashtable]$Translation = @{ }
|
|
);
|
|
|
|
if ($null -eq $Value) {
|
|
return 'Nothing';
|
|
}
|
|
|
|
if ($null -eq $Translation -Or $Translation.Count -eq 0) {
|
|
return $Value;
|
|
}
|
|
|
|
[array]$TranslationKeys = $Translation.Keys;
|
|
[array]$TranslationValues = $Translation.Values;
|
|
[int]$Index = 0;
|
|
[bool]$FoundTranslation = $FALSE;
|
|
|
|
foreach ($entry in $TranslationKeys) {
|
|
if (([string]($Value)).ToLower() -eq ([string]($entry)).ToLower()) {
|
|
$FoundTranslation = $TRUE;
|
|
break;
|
|
}
|
|
$Index += 1;
|
|
}
|
|
|
|
if ($FoundTranslation -eq $FALSE) {
|
|
return $Value;
|
|
}
|
|
|
|
return $TranslationValues[$Index];
|
|
}
|
|
|
|
function Exit-IcingaExecutePlugin()
|
|
{
|
|
param (
|
|
[string]$Command = ''
|
|
);
|
|
|
|
Invoke-IcingaInternalServiceCall -Command $Command -Arguments $args;
|
|
|
|
try {
|
|
# Load the entire framework now, as we require to execute plugins locally
|
|
if ($null -eq $global:IcingaDaemonData) {
|
|
Use-Icinga;
|
|
}
|
|
|
|
Exit-IcingaPluginNotInstalled -Command $Command;
|
|
|
|
exit (& $Command @args);
|
|
} catch {
|
|
$ExMsg = $_.Exception.Message;
|
|
$StackTrace = $_.ScriptStackTrace;
|
|
$ExErrorId = $_.FullyQualifiedErrorId;
|
|
$ArgName = $_.Exception.ParameterName;
|
|
$ListArgs = $args;
|
|
|
|
if ($ExErrorId -Like "*ParameterArgumentTransformationError*" -And $ExMsg.Contains('System.Security.SecureString')) {
|
|
$ExMsg = [string]::Format(
|
|
'Cannot bind parameter {0}. Cannot convert the provided value for argument "{0}" of type "System.String" to type "System.Security.SecureString".',
|
|
$ArgName
|
|
);
|
|
|
|
$args.Clear();
|
|
$ListArgs = 'Hidden for security reasons';
|
|
}
|
|
|
|
Write-IcingaConsolePlain '[UNKNOWN] Icinga Exception: {0}{1}{1}CheckCommand: {2}{1}Arguments: {3}{1}{1}StackTrace:{1}{4}' -Objects $ExMsg, (New-IcingaNewLine), $Command, $ListArgs, $StackTrace;
|
|
exit 3;
|
|
}
|
|
}
|
|
|
|
function Get-IcingaThresholdCache()
|
|
{
|
|
param (
|
|
[string]$CheckCommand = $null
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($CheckCommand)) {
|
|
return $null;
|
|
}
|
|
|
|
if ($null -eq $Global:Icinga) {
|
|
return $null;
|
|
}
|
|
|
|
if ($Global:Icinga.ContainsKey('ThresholdCache') -eq $FALSE) {
|
|
return $null;
|
|
}
|
|
|
|
if ($Global:Icinga.ThresholdCache.ContainsKey($CheckCommand) -eq $FALSE) {
|
|
return $null;
|
|
}
|
|
|
|
return $Global:Icinga.ThresholdCache[$CheckCommand];
|
|
}
|
|
|
|
function New-IcingaCheck()
|
|
{
|
|
param(
|
|
[string]$Name = '',
|
|
$Value = $null,
|
|
$BaseValue = $null,
|
|
$Unit = '',
|
|
[string]$Minimum = '',
|
|
[string]$Maximum = '',
|
|
$ObjectExists = -1,
|
|
$Translation = $null,
|
|
[string]$LabelName = $null,
|
|
[switch]$NoPerfData = $FALSE
|
|
);
|
|
|
|
$IcingaCheck = New-IcingaCheckBaseObject;
|
|
|
|
$IcingaCheck.Name = $Name;
|
|
$IcingaCheck.__ObjectType = 'IcingaCheck';
|
|
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name 'Value' -Value $Value;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name 'BaseValue' -Value $BaseValue;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name 'Unit' -Value $Unit;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name 'Minimum' -Value $Minimum;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name 'Maximum' -Value $Maximum;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name 'ObjectExists' -Value $ObjectExists;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name 'Translation' -Value $Translation;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name 'LabelName' -Value $LabelName;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name 'NoPerfData' -Value $NoPerfData;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name '__WarningValue' -Value $null;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name '__CriticalValue' -Value $null;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name '__LockedState' -Value $FALSE;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name '__ThresholdObject' -Value $null;
|
|
$IcingaCheck | Add-Member -MemberType NoteProperty -Name '__TimeInterval' -Value $null;
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Force -Name 'Compile' -Value {
|
|
$this.__ValidateThresholdInput();
|
|
if ($null -eq $this.__ThresholdObject) {
|
|
$this.__CreateDefaultThresholdObject();
|
|
}
|
|
$this.__SetCheckOutput();
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Force -Name '__SetInternalTimeInterval' -Value {
|
|
$CallStack = Get-PSCallStack;
|
|
[bool]$FoundInterval = $FALSE;
|
|
|
|
foreach ($entry in $CallStack) {
|
|
if ($FoundInterval) {
|
|
break;
|
|
}
|
|
[string]$CheckCommand = $entry.Command;
|
|
if ($CheckCommand -eq $this.__CheckCommand) {
|
|
[string]$CheckArguments = $entry.Arguments.Replace('{', '').Replace('}', '');
|
|
[array]$SplitArgs = $CheckArguments.Split(',');
|
|
|
|
foreach ($SetArg in $SplitArgs) {
|
|
$SetArg = $SetArg.Replace(' ', '');
|
|
if ($FoundInterval) {
|
|
$this.__TimeInterval = $SetArg;
|
|
break;
|
|
}
|
|
if ($SetArg -eq '-ThresholdInterval') {
|
|
$FoundInterval = $TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Override shared function
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Force -Name '__GetHeaderOutputValue' -Value {
|
|
if ($null -eq $this.__ThresholdObject) {
|
|
return ''
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($this.__ThresholdObject.HeaderValue)) {
|
|
return '';
|
|
}
|
|
|
|
return (
|
|
[string]::Format(
|
|
' ({0})',
|
|
$this.__ThresholdObject.HeaderValue
|
|
)
|
|
)
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Force -Name '__CreateDefaultThresholdObject' -Value {
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$this.__ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
$this.__SetCheckState($this.__ThresholdObject, $IcingaEnums.IcingaExitCode.Ok);
|
|
}
|
|
|
|
# Override shared function
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Force -Name '__SetCheckOutput' -Value {
|
|
param ($PluginOutput);
|
|
|
|
if ($this.__InLockState()) {
|
|
return;
|
|
}
|
|
|
|
$PluginThresholds = '';
|
|
$TimeSpan = '';
|
|
$PluginThresholds = $this.__ThresholdObject.FullMessage;
|
|
|
|
if ([string]::IsNullOrEmpty($PluginOutput) -eq $FALSE) {
|
|
$PluginThresholds = $PluginOutput;
|
|
}
|
|
|
|
if ($null -ne $this.__ThresholdObject -And [string]::IsNullOrEmpty($this.__ThresholdObject.TimeSpan) -eq $FALSE) {
|
|
$TimeSpan = [string]::Format(
|
|
'{0}({1}m avg.)',
|
|
(&{ if ([string]::IsNullOrEmpty($PluginThresholds)) { return ''; } else { return ' ' } }),
|
|
$this.__ThresholdObject.TimeSpan
|
|
);
|
|
}
|
|
|
|
[bool]$AddColon = $TRUE;
|
|
|
|
if ([string]::IsNullOrEmpty($this.Name) -eq $FALSE -And $this.Name[$this.Name.Length - 1] -eq ':') {
|
|
$AddColon = $FALSE;
|
|
}
|
|
|
|
$this.__CheckOutput = [string]::Format(
|
|
'{0} {1}{2} {3}{4}',
|
|
$IcingaEnums.IcingaExitCodeText[$this.__CheckState],
|
|
$this.Name,
|
|
(&{ if ($AddColon) { return ':'; } else { return ''; } }),
|
|
$PluginThresholds,
|
|
$TimeSpan
|
|
);
|
|
|
|
$this.__SetPerformanceData();
|
|
}
|
|
|
|
# __GetTimeSpanThreshold(0, 'Core_30_20', 'Core_30')
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Force -Name '__GetTimeSpanThreshold' -Value {
|
|
param ($TimeSpanLabel, $Label);
|
|
|
|
[hashtable]$TimeSpans = @{
|
|
'Warning' = '';
|
|
'Critical' = '';
|
|
}
|
|
|
|
[string]$LabelName = (Format-IcingaPerfDataLabel $this.Name);
|
|
if ([string]::IsNullOrEmpty($this.LabelName) -eq $FALSE) {
|
|
$LabelName = $this.LabelName;
|
|
}
|
|
|
|
if ($Label -ne $LabelName) {
|
|
return $TimeSpans;
|
|
}
|
|
|
|
$TimeSpan = $TimeSpanLabel.Replace($Label, '').Replace('_', '');
|
|
|
|
if ($null -ne $this.__WarningValue -And [string]::IsNullOrEmpty($this.__WarningValue.TimeSpan) -eq $FALSE -And $this.__WarningValue.TimeSpan -eq $TimeSpan) {
|
|
$TimeSpans.Warning = $this.__WarningValue.IcingaThreshold;
|
|
}
|
|
if ($null -ne $this.__CriticalValue -And [string]::IsNullOrEmpty($this.__CriticalValue.TimeSpan) -eq $FALSE -And $this.__CriticalValue.TimeSpan -eq $TimeSpan) {
|
|
$TimeSpans.Critical = $this.__CriticalValue.IcingaThreshold;
|
|
}
|
|
|
|
return $TimeSpans;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__GetWarningThresholdObject' -Value {
|
|
return $this.__WarningValue;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__GetCriticalThresholdObject' -Value {
|
|
return $this.__CriticalValue;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__SetPerformanceData' -Value {
|
|
if ($null -eq $this.__ThresholdObject -Or $this.NoPerfData) {
|
|
return;
|
|
}
|
|
|
|
[string]$LabelName = (Format-IcingaPerfDataLabel $this.Name);
|
|
$value = ConvertTo-Integer -Value $this.__ThresholdObject.RawValue -NullAsEmpty;
|
|
$warning = '';
|
|
$critical = '';
|
|
|
|
# Set our threshold to nothing if we use time spans, as it would cause performance metrics to
|
|
# contain warning/critical values for everything, which is not correct
|
|
if ([string]::IsNullOrEmpty($this.__WarningValue.TimeSpan)) {
|
|
$warning = ConvertTo-Integer -Value $this.__WarningValue.IcingaThreshold -NullAsEmpty;
|
|
}
|
|
if ([string]::IsNullOrEmpty($this.__CriticalValue.TimeSpan)) {
|
|
$critical = ConvertTo-Integer -Value $this.__CriticalValue.IcingaThreshold -NullAsEmpty;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($this.LabelName) -eq $FALSE) {
|
|
$LabelName = $this.LabelName;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($this.Minimum) -And [string]::IsNullOrEmpty($this.Maximum)) {
|
|
if ($this.Unit -eq '%') {
|
|
$this.Minimum = '0';
|
|
$this.Maximum = '100';
|
|
} elseif ($null -ne $this.BaseValue) {
|
|
$this.Minimum = '0';
|
|
$this.Maximum = $this.__ThresholdObject.BaseValue;
|
|
}
|
|
|
|
if ($this.Value -gt $this.Maximum -And [string]::IsNullOrEmpty($this.Maximum) -eq $FALSE) {
|
|
$this.Maximum = $this.__ThresholdObject.RawValue;
|
|
}
|
|
}
|
|
|
|
$this.__CheckPerfData = @{
|
|
'label' = $LabelName;
|
|
'perfdata' = '';
|
|
'unit' = $this.__ThresholdObject.PerfUnit;
|
|
'value' = (Format-IcingaPerfDataValue $value);
|
|
'warning' = (Format-IcingaPerfDataValue $warning);
|
|
'critical' = (Format-IcingaPerfDataValue $critical);
|
|
'minimum' = (Format-IcingaPerfDataValue $this.Minimum);
|
|
'maximum' = (Format-IcingaPerfDataValue $this.Maximum);
|
|
'package' = $FALSE;
|
|
};
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__ValidateObject' -Value {
|
|
if ($null -eq $this.ObjectExists) {
|
|
$this.SetUnknown() | Out-Null;
|
|
$this.__SetCheckOutput('The object does not exist');
|
|
$this.__LockState();
|
|
}
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__LockState' -Value {
|
|
$this.__LockedState = $TRUE;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__InLockState' -Value {
|
|
return $this.__LockedState;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__ValidateUnit' -Value {
|
|
if ([string]::IsNullOrEmpty($this.Unit) -eq $FALSE -And (-Not $IcingaEnums.IcingaMeasurementUnits.ContainsKey($this.Unit))) {
|
|
$this.SetUnknown();
|
|
$this.__SetCheckOutput(
|
|
[string]::Format(
|
|
'Usage of invalid plugin unit "{0}". Allowed units are: {1}',
|
|
$this.Unit,
|
|
(($IcingaEnums.IcingaMeasurementUnits.Keys | Sort-Object name) -Join ', ')
|
|
)
|
|
);
|
|
|
|
$this.__LockState();
|
|
$this.unit = $null;
|
|
}
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__ConvertMinMax' -Value {
|
|
if ([string]::IsNullOrEmpty($this.Unit) -eq $FALSE) {
|
|
if ([string]::IsNullOrEmpty($this.Minimum) -eq $FALSE) {
|
|
$this.Minimum = (Convert-IcingaPluginThresholds -Threshold ([string]::Format('{0}{1}', $this.Minimum, $this.Unit))).Value;
|
|
}
|
|
if ([string]::IsNullOrEmpty($this.Maximum) -eq $FALSE) {
|
|
$this.Maximum = (Convert-IcingaPluginThresholds -Threshold ([string]::Format('{0}{1}', $this.Maximum, $this.Unit))).Value;
|
|
}
|
|
}
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__SetCurrentExecutionTime' -Value {
|
|
if ($null -eq $global:Icinga) {
|
|
$global:Icinga = @{ };
|
|
}
|
|
|
|
if ($global:Icinga.ContainsKey('CurrentDate') -eq $FALSE) {
|
|
$global:Icinga.Add('CurrentDate', (Get-Date));
|
|
return;
|
|
}
|
|
|
|
if ($null -ne $global:Icinga.CurrentDate) {
|
|
return;
|
|
}
|
|
|
|
$global:Icinga.CurrentDate = (Get-Date).ToUniversalTime();
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__AddCheckDataToCache' -Value {
|
|
|
|
# We only require this in case we are running as daemon
|
|
if ([string]::IsNullOrEmpty($this.__CheckCommand) -Or $global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE) {
|
|
return;
|
|
}
|
|
|
|
# If no check table has been created, do nothing
|
|
if ($null -eq $global:Icinga -Or $global:Icinga.ContainsKey('CheckData') -eq $FALSE) {
|
|
return;
|
|
}
|
|
|
|
if ($global:Icinga.CheckData.ContainsKey($this.__CheckCommand) -eq $FALSE) {
|
|
return;
|
|
}
|
|
|
|
# Fix possible error for identical time stamps due to internal exceptions
|
|
# and check execution within the same time slot because of this
|
|
[string]$TimeIndex = Get-IcingaUnixTime;
|
|
|
|
Add-IcingaHashtableItem -Hashtable $global:Icinga.CheckData[$this.__CheckCommand]['results'] -Key $this.Name -Value @{ } | Out-Null;
|
|
Add-IcingaHashtableItem -Hashtable $global:Icinga.CheckData[$this.__CheckCommand]['results'][$this.Name] -Key $TimeIndex -Value $this.Value -Override | Out-Null;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'SetOk' -Value {
|
|
param ([string]$Message, [bool]$Lock);
|
|
|
|
if ($this.__InLockState() -eq $FALSE) {
|
|
$this.__CheckState = $IcingaEnums.IcingaExitCode.Ok;
|
|
$this.__SetCheckOutput($Message);
|
|
}
|
|
|
|
if ($Lock) {
|
|
$this.__LockState();
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'SetWarning' -Value {
|
|
param ([string]$Message, [bool]$Lock);
|
|
|
|
if ($this.__InLockState() -eq $FALSE) {
|
|
$this.__CheckState = $IcingaEnums.IcingaExitCode.Warning;
|
|
$this.__SetCheckOutput($Message);
|
|
}
|
|
|
|
if ($Lock) {
|
|
$this.__LockState();
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'SetCritical' -Value {
|
|
param ([string]$Message, [bool]$Lock);
|
|
|
|
if ($this.__InLockState() -eq $FALSE) {
|
|
$this.__CheckState = $IcingaEnums.IcingaExitCode.Critical;
|
|
$this.__SetCheckOutput($Message);
|
|
}
|
|
|
|
if ($Lock) {
|
|
$this.__LockState();
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'SetUnknown' -Value {
|
|
param ([string]$Message, [bool]$Lock);
|
|
|
|
if ($this.__InLockState() -eq $FALSE) {
|
|
$this.__CheckState = $IcingaEnums.IcingaExitCode.Unknown;
|
|
$this.__SetCheckOutput($Message);
|
|
}
|
|
|
|
if ($Lock) {
|
|
$this.__LockState();
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__SetCheckState' -Value {
|
|
param ($ThresholdObject, $State);
|
|
|
|
if ($ThresholdObject.HasError) {
|
|
$this.SetUnknown() | Out-Null;
|
|
$this.__ThresholdObject = $ThresholdObject;
|
|
$this.__SetCheckOutput($this.__ThresholdObject.ErrorMessage);
|
|
$this.__LockState();
|
|
return;
|
|
}
|
|
|
|
if ($this.__InLockState()) {
|
|
return;
|
|
}
|
|
|
|
# In case no thresholds are set, always set the first value
|
|
if ($null -eq $this.__ThresholdObject) {
|
|
$this.__ThresholdObject = $ThresholdObject;
|
|
}
|
|
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
if ($this.__CheckState -lt $State) {
|
|
$this.__CheckState = $State;
|
|
$this.__ThresholdObject = $ThresholdObject;
|
|
}
|
|
}
|
|
|
|
$this.__SetCheckOutput();
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name '__GetBaseThresholdArguments' -Value {
|
|
return @{
|
|
'-InputValue' = $this.Value;
|
|
'-BaseValue' = $this.BaseValue;
|
|
'-Unit' = $this.Unit;
|
|
'-CheckName' = $this.__GetName();
|
|
'-ThresholdCache' = (Get-IcingaThresholdCache -CheckCommand $this.__CheckCommand);
|
|
'-Translation' = $this.Translation;
|
|
'-TimeInterval' = $this.__TimeInterval;
|
|
};
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnOutOfRange' -Value {
|
|
param ($Threshold);
|
|
|
|
if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Threshold) {
|
|
$this.WarnOutOfRange($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Threshold', $Threshold);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__WarningValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnDateTime' -Value {
|
|
param ($Threshold);
|
|
|
|
if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Threshold) {
|
|
$this.WarnDateTime($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Threshold', $Threshold);
|
|
$ThresholdArguments.Add('-DateTime', $TRUE);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__WarningValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfLike' -Value {
|
|
param ($Threshold);
|
|
|
|
if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Threshold) {
|
|
$this.WarnIfLike($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Threshold', $Threshold);
|
|
$ThresholdArguments.Add('-Matches', $TRUE);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__WarningValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfNotLike' -Value {
|
|
param ($Threshold);
|
|
|
|
if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Threshold) {
|
|
$this.WarnIfNotLike($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Threshold', $Threshold);
|
|
$ThresholdArguments.Add('-NotMatches', $TRUE);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__WarningValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfMatch' -Value {
|
|
param ($Threshold);
|
|
|
|
return $this.WarnIfLike($Threshold);
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfNotMatch' -Value {
|
|
param ($Threshold);
|
|
|
|
return $this.WarnIfNotLike($Threshold);
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritOutOfRange' -Value {
|
|
param ($Threshold);
|
|
|
|
if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Threshold) {
|
|
$this.CritOutOfRange($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Threshold', $Threshold);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__CriticalValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritDateTime' -Value {
|
|
param ($Threshold);
|
|
|
|
if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Threshold) {
|
|
$this.CritDateTime($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Threshold', $Threshold);
|
|
$ThresholdArguments.Add('-DateTime', $TRUE);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__CriticalValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfLike' -Value {
|
|
param ($Threshold);
|
|
|
|
if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Threshold) {
|
|
$this.CritIfLike($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Threshold', $Threshold);
|
|
$ThresholdArguments.Add('-Matches', $TRUE);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__CriticalValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfNotLike' -Value {
|
|
param ($Threshold);
|
|
|
|
if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Threshold) {
|
|
$this.CritIfNotLike($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Threshold', $Threshold);
|
|
$ThresholdArguments.Add('-NotMatches', $TRUE);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__CriticalValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfMatch' -Value {
|
|
param ($Threshold);
|
|
|
|
return $this.CritIfLike($Threshold);
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfNotMatch' -Value {
|
|
param ($Threshold);
|
|
|
|
return $this.CritIfNotLike($Threshold);
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfBetweenAndEqual' -Value {
|
|
param ($Min, $Max);
|
|
|
|
[string]$Threshold = [string]::Format('@{0}:{1}', $Min, $Max);
|
|
|
|
return $this.WarnOutOfRange($Threshold);
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfBetweenAndEqual' -Value {
|
|
param ($Min, $Max);
|
|
|
|
[string]$Threshold = [string]::Format('@{0}:{1}', $Min, $Max);
|
|
|
|
return $this.CritOutOfRange($Threshold);
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfLowerThan' -Value {
|
|
param ($Value);
|
|
|
|
if ($null -ne $Value -And $Value.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Value) {
|
|
$this.WarnIfLowerThan($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[string]$Threshold = [string]::Format('{0}:', $Value);
|
|
|
|
return $this.WarnOutOfRange($Threshold);
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfLowerThan' -Value {
|
|
param ($Value);
|
|
|
|
if ($null -ne $Value -And $Value.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Value) {
|
|
$this.CritIfLowerThan($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[string]$Threshold = [string]::Format('{0}:', $Value);
|
|
|
|
return $this.CritOutOfRange($Threshold);
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfGreaterThan' -Value {
|
|
param ($Value);
|
|
|
|
if ($null -ne $Value -And $Value.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Value) {
|
|
$this.WarnIfGreaterThan($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[string]$Threshold = [string]::Format('~:{0}', $Value);
|
|
|
|
return $this.WarnOutOfRange($Threshold);
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfGreaterThan' -Value {
|
|
param ($Value);
|
|
|
|
if ($null -ne $Value -And $Value.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Value) {
|
|
$this.CritIfGreaterThan($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[string]$Threshold = [string]::Format('~:{0}', $Value);
|
|
|
|
return $this.CritOutOfRange($Threshold);
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfBetween' -Value {
|
|
param ($Min, $Max);
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Minimum', $Min);
|
|
$ThresholdArguments.Add('-Maximum', $Max);
|
|
$ThresholdArguments.Add('-IsBetween', $TRUE);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__WarningValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfBetween' -Value {
|
|
param ($Min, $Max);
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Minimum', $Min);
|
|
$ThresholdArguments.Add('-Maximum', $Max);
|
|
$ThresholdArguments.Add('-IsBetween', $TRUE);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__CriticalValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfLowerEqualThan' -Value {
|
|
param ($Threshold);
|
|
|
|
if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Threshold) {
|
|
$this.WarnIfLowerEqualThan($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Threshold', $Threshold);
|
|
$ThresholdArguments.Add('-IsLowerEqual', $TRUE);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__WarningValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfLowerEqualThan' -Value {
|
|
param ($Threshold);
|
|
|
|
if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Threshold) {
|
|
$this.CritIfLowerEqualThan($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Threshold', $Threshold);
|
|
$ThresholdArguments.Add('-IsLowerEqual', $TRUE);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__CriticalValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'WarnIfGreaterEqualThan' -Value {
|
|
param ($Threshold);
|
|
|
|
if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Threshold) {
|
|
$this.WarnIfGreaterEqualThan($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Threshold', $Threshold);
|
|
$ThresholdArguments.Add('-IsGreaterEqual', $TRUE);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__WarningValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Warning);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Name 'CritIfGreaterEqualThan' -Value {
|
|
param ($Threshold);
|
|
|
|
if ($null -ne $Threshold -And $Threshold.GetType().BaseType.Name.ToLower() -eq 'array') {
|
|
foreach ($entry in $Threshold) {
|
|
$this.CritIfGreaterEqualThan($entry) | Out-Null;
|
|
|
|
# Break on first value causing a warning
|
|
if ($ThresholdObject.InRange -eq $FALSE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
[hashtable]$ThresholdArguments = $this.__GetBaseThresholdArguments();
|
|
$ThresholdArguments.Add('-Threshold', $Threshold);
|
|
$ThresholdArguments.Add('-IsGreaterEqual', $TRUE);
|
|
|
|
$ThresholdObject = Compare-IcingaPluginThresholds @ThresholdArguments;
|
|
|
|
$this.__CriticalValue = $ThresholdObject;
|
|
$this.__SetCheckState($ThresholdObject, $IcingaEnums.IcingaExitCode.Critical);
|
|
|
|
return $this;
|
|
}
|
|
|
|
$IcingaCheck | Add-Member -MemberType ScriptMethod -Force -Name '__ValidateThresholdInput' -Value {
|
|
if ($null -eq $this.__WarningValue -Or $null -eq $this.__CriticalValue) {
|
|
return;
|
|
}
|
|
|
|
[bool]$OutOfRange = $FALSE;
|
|
|
|
#Handles 20
|
|
if ($null -ne $this.__WarningValue.CompareValue -And $null -ne $this.__CriticalValue.CompareValue) {
|
|
if ($this.__WarningValue.CompareValue -gt $this.__CriticalValue.CompareValue) {
|
|
$OutOfRange = $TRUE;
|
|
}
|
|
}
|
|
|
|
# Handles: @30:40 and 30:40
|
|
# Never throw an "error" here, as these ranges can be dynamic
|
|
if ($null -ne $this.__WarningValue.MinRangeValue -And $null -ne $this.__CriticalValue.MinRangeValue -And $null -ne $this.__WarningValue.MaxRangeValue -And $null -ne $this.__CriticalValue.MaxRangeValue) {
|
|
return;
|
|
}
|
|
|
|
# Handles: 20:
|
|
if ($null -ne $this.__WarningValue.MinRangeValue -And $null -ne $this.__CriticalValue.MinRangeValue -And $null -eq $this.__WarningValue.MaxRangeValue -And $null -eq $this.__CriticalValue.MaxRangeValue) {
|
|
if ($this.__WarningValue.MinRangeValue -lt $this.__CriticalValue.MinRangeValue) {
|
|
$OutOfRange = $TRUE;
|
|
}
|
|
}
|
|
|
|
# Handles: ~:20
|
|
if ($null -eq $this.__WarningValue.MinRangeValue -And $null -eq $this.__CriticalValue.MinRangeValue -And $null -ne $this.__WarningValue.MaxRangeValue -And $null -ne $this.__CriticalValue.MaxRangeValue) {
|
|
if ($this.__WarningValue.MaxRangeValue -gt $this.__CriticalValue.MaxRangeValue) {
|
|
$OutOfRange = $TRUE;
|
|
}
|
|
}
|
|
|
|
if ($OutOfRange) {
|
|
$this.SetUnknown([string]::Format('Warning threshold range "{0}" is greater than Critical threshold range "{1}"', $this.__WarningValue.RawThreshold, $this.__CriticalValue.RawThreshold), $TRUE) | Out-Null;
|
|
}
|
|
}
|
|
|
|
$IcingaCheck.__ValidateObject();
|
|
$IcingaCheck.__ValidateUnit();
|
|
$IcingaCheck.__SetCurrentExecutionTime();
|
|
$IcingaCheck.__AddCheckDataToCache();
|
|
$IcingaCheck.__SetInternalTimeInterval();
|
|
$IcingaCheck.__ConvertMinMax();
|
|
|
|
return $IcingaCheck;
|
|
}
|
|
|
|
function New-IcingaCheckBaseObject()
|
|
{
|
|
$IcingaCheckBaseObject = New-Object -TypeName PSObject;
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name 'Name' -Value '';
|
|
$IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name 'Verbose' -Value 0;
|
|
$IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__CheckPerfData' -Value @{ };
|
|
$IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__Hidden' -Value $FALSE;
|
|
$IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__Parent' -Value $IcingaCheckBaseObject;
|
|
$IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__Indention' -Value 0;
|
|
$IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__ErrorMessage' -Value '';
|
|
$IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__CheckState' -Value $IcingaEnums.IcingaExitCode.Ok;
|
|
$IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__CheckCommand' -Value '';
|
|
$IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__CheckOutput' -Value $null;
|
|
$IcingaCheckBaseObject | Add-Member -MemberType NoteProperty -Name '__ObjectType' -Value 'IcingaCheckBaseObject';
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__SetCheckCommand' -Value {
|
|
$CallStack = Get-PSCallStack;
|
|
|
|
foreach ($entry in $CallStack) {
|
|
[string]$CheckCommand = $entry.Command;
|
|
if ($CheckCommand.ToLower() -Like 'invoke-icingacheck*') {
|
|
$this.__CheckCommand = $CheckCommand;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($this.__CheckCommand)) {
|
|
return;
|
|
}
|
|
|
|
if ($null -eq $Global:Icinga) {
|
|
$Global:Icinga = @{ };
|
|
}
|
|
|
|
if ($Global:Icinga.ContainsKey('ThresholdCache') -eq $FALSE) {
|
|
$Global:Icinga.Add('ThresholdCache', @{ });
|
|
}
|
|
|
|
if ($Global:Icinga.ThresholdCache.ContainsKey($this.__CheckCommand) -eq $FALSE) {
|
|
$Global:Icinga.ThresholdCache.Add($this.__CheckCommand, $null);
|
|
}
|
|
|
|
if ($null -ne $Global:Icinga.ThresholdCache[$this.__CheckCommand]) {
|
|
return;
|
|
}
|
|
|
|
$Global:Icinga.ThresholdCache[$this.__CheckCommand] = (Get-IcingaCacheData -Space 'sc_daemon' -CacheStore 'checkresult' -KeyName $this.__CheckCommand);
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__SetParent' -Value {
|
|
param ($Parent);
|
|
|
|
$this.__Parent = $Parent;
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetParent' -Value {
|
|
return $this.__Parent;
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__IsHidden' -Value {
|
|
return $this.__Hidden;
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__SetHidden' -Value {
|
|
param ([bool]$Hidden);
|
|
|
|
$this.__Hidden = $Hidden;
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetName' -Value {
|
|
return $this.Name;
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__SetIndention' -Value {
|
|
param ($Indention);
|
|
|
|
$this.__Indention = $Indention;
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetIndention' -Value {
|
|
return $this.__Indention;
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__NewIndention' -Value {
|
|
return ($this.__Indention + 1);
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetCheckState' -Value {
|
|
return $this.__CheckState;
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetCheckCommand' -Value {
|
|
return $this.__CheckCommand;
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Force -Name '__SetCheckOutput' -Value {
|
|
param ($PluginOutput);
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetCheckOutput' -Value {
|
|
|
|
if ($this.__IsHidden()) {
|
|
return ''
|
|
};
|
|
|
|
if ($this._CanOutput() -eq $FALSE) {
|
|
return '';
|
|
}
|
|
|
|
return (
|
|
[string]::Format(
|
|
'{0}{1}',
|
|
(New-StringTree -Spacing $this.__GetIndention()),
|
|
$this.__CheckOutput
|
|
)
|
|
);
|
|
}
|
|
|
|
# Shared function
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name 'Compile' -Value {
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__SetVerbosity' -Value {
|
|
param ($Verbosity);
|
|
|
|
$this.Verbose = $Verbosity;
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetVerbosity' -Value {
|
|
return $this.Verbose;
|
|
}
|
|
|
|
# Shared function
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetHeaderOutputValue' -Value {
|
|
return '';
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '_CanOutput' -Value {
|
|
# Always allow the output of the top parent elements
|
|
if ($this.__GetIndention() -eq 0) {
|
|
return $TRUE;
|
|
}
|
|
|
|
switch ($this.Verbose) {
|
|
0 { # Only print states not being OK
|
|
if ($this.__CheckState -ne $IcingaEnums.IcingaExitCode.Ok) {
|
|
return $TRUE;
|
|
}
|
|
|
|
if ($this.__ObjectType -eq 'IcingaCheckPackage') {
|
|
return $this.__HasNotOkChecks();
|
|
}
|
|
|
|
return $FALSE;
|
|
};
|
|
1 { # Print states not being OK and all content of affected check packages
|
|
if ($this.__CheckState -ne $IcingaEnums.IcingaExitCode.Ok) {
|
|
return $TRUE;
|
|
}
|
|
|
|
if ($this.__ObjectType -eq 'IcingaCheckPackage') {
|
|
return $this.__HasNotOkChecks();
|
|
}
|
|
|
|
if ($this.__GetParent().__ObjectType -eq 'IcingaCheckPackage') {
|
|
return $this.__GetParent().__HasNotOkChecks();
|
|
}
|
|
|
|
return $FALSE;
|
|
};
|
|
}
|
|
|
|
# For any other verbosity, print everything
|
|
return $TRUE;
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__GetPerformanceData' -Value {
|
|
return $this.__CheckPerfData;
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name '__ValidateThresholdInput' -Value {
|
|
# Shared function
|
|
}
|
|
|
|
$IcingaCheckBaseObject | Add-Member -MemberType ScriptMethod -Name 'HasChecks' -Value {
|
|
# Shared function
|
|
}
|
|
|
|
$IcingaCheckBaseObject.__SetCheckCommand();
|
|
|
|
return $IcingaCheckBaseObject;
|
|
}
|
|
|
|
function New-IcingaCheckPackage()
|
|
{
|
|
param (
|
|
[string]$Name = '',
|
|
[switch]$OperatorAnd = $FALSE,
|
|
[switch]$OperatorOr = $FALSE,
|
|
[switch]$OperatorNone = $FALSE,
|
|
[int]$OperatorMin = -1,
|
|
[int]$OperatorMax = -1,
|
|
[array]$Checks = @(),
|
|
[int]$Verbose = 0,
|
|
[switch]$IgnoreEmptyPackage = $FALSE,
|
|
[switch]$Hidden = $FALSE,
|
|
[switch]$AddSummaryHeader = $FALSE
|
|
);
|
|
|
|
$IcingaCheckPackage = New-IcingaCheckBaseObject;
|
|
|
|
$IcingaCheckPackage.Name = $Name;
|
|
$IcingaCheckPackage.__ObjectType = 'IcingaCheckPackage';
|
|
$IcingaCheckPackage.__SetHidden($Hidden);
|
|
$IcingaCheckPackage.__SetVerbosity($Verbose);
|
|
|
|
$IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'OperatorAnd' -Value $OperatorAnd;
|
|
$IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'OperatorOr' -Value $OperatorOr;
|
|
$IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'OperatorNone' -Value $OperatorNone;
|
|
$IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'OperatorMin' -Value $OperatorMin;
|
|
$IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'OperatorMax' -Value $OperatorMax;
|
|
$IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'IgnoreEmptyPackage' -Value $IgnoreEmptyPackage;
|
|
$IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name 'AddSummaryHeader' -Value $AddSummaryHeader;
|
|
$IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name '__Checks' -Value @();
|
|
$IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name '__OkChecks' -Value @();
|
|
$IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name '__WarningChecks' -Value @();
|
|
$IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name '__CriticalChecks' -Value @();
|
|
$IcingaCheckPackage | Add-Member -MemberType NoteProperty -Name '__UnknownChecks' -Value @();
|
|
|
|
$IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Name 'ValidateOperators' -Value {
|
|
if ($this.OperatorMin -ne -1) {
|
|
return;
|
|
}
|
|
|
|
if ($this.OperatorMax -ne -1) {
|
|
return;
|
|
}
|
|
|
|
if ($this.OperatorNone -ne $FALSE) {
|
|
return;
|
|
}
|
|
|
|
if ($this.OperatorOr -ne $FALSE) {
|
|
return;
|
|
}
|
|
|
|
# If no operator is set, use And as default
|
|
$this.OperatorAnd = $TRUE;
|
|
}
|
|
|
|
$IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Name 'AddCheck' -Value {
|
|
param([array]$Checks);
|
|
|
|
if ($null -eq $Checks -Or $Checks.Count -eq 0) {
|
|
return;
|
|
}
|
|
|
|
foreach ($check in $Checks) {
|
|
$check.__SetIndention($this.__NewIndention());
|
|
$check.__SetCheckOutput();
|
|
$check.__SetVerbosity($this.__GetVerbosity());
|
|
$check.__SetParent($this);
|
|
[array]$this.__Checks += $check;
|
|
}
|
|
}
|
|
|
|
# Override shared function
|
|
$IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__SetIndention' -Value {
|
|
param ($Indention);
|
|
|
|
$this.__Indention = $Indention;
|
|
|
|
foreach ($check in $this.__Checks) {
|
|
$check.__SetIndention($this.__NewIndention());
|
|
}
|
|
}
|
|
|
|
$IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Name '__SetCheckState' -Value {
|
|
param ($State);
|
|
|
|
if ($this.__GetCheckState() -lt $State) {
|
|
$this.__CheckState = $State;
|
|
$this.__SetCheckOutput();
|
|
}
|
|
}
|
|
|
|
# Override shared function
|
|
$IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__SetCheckOutput' -Value {
|
|
param ($PluginOutput);
|
|
|
|
$UnknownChecks = '';
|
|
$CriticalChecks = '';
|
|
$WarningChecks = '';
|
|
$CheckSummary = New-Object -TypeName 'System.Text.StringBuilder';
|
|
[bool]$HasContent = $FALSE;
|
|
|
|
# Only apply this to the top parent package
|
|
if ($this.__GetIndention() -eq 0) {
|
|
if ($this.__UnknownChecks.Count -ne 0) {
|
|
$UnknownChecks = [string]::Format(' [UNKNOWN] {0}', ([string]::Join(', ', $this.__UnknownChecks)));
|
|
$CheckSummary.Append(
|
|
[string]::Format(' {0} Unknown', $this.__UnknownChecks.Count)
|
|
) | Out-Null;
|
|
}
|
|
if ($this.__CriticalChecks.Count -ne 0) {
|
|
$CriticalChecks = [string]::Format(' [CRITICAL] {0}', ([string]::Join(', ', $this.__CriticalChecks)));
|
|
$CheckSummary.Append(
|
|
[string]::Format(' {0} Critical', $this.__CriticalChecks.Count)
|
|
) | Out-Null;
|
|
}
|
|
if ($this.__WarningChecks.Count -ne 0) {
|
|
$WarningChecks = [string]::Format(' [WARNING] {0}', ([string]::Join(', ', $this.__WarningChecks)));
|
|
$CheckSummary.Append(
|
|
[string]::Format(' {0} Warning', $this.__WarningChecks.Count)
|
|
) | Out-Null;
|
|
}
|
|
}
|
|
|
|
if ($this.__OkChecks.Count -ne 0) {
|
|
$CheckSummary.Append(
|
|
[string]::Format(' {0} Ok', $this.__OkChecks.Count)
|
|
) | Out-Null;
|
|
}
|
|
|
|
if ($this.AddSummaryHeader -eq $FALSE) {
|
|
$CheckSummary.Clear() | Out-Null;
|
|
$CheckSummary.Append('') | Out-Null;
|
|
} elseif ($CheckSummary.Length -ne 0) {
|
|
$HasContent = $TRUE;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($this.__ErrorMessage) -eq $FALSE) {
|
|
$HasContent = $TRUE;
|
|
}
|
|
|
|
$this.__CheckOutput = [string]::Format(
|
|
'{0} {1}{2}{3}{4}{5}{6}{7}{8}',
|
|
$IcingaEnums.IcingaExitCodeText[$this.__GetCheckState()],
|
|
$this.Name,
|
|
(&{ if ($HasContent) { return ':'; } else { return ''; } }),
|
|
$CheckSummary.ToString(),
|
|
([string]::Format('{0}{1}', (&{ if ($this.__ErrorMessage.Length -gt 1) { return ' '; } else { return ''; } }), $this.__ErrorMessage)),
|
|
$UnknownChecks,
|
|
$CriticalChecks,
|
|
$WarningChecks,
|
|
$this.__ShowPackageConfig()
|
|
);
|
|
}
|
|
|
|
$IcingaCheckPackage | Add-Member -Force -MemberType ScriptMethod -Name 'Compile' -Value {
|
|
$this.__OkChecks.Clear();
|
|
$this.__WarningChecks.Clear();
|
|
$this.__CriticalChecks.Clear();
|
|
$this.__UnknownChecks.Clear();
|
|
|
|
$WorstState = $IcingaEnums.IcingaExitCode.Ok;
|
|
$BestState = $IcingaEnums.IcingaExitCode.Ok;
|
|
$NotOkChecks = 0;
|
|
$OkChecks = 0;
|
|
|
|
if ($this.__Checks.Count -eq 0 -And $this.IgnoreEmptyPackage -eq $FALSE) {
|
|
$this.__ErrorMessage = 'No checks added to this package';
|
|
$this.__SetCheckState($IcingaEnums.IcingaExitCode.Unknown);
|
|
$this.__SetCheckOutput();
|
|
return;
|
|
}
|
|
|
|
[array]$this.__Checks = ($this.__Checks | Sort-Object -Property Name);
|
|
|
|
# Loop all checks to understand the content of result
|
|
foreach ($check in $this.__Checks) {
|
|
|
|
$check.Compile();
|
|
|
|
if ($check.__IsHidden()) {
|
|
continue;
|
|
}
|
|
|
|
if ($WorstState -lt $check.__GetCheckState()) {
|
|
$WorstState = $check.__GetCheckState();
|
|
}
|
|
|
|
if ($BestState -gt $check.__GetCheckState()) {
|
|
$BestState = $check.__GetCheckState();
|
|
}
|
|
|
|
[string]$CheckStateOutput = [string]::Format(
|
|
'{0}{1}',
|
|
$check.__GetName(),
|
|
$check.__GetHeaderOutputValue()
|
|
);
|
|
|
|
switch ($check.__GetCheckState()) {
|
|
$IcingaEnums.IcingaExitCode.Ok {
|
|
$this.__OkChecks += $CheckStateOutput;
|
|
$OkChecks += 1;
|
|
break;
|
|
};
|
|
$IcingaEnums.IcingaExitCode.Warning {
|
|
$this.__WarningChecks += $CheckStateOutput;
|
|
$NotOkChecks += 1;
|
|
break;
|
|
};
|
|
$IcingaEnums.IcingaExitCode.Critical {
|
|
$this.__CriticalChecks += $CheckStateOutput;
|
|
$NotOkChecks += 1;
|
|
break;
|
|
};
|
|
$IcingaEnums.IcingaExitCode.Unknown {
|
|
$this.__UnknownChecks += $CheckStateOutput;
|
|
$NotOkChecks += 1;
|
|
break;
|
|
};
|
|
}
|
|
}
|
|
|
|
if ($this.OperatorAnd -And $NotOkChecks -ne 0) {
|
|
$this.__SetCheckState($WorstState);
|
|
} elseif ($this.OperatorOr -And $OkChecks -eq 0 ) {
|
|
$this.__SetCheckState($WorstState);
|
|
} elseif ($this.OperatorNone -And $OkChecks -ne 0 ) {
|
|
$this.__SetCheckState($WorstState);
|
|
} elseif ($this.OperatorMin -ne -1) {
|
|
if (-Not ($this.__Checks.Count -eq 0 -And $this.IgnoreEmptyPackage -eq $TRUE)) {
|
|
if ($this.OperatorMin -gt $this.__Checks.Count) {
|
|
$this.__SetCheckState($IcingaEnums.IcingaExitCode.Unknown);
|
|
$this.__ErrorMessage = [string]::Format('Minium check count ({0}) is larger than number of assigned checks ({1})', $this.OperatorMin, $this.__Checks.Count);
|
|
} elseif ($OkChecks -lt $this.OperatorMin) {
|
|
$this.__SetCheckState($WorstState);
|
|
$this.__ErrorMessage = '';
|
|
}
|
|
}
|
|
} elseif ($this.OperatorMax -ne -1) {
|
|
if (-Not ($this.__Checks.Count -eq 0 -And $this.IgnoreEmptyPackage -eq $TRUE)) {
|
|
if ($this.OperatorMax -gt $this.__Checks.Count) {
|
|
$this.__SetCheckState($IcingaEnums.IcingaExitCode.Unknown);
|
|
$this.__ErrorMessage = [string]::Format('Maximum check count ({0}) is larger than number of assigned checks ({1})', $this.OperatorMax, $this.__Checks.Count);
|
|
} elseif ($OkChecks -gt $this.OperatorMax) {
|
|
$this.__SetCheckState($WorstState);
|
|
$this.__ErrorMessage = '';
|
|
}
|
|
}
|
|
}
|
|
|
|
$this.__SetCheckOutput();
|
|
}
|
|
|
|
# Override default behaviour from shared function
|
|
$IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__SetVerbosity' -Value {
|
|
param ($Verbosity);
|
|
# Do nothing for check packages
|
|
}
|
|
|
|
# Override default behaviour from shared function
|
|
$IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__GetCheckOutput' -Value {
|
|
|
|
if ($this.__IsHidden()) {
|
|
return ''
|
|
};
|
|
|
|
if ($this._CanOutput() -eq $FALSE) {
|
|
return '';
|
|
}
|
|
|
|
$CheckOutput = [string]::Format(
|
|
'{0}{1}',
|
|
(New-StringTree -Spacing $this.__GetIndention()),
|
|
$this.__CheckOutput
|
|
);
|
|
|
|
foreach ($check in $this.__Checks) {
|
|
if ($check.__IsHidden()) {
|
|
continue;
|
|
};
|
|
|
|
if ($check._CanOutput() -eq $FALSE) {
|
|
continue;
|
|
}
|
|
|
|
$CheckOutput = [string]::Format(
|
|
'{0}{1}{2}',
|
|
$CheckOutput,
|
|
"`n",
|
|
$check.__GetCheckOutput()
|
|
);
|
|
}
|
|
|
|
return $CheckOutput;
|
|
}
|
|
|
|
$IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__HasNotOkChecks' -Value {
|
|
|
|
if ($this.__WarningChecks.Count -ne 0) {
|
|
return $TRUE;
|
|
}
|
|
|
|
if ($this.__CriticalChecks.Count -ne 0) {
|
|
return $TRUE;
|
|
}
|
|
|
|
if ($this.__UnknownChecks.Count -ne 0) {
|
|
return $TRUE;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
$IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__ShowPackageConfig' -Value {
|
|
if ($this.__GetVerbosity() -lt 3) {
|
|
return '';
|
|
}
|
|
|
|
if ($this.OperatorAnd) {
|
|
return ' (All must be [OK])';
|
|
}
|
|
if ($this.OperatorOr) {
|
|
return ' (Atleast one must be [OK])';
|
|
}
|
|
if ($this.OperatorMin -ne -1) {
|
|
return ([string]::Format(' (Atleast {0} must be [OK])', $this.OperatorMin));
|
|
}
|
|
if ($this.OperatorMax -ne -1) {
|
|
return ([string]::Format(' (Not more than {0} must be [OK])', $this.OperatorMax));
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
# Override default behaviour from shared function
|
|
$IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__GetPerformanceData' -Value {
|
|
[string]$perfData = '';
|
|
[hashtable]$CollectedPerfData = @{ };
|
|
|
|
# At first lets collect all perf data, but ensure we only add possible label duplication only once
|
|
foreach ($check in $this.__Checks) {
|
|
$data = $check.__GetPerformanceData();
|
|
|
|
if ($null -eq $data -Or $null -eq $data.label) {
|
|
continue;
|
|
}
|
|
|
|
if ($CollectedPerfData.ContainsKey($data.label)) {
|
|
continue;
|
|
}
|
|
|
|
$CollectedPerfData.Add($data.label, $data);
|
|
}
|
|
|
|
return @{
|
|
'label' = $this.Name;
|
|
'perfdata' = $CollectedPerfData;
|
|
'package' = $TRUE;
|
|
}
|
|
}
|
|
|
|
# __GetTimeSpanThreshold(0, 'Core_30_20', 'Core_30')
|
|
$IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name '__GetTimeSpanThreshold' -Value {
|
|
param ($TimeSpanLabel, $Label);
|
|
|
|
foreach ($check in $this.__Checks) {
|
|
$Result = $check.__GetTimeSpanThreshold($TimeSpanLabel, $Label);
|
|
|
|
if ([string]::IsNullOrEmpty($Result) -eq $FALSE) {
|
|
return $Result;
|
|
}
|
|
}
|
|
|
|
return @{
|
|
'Warning' = '';
|
|
'Critical' = '';
|
|
};
|
|
}
|
|
|
|
# Override shared function
|
|
$IcingaCheckPackage | Add-Member -MemberType ScriptMethod -Force -Name 'HasChecks' -Value {
|
|
if ($this.__Checks.Count -eq 0) {
|
|
return $FALSE;
|
|
}
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
$IcingaCheckPackage.ValidateOperators();
|
|
$IcingaCheckPackage.AddCheck($Checks);
|
|
|
|
return $IcingaCheckPackage;
|
|
}
|
|
|
|
function New-IcingaCheckResult()
|
|
{
|
|
param (
|
|
$Check,
|
|
[bool]$NoPerfData = $FALSE,
|
|
[switch]$Compile = $FALSE
|
|
);
|
|
|
|
$IcingaCheckResult = New-Object -TypeName PSObject;
|
|
$IcingaCheckResult | Add-Member -MemberType NoteProperty -Name 'Check' -Value $Check;
|
|
$IcingaCheckResult | Add-Member -MemberType NoteProperty -Name 'NoPerfData' -Value $NoPerfData;
|
|
|
|
$IcingaCheckResult | Add-Member -MemberType ScriptMethod -Name 'Compile' -Value {
|
|
if ($null -eq $this.Check) {
|
|
return $IcingaEnums.IcingaExitCode.Unknown;
|
|
}
|
|
|
|
# Compile the check / package if not already done
|
|
$this.Check.Compile();
|
|
|
|
Write-IcingaPluginOutput -Output ($this.Check.__GetCheckOutput());
|
|
|
|
if ($this.NoPerfData -eq $FALSE) {
|
|
Write-IcingaPluginPerfData -IcingaCheck $this.Check;
|
|
}
|
|
|
|
# Ensure we reset our internal cache once the plugin was executed
|
|
$Global:Icinga.ThresholdCache[$this.Check.__GetCheckCommand()] = $null;
|
|
# Reset the current execution date
|
|
$Global:Icinga.CurrentDate = $null;
|
|
|
|
$ExitCode = $this.Check.__GetCheckState();
|
|
|
|
Set-IcingaInternalPluginExitCode -ExitCode $ExitCode;
|
|
|
|
return $ExitCode;
|
|
}
|
|
|
|
if ($Compile) {
|
|
return $IcingaCheckResult.Compile();
|
|
}
|
|
|
|
return $IcingaCheckResult;
|
|
}
|
|
|
|
function New-IcingaPerformanceDataEntry()
|
|
{
|
|
param (
|
|
$PerfDataObject,
|
|
$Label = $null,
|
|
$Value = $null,
|
|
$Warning = $null,
|
|
$Critical = $null
|
|
);
|
|
|
|
if ($null -eq $PerfDataObject) {
|
|
return '';
|
|
}
|
|
|
|
[string]$LabelName = $PerfDataObject.label;
|
|
[string]$PerfValue = $PerfDataObject.value;
|
|
[string]$WarningValue = $PerfDataObject.warning;
|
|
[string]$CriticalValue = $PerfDataObject.critical;
|
|
|
|
if ([string]::IsNullOrEmpty($Label) -eq $FALSE) {
|
|
$LabelName = $Label;
|
|
}
|
|
if ([string]::IsNullOrEmpty($Value) -eq $FALSE) {
|
|
$PerfValue = $Value;
|
|
}
|
|
|
|
# Override our warning/critical values only if the label does not match.
|
|
# Eg. Core_1 not matching Core_1_5 - this is only required for time span checks
|
|
if ([string]::IsNullOrEmpty($Label) -eq $FALSE -And $Label -ne $PerfDataObject.label) {
|
|
$WarningValue = $Warning;
|
|
$CriticalValue = $Critical;
|
|
}
|
|
|
|
$minimum = '';
|
|
$maximum = '';
|
|
|
|
if ([string]::IsNullOrEmpty($PerfDataObject.minimum) -eq $FALSE) {
|
|
$minimum = [string]::Format(';{0}', $PerfDataObject.minimum);
|
|
}
|
|
if ([string]::IsNullOrEmpty($PerfDataObject.maximum) -eq $FALSE) {
|
|
$maximum = [string]::Format(';{0}', $PerfDataObject.maximum);
|
|
}
|
|
|
|
return (
|
|
[string]::Format(
|
|
"'{0}'={1}{2};{3};{4}{5}{6} ",
|
|
$LabelName.ToLower(),
|
|
(Format-IcingaPerfDataValue $PerfValue),
|
|
$PerfDataObject.unit,
|
|
(Format-IcingaPerfDataValue $WarningValue),
|
|
(Format-IcingaPerfDataValue $CriticalValue),
|
|
(Format-IcingaPerfDataValue $minimum),
|
|
(Format-IcingaPerfDataValue $maximum)
|
|
)
|
|
);
|
|
}
|
|
|
|
function Set-IcingaInternalPluginException()
|
|
{
|
|
param (
|
|
[string]$PluginException = ''
|
|
);
|
|
|
|
if ($null -eq $Global:Icinga) {
|
|
$Global:Icinga = @{ };
|
|
}
|
|
|
|
if ($Global:Icinga.ContainsKey('PluginExecution') -eq $FALSE) {
|
|
$Global:Icinga.Add(
|
|
'PluginExecution',
|
|
@{
|
|
'PluginException' = $PluginException;
|
|
}
|
|
)
|
|
} else {
|
|
if ($Global:Icinga.PluginExecution.ContainsKey('PluginException') -eq $FALSE) {
|
|
$Global:Icinga.PluginExecution.Add('PluginException', $PluginException);
|
|
return;
|
|
}
|
|
|
|
# Only catch the first exception
|
|
if ([string]::IsNullOrEmpty($Global:Icinga.PluginExecution.PluginException)) {
|
|
$Global:Icinga.PluginExecution.PluginException = $PluginException;
|
|
}
|
|
}
|
|
}
|
|
|
|
function Set-IcingaInternalPluginExitCode()
|
|
{
|
|
param (
|
|
$ExitCode = 0
|
|
);
|
|
|
|
if ($null -eq $Global:Icinga) {
|
|
$Global:Icinga = @{ };
|
|
}
|
|
|
|
if ($Global:Icinga.ContainsKey('PluginExecution') -eq $FALSE) {
|
|
$Global:Icinga.Add(
|
|
'PluginExecution',
|
|
@{
|
|
'LastExitCode' = $ExitCode;
|
|
}
|
|
)
|
|
} else {
|
|
if ($Global:Icinga.PluginExecution.ContainsKey('LastExitCode') -eq $FALSE) {
|
|
$Global:Icinga.PluginExecution.Add('LastExitCode', $ExitCode);
|
|
return;
|
|
}
|
|
|
|
# Only add the first exit code we should cover during one runtime
|
|
if ($null -eq $Global:Icinga.PluginExecution.LastExitCode) {
|
|
$Global:Icinga.PluginExecution.LastExitCode = $ExitCode;
|
|
}
|
|
}
|
|
}
|
|
|
|
function Write-IcingaPluginOutput()
|
|
{
|
|
param (
|
|
$Output
|
|
);
|
|
|
|
if ($global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE) {
|
|
if ($null -ne $global:Icinga -And $global:Icinga.Minimal) {
|
|
Clear-Host;
|
|
}
|
|
Write-IcingaConsolePlain $Output;
|
|
} else {
|
|
# New behavior with local thread separated results
|
|
$global:Icinga.CheckResults += $Output;
|
|
}
|
|
}
|
|
|
|
function Write-IcingaPluginPerfData()
|
|
{
|
|
param (
|
|
$IcingaCheck = $null
|
|
);
|
|
|
|
if ($null -eq $IcingaCheck) {
|
|
return;
|
|
}
|
|
|
|
$PerformanceData = $IcingaCheck.__GetPerformanceData();
|
|
$CheckCommand = $IcingaCheck.__GetCheckCommand();
|
|
|
|
if ($PerformanceData.package -eq $FALSE) {
|
|
$PerformanceData = @{
|
|
$PerformanceData.label = $PerformanceData;
|
|
}
|
|
} else {
|
|
$PerformanceData = $PerformanceData.perfdata;
|
|
}
|
|
|
|
$CheckResultCache = $Global:Icinga.ThresholdCache[$CheckCommand];
|
|
|
|
if ($global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE) {
|
|
[string]$PerfDataOutput = (Get-IcingaPluginPerfDataContent -PerfData $PerformanceData -CheckResultCache $CheckResultCache -IcingaCheck $IcingaCheck);
|
|
Write-IcingaConsolePlain ([string]::Format('| {0}', $PerfDataOutput));
|
|
} else {
|
|
[void](Get-IcingaPluginPerfDataContent -PerfData $PerformanceData -CheckResultCache $CheckResultCache -AsObject $TRUE -IcingaCheck $IcingaCheck);
|
|
}
|
|
}
|
|
|
|
function Get-IcingaPluginPerfDataContent()
|
|
{
|
|
param(
|
|
$PerfData,
|
|
$CheckResultCache,
|
|
[bool]$AsObject = $FALSE,
|
|
$IcingaCheck = $null
|
|
);
|
|
|
|
[string]$PerfDataOutput = '';
|
|
|
|
foreach ($package in $PerfData.Keys) {
|
|
$data = $PerfData[$package];
|
|
if ($data.package) {
|
|
$PerfDataOutput += (Get-IcingaPluginPerfDataContent -PerfData $data.perfdata -CheckResultCache $CheckResultCache -AsObject $AsObject -IcingaCheck $IcingaCheck);
|
|
} else {
|
|
foreach ($checkresult in $CheckResultCache.PSobject.Properties) {
|
|
|
|
$SearchPattern = [string]::Format('{0}_', $data.label);
|
|
$SearchEntry = $checkresult.Name;
|
|
if ($SearchEntry -like "$SearchPattern*") {
|
|
$TimeSpan = $IcingaCheck.__GetTimeSpanThreshold($SearchEntry, $data.label);
|
|
|
|
$cachedresult = (New-IcingaPerformanceDataEntry -PerfDataObject $data -Label $SearchEntry -Value $checkresult.Value -Warning $TimeSpan.Warning -Critical $TimeSpan.Critical);
|
|
|
|
if ($AsObject) {
|
|
# New behavior with local thread separated results
|
|
$global:Icinga.PerfData += $cachedresult;
|
|
}
|
|
$PerfDataOutput += $cachedresult;
|
|
}
|
|
}
|
|
|
|
$compiledPerfData = (New-IcingaPerformanceDataEntry $data);
|
|
|
|
if ($AsObject) {
|
|
# New behavior with local thread separated results
|
|
$global:Icinga.PerfData += $compiledPerfData;
|
|
}
|
|
$PerfDataOutput += $compiledPerfData;
|
|
}
|
|
}
|
|
|
|
return $PerfDataOutput;
|
|
}
|
|
|
|
Export-ModuleMember -Function @( 'Write-IcingaPluginPerfData' );
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Closes a open connection to a MSSQL server
|
|
.DESCRIPTION
|
|
This Cmdlet will close an open connection to a MSSQL server.
|
|
.FUNCTIONALITY
|
|
Closes an open connection to a MSSQL server.
|
|
.EXAMPLE
|
|
PS>Close-IcingaMSSQLConnection $OpenMSSQLConnection;
|
|
.INPUTS
|
|
System.Data.SqlClient.SqlConnection
|
|
.OUTPUTS
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
function Close-IcingaMSSQLConnection()
|
|
{
|
|
param (
|
|
[System.Data.SqlClient.SqlConnection]$SqlConnection = $null
|
|
);
|
|
|
|
if ($null -eq $SqlConnection) {
|
|
return;
|
|
}
|
|
|
|
Write-IcingaDebugMessage `
|
|
-Message 'Closing client connection for endpoint {0}' `
|
|
-Objects $SqlConnection;
|
|
|
|
$SqlConnection.Close();
|
|
$SqlConnection.Dispose();
|
|
$SqlConnection = $null;
|
|
}
|
|
|
|
function Get-IcingaMSSQLInstanceName()
|
|
{
|
|
param (
|
|
$SqlConnection = $null,
|
|
[string]$Username,
|
|
[securestring]$Password,
|
|
[string]$Address = "localhost",
|
|
[int]$Port = 1433,
|
|
[switch]$IntegratedSecurity = $FALSE,
|
|
[switch]$TestConnection = $FALSE
|
|
);
|
|
|
|
[bool]$NewSqlConnection = $FALSE;
|
|
|
|
if ($null -eq $SqlConnection) {
|
|
$SqlConnection = Open-IcingaMSSQLConnection -Username $Username -Password $Password -Address $Address -IntegratedSecurity:$IntegratedSecurity -Port $Port -TestConnection:$TestConnection;
|
|
|
|
if ($null -eq $SqlConnection) {
|
|
return 'Unknown';
|
|
}
|
|
|
|
$NewSqlConnection = $TRUE;
|
|
}
|
|
|
|
$Query = 'SELECT @@servicename'
|
|
$SqlCommand = New-IcingaMSSQLCommand -SqlConnection $SqlConnection -SqlQuery $Query;
|
|
$InstanceName = (Send-IcingaMSSQLCommand -SqlCommand $SqlCommand).Column1;
|
|
|
|
if ($NewSqlConnection -eq $TRUE) {
|
|
Close-IcingaMSSQLConnection -SqlConnection $SqlConnection;
|
|
}
|
|
|
|
return $InstanceName;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Builds a SQL query
|
|
.DESCRIPTION
|
|
This Cmdlet will build a SQL query
|
|
and returns it as an string.
|
|
.FUNCTIONALITY
|
|
Build a SQL query
|
|
.EXAMPLE
|
|
PS>New-IcingaMSSQLCommand -SqlConnection $SqlConnection -SqlQuery "SELECT object_name FROM sys.dm_os_performance_counters";
|
|
.PARAMETER SqlConnection
|
|
An open SQL connection object e.g. $SqlConnection = Open-IcingaMSSQLConnection -IntegratedSecurity;
|
|
.PARAMETER SqlQuery
|
|
A SQL query as string.
|
|
.INPUTS
|
|
System.Data.SqlClient.SqlConnection
|
|
System.String
|
|
.OUTPUTS
|
|
System.Data.SqlClient.SqlCommand
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
function New-IcingaMSSQLCommand()
|
|
{
|
|
param (
|
|
[System.Data.SqlClient.SqlConnection]$SqlConnection = $null,
|
|
[string]$SqlQuery = $null
|
|
);
|
|
|
|
$SqlCommand = New-Object System.Data.SqlClient.SqlCommand;
|
|
$SqlCommand.Connection = $SqlConnection;
|
|
|
|
if ($null -eq $SqlCommand.Connection) {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' `
|
|
-ExceptionThrown $IcingaExceptions.Inputs.MSSQLCommandMissing `
|
|
-CustomMessage 'It seems the -SqlConnection is empty or invalid' `
|
|
-Force;
|
|
}
|
|
|
|
$SqlCommand.CommandText = $SqlQuery;
|
|
|
|
return $SqlCommand;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Opens a connection to a MSSQL server
|
|
.DESCRIPTION
|
|
This Cmdlet will open a connection to a MSSQL server
|
|
and returns that connection object.
|
|
.FUNCTIONALITY
|
|
Opens a connection to a MSSQL server
|
|
.EXAMPLE
|
|
PS>Open-IcingaMSSQLConnection -IntegratedSecurity -Address localhost;
|
|
.EXAMPLE
|
|
PS>Open-IcingaMSSQLConnection -Username Exampleuser -Password (ConvertTo-IcingaSecureString 'examplePassword') -Address 123.125.123.2;
|
|
.PARAMETER Username
|
|
The username for connecting to the MSSQL database
|
|
.PARAMETER Password
|
|
The password for connecting to the MSSQL database as secure string
|
|
.PARAMETER Address
|
|
The IP address or FQDN to the MSSQL server to connect to (default: localhost)
|
|
.PARAMETER Port
|
|
The port of the MSSQL server/instance to connect to with the provided credentials (default: 1433)
|
|
.PARAMETER SqlDatabase
|
|
The name of a specific database to connect to. Leave empty to connect "globaly"
|
|
.PARAMETER IntegratedSecurity
|
|
Allows this plugin to use the credentials of the current PowerShell session inherited by
|
|
the user the PowerShell is running with. If this is set and the user the PowerShell is
|
|
running with can access to the MSSQL database you will not require to provide username
|
|
and password
|
|
.PARAMETER TestConnection
|
|
Set this if you want to return $null on connection errors during MSSQL.open() instead of
|
|
exception messages.
|
|
.OUTPUTS
|
|
System.Data.SqlClient.SqlConnection
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
function Open-IcingaMSSQLConnection()
|
|
{
|
|
param (
|
|
[string]$Username,
|
|
[securestring]$Password,
|
|
[string]$Address = "localhost",
|
|
[int]$Port = 1433,
|
|
[string]$SqlDatabase,
|
|
[switch]$IntegratedSecurity = $FALSE,
|
|
[switch]$TestConnection = $FALSE
|
|
);
|
|
|
|
if ($IntegratedSecurity -eq $FALSE) {
|
|
if ([string]::IsNullOrEmpty($Username)) {
|
|
Exit-IcingaThrowException `
|
|
-ExceptionType 'Input' `
|
|
-ExceptionThrown $IcingaExceptions.Inputs.MSSQLCredentialHandling `
|
|
-CustomMessage '-Username not set and -IntegratedSecurity is false' `
|
|
-Force;
|
|
} elseif ($null -eq $Password) {
|
|
Exit-IcingaThrowException `
|
|
-ExceptionType 'Input' `
|
|
-ExceptionThrown $IcingaExceptions.Inputs.MSSQLCredentialHandling `
|
|
-CustomMessage '-Password not set and -IntegratedSecurity is false' `
|
|
-Force;
|
|
}
|
|
|
|
$Password.MakeReadOnly();
|
|
$SqlCredential = New-Object System.Data.SqlClient.SqlCredential($Username, $Password);
|
|
}
|
|
|
|
try {
|
|
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection;
|
|
$SqlConnection.ConnectionString = "Server=$Address,$Port;";
|
|
|
|
if ([string]::IsNullOrEmpty($SqlDatabase) -eq $FALSE) {
|
|
$SqlConnection.ConnectionString += "Database=$SqlDatabase;";
|
|
}
|
|
|
|
if ($IntegratedSecurity -eq $TRUE) {
|
|
$SqlConnection.ConnectionString += "Integrated Security=True;";
|
|
}
|
|
|
|
$SqlConnection.Credential = $SqlCredential;
|
|
|
|
Write-IcingaDebugMessage `
|
|
-Message 'Open client connection for endpoint {0}' `
|
|
-Objects $SqlConnection;
|
|
|
|
$SqlConnection.Open();
|
|
} catch {
|
|
|
|
if ($TestConnection) {
|
|
return $null;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Username) -eq $FALSE) {
|
|
Exit-IcingaThrowException `
|
|
-InputString $_.Exception.Message `
|
|
-StringPattern $Username `
|
|
-ExceptionType 'Input' `
|
|
-ExceptionThrown $IcingaExceptions.Inputs.MSSQLCredentialHandling;
|
|
}
|
|
|
|
Exit-IcingaThrowException `
|
|
-InputString $_.Exception.Message `
|
|
-StringPattern 'error: 40' `
|
|
-ExceptionType 'Connection' `
|
|
-ExceptionThrown $IcingaExceptions.Connection.MSSQLConnectionError;
|
|
|
|
Exit-IcingaThrowException `
|
|
-InputString $_.Exception.Message `
|
|
-StringPattern 'error: 0' `
|
|
-ExceptionType 'Connection' `
|
|
-ExceptionThrown $IcingaExceptions.Connection.MSSQLConnectionError;
|
|
|
|
Exit-IcingaThrowException `
|
|
-InputString $_.Exception.Message `
|
|
-StringPattern 'error: 25' `
|
|
-ExceptionType 'Connection' `
|
|
-ExceptionThrown $IcingaExceptions.Connection.MSSQLConnectionError;
|
|
# Last resort
|
|
Exit-IcingaThrowException `
|
|
-InputString $_.Exception.Message `
|
|
-ExceptionType 'Custom' `
|
|
-Force;
|
|
}
|
|
|
|
return $SqlConnection;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Executes a SQL query
|
|
.DESCRIPTION
|
|
This Cmdlet will send a SQL query to a given database and
|
|
execute the query and returns the output.
|
|
.FUNCTIONALITY
|
|
Executes a SQL query
|
|
.EXAMPLE
|
|
PS> Send-IcingaMSSQLCommand -SqlCommand $SqlCommand;
|
|
.PARAMETER SqlCommand
|
|
The SQL query which will be executed, e.g. $SqlCommand = New-IcingaMSSQLCommand
|
|
.INPUTS
|
|
System.Data.SqlClient.SqlCommand
|
|
.OUTPUTS
|
|
System.Data.DataSet
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
function Send-IcingaMSSQLCommand()
|
|
{
|
|
param (
|
|
[System.Data.SqlClient.SqlCommand]$SqlCommand = $null
|
|
);
|
|
|
|
$Adapter = New-Object System.Data.SqlClient.SqlDataAdapter $SqlCommand;
|
|
|
|
$Data = New-Object System.Data.DataSet;
|
|
$Adapter.Fill($Data) | Out-Null;
|
|
|
|
return $Data.Tables;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Disables the progress bar during file downloads or while loading certain modules.
|
|
This will increase the speed of certain tasks, for example file downloads
|
|
.DESCRIPTION
|
|
Disables the progress bar during file downloads or while loading certain modules.
|
|
This will increase the speed of certain tasks, for example file downloads
|
|
.FUNCTIONALITY
|
|
Sets the $ProgressPreference to 'SilentlyContinue'
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Disable-IcingaProgressPreference()
|
|
{
|
|
$global:ProgressPreference = "SilentlyContinue";
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Fetches the configuration of the configured Proxy server for the Framework, in
|
|
case it is set
|
|
.DESCRIPTION
|
|
etches the configuration of the configured Proxy server for the Framework, in
|
|
case it is set
|
|
.FUNCTIONALITY
|
|
etches the configuration of the configured Proxy server for the Framework, in
|
|
case it is set
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Get-IcingaFrameworkProxyServer()
|
|
{
|
|
return (Get-IcingaPowerShellConfig -Path 'Framework.Proxy.Server');
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
A wrapper function for Invoke-WebRequest to allow easier proxy support and
|
|
to catch errors more directly.
|
|
.DESCRIPTION
|
|
A wrapper function for Invoke-WebRequest to allow easier proxy support and
|
|
to catch errors more directly.
|
|
.FUNCTIONALITY
|
|
Uses Invoke-WebRequest to fetch information and returns the same output, but
|
|
with direct error handling and global proxy support by configuration
|
|
.EXAMPLE
|
|
PS>Invoke-IcingaWebRequest -Uri 'https://icinga.com';
|
|
.EXAMPLE
|
|
PS>Invoke-IcingaWebRequest -Uri 'https://icinga.com' -UseBasicParsing;
|
|
.EXAMPLE
|
|
PS>Invoke-IcingaWebRequest -Uri 'https://{0}.com' -UseBasicParsing -Objects 'icinga';
|
|
.EXAMPLE
|
|
PS>Invoke-IcingaWebRequest -Uri 'https://{0}.com' -UseBasicParsing -Objects 'icinga' -Headers @{ 'accept' = 'application/json' };
|
|
.PARAMETER Uri
|
|
The Uri for the web request
|
|
.PARAMETER Body
|
|
Specifies the body of the request. The body is the content of the request that follows the headers. You can
|
|
also pipe a body value to Invoke-WebRequest.
|
|
|
|
The Body parameter can be used to specify a list of query parameters or specify the content of the response.
|
|
|
|
When the input is a GET request and the body is an IDictionary (typically, a hash table), the body is added
|
|
to the URI as query parameters. For other GET requests, the body is set as the value of the request body in
|
|
the standard name=value format.
|
|
|
|
When the body is a form, or it is the output of an Invoke-WebRequest call, Windows PowerShell sets the
|
|
request content to the form fields.
|
|
.PARAMETER Headers
|
|
Web headers send with the request as hashtable
|
|
.PARAMETER Method
|
|
The request method to send to the destination.
|
|
Allowed values: 'Get', 'Post', 'Put', 'Trace', 'Patch', 'Options', 'Merge', 'Head', 'Default', 'Delete'
|
|
.PARAMETER OutFile
|
|
Specifies the output file for which this cmdlet saves the response body. Enter a path and file name. If you omit the path, the default is the current location.
|
|
.PARAMETER UseBasicParsing
|
|
Indicates that the cmdlet uses the response object for HTML content without Document Object Model (DOM)
|
|
parsing.
|
|
|
|
This parameter is required when Internet Explorer is not installed on the computers, such as on a Server
|
|
Core installation of a Windows Server operating system.
|
|
.PARAMETER Objects
|
|
Use placeholders within the `-Uri` argument, like {0} and replace them with array elements of this argument.
|
|
The index entry of {0} has to match the order of this argument.
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Invoke-IcingaWebRequest()
|
|
{
|
|
param (
|
|
[string]$Uri = '',
|
|
$Body,
|
|
[hashtable]$Headers,
|
|
[ValidateSet('Get', 'Post', 'Put', 'Trace', 'Patch', 'Options', 'Merge', 'Head', 'Default', 'Delete')]
|
|
[string]$Method = 'Get',
|
|
[string]$OutFile,
|
|
[switch]$UseBasicParsing,
|
|
[array]$Objects = @()
|
|
);
|
|
|
|
[int]$Index = 0;
|
|
foreach ($entry in $Objects) {
|
|
|
|
$Uri = $Uri.Replace(
|
|
[string]::Format('{0}{1}{2}', '{', $Index, '}'),
|
|
$entry
|
|
);
|
|
$Index++;
|
|
}
|
|
|
|
$WebArguments = @{
|
|
'Uri' = $Uri;
|
|
'Method' = $Method;
|
|
}
|
|
|
|
if ($Method -ne 'Get' -And $null -ne $Body -and [string]::IsNullOrEmpty($Body) -eq $FALSE) {
|
|
$WebArguments.Add('Body', $Body);
|
|
}
|
|
|
|
if ($Headers.Count -ne 0) {
|
|
$WebArguments.Add('Headers', $Headers);
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($OutFile) -eq $FALSE) {
|
|
$WebArguments.Add('OutFile', $OutFile);
|
|
}
|
|
|
|
$ProxyServer = Get-IcingaFrameworkProxyServer;
|
|
|
|
if ([string]::IsNullOrEmpty($ProxyServer) -eq $FALSE) {
|
|
$WebArguments.Add('Proxy', $ProxyServer);
|
|
}
|
|
|
|
Set-IcingaTLSVersion;
|
|
Disable-IcingaProgressPreference;
|
|
|
|
try {
|
|
$Response = Invoke-WebRequest -UseBasicParsing:$UseBasicParsing @WebArguments -ErrorAction Stop;
|
|
} catch {
|
|
[string]$ErrorId = ([string]$_.FullyQualifiedErrorId).Split(',')[0];
|
|
[string]$Message = $_.Exception.Message;
|
|
|
|
switch ($ErrorId) {
|
|
'System.UriFormatException' {
|
|
Write-IcingaConsoleError 'The provided Url "{0}" is not a valid format' -Objects $Uri;
|
|
break;
|
|
};
|
|
'WebCmdletWebResponseException' {
|
|
Write-IcingaConsoleError 'The remote host for address "{0}" could not be resolved' -Objects $Uri;
|
|
break;
|
|
};
|
|
'System.InvalidOperationException' {
|
|
Write-IcingaConsoleError 'Failed to query host "{0}". Possible this is caused by an invalid Proxy Server configuration: "{1}".' -Objects $Uri, $ProxyServer;
|
|
break;
|
|
};
|
|
Default {
|
|
Write-IcingaConsoleError 'Unhandled exception for Url "{0}" with error id "{1}":{2}{2}{3}' -Objects $Uri, $ErrorId, (New-IcingaNewLine), $Message;
|
|
break;
|
|
};
|
|
}
|
|
|
|
# Return some sort of objects which are often used to ensure we at least have some out-of-the-box compatibility
|
|
return @{
|
|
'HasErrors' = $TRUE;
|
|
'BaseResponse' = @{
|
|
'ResponseUri' = @{
|
|
'AbsoluteUri' = $Uri;
|
|
};
|
|
};
|
|
'StatusCode' = 900;
|
|
};
|
|
}
|
|
|
|
return $Response;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Sets the configuration for a proxy server which is used by all Invoke-WebRequests
|
|
to ensure internet connections are working correctly.
|
|
.DESCRIPTION
|
|
Sets the configuration for a proxy server which is used by all Invoke-WebRequests
|
|
to ensure internet connections are working correctly.
|
|
.FUNCTIONALITY
|
|
Sets the configuration for a proxy server which is used by all Invoke-WebRequests
|
|
to ensure internet connections are working correctly.
|
|
.EXAMPLE
|
|
PS>Set-IcingaFrameworkProxyServer -Server 'http://example.com:8080';
|
|
.PARAMETER Server
|
|
The server with the port for the Proxy. Example: 'http://example.com:8080'
|
|
.INPUTS
|
|
System.String
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Set-IcingaFrameworkProxyServer()
|
|
{
|
|
param (
|
|
[string]$Server = ''
|
|
);
|
|
|
|
Set-IcingaPowerShellConfig -Path 'Framework.Proxy.Server' -Value $Server;
|
|
|
|
Write-IcingaConsoleNotice 'The Proxy server for the PowerShell Framework has been set to "{0}"' -Objects $Server;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Sets the allowed TLS version for communicating with endpoints to TLS 1.2 and 1.1
|
|
.DESCRIPTION
|
|
Sets the allowed TLS version for communicating with endpoints to TLS 1.2 and 1.1
|
|
.FUNCTIONALITY
|
|
Uses the [Net.ServicePointManager] to set the SecurityProtocol to TLS 1.2 and 1.1
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Set-IcingaTLSVersion()
|
|
{
|
|
[Net.ServicePointManager]::SecurityProtocol = "tls12, tls11";
|
|
}
|
|
|
|
function Close-IcingaTCPConnection()
|
|
{
|
|
param(
|
|
[System.Net.Sockets.TcpClient]$Client = $null
|
|
);
|
|
|
|
if ($null -eq $Client) {
|
|
return;
|
|
}
|
|
|
|
Write-IcingaDebugMessage -Message (
|
|
[string]::Format(
|
|
'Closing client connection for endpoint {0}',
|
|
(Get-IcingaTCPClientRemoteEndpoint -Client $Client)
|
|
)
|
|
);
|
|
|
|
$Client.Close();
|
|
$Client.Dispose();
|
|
$Client = $null;
|
|
}
|
|
|
|
function Close-IcingaTCPSocket()
|
|
{
|
|
param(
|
|
[System.Net.Sockets.TcpListener]$Socket = $null
|
|
);
|
|
|
|
if ($null -eq $Socket) {
|
|
return;
|
|
}
|
|
|
|
Write-IcingaDebugMessage -Message (
|
|
[string]::Format(
|
|
'Closing TCP socket {0}',
|
|
$Socket.LocalEndpoint
|
|
)
|
|
);
|
|
|
|
$Socket.Stop();
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Converts a provided Authorization header to credentials
|
|
.DESCRIPTION
|
|
Converts a provided Authorization header to credentials
|
|
.FUNCTIONALITY
|
|
Converts a provided Authorization header to credentials
|
|
.EXAMPLE
|
|
PS>Convert-Base64ToCredentials -AuthString "Basic =Bwebb474567b56756b...";
|
|
.PARAMETER AuthString
|
|
The value of the Authorization header of the web request
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Hashtable
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Convert-Base64ToCredentials()
|
|
{
|
|
param (
|
|
[String]$AuthString
|
|
);
|
|
|
|
[hashtable]$Credentials = @{};
|
|
|
|
$AuthArray = $AuthString.Split(' ');
|
|
|
|
switch ($AuthArray[0]) {
|
|
'Basic' {
|
|
$AuthString = $AuthArray[1];
|
|
};
|
|
default {
|
|
Write-IcingaEventMessage -EventId 1550 -Namespace 'Framework' -Objects $AuthArray[0];
|
|
return @{};
|
|
}
|
|
}
|
|
|
|
# Convert the Base64 Secure String back to a normal string
|
|
[string]$AuthString = [System.Text.Encoding]::UTF8.GetString(
|
|
[System.Convert]::FromBase64String(
|
|
$AuthString
|
|
)
|
|
);
|
|
|
|
# If no ':' is within the string, the credential data is not properly formated
|
|
if ($AuthString.Contains(':') -eq $FALSE) {
|
|
Write-IcingaEventMessage -EventId 1551 -Namespace 'Framework';
|
|
$AuthString = $null;
|
|
return $Credentials;
|
|
}
|
|
|
|
try {
|
|
# Build our User Data and Password from the string
|
|
[string]$UserData = $AuthString.Substring(
|
|
0,
|
|
$AuthString.IndexOf(':')
|
|
);
|
|
$Credentials.Add(
|
|
'password',
|
|
(
|
|
ConvertTo-IcingaSecureString `
|
|
$AuthString.Substring($AuthString.IndexOf(':') + 1, $AuthString.Length - $UserData.Length - 1)
|
|
)
|
|
);
|
|
|
|
$AuthString = $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',
|
|
(
|
|
ConvertTo-IcingaSecureString $AuthData[1]
|
|
)
|
|
);
|
|
$AuthData = $null;
|
|
} else {
|
|
$Credentials.Add('domain', $null);
|
|
$Credentials.Add(
|
|
'user',
|
|
(
|
|
ConvertTo-IcingaSecureString $UserData
|
|
)
|
|
);
|
|
}
|
|
|
|
$UserData = $null;
|
|
} catch {
|
|
Write-IcingaEventMessage -EventId 1552 -Namespace 'Framework' -Objects $_.Exception;
|
|
return @{};
|
|
}
|
|
|
|
return $Credentials;
|
|
}
|
|
|
|
function ConvertTo-IcingaX509Certificate()
|
|
{
|
|
param(
|
|
[string]$CertFile = $null,
|
|
[string]$OutFile = $null,
|
|
[switch]$Force = $FALSE
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($CertFile)) {
|
|
throw 'Please specify a valid path to an existing certificate (.cer, .pem, .cert)';
|
|
}
|
|
|
|
if ((Test-Path $CertFile) -eq $FALSE) {
|
|
throw 'The provided path to your certificate was not valid';
|
|
}
|
|
|
|
# Use an empty password for converted certificates
|
|
$Password = $null;
|
|
# Use a target file to specify if we use temp files or not
|
|
$TargetFile = $OutFile;
|
|
# Temp Cert
|
|
[bool]$TempFile = $FALSE;
|
|
|
|
# Create a temp file to store the certificate in
|
|
if ([string]::IsNullOrEmpty($OutFile)) {
|
|
# Create a temporary file for full path and name
|
|
$TargetFile = New-IcingaTemporaryFile;
|
|
# Get the actual path to work with
|
|
$TargetFile = $TargetFile.FullName;
|
|
# Set internally that we are using a temp file
|
|
$TempFile = $TRUE;
|
|
# Delete the file again
|
|
Remove-Item $TargetFile -Force -ErrorAction SilentlyContinue;
|
|
}
|
|
|
|
# Convert our certificate if our target file does not exist
|
|
# it is a temp file or we force its creation
|
|
if (-Not (Test-Path $TargetFile) -Or $TempFile -Or $Force) {
|
|
Write-Output "$Password
|
|
$Password" | certutil -mergepfx "$CertFile" "$TargetFile" | Set-Variable -Name 'CertUtilOutput';
|
|
}
|
|
|
|
Write-IcingaDebugMessage -Message (
|
|
[string]::Format(
|
|
'Certutil merge request has been completed. Certutil message:{0}{0}{1}',
|
|
(New-IcingaNewLine),
|
|
$CertUtilOutput
|
|
)
|
|
);
|
|
|
|
# If no target file exists afterwards (a valid PFX certificate)
|
|
# then throw an exception
|
|
if (-Not (Test-Path $TargetFile)) {
|
|
throw 'The specified/created certificate file could not be found.';
|
|
}
|
|
|
|
# Now load the actual certificate from the path
|
|
$Certificate = New-Object Security.Cryptography.X509Certificates.X509Certificate2 $TargetFile;
|
|
# Delete the PFX-Certificate which will be present after certutil merge
|
|
if ($TempFile) {
|
|
Remove-Item $TargetFile -Force -ErrorAction SilentlyContinue;
|
|
}
|
|
|
|
# Return the certificate
|
|
return $Certificate
|
|
}
|
|
|
|
function Disable-IcingaUntrustedCertificateValidation()
|
|
{
|
|
try {
|
|
[System.Net.ServicePointManager]::CertificatePolicy = $null;
|
|
|
|
Write-IcingaConsoleNotice 'Successfully disabled untrusted certificate validation for this shell instance';
|
|
} catch {
|
|
Write-IcingaConsoleError (
|
|
[string]::Format(
|
|
'Failed to disable untrusted certificate policy: {0}', $_.Exception.Message
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
function Enable-IcingaUntrustedCertificateValidation()
|
|
{
|
|
param (
|
|
[switch]$SuppressMessages = $FALSE
|
|
);
|
|
|
|
try {
|
|
# There is no other way as to use C# for this specific
|
|
# case to configure the certificate validation check
|
|
Add-Type @"
|
|
using System.Net;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
|
|
public class IcingaUntrustedCertificateValidation : ICertificatePolicy {
|
|
public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) {
|
|
return true;
|
|
}
|
|
}
|
|
"@
|
|
|
|
[System.Net.ServicePointManager]::CertificatePolicy = New-Object IcingaUntrustedCertificateValidation;
|
|
|
|
if ($SuppressMessages -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'Successfully enabled untrusted certificate validation for this shell instance';
|
|
}
|
|
} catch {
|
|
if ($SuppressMessages -eq $FALSE) {
|
|
Write-IcingaConsoleError -Message 'Failed to enable untrusted certificate policy: {0}' -Objects $_.Exception.Message;
|
|
}
|
|
}
|
|
}
|
|
|
|
function Get-IcingaRESTHeaderValue()
|
|
{
|
|
param(
|
|
[hashtable]$Request = @{},
|
|
[string]$Header = $null
|
|
);
|
|
|
|
if ($null -eq $Request -or [string]::IsNullOrEmpty($Header) -Or $Request.Count -eq 0) {
|
|
return $null;
|
|
}
|
|
|
|
if ($Request.Header.ContainsKey($Header) -eq $FALSE) {
|
|
return $null
|
|
}
|
|
|
|
return $Request.Header[$Header];
|
|
}
|
|
|
|
function Get-IcingaRESTPathElement()
|
|
{
|
|
param(
|
|
[Hashtable]$Request = @{},
|
|
[int]$Index = 0
|
|
);
|
|
|
|
if ($null -eq $Request -Or $Request.Count -eq 0) {
|
|
return '';
|
|
}
|
|
|
|
if ($Request.ContainsKey('RequestPath') -eq $FALSE) {
|
|
return '';
|
|
}
|
|
|
|
if (($Index + 1) -gt $Request.RequestPath.PathArray.Count) {
|
|
return '';
|
|
}
|
|
|
|
return $Request.RequestPath.PathArray[$Index];
|
|
}
|
|
|
|
function Get-IcingaSSLCertForSocket()
|
|
{
|
|
param(
|
|
[string]$CertFile = $null,
|
|
[string]$CertThumbprint = $null
|
|
);
|
|
|
|
# At first check if we assigned a cert file to use directly and check
|
|
# if it is there and either import a PFX or use our convert function
|
|
# to get a proper certificate
|
|
if ([string]::IsNullOrEmpty($CertFile) -eq $FALSE) {
|
|
if ((Test-Path $CertFile)) {
|
|
if ([IO.Path]::GetExtension($CertFile) -eq '.pfx') {
|
|
return (New-Object Security.Cryptography.X509Certificates.X509Certificate2 $CertFile);
|
|
} else {
|
|
return ConvertTo-IcingaX509Certificate -CertFile $CertFile;
|
|
}
|
|
}
|
|
}
|
|
|
|
# We could also have assigned a Thumbprint to use from the
|
|
# Windows cert store. Try to look it up an return it if
|
|
# it is found
|
|
if ([string]::IsNullOrEmpty($CertThumbprint) -eq $FALSE) {
|
|
$Certificates = Get-ChildItem `
|
|
-Path 'cert:\*' `
|
|
-Recurse `
|
|
-Include $CertThumbprint `
|
|
-ErrorAction SilentlyContinue `
|
|
-WarningAction SilentlyContinue;
|
|
|
|
if ($Certificates.Count -ne 0) {
|
|
return $Certificates[0];
|
|
}
|
|
}
|
|
|
|
# If no cert file or thumbprint was specified or simpy as fallback,
|
|
# we should use the Icinga 2 Agent certificates
|
|
$AgentCertificate = Get-IcingaAgentHostCertificate;
|
|
|
|
# If Agent is not installed or certificates were not found,
|
|
# simply return null
|
|
if ($null -eq $AgentCertificate) {
|
|
return $null;
|
|
}
|
|
|
|
return (ConvertTo-IcingaX509Certificate -CertFile $AgentCertificate.CertFile);
|
|
}
|
|
|
|
function Get-IcingaTCPClientRemoteEndpoint()
|
|
{
|
|
param(
|
|
[System.Net.Sockets.TcpClient]$Client = $null
|
|
);
|
|
|
|
if ($null -eq $Client) {
|
|
return 'unknown';
|
|
}
|
|
|
|
return $Client.Client.RemoteEndPoint;
|
|
}
|
|
|
|
<#
|
|
# 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]$HTTPResponseCode = @{
|
|
200 = 'Ok';
|
|
400 = 'Bad Request';
|
|
401 = 'Unauthorized';
|
|
403 = 'Forbidden';
|
|
404 = 'Not Found'
|
|
500 = 'Internal Server Error';
|
|
};
|
|
|
|
[hashtable]$HTTPResponseType = @{
|
|
'Ok' = 200;
|
|
'Bad Request' = 400;
|
|
'Unauthorized' = 401;
|
|
'Forbidden' = 403;
|
|
'Not Found' = 404;
|
|
'Internal Server Error' = 500;
|
|
};
|
|
|
|
<#
|
|
# Once we defined a new enum hashtable above, simply add it to this list
|
|
# to make it available within the entire module.
|
|
#
|
|
# Example usage:
|
|
# $IcingaHTTPEnums.HTTPResponseType.Ok
|
|
#>
|
|
[hashtable]$IcingaHTTPEnums = @{
|
|
HTTPResponseCode = $HTTPResponseCode;
|
|
HTTPResponseType = $HTTPResponseType;
|
|
}
|
|
|
|
Export-ModuleMember -Variable @( 'IcingaHTTPEnums' );
|
|
|
|
function New-IcingaSSLStream()
|
|
{
|
|
param(
|
|
[System.Net.Sockets.TcpClient]$Client = $null,
|
|
[Security.Cryptography.X509Certificates.X509Certificate2]$Certificate = $null
|
|
);
|
|
|
|
if ($null -eq $Client) {
|
|
return $null;
|
|
}
|
|
|
|
try {
|
|
$SSLStream = New-Object System.Net.Security.SslStream($Client.GetStream(), $false)
|
|
$SSLStream.AuthenticateAsServer($Certificate, $false, [System.Security.Authentication.SslProtocols]::Tls12, $true) | Out-Null;
|
|
} catch {
|
|
Write-IcingaEventMessage -EventId 1500 -Namespace 'Framework' -Objects $Client.Client;
|
|
return $null;
|
|
}
|
|
|
|
return $SSLStream;
|
|
}
|
|
|
|
function New-IcingaTCPClient()
|
|
{
|
|
param(
|
|
[System.Net.Sockets.TcpListener]$Socket = $null
|
|
);
|
|
|
|
if ($null -eq $Socket) {
|
|
return $null;
|
|
}
|
|
|
|
[System.Net.Sockets.TcpClient]$Client = $Socket.AcceptTcpClient();
|
|
|
|
Write-IcingaDebugMessage -Message (
|
|
[string]::Format(
|
|
'New incoming client connection for endpoint {0}',
|
|
(Get-IcingaTCPClientRemoteEndpoint -Client $Client)
|
|
)
|
|
);
|
|
|
|
return $Client;
|
|
}
|
|
|
|
function New-IcingaTCPClientRESTMessage()
|
|
{
|
|
param(
|
|
[Hashtable]$Headers = $null,
|
|
$ContentBody = $null,
|
|
[int]$HTTPResponse = 200,
|
|
[switch]$BasicAuth = $FALSE
|
|
);
|
|
|
|
[string]$ContentLength = '';
|
|
[string]$HTMLContent = '';
|
|
[string]$AuthHeader = '';
|
|
|
|
if ($null -ne $ContentBody) {
|
|
$json = ConvertTo-Json $ContentBody -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,
|
|
(New-IcingaNewLine)
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($BasicAuth) {
|
|
$AuthHeader = [string]::Format(
|
|
'WWW-Authenticate: Basic realm="Icinga for Windows"{0}',
|
|
(New-IcingaNewLine)
|
|
);
|
|
}
|
|
|
|
$ResponseMeessage = -Join(
|
|
[string]::Format(
|
|
'HTTP/1.1 {0} {1}{2}',
|
|
$HTTPResponse,
|
|
$IcingaHTTPEnums.HTTPResponseCode[$HTTPResponse],
|
|
(New-IcingaNewLine)
|
|
),
|
|
[string]::Format(
|
|
'Server: {0}{1}',
|
|
(Get-IcingaHostname -LowerCase $TRUE -AutoUseFQDN $TRUE),
|
|
(New-IcingaNewLine)
|
|
),
|
|
[string]::Format(
|
|
'Content-Type: application/json{0}',
|
|
(New-IcingaNewLine)
|
|
),
|
|
$AuthHeader,
|
|
$ContentLength,
|
|
(New-IcingaNewLine),
|
|
$HTMLContent
|
|
);
|
|
|
|
# Encode our message before sending it
|
|
$UTF8Message = [System.Text.Encoding]::UTF8.GetBytes($ResponseMeessage);
|
|
|
|
return @{
|
|
'message' = $UTF8Message;
|
|
'length' = $UTF8Message.Length;
|
|
};
|
|
}
|
|
|
|
function New-IcingaTCPSocket()
|
|
{
|
|
param (
|
|
[string]$Address = '',
|
|
[int]$Port = 0,
|
|
[switch]$Start = $FALSE
|
|
);
|
|
|
|
if ($Port -eq 0) {
|
|
throw 'Please specify a valid port to open a TCP socket for';
|
|
}
|
|
|
|
# Listen on localhost by default
|
|
$ListenAddress = New-Object System.Net.IPEndPoint([IPAddress]::Loopback, $Port);
|
|
|
|
if ([string]::IsNullOrEmpty($Address) -eq $FALSE) {
|
|
$ListenAddress = New-Object System.Net.IPEndPoint([IPAddress]::Parse($Address), $Port);
|
|
}
|
|
|
|
$TCPSocket = New-Object 'System.Net.Sockets.TcpListener' $ListenAddress;
|
|
|
|
Write-IcingaDebugMessage -Message (
|
|
[string]::Format(
|
|
'Creating new TCP socket on Port {0}. Endpoint configuration {1}',
|
|
$Port,
|
|
$TCPSocket.LocalEndpoint
|
|
)
|
|
);
|
|
|
|
if ($Start) {
|
|
Write-IcingaDebugMessage -Message (
|
|
[string]::Format(
|
|
'Starting TCP socket for endpoint {0}',
|
|
$TCPSocket.LocalEndpoint
|
|
)
|
|
);
|
|
$TCPSocket.Start();
|
|
}
|
|
|
|
return $TCPSocket;
|
|
}
|
|
|
|
function Open-IcingaTCPClientConnection()
|
|
{
|
|
param(
|
|
[System.Net.Sockets.TcpClient]$Client = $null,
|
|
[Security.Cryptography.X509Certificates.X509Certificate2]$Certificate = $null
|
|
);
|
|
|
|
if ($null -eq $Client -Or $null -eq $Certificate) {
|
|
return $null;
|
|
}
|
|
|
|
$Stream = New-IcingaSSLStream -Client $Client -Certificate $Certificate;
|
|
|
|
return @{
|
|
'Client' = $Client;
|
|
'Stream' = $Stream;
|
|
};
|
|
}
|
|
|
|
function Read-IcingaRESTMessage()
|
|
{
|
|
param(
|
|
[string]$RestMessage = $null,
|
|
[hashtable]$Connection = $null
|
|
);
|
|
|
|
# Just in case we didnt receive anything - no need to
|
|
# parse through everything
|
|
if ([string]::IsNullOrEmpty($RestMessage)) {
|
|
return $null;
|
|
}
|
|
|
|
Write-IcingaDebugMessage (
|
|
[string]::Format(
|
|
'Receiving client message{0}{0}{1}',
|
|
(New-IcingaNewline),
|
|
$RestMessage
|
|
)
|
|
);
|
|
|
|
[hashtable]$Request = @{};
|
|
$RestMessage -match '(.+) (.+) (.+)' | Out-Null;
|
|
|
|
$Request.Add('Method', $Matches[1]);
|
|
$Request.Add('FullRequest', $Matches[2]);
|
|
$Request.Add('RequestPath', @{});
|
|
$Request.Add('RequestArguments', @{});
|
|
|
|
#Path
|
|
$PathMatch = $Matches[2];
|
|
$PathMatch -match '((\/[^\/\?]+)*)\??([^\/]*)' | Out-Null;
|
|
$Arguments = $Matches[3];
|
|
$Request.RequestPath.Add('FullPath', $Matches[1]);
|
|
$Request.RequestPath.Add('PathArray', $Matches[1].TrimStart('/').Split('/'));
|
|
|
|
$Matches = $null;
|
|
|
|
# Arguments
|
|
$ArgumentsSplit = $Arguments.Split('&');
|
|
$ArgumentsSplit+='\\\\\\\\\\\\=FIN';
|
|
foreach ( $Argument in $ArgumentsSplit | Sort-Object -Descending) {
|
|
if ($Argument.Contains('=')) {
|
|
$Argument -match '(.+)=(.+)' | Out-Null;
|
|
If (($Matches[1] -ne $Current) -And ($NULL -ne $Current)) {
|
|
$Request.RequestArguments.Add( $Current, $ArgumentContent );
|
|
[array]$ArgumentContent = $null;
|
|
}
|
|
$Current = $Matches[1];
|
|
[array]$ArgumentContent += ($Matches[2]);
|
|
} else {
|
|
$Request.RequestArguments.Add( $Argument, $null );
|
|
}
|
|
}
|
|
|
|
# Header
|
|
$Request.Add( 'Header', @{ } );
|
|
$SplitString = $RestMessage.Split("`r`n");
|
|
|
|
foreach ( $SingleString in $SplitString ) {
|
|
if ( ([string]::IsNullOrEmpty($SingleString) -eq $FALSE) -And ($SingleString -match '^{.+' -eq $FALSE) -And $SingleString.Contains(':') -eq $TRUE ) {
|
|
$SingleSplitString = $SingleString.Split(':', 2);
|
|
$Request.Header.Add( $SingleSplitString[0], $SingleSplitString[1].Trim());
|
|
}
|
|
}
|
|
|
|
$Request.Add('ContentLength', [int](Get-IcingaRESTHeaderValue -Header 'Content-Length' -Request $Request));
|
|
|
|
$Matches = $null;
|
|
|
|
# Body
|
|
$RestMessage -match '(\{(.*\n)*}|\{.*\})' | Out-Null;
|
|
|
|
if ($null -ne $Matches) {
|
|
$Request.Add('Body', $Matches[1]);
|
|
}
|
|
|
|
# We received a content length, but couldnt load the body. Some clients will send the body as separate message
|
|
# Lets try to read the body content
|
|
if ($null -ne $Connection) {
|
|
if ($Request.ContainsKey('ContentLength') -And $Request.ContentLength -gt 0 -And ($Request.ContainsKey('Body') -eq $FALSE -Or [string]::IsNullOrEmpty($Request.Body))) {
|
|
$Request.Body = Read-IcingaTCPStream -Client $Connection.Client -Stream $Connection.Stream -ReadLength $Request.ContentLength;
|
|
Write-IcingaDebugMessage -Message 'Body Content' -Objects $Request;
|
|
}
|
|
}
|
|
|
|
return $Request;
|
|
}
|
|
|
|
function Read-IcingaTCPStream()
|
|
{
|
|
param(
|
|
[System.Net.Sockets.TcpClient]$Client = @{},
|
|
[System.Net.Security.SslStream]$Stream = $null,
|
|
[int]$ReadLength = 0
|
|
);
|
|
|
|
if ($ReadLength -eq 0) {
|
|
$ReadLength = $Client.ReceiveBufferSize;
|
|
}
|
|
|
|
if ($null -eq $Stream) {
|
|
return $null;
|
|
}
|
|
|
|
# Get the maxium size of our buffer
|
|
[byte[]]$bytes = New-Object byte[] $ReadLength;
|
|
|
|
# Read the content of our SSL stream
|
|
$MessgeSize = $Stream.Read($bytes, 0, $ReadLength);
|
|
|
|
Write-IcingaDebugMessage -Message 'Network Stream message size and content in bytes' -Objects $MessgeSize, $bytes;
|
|
|
|
# Resize our array to the correct size
|
|
[byte[]]$resized = New-Object byte[] $MessgeSize;
|
|
[array]::Copy($bytes, 0, $resized, 0, $MessgeSize);
|
|
|
|
# Return our message content
|
|
return [System.Text.Encoding]::UTF8.GetString($resized);
|
|
}
|
|
|
|
function Send-IcingaTCPClientMessage()
|
|
{
|
|
param(
|
|
[Hashtable]$Message = @{},
|
|
[System.Net.Security.SslStream]$Stream = $null
|
|
);
|
|
|
|
if ($null -eq $Message -Or $Message.Count -eq 0 -Or $Message.length -eq 0) {
|
|
return;
|
|
}
|
|
|
|
$Stream.Write($Message.message, 0, $Message.length);
|
|
$Stream.Flush();
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Sends a basic auth request back to the client
|
|
.DESCRIPTION
|
|
Sends a basic auth request back to the client
|
|
.FUNCTIONALITY
|
|
Sends a basic auth request back to the client
|
|
.EXAMPLE
|
|
PS>Send-IcingaWebAuthMessage -Connection $Connection;
|
|
.PARAMETER Connection
|
|
The connection data of the Framework containing the client and stream object
|
|
.INPUTS
|
|
System.Hashtable
|
|
.OUTPUTS
|
|
Null
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Send-IcingaWebAuthMessage()
|
|
{
|
|
param (
|
|
[Hashtable]$Connection = @{}
|
|
);
|
|
|
|
Send-IcingaTCPClientMessage -Message (
|
|
New-IcingaTCPClientRESTMessage `
|
|
-HTTPResponse ($IcingaHTTPEnums.HTTPResponseType.Unauthorized) `
|
|
-ContentBody 'Please provide your credentials for login.' `
|
|
-BasicAuth
|
|
) -Stream $Connection.Stream;
|
|
}
|
|
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Tests provided credentials against either the local machine or a domain controller
|
|
.DESCRIPTION
|
|
Tests provided credentials against either the local machine or a domain controller
|
|
.FUNCTIONALITY
|
|
Tests provided credentials against either the local machine or a domain controller
|
|
.EXAMPLE
|
|
PS>Test-IcingaRESTCredentials $UserName $SecureUser -Password $SecurePassword;
|
|
.EXAMPLE
|
|
PS>Test-IcingaRESTCredentials $UserName $SecureUser -Password $SecurePassword -Domain 'Example';
|
|
.PARAMETER UserName
|
|
The username to use for login as SecureString
|
|
.PARAMETER Password
|
|
The password to use for login as SecureString
|
|
.PARAMETER Domain
|
|
The domain to use for login as string
|
|
.INPUTS
|
|
System.SecureString
|
|
.OUTPUTS
|
|
System.Boolean
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
|
|
function Test-IcingaRESTCredentials()
|
|
{
|
|
param (
|
|
[SecureString]$UserName,
|
|
[SecureString]$Password,
|
|
[String]$Domain
|
|
);
|
|
|
|
Add-Type -AssemblyName System.DirectoryServices.AccountManagement;
|
|
|
|
# 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
|
|
Write-IcingaEventMessage -EventId 1560 -Namespace 'Framework' -Objects $_.Exception;
|
|
return $FALSE;
|
|
}
|
|
|
|
# In case we couldn't setup the Account Service, always return false
|
|
if ($null -eq $AccountService) {
|
|
return $FALSE;
|
|
}
|
|
|
|
try {
|
|
# Try to authenticate and either return true or false as integer
|
|
[bool]$AuthResult = [int]($AccountService.ValidateCredentials(
|
|
(ConvertFrom-IcingaSecureString $UserName),
|
|
(ConvertFrom-IcingaSecureString $Password)
|
|
)
|
|
);
|
|
|
|
return $AuthResult;
|
|
} catch {
|
|
Write-IcingaEventMessage -EventId 1561 -Namespace 'Framework' -Objects $_.Exception;
|
|
}
|
|
|
|
return $FALSE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Sets permissions for a specific Wmi namespace for a user. You can grant basic permissions based
|
|
on the arguments available and grant additional ones with the `-Flags` argument.
|
|
.DESCRIPTION
|
|
Sets permissions for a specific Wmi namespace for a user. You can grant basic permissions based
|
|
on the arguments available and grant additional ones with the `-Flags` argument.
|
|
.PARAMETER User
|
|
The user to set permissions for. Can either be a local or domain user
|
|
.PARAMETER Namespace
|
|
The Wmi namespace to grant permissions for. Required namespaces are listed within each plugin documentation
|
|
.PARAMETER Enable
|
|
Enables the account and grants the user read permissions. This is a default access right for all users and corresponds to the Enable Account permission on the Security tab of the WMI Control. For more information, see Setting Namespace Security with the WMI Control.
|
|
.PARAMETER RemoteAccess
|
|
Allows a user account to remotely perform any operations allowed by the permissions described above. Only members of the Administrators group have this right. WBEM_REMOTE_ACCESS corresponds to the Remote Enable permission on the Security tab of the WMI Control.
|
|
.PARAMETER Recurse
|
|
Applies a container inherit flag and grants permission not only on the specific Wmi tree but also objects within this namespace (recommended)
|
|
.PARAMETER DenyAccess
|
|
Blocks the user from having access to this Wmi and or subnamespace tree.
|
|
.PARAMETER Flags
|
|
Allows to specify additional flags for permssion granting: PartialWrite, Subscribe, ProviderWrite,ReadSecurity, WriteSecurity, Publish, MethodExecute, FullWrite
|
|
.EXAMPLE
|
|
PS>Add-IcingaWmiPermissions -Namespace 'root\cimv2' -User icinga -Enable;
|
|
.EXAMPLE
|
|
PS>Add-IcingaWmiPermissions -Namespace 'root\cimv2' -User 'ICINGADOMAIN\icinga' -Enable -RemoteAccess;
|
|
.EXAMPLE
|
|
PS>Add-IcingaWmiPermissions -Namespace 'root\cimv2' -User 'ICINGADOMAIN\icinga' -Enable -RemoteAccess -Recurse;
|
|
.EXAMPLE
|
|
PS>Add-IcingaWmiPermissions -Namespace 'root\cimv2' -User 'ICINGADOMAIN\icinga' -Enable -RemoteAccess -Flags 'ReadSecurity', 'MethodExecute' -Recurse;
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
#>
|
|
|
|
function Add-IcingaWmiPermissions()
|
|
{
|
|
param (
|
|
[string]$User,
|
|
[string]$Namespace,
|
|
[switch]$Enable,
|
|
[switch]$RemoteAccess,
|
|
[switch]$Recurse,
|
|
[switch]$DenyAccess,
|
|
[array]$Flags
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($User)) {
|
|
Write-IcingaConsoleError 'Please enter a valid username';
|
|
return $FALSE;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Namespace)) {
|
|
Write-IcingaConsoleError 'You have to specify a Wmi namespace to grant permissions for';
|
|
return $FALSE;
|
|
}
|
|
|
|
[int]$PermissionMask = New-IcingaWmiPermissionMask -Enable:$Enable -RemoteAccess:$RemoteAccess -Flags $Flags;
|
|
|
|
if ($PermissionMask -eq 0) {
|
|
Write-IcingaConsoleError 'You have to specify permissions to grant for a specific user';
|
|
return $FALSE;
|
|
}
|
|
|
|
if (Test-IcingaWmiPermissions -User $User -Namespace $Namespace -Enable:$Enable -RemoteAccess:$RemoteAccess -Recurse:$Recurse -DenyAccess:$DenyAccess -Flags $Flags) {
|
|
Write-IcingaConsoleNotice 'Wmi permissions for user "{0}" are already set.' -Objects $User;
|
|
return $TRUE;
|
|
} else {
|
|
Write-IcingaConsoleNotice 'Removing possible existing configuration for this user before continuing';
|
|
Remove-IcingaWmiPermissions -User $User -Namespace $Namespace | Out-Null;
|
|
}
|
|
|
|
$WmiSecurity = Get-IcingaWmiSecurityData -User $User -Namespace $Namespace;
|
|
|
|
if ($null -eq $WmiSecurity) {
|
|
return $FALSE;
|
|
}
|
|
|
|
$WmiAce = (New-Object System.Management.ManagementClass("Win32_Ace")).CreateInstance();
|
|
$WmiAce.AccessMask = $PermissionMask;
|
|
|
|
if ($Recurse) {
|
|
$WmiAce.AceFlags = $IcingaWBEM.AceFlags.Container_Inherit;
|
|
} else {
|
|
$WmiAce.AceFlags = 0;
|
|
}
|
|
|
|
$WmiTrustee = (New-Object System.Management.ManagementClass("Win32_Trustee")).CreateInstance();
|
|
$WmiTrustee.SidString = Get-IcingaUserSID -User $User;
|
|
$WmiAce.Trustee = $WmiTrustee
|
|
|
|
if ($DenyAccess) {
|
|
$WmiAce.AceType = $IcingaWBEM.AceFlags.Access_Denied;
|
|
} else {
|
|
$WmiAce.AceType = $IcingaWBEM.AceFlags.Access_Allowed;
|
|
}
|
|
|
|
$WmiSecurity.WmiAcl.DACL += $WmiAce.PSObject.immediateBaseObject;
|
|
|
|
$WmiSecurity.WmiArguments.Name = 'SetSecurityDescriptor';
|
|
$WmiSecurity.WmiArguments.Add('ArgumentList', $WmiSecurity.WmiAcl.PSObject.immediateBaseObject);
|
|
$WmiArguments = $WmiSecurity.WmiArguments;
|
|
|
|
$WmiSecurityData = Invoke-WmiMethod @WmiArguments;
|
|
if ($WmiSecurityData.ReturnValue -ne 0) {
|
|
Write-IcingaConsoleError 'Failed to set Wmi security descriptor information with error {0}' -Objects $WmiSecurityData.ReturnValue;
|
|
return $FALSE;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Wmi permissions for Namespace "{0}" and user "{1}" have been set successfully' -Objects $Namespace, $User;
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Allows to query Wmi information by either using Wmi directly or Cim. This provides a save handling
|
|
to call Wmi classes, as we are catching possible errors including missing permissions for better
|
|
and improved error output during plugin execution.
|
|
.DESCRIPTION
|
|
Allows to query Wmi information by either using Wmi directly or Cim. This provides a save handling
|
|
to call Wmi classes, as we are catching possible errors including missing permissions for better
|
|
and improved error output during plugin execution.
|
|
.PARAMETER ClassName
|
|
The Wmi class to fetch information from
|
|
.PARAMETER Filter
|
|
Allows to filter only for specific Wmi information. The syntax is identical to Get-WmiObject and Get-CimInstance
|
|
.PARAMETER Namespace
|
|
The Wmi namespace to lookup additional information. The syntax is identical to Get-WmiObject and Get-CimInstance
|
|
.PARAMETER ForceWMI
|
|
Forces the usage of `Get-WmiObject` instead of `Get-CimInstance`
|
|
.EXAMPLE
|
|
PS>Get-IcingaWindowsInformation -ClassName Win32_Service;
|
|
.EXAMPLE
|
|
PS>Get-IcingaWindowsInformation -ClassName Win32_Service -ForceWMI;
|
|
.EXAMPLE
|
|
PS>Get-IcingaWindowsInformation -ClassName MSFT_NetAdapter -NameSpace 'root\StandardCimv2';
|
|
.EXAMPLE
|
|
PS>Get-IcingaWindowsInformation Win32_LogicalDisk -Filter 'DriveType = 3';
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
#>
|
|
|
|
function Get-IcingaWindowsInformation()
|
|
{
|
|
param (
|
|
[string]$ClassName,
|
|
$Filter,
|
|
$Namespace,
|
|
[switch]$ForceWMI = $FALSE
|
|
);
|
|
|
|
$Arguments = @{
|
|
'ClassName' = $ClassName;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Filter) -eq $FALSE) {
|
|
$Arguments.Add(
|
|
'Filter', $Filter
|
|
);
|
|
}
|
|
if ([string]::IsNullOrEmpty($Namespace) -eq $FALSE) {
|
|
$Arguments.Add(
|
|
'Namespace', $Namespace
|
|
);
|
|
}
|
|
|
|
if ($ForceWMI -eq $FALSE -And (Get-Command 'Get-CimInstance' -ErrorAction SilentlyContinue)) {
|
|
try {
|
|
$CimData = (Get-CimInstance @Arguments -ErrorAction Stop);
|
|
|
|
Write-IcingaDebugMessage 'Debug output for "Get-IcingaWindowsInformation::Get-CimInstance"' -Objects $ClassName, $Filter, $Namespace, ($CimData | Out-String);
|
|
|
|
return $CimData;
|
|
} catch {
|
|
$ErrorName = $_.Exception.NativeErrorCode;
|
|
$ErrorMessage = $_.Exception.Message;
|
|
$ErrorCode = $_.Exception.StatusCode;
|
|
|
|
if ([string]::IsNullOrEmpty($Namespace)) {
|
|
$Namespace = 'root/cimv2';
|
|
}
|
|
|
|
switch ($ErrorCode) {
|
|
# Permission error
|
|
2 {
|
|
Exit-IcingaThrowException -ExceptionType 'Permission' -ExceptionThrown $IcingaExceptions.Permission.CimInstance -CustomMessage ([string]::Format('Class: "{0}", Namespace: "{1}"', $ClassName, $Namespace)) -Force;
|
|
};
|
|
# InvalidClass
|
|
5 {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.CimClassNameUnknown -CustomMessage $ClassName -Force;
|
|
};
|
|
# All other errors
|
|
default {
|
|
Exit-IcingaThrowException -ExceptionType 'Custom' -InputString $ErrorMessage -CustomMessage ([string]::Format('CimInstanceUnhandledError: Class "{0}": Error "{1}": Id "{2}"', $ClassName, $ErrorName, $ErrorCode)) -Force;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((Get-Command 'Get-WmiObject' -ErrorAction SilentlyContinue)) {
|
|
try {
|
|
$WmiData = (Get-WmiObject @Arguments -ErrorAction Stop);
|
|
|
|
Write-IcingaDebugMessage 'Debug output for "Get-IcingaWindowsInformation::Get-WmiObject"' -Objects $ClassName, $Filter, $Namespace, ($WmiData | Out-String);
|
|
|
|
return $WmiData;
|
|
} catch {
|
|
$ErrorName = $_.CategoryInfo.Category;
|
|
$ErrorMessage = $_.Exception.Message;
|
|
$ErrorCode = ($_.Exception.HResult -band 0xFFFF);
|
|
|
|
if ([string]::IsNullOrEmpty($Namespace)) {
|
|
$Namespace = 'root/cimv2';
|
|
}
|
|
|
|
switch ($ErrorName) {
|
|
# Permission error
|
|
'InvalidOperation' {
|
|
Exit-IcingaThrowException -ExceptionType 'Permission' -ExceptionThrown $IcingaExceptions.Permission.WMIObject -CustomMessage ([string]::Format('Class: "{0}", Namespace: "{1}"', $ClassName, $Namespace)) -Force;
|
|
};
|
|
# Invalid Class
|
|
'InvalidType' {
|
|
Exit-IcingaThrowException -ExceptionType 'Input' -ExceptionThrown $IcingaExceptions.Inputs.WmiObjectClassUnknown -CustomMessage $ClassName -Force;
|
|
};
|
|
# All other errors
|
|
default {
|
|
Exit-IcingaThrowException -ExceptionType 'Custom' -InputString $ErrorMessage -CustomMessage ([string]::Format('WmiObjectUnhandledError: Class "{0}": Error "{1}": Id "{2}"', $ClassName, $ErrorName, $ErrorCode)) -Force;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Exception
|
|
Exit-IcingaThrowException -ExceptionType 'Custom' -InputString 'Failed to fetch Windows information by using CimInstance or WmiObject. Both commands are not present on the system.' -CustomMessage ([string]::Format('CimWmiUnhandledError: Class "{0}"', $ClassName)) -Force;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Returns several information about the Wmi namespace and the provided user data to
|
|
work with them while adding/testing/removing Wmi permissions
|
|
.DESCRIPTION
|
|
Returns several information about the Wmi namespace and the provided user data to
|
|
work with them while adding/testing/removing Wmi permissions
|
|
.PARAMETER User
|
|
The user to set permissions for. Can either be a local or domain user
|
|
.PARAMETER Namespace
|
|
The Wmi namespace to grant permissions for. Required namespaces are listed within each plugin documentation
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Hashtable
|
|
#>
|
|
|
|
function Get-IcingaWmiSecurityData()
|
|
{
|
|
param (
|
|
[string]$User,
|
|
[string]$Namespace
|
|
);
|
|
|
|
[hashtable]$WmiArguments = @{
|
|
'Name' = 'GetSecurityDescriptor';
|
|
'Namespace' = $Namespace;
|
|
'Path' = "__systemsecurity=@";
|
|
}
|
|
|
|
$WmiSecurityData = Invoke-WmiMethod @WmiArguments;
|
|
|
|
if ($WmiSecurityData.ReturnValue -ne 0) {
|
|
Write-IcingaConsoleError 'Fetching Wmi security descriptor information failed with error {0}' -Objects $WmiSecurityData.ReturnValue;
|
|
return $null;
|
|
}
|
|
|
|
$UserData = Split-IcingaUserDomain -User $User;
|
|
$UserSID = Get-IcingaUserSID -User $User;
|
|
$WmiAcl = $WmiSecurityData.Descriptor;
|
|
|
|
if ([string]::IsNullOrEmpty($UserSID)) {
|
|
Write-IcingaConsoleError 'Unable to load the SID for user "{0}"' -Objects $User;
|
|
return $null;
|
|
}
|
|
|
|
return @{
|
|
'WmiArguments' = $WmiArguments;
|
|
'UserData' = $UserData;
|
|
'UserSID' = $UserSID;
|
|
'WmiAcl' = $WmiAcl;
|
|
}
|
|
}
|
|
|
|
<#
|
|
# WMI WBEM_SECURITY_FLAGS
|
|
# https://docs.microsoft.com/en-us/windows/win32/api/wbemcli/ne-wbemcli-wbem_security_flags
|
|
# https://docs.microsoft.com/en-us/windows/win32/secauthz/standard-access-rights
|
|
#>
|
|
|
|
[hashtable]$SecurityFlags = @{
|
|
'WBEM_Enable' = 1;
|
|
'WBEM_Method_Execute' = 2;
|
|
'WBEM_Full_Write_Rep' = 4;
|
|
'WBEM_Partial_Write_Rep' = 8;
|
|
'WBEM_Write_Provider' = 0x10;
|
|
'WBEM_Remote_Access' = 0x20;
|
|
'WBEM_Right_Subscribe' = 0x40;
|
|
'WBEM_Right_Publish' = 0x80;
|
|
'Read_Control' = 0x20000;
|
|
'Write_DAC' = 0x40000;
|
|
};
|
|
|
|
[hashtable]$SecurityDescription = @{
|
|
1 = 'Enables the account and grants the user read permissions. This is a default access right for all users and corresponds to the Enable Account permission on the Security tab of the WMI Control. For more information, see Setting Namespace Security with the WMI Control.';
|
|
2 = 'Allows the execution of methods. Providers can perform additional access checks. This is a default access right for all users and corresponds to the Execute Methods permission on the Security tab of the WMI Control.';
|
|
4 = 'Allows a user account to write to classes in the WMI repository as well as instances. A user cannot write to system classes. Only members of the Administrators group have this permission. WBEM_FULL_WRITE_REP corresponds to the Full Write permission on the Security tab of the WMI Control.';
|
|
8 = 'Allows you to write data to instances only, not classes. A user cannot write classes to the WMI repository. Only members of the Administrators group have this right. WBEM_PARTIAL_WRITE_REP corresponds to the Partial Write permission on the Security tab of the WMI Control.';
|
|
0x10 = 'Allows writing classes and instances to providers. Note that providers can do additional access checks when impersonating a user. This is a default access right for all users and corresponds to the Provider Write permission on the Security tab of the WMI Control.';
|
|
0x20 = 'Allows a user account to remotely perform any operations allowed by the permissions described above. Only members of the Administrators group have this right. WBEM_REMOTE_ACCESS corresponds to the Remote Enable permission on the Security tab of the WMI Control.';
|
|
0x40 = 'Specifies that a consumer can subscribe to the events delivered to a sink. Used in IWbemEventSink::SetSinkSecurity.';
|
|
0x80 = 'Specifies that the account can publish events to the instance of __EventFilter that defines the event filter for a permanent consumer. Available in wbemcli.h.';
|
|
0x20000 = 'The right to read the information in the objects security descriptor, not including the information in the system access control list (SACL).';
|
|
0x40000 = 'The right to modify the discretionary access control list (DACL) in the objects security descriptor.';
|
|
};
|
|
|
|
[hashtable]$SecurityNames = @{
|
|
'Enable' = 'WBEM_Enable';
|
|
'MethodExecute' = 'WBEM_Method_Execute';
|
|
'FullWrite' = 'WBEM_Full_Write_Rep';
|
|
'PartialWrite' = 'WBEM_Partial_Write_Rep';
|
|
'ProviderWrite' = 'WBEM_Write_Provider';
|
|
'RemoteAccess' = 'WBEM_Remote_Access';
|
|
'Subscribe' = 'WBEM_Right_Subscribe';
|
|
'Publish' = 'WBEM_Right_Publish';
|
|
'ReadSecurity' = 'Read_Control';
|
|
'WriteSecurity' = 'Write_DAC';
|
|
};
|
|
|
|
[hashtable]$AceFlags = @{
|
|
'Access_Allowed' = 0x0;
|
|
'Access_Denied' = 0x1;
|
|
'Container_Inherit' = 0x2;
|
|
}
|
|
|
|
[hashtable]$IcingaWBEM = @{
|
|
SecurityFlags = $SecurityFlags;
|
|
SecurityDescription = $SecurityDescription
|
|
SecurityNames = $SecurityNames;
|
|
AceFlags = $AceFlags;
|
|
}
|
|
|
|
Export-ModuleMember -Variable @( 'IcingaWBEM' );
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Generates a permission mask based on the set and provided flags which are used
|
|
for adding/testing Wmi permissions
|
|
.DESCRIPTION
|
|
Generates a permission mask based on the set and provided flags which are used
|
|
for adding/testing Wmi permissions
|
|
.PARAMETER Enable
|
|
Enables the account and grants the user read permissions. This is a default access right for all users and corresponds to the Enable Account permission on the Security tab of the WMI Control. For more information, see Setting Namespace Security with the WMI Control.
|
|
.PARAMETER RemoteAccess
|
|
Allows a user account to remotely perform any operations allowed by the permissions described above. Only members of the Administrators group have this right. WBEM_REMOTE_ACCESS corresponds to the Remote Enable permission on the Security tab of the WMI Control.
|
|
.PARAMETER Flags
|
|
Allows to specify additional flags for permssion granting: PartialWrite, Subscribe, ProviderWrite,ReadSecurity, WriteSecurity, Publish, MethodExecute, FullWrite
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Int
|
|
#>
|
|
|
|
function New-IcingaWmiPermissionMask()
|
|
{
|
|
param (
|
|
[switch]$Enable,
|
|
[switch]$RemoteAccess,
|
|
[array]$Flags
|
|
);
|
|
|
|
[int]$PermissionMask = 0;
|
|
|
|
if ($Enable) {
|
|
$PermissionMask += $IcingaWBEM.SecurityFlags.WBEM_Enable;
|
|
}
|
|
if ($RemoteAccess) {
|
|
$PermissionMask += $IcingaWBEM.SecurityFlags.WBEM_Remote_Access;
|
|
}
|
|
|
|
foreach ($flag in $Flags) {
|
|
if ($flag -like 'Enable' -And $Enable) {
|
|
continue;
|
|
}
|
|
if ($flag -like 'RemoteAccess' -And $RemoteAccess) {
|
|
continue;
|
|
}
|
|
|
|
if ($IcingaWBEM.SecurityNames.ContainsKey($flag) -eq $FALSE) {
|
|
Write-IcingaConsoleError 'Invalid Security flag "{0}" . Supported flags: {1}' -Objects $flag, $IcingaWBEM.SecurityNames.Keys;
|
|
return $FALSE;
|
|
}
|
|
|
|
$PermissionMask += $IcingaWBEM.SecurityFlags[$IcingaWBEM.SecurityNames[$flag]];
|
|
}
|
|
|
|
return $PermissionMask;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Removes a user from a specific Wmi namespace
|
|
.DESCRIPTION
|
|
Removes a user from a specific Wmi namespace
|
|
.PARAMETER User
|
|
The user to set permissions for. Can either be a local or domain user
|
|
.PARAMETER Namespace
|
|
The Wmi namespace to grant permissions for. Required namespaces are listed within each plugin documentation
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
#>
|
|
|
|
function Remove-IcingaWmiPermissions()
|
|
{
|
|
param (
|
|
[string]$User,
|
|
[string]$Namespace
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($User)) {
|
|
Write-IcingaConsoleError 'Please enter a valid username';
|
|
return $FALSE;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Namespace)) {
|
|
Write-IcingaConsoleError 'You have to specify a Wmi namespace to grant permissions for';
|
|
return $FALSE;
|
|
}
|
|
|
|
$WmiSecurity = Get-IcingaWmiSecurityData -User $User -Namespace $Namespace;
|
|
|
|
if ($null -eq $WmiSecurity) {
|
|
return $FALSE;
|
|
}
|
|
|
|
[System.Management.ManagementBaseObject[]]$RebasedDACL = @()
|
|
[bool]$UserPresent = $FALSE;
|
|
|
|
foreach ($entry in $WmiSecurity.WmiAcl.DACL) {
|
|
if ($entry.Trustee.SidString -ne $WmiSecurity.UserSID) {
|
|
$RebasedDACL += $entry.PSObject.immediateBaseObject;
|
|
} else {
|
|
$UserPresent = $TRUE;
|
|
}
|
|
}
|
|
|
|
if ($UserPresent -eq $FALSE) {
|
|
Write-IcingaConsoleNotice 'User "{0}" is not configured for namespace "{1}"' -Objects $User, $Namespace;
|
|
return $TRUE;
|
|
}
|
|
|
|
$WmiSecurity.WmiAcl.DACL = $RebasedDACL.PSObject.immediateBaseObject;
|
|
|
|
$WmiSecurity.WmiArguments.Name = 'SetSecurityDescriptor';
|
|
$WmiSecurity.WmiArguments.Add('ArgumentList', $WmiSecurity.WmiAcl.PSObject.immediateBaseObject);
|
|
$WmiArguments = $WmiSecurity.WmiArguments
|
|
|
|
$WmiSecurityData = Invoke-WmiMethod @WmiArguments;
|
|
if ($WmiSecurityData.ReturnValue -ne 0) {
|
|
Write-IcingaConsoleError 'Failed to set Wmi security descriptor information with error {0}' -Objects $WmiSecurityData.ReturnValue;
|
|
return $FALSE;
|
|
}
|
|
|
|
Write-IcingaConsoleNotice 'Removed user "{0}" from Namespace "{1}" successfully' -Objects $User, $Namespace;
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Tests if a specific WMI class including the Namespace can be accessed and returns status codes for possible errors/exceptions that might occur.
|
|
Returns binary operator values for easier comparison. In case no errors occurred it will return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.Ok
|
|
.DESCRIPTION
|
|
Tests if a specific WMI class including the Namespace can be accessed and returns status codes for possible errors/exceptions that might occur.
|
|
Returns binary operator values for easier comparison. In case no errors occurred it will return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.Ok
|
|
.ROLE
|
|
### WMI Permissions
|
|
|
|
No special permissions required as this Cmdlet will validate all input data and reports back the result.
|
|
.OUTPUTS
|
|
Name Value
|
|
---- -----
|
|
Ok 1
|
|
EmptyClass 2
|
|
PermissionError 4
|
|
ObjectNotFound 8
|
|
InvalidNameSpace 16
|
|
UnhandledException 32
|
|
NotSpecified 64
|
|
CimNotInstalled 128
|
|
.LINK
|
|
https://github.com/Icinga/icinga-powershell-framework
|
|
#>
|
|
function Test-IcingaWindowsInformation()
|
|
{
|
|
param (
|
|
[string]$ClassName,
|
|
[string]$NameSpace = 'Root\Cimv2'
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($ClassName)) {
|
|
return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.EmptyClass;
|
|
}
|
|
|
|
# Check with Get-CimClass for the specified WMI class and in the specified namespace default root\cimv2
|
|
if ((Test-IcingaFunction 'Get-CimInstance') -eq $FALSE ) {
|
|
return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.CimNotInstalled;
|
|
}
|
|
|
|
# We clear all previous errors so that we can catch the last error message from this try/catch in the plugins.
|
|
$Error.Clear();
|
|
|
|
try {
|
|
Get-CimInstance -ClassName $ClassName -Namespace $NameSpace -ErrorAction Stop | Out-Null;
|
|
} catch {
|
|
|
|
Write-IcingaConsoleDebug `
|
|
-Message "WMIClass: '{0}' : Namespace : {1} {2} {3}" `
|
|
-Objects $ClassName, $NameSpace, (New-IcingaNewLine), $_.Exception.Message;
|
|
|
|
if ($_.CategoryInfo.Category -like 'MetadataError') {
|
|
return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.InvalidNameSpace;
|
|
}
|
|
|
|
if ($_.CategoryInfo.Category -like 'ObjectNotFound') {
|
|
return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.ObjectNotFound;
|
|
}
|
|
|
|
if ($_.CategoryInfo.Category -like 'NotSpecified') {
|
|
return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.NotSpecified;
|
|
}
|
|
|
|
if ($_.CategoryInfo.Category -like 'PermissionDenied') {
|
|
return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.PermissionError;
|
|
}
|
|
|
|
return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.UnhandledException;
|
|
}
|
|
|
|
return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.Ok;
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Tests the current set permissions for a user on a specific namespace and returns true if the
|
|
current configuration is matching the intended configuration and returns false if either no
|
|
permissions are set yet or the intended configuration is not matching the current configuration
|
|
.DESCRIPTION
|
|
Tests the current set permissions for a user on a specific namespace and returns true if the
|
|
current configuration is matching the intended configuration and returns false if either no
|
|
permissions are set yet or the intended configuration is not matching the current configuration
|
|
.PARAMETER User
|
|
The user to set permissions for. Can either be a local or domain user
|
|
.PARAMETER Namespace
|
|
The Wmi namespace to grant permissions for. Required namespaces are listed within each plugin documentation
|
|
.PARAMETER Enable
|
|
Enables the account and grants the user read permissions. This is a default access right for all users and corresponds to the Enable Account permission on the Security tab of the WMI Control. For more information, see Setting Namespace Security with the WMI Control.
|
|
.PARAMETER RemoteAccess
|
|
Allows a user account to remotely perform any operations allowed by the permissions described above. Only members of the Administrators group have this right. WBEM_REMOTE_ACCESS corresponds to the Remote Enable permission on the Security tab of the WMI Control.
|
|
.PARAMETER Recurse
|
|
Applies a container inherit flag and grants permission not only on the specific Wmi tree but also objects within this namespace (recommended)
|
|
.PARAMETER DenyAccess
|
|
Blocks the user from having access to this Wmi and or subnamespace tree.
|
|
.PARAMETER Flags
|
|
Allows to specify additional flags for permssion granting: PartialWrite, Subscribe, ProviderWrite,ReadSecurity, WriteSecurity, Publish, MethodExecute, FullWrite
|
|
.INPUTS
|
|
System.String
|
|
.OUTPUTS
|
|
System.Boolean
|
|
#>
|
|
|
|
function Test-IcingaWmiPermissions()
|
|
{
|
|
param (
|
|
[string]$User,
|
|
[string]$Namespace,
|
|
[switch]$Enable,
|
|
[switch]$RemoteAccess,
|
|
[switch]$Recurse,
|
|
[switch]$DenyAccess,
|
|
[array]$Flags
|
|
);
|
|
|
|
if ([string]::IsNullOrEmpty($User)) {
|
|
Write-IcingaConsoleError 'Please enter a valid username';
|
|
return $FALSE;
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($Namespace)) {
|
|
Write-IcingaConsoleError 'You have to specify a Wmi namespace to grant permissions for';
|
|
return $FALSE;
|
|
}
|
|
|
|
[int]$PermissionMask = [int]$PermissionMask = New-IcingaWmiPermissionMask -Enable:$Enable -RemoteAccess:$RemoteAccess -Flags $Flags;
|
|
|
|
if ($PermissionMask -eq 0) {
|
|
Write-IcingaConsoleError 'You have to specify permissions to grant for a specific user';
|
|
return $FALSE;
|
|
}
|
|
|
|
$WmiSecurity = Get-IcingaWmiSecurityData -User $User -Namespace $Namespace;
|
|
|
|
if ($null -eq $WmiSecurity) {
|
|
return $FALSE;
|
|
}
|
|
|
|
[System.Management.ManagementBaseObject]$UserACL = $null;
|
|
|
|
foreach ($entry in $WmiSecurity.WmiAcl.DACL) {
|
|
if ($entry.Trustee.SidString -eq $WmiSecurity.UserSID) {
|
|
$UserACL = $entry.PSObject.immediateBaseObject;
|
|
break;
|
|
}
|
|
}
|
|
|
|
# No permissions granted for this user
|
|
if ($null -eq $UserACL) {
|
|
return $FALSE;
|
|
}
|
|
|
|
[bool]$RecurseMatch = $TRUE;
|
|
|
|
if ($Recurse -And $UserACL.AceFlags -ne $IcingaWBEM.AceFlags.Container_Inherit) {
|
|
$RecurseMatch = $FALSE;
|
|
} elseif ($Recurse -eq $FALSE -And $UserACL.AceFlags -ne 0) {
|
|
$RecurseMatch = $FALSE;
|
|
}
|
|
|
|
if ($UserACL.AccessMask -ne $PermissionMask -Or $RecurseMatch -eq $FALSE) {
|
|
return $FALSE;
|
|
}
|
|
|
|
return $TRUE;
|
|
}
|
|
|
|
Export-ModuleMember -Function @( '*' )
|