diff --git a/doc/04-Developer-Guide.md b/doc/04-Developer-Guide.md index 1338a7d..6702cae 100644 --- a/doc/04-Developer-Guide.md +++ b/doc/04-Developer-Guide.md @@ -12,4 +12,6 @@ A detailed overview of functions can be found below * [New-IcingaCheck](developerguide/01-New-IcingaCheck.md) * [New-IcingaCheckPackage](developerguide/02-New-IcingaCheckPackage.md) +* [New-IcingaCheckResult](developerguide/03-New-IcingaCheckResult.md) * [Custom Daemons](developerguide/10-Custom-Daemons.md) +* [Custom Plugins](developerguide/11-Custom-Plugins.md) diff --git a/doc/developerguide/02-New-IcingaCheckPackage.md b/doc/developerguide/02-New-IcingaCheckPackage.md index 68a9507..e900780 100644 --- a/doc/developerguide/02-New-IcingaCheckPackage.md +++ b/doc/developerguide/02-New-IcingaCheckPackage.md @@ -20,11 +20,11 @@ $IcingaPackage = New-IcingaCheckPackage -Name 'My Package' -OperatorAnd; | Argument | Input | Mandatory | Description | | --- | --- | --- | --- | | Name | String | * | The unique name of each package within a plugin. Will be displayed in the check output. | -| OperatorAnd | Switch | | Logical relation of the check within the package becomes an AND | -| OperatorOr | Switch | | Logical relation of the check within the package becomes an Or | -| OperatorNone | Switch | | - | -| OperatorMin | Int | | - | -| OperatorMax | Int | | - | +| OperatorAnd | Switch | | Every added check/package requires to return Ok for this package to be Ok | +| OperatorOr | Switch | | One added check/package requires to return Ok for this package to be Ok | +| OperatorNone | Switch | | None of added check/package has to return Ok for this package to be Ok | +| OperatorMin | Int | | Minimum of `n` added checks/packages requires to return Ok for this package to be Ok | +| OperatorMax | Int | | Maximum of `n` added checks/packages requires to return Ok for this package to be Ok | | Checks | Array | | Array of checks to be added to the check package | | Verbose | int | | Defines the level of output detail from 0 lowest to 3 highest detail | | Hidden | Switch | | If set, the check package doesn't generate output | diff --git a/doc/developerguide/03-New-IcingaCheckResult.md b/doc/developerguide/03-New-IcingaCheckResult.md new file mode 100644 index 0000000..aa24bc3 --- /dev/null +++ b/doc/developerguide/03-New-IcingaCheckResult.md @@ -0,0 +1,83 @@ +# Developer Guide: New-IcingaCheckResult + +Below you will find a list of functions and detailed descriptions including use cases for Cmdlets and features the PowerShell Framework provides. + +| Type | Return Value | Description | +| --- | --- | --- | +| Cmdlet | Integer | Compiles [Icinga Check](01-New-IcingaCheck.md)/[Check Package](02-New-IcingaCheckPackage.md) objects for valid Icinga Plugin output including performance data and returns the Icinga exit code as Integer | + +The `IcingaCheckResult` is the final step to finalyse a Icinga Plugin with the Powershell Framework. The checkresult Cmdlet will process either an [Icinga Check](01-New-IcingaCheck.md) or [Check Package](02-New-IcingaCheckPackage.md) object and `compile` the stored details within to write the plugin output, performance data and return the exit code for Icinga as integer. + +It will be used like in this example: + +```powershell +return New-IcingaCheckresult -Check $MyCheckObject -Compile; +``` + +## Arguments + +| Argument | Input | Mandatory | Description | +| --- | --- | --- | --- | +| Check | PSObject | * | [Icinga Check](01-New-IcingaCheck.md) or [Check Package](02-New-IcingaCheckPackage.md) object | +| NoPerfData | Bool | | Bool value with `true` or `false` to print performance metrics for the plugin or to drop them | +| Compile | Switch | | Will directly compile the checkresult, print the output to console and return the exit code as Integer | + +### Examples + +Please note that within the plugin output on console you will see a number at the end, which is the actual exit code of the plugin which is returned. If you are calling `Cmdlets` from within Icinga, you can simply use `exit` for the plugin call with PowerShell to tell Icinga the correct status. + +```powershell +exit Invoke-IcingaCheckCPU; +``` + +#### Simple Check Output + +```powershell +$IcingaCheck = New-IcingaCheck -Name 'My Check 1' -Value 37 -Unit '%'; +$IcingaCheck.WarnOutOfRange(20).CritOutOfRange(35) | Out-Null; + +return New-IcingaCheckresult -Check $IcingaCheck -Compile; +``` + +```text +[CRITICAL] My Check 1: Value "37%" is greater than threshold "35%" +| 'my_check_1'=37%;20;35;0;100 +2 +``` + +#### Simple Check Output without PerfData + +```powershell +$IcingaCheck = New-IcingaCheck -Name 'My Check 1' -Value 37 -Unit '%'; +$IcingaCheck.WarnOutOfRange(20).CritOutOfRange(35) | Out-Null; + +return New-IcingaCheckresult -Check $IcingaCheck -NoPerfData $TRUE -Compile; +``` + +```text +[CRITICAL] My Check 1: Value "37%" is greater than threshold "35%" +2 +``` + +#### Checkresult with check package + +```powershell +$IcingaCheck1 = New-IcingaCheck -Name 'My Check 1' -Value 37 -Unit '%'; +$IcingaCheck1.WarnOutOfRange(20).CritOutOfRange(35) | Out-Null; + +$IcingaCheck2 = New-IcingaCheck -Name 'My Check 2' -Value 18 -Unit '%'; +$IcingaCheck2.WarnOutOfRange(20).CritOutOfRange(35) | Out-Null; + +$IcingaPackage = New-IcingaCheckPackage -Name 'My Package' -OperatorAnd; +$IcingaPackage.AddCheck($IcingaCheck1); +$IcingaPackage.AddCheck($IcingaCheck2); + +return New-IcingaCheckresult -Check $IcingaPackage -Compile; +``` + +```text +[CRITICAL] Check package "My Package" - [CRITICAL] My Check 1 +\_ [CRITICAL] My Check 1: Value "37%" is greater than threshold "35%" +| 'my_check_1'=37%;20;35;0;100 'my_check_2'=18%;20;35;0;100 +2 +``` diff --git a/doc/developerguide/10-Custom-Daemons.md b/doc/developerguide/10-Custom-Daemons.md index ea89c0e..05883f3 100644 --- a/doc/developerguide/10-Custom-Daemons.md +++ b/doc/developerguide/10-Custom-Daemons.md @@ -8,7 +8,7 @@ Creating A New Module The best approach for creating a custom daemon is by creating an independent module which is installed in your PowerShell modules directly. This will ensure you are not overwriting your custom data with possible framework updates. -In this guide, we will assume the name of the module is `icinga-psdaemon-agentservice`. +In this guide, we will assume the name of the module is `icinga-powershell-agentservice`. At first we will have to create a new module. Navigate to the PowerShell modules folder the Framework itself is installed to. In this tutorial we will assume the location is @@ -16,14 +16,14 @@ At first we will have to create a new module. Navigate to the PowerShell modules C:\Program Files\WindowsPowerShell\Modules ``` -Now create a new folder with the name `icinga-psdaemon-agentservice` and navigate into it. +Now create a new folder with the name `icinga-powershell-agentservice` and navigate into it. -As we require a `psm1` file which contains our code, we will create a new file with the name `icinga-psdaemon-agentservice.psm1`. This will allow the PowerShell autoloader to load the module automaticly. +As we require a `psm1` file which contains our code, we will create a new file with the name `icinga-powershell-agentservice.psm1`. This will allow the PowerShell autoloader to load the module automaticly. **Note:** It could be possible, depending on your [execution policies](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy?view=powershell-6), that your module is not loaded properly. If this is the case, you can try to unblock the file by opening a PowerShell and use the `Unblock-File` Cmdelet ```powershell -Unblock-File -Path 'C:\Program Files\WindowsPowerShell\Modules\icinga-psdaemon-agentservice\icinga-psdaemon-agentservice.psm1' +Unblock-File -Path 'C:\Program Files\WindowsPowerShell\Modules\icinga-powershell-agentservice\icinga-powershell-agentservice.psm1' ``` Testing The Module @@ -31,7 +31,7 @@ Testing The Module Once the modules files are created and unblocked, we can start testing if the autoloader is properly working and our module is detected. -For this open the file `icinga-psdaemon-agentservice.psm1` in your prefered editor and add the following code snippet +For this open the file `icinga-powershell-agentservice.psm1` in your prefered editor and add the following code snippet ```powershell function Test-MyIcingaAgentServiceCommand() @@ -45,7 +45,7 @@ Now open a **new** PowerShell terminal or write `powershell` into an already ope If everything went properly, you should now read the output `Module was loaded` in our prompt. If not, you can try to import the module by using ```powershell -Import-Module 'C:\Program Files\WindowsPowerShell\Modules\icinga-psdaemon-agentservice\icinga-psdaemon-agentservice.psm1'; +Import-Module 'C:\Program Files\WindowsPowerShell\Modules\icinga-powershell-agentservice\icinga-powershell-agentservice.psm1'; ``` inside your console prompt. After that try again to execute the command `Test-MyIcingaAgentServiceCommand` and check if it works this time. If not, you might check the naming of your module to ensure `folder name` and `.psm1 file name` is identical. @@ -296,7 +296,13 @@ function Start-IcingaAgentServiceTest() if ($ServiceState.Status -ne 'Running') { try { # Try to restart the service - Restart-Service 'icinga2'; + Restart-Service 'icinga2' -ErrorAction Stop; + + Add-IcingaHashtableItem ` + -Hashtable $IcingaDaemonData.BackgroundDaemon.TestIcingaAgentService.ServiceState ` + -Key 'restart_error' ` + -Value 0 ` + -Override | Out-Null; } catch { # Add an error counter in case we failed $RestartErrors += 1; @@ -378,7 +384,13 @@ function Start-IcingaAgentServiceTest() if ($ServiceState.Status -ne 'Running') { try { # Try to restart the service - Restart-Service 'icinga2'; + Restart-Service 'icinga2' -ErrorAction Stop; + + Add-IcingaHashtableItem ` + -Hashtable $IcingaDaemonData.BackgroundDaemon.TestIcingaAgentService.ServiceState ` + -Key 'restart_error' ` + -Value 0 ` + -Override | Out-Null; } catch { # Add an error counter in case we failed $RestartErrors += 1; diff --git a/doc/developerguide/11-Custom-Plugins.md b/doc/developerguide/11-Custom-Plugins.md new file mode 100644 index 0000000..1fa5488 --- /dev/null +++ b/doc/developerguide/11-Custom-Plugins.md @@ -0,0 +1,595 @@ +# Developer Guide: Custom Plugins + +With the [Icinga PowerShell Framework](https://icinga.com/docs/windows/latest) you have the possibility to create new check plugins with very small effort. Below you will find a step-by-step tutorial for writing an example one. + +## File Structure + +For plugins we will have to distinguish between general components. The plugin file itself with the Cmdlet and the general check/treshold comparison and possible data providers, delivery the content for our modules. If you for example write plugins for your application monitoring and you require different functions to collect these information, the way to gois to separate the collector functions from the plugin itself. + +This will result in the following file structure + +```text +module + |_ plugin.psd1 + |_ plugin.psm1 + |_ provider + |_ your_plugin_provider.psm1 +``` + +This will ensure these functions can be called separately from the plugin itself and make re-using them a lot easier. In addition, it will help other developers to build dependencies based on your module and data collectors to allow an easier re-usage of already existing components. + +Additional required files within the `provider` folder can be included by using the `NestedModules` array within your `psd1` file. This will ensure these files are automatically loaded once a new PowerShell session is started. + +## Creating A New Module + +The best approach for creating a custom plugin is by creating an independent module which is installed in your PowerShell modules directly. This will ensure you are not overwriting your custom data with possible framework updates. + +In this guide, we will assume the name of the module is `icinga-powershell-plugintutorial`. + +At first we will have to create a new module. Navigate to the PowerShell modules folder the Framework itself is installed to. In this tutorial we will assume the location is + +```powershell +C:\Program Files\WindowsPowerShell\Modules +``` + +Now create a new folder with the name `icinga-powershell-plugintutorial` and navigate into it. + +As we require a `psm1` file which contains our code, we will create a new file with the name `icinga-powershell-plugintutorial.psm1`. This will allow the PowerShell autoloader to load the module automaticly. + +**Note:** It could be possible, depending on your [execution policies](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy?view=powershell-6), that your module is not loaded properly. If this is the case, you can try to unblock the file by opening a PowerShell and use the `Unblock-File` Cmdelet + +```powershell +Unblock-File -Path 'C:\Program Files\WindowsPowerShell\Modules\icinga-powershell-plugintutorial\icinga-powershell-plugintutorial.psm1' +``` + +## Testing The Module + +Once the module files are created and unblocked, we can start testing if the autoloader is properly working and our module is detected. + +For this open the file `icinga-powershell-plugintutorial.psm1` in your prefered editor and add the following code snippet + +```powershell +function Test-MyIcingaPluginTutorialCommand() +{ + Write-Host 'Module was loaded'; +} +``` + +Now open a **new** PowerShell terminal or write `powershell` into an already open PowerShell prompt and execute the command `Test-MyIcingaPluginTutorialCommand`. + +If everything went properly, you should now read the output `Module was loaded` in our prompt. If not, you can try to import the module by using + +```powershell +Import-Module 'C:\Program Files\WindowsPowerShell\Modules\icinga-powershell-plugintutorial\icinga-powershell-plugintutorial.psm1'; +``` + +inside your console prompt. After that try again to execute the command `Test-MyIcingaPluginTutorialCommand` and check if it works this time. If not, you might check the naming of your module to ensure `folder name` and `.psm1 file name` is identical. + +Once this is working, we can remove the function again as we no longer require it. + +## Create A New Plugin + +Once everything is working properly we can create our starting function we later use to execute our plugin. + +For naming guidelines we will have to begin with the `Invoke-IcingaCheck` naming and an identifier of what are going to achieve with our plugin. This is `mandatory` to ensure all auto-generation Cmdlets are still working. In our example we will simply name it `Tutorial`. + +So lets get started with the function + +```powershell +function Invoke-IcingaCheckTutorial() +{ + # Our code belongs here +} +``` + +### Basic Plugin Architecture + +A basic plugin contains of multiple parts. At first we general `arguments` to parse thresholds through. In addition to that we will make use of several functions to create our check and check results. The functions [New-IcingaCheck](01-New-IcingaCheck), [New-IcingaCheckPackage](02-New-IcingaCheckPackage) and `New-IcingaCheckResult` will do the work for us. + +### Writing Our Base-Skeleton + +For our plugin we will start with `param()` to parse arguments to our module, create a check objects and return the result. + +At first we will create a variable inside our `Start-IcingaAgentServiceTest` function. + +```powershell +function Invoke-IcingaCheckTutorial() +{ + # Create our arguments we can use to parese thresholds + # Example: Invoke-IcingaCheckTutorial -Warning 10 -Critical 30 + param ( + $Warning = $null, + $Critical = $null + ); + + # Create a new object we can check on. This will include + # comparing values and checking if they are between a + # range is Unknown + $Check = New-IcingaCheck ` + -Name 'Tutorial'; + + # Return our checkresult for the provided check and compile it + # This function will take care to write the plugin output and + # with return we will return the exit code to determine if our + # check is Ok, Warning, Critical or Unknown + return (New-IcingaCheckResult -Check $Check -Compile) +} +``` + +To test this module, we can call another PowerShell instance within our current session and execute the code. This will ensure, we are always loading changes we are making: + +```powershell +powershell -C { Use-Icinga; Invoke-IcingaCheckTutorial; } +``` + +Our tutorial plugin will now output the current status, the name, performance data and the exit. + +```text +[OK] Tutorial: +| 'tutorial'=;; +0 +``` + +### Optional Performance Data + +To make performance data optional on user input, we can now add another argument to our paramter list and update our check result object to use this argument + +```powershell +function Invoke-IcingaCheckTutorial() +{ + # Create our arguments we can use to parese thresholds + # Example: Invoke-IcingaCheckTutorial -Warning 10 -Critical 30 + param ( + $Warning = $null, + $Critical = $null, + [switch]$NoPerfData = $FALSE + ); + + # Create a new object we can check on. This will include + # comparing values and checking if they are between a + # range is Unknown + $Check = New-IcingaCheck ` + -Name 'Tutorial'; + + # Return our checkresult for the provided check and compile it + # This function will take care to write the plugin output and + # with return we will return the exit code to determine if our + # check is Ok, Warning, Critical or Unknown + return (New-IcingaCheckResult -Check $Check -NoPerfData $NoPerfData -Compile) +} +``` + +Once we call the module with the `NoPerfData` argument, performance data is no longer printed + +```powershell +powershell -C { Use-Icinga; Invoke-IcingaCheckTutorial -NoPerfData; } +``` + +```text +[OK] Tutorial: +0 +``` + +### Add Value to Check-Object + +Now as the basic skeleton is ready, we can dive into the actual check object. In our example we will use a `random value`, but feel free to add any other related PowerShell value fetched by WMI, APIs or other components here. + +```powershell +function Invoke-IcingaCheckTutorial() +{ + # Create our arguments we can use to parese thresholds + # Example: Invoke-IcingaCheckTutorial -Warning 10 -Critical 30 + param ( + $Warning = $null, + $Critical = $null, + [switch]$NoPerfData = $FALSE + ); + + # Create a new object we can check on. This will include + # comparing values and checking if they are between a + # range is Unknown + $Check = New-IcingaCheck ` + -Name 'Tutorial' ` + -Value ( + Get-Random -Minimum 10 -Maximum 100 + ); + + # Return our checkresult for the provided check and compile it + # This function will take care to write the plugin output and + # with return we will return the exit code to determine if our + # check is Ok, Warning, Critical or Unknown + return (New-IcingaCheckResult -Check $Check -NoPerfData $NoPerfData -Compile) +} +``` + +By doing so, nothing will change from the plugin output in general, besides the performance data in case we wish to output them and the value the object is now holding. + +```powershell +powershell -C { Use-Icinga; Invoke-IcingaCheckTutorial } +``` + +```text +[OK] Tutorial: 79 +| 'tutorial'=79;; +0 +``` + +### Compare Value with Tresholds + +Now as we are holding a value inside our check object, we can start to compare it with our `Warning` and `Critical` tresholds. There are a bunch of functions inside the check object avaialble for this which can be found in the [check object documentation](01-New-IcingaCheck.md). + +For most plugins the generic approach will do just fine. This one will ensure we can use the Nagios/Icinga treshold syntax to compare values more dynamicly and add ranges support. (See also [Icinga Plugins](https://icinga.com/docs/windows/latest/plugins/doc/10-Icinga-Plugins/)) + +The two functions we will use for this are `WarnOutOfRange` and `CritOutOfRange`. + +```powershell +function Invoke-IcingaCheckTutorial() +{ + # Create our arguments we can use to parese thresholds + # Example: Invoke-IcingaCheckTutorial -Warning 10 -Critical 30 + param ( + $Warning = $null, + $Critical = $null, + [switch]$NoPerfData = $FALSE + ); + + # Create a new object we can check on. This will include + # comparing values and checking if they are between a + # range is Unknown + $Check = New-IcingaCheck ` + -Name 'Tutorial' ` + -Value ( + Get-Random -Minimum 10 -Maximum 100 + ); + # Each compare function within our check object will return the + # object itself, allowing us to write a nested call like below + # to compare multiple values at once. + # IMPORTANT: We have to output the last call either to Out-Null + # or store the result inside a variable, as the check + # object is otherwise written into our plugin output + $Check.WarnOutOfRange($Warning).CritOutOfRange($Critical) | Out-Null; + + # Return our checkresult for the provided check and compile it + # This function will take care to write the plugin output and + # with return we will return the exit code to determine if our + # check is Ok, Warning, Critical or Unknown + return (New-IcingaCheckResult -Check $Check -NoPerfData $NoPerfData -Compile) +} +``` + +**NOTE:** It is very important to output the function calls either to `Out-Null` or assign a variable to store the content, as otherwise we will spam our check object into our plugin output + +```powershell +$dump = $Check.WarnOutOfRange($Warning).CritOutOfRange($Critical); +``` + +As we have now added comparing functions to our plugin, we can execute the plugin again and check if everything works as intended + +```powershell +powershell -C { Use-Icinga; Invoke-IcingaCheckTutorial -Warning 20 -Critical 30 } +``` + +```text +[CRITICAL] Tutorial: Value "76" is greater than threshold "30" +| 'tutorial'=76;20;30 +2 +``` + +### Using Check Packages + +Now it is time to combine multiple check objects into one check package. Our basic plugin works just fine, but maybe we wish to compare multiple values for multiple checks. To do so, we will create another `check object` and one `check package object`. + +Dont forget to add the compare functions `WarnOutOfRange` and `CritOutOfRange` for the new `check object`! + +Last but not least we will modify our `New-IcingaCheckResult` fuction to use the `check package` instead of our old `check object` + +```powershell +function Invoke-IcingaCheckTutorial() +{ + # Create our arguments we can use to parese thresholds + # Example: Invoke-IcingaCheckTutorial -Warning 10 -Critical 30 + param ( + $Warning = $null, + $Critical = $null, + [switch]$NoPerfData = $FALSE + ); + + # Create a new object we can check on. This will include + # comparing values and checking if they are between a + # range is Unknown + $Check = New-IcingaCheck ` + -Name 'Tutorial' ` + -Value ( + Get-Random -Minimum 10 -Maximum 100 + ); + # Add another check objects with a different name for identifying + # which check is holding which value + $Check2 = New-IcingaCheck ` + -Name 'Tutorial 2' ` + -Value ( + Get-Random -Minimum 10 -Maximum 100 + ); + # Each compare function within our check object will return the + # object itself, allowing us to write a nested call like below + # to compare multiple values at once. + # IMPORTANT: We have to output the last call either to Out-Null + # or store the result inside a variable, as the check + # object is otherwise written into our plugin output + $Check.WarnOutOfRange($Warning).CritOutOfRange($Critical) | Out-Null; + # Dont forget to add our comparison for the second check with + # the identical tresholds. If you want to, you could compare + # them to different arguments + $Check2.WarnOutOfRange($Warning).CritOutOfRange($Critical) | Out-Null; + + # Now lets define a check package we can combine our checks into. + # Check packages have names themself and provide a function to + # add checks into. We can either add them directly during creation + # or later + $CheckPackage = New-IcingaCheckPackage ` + -Name 'Tutorial Package' ` + -Checks @( + $Check, + $Check2 + ); + + # Alternatively we can also call the method AddCheck + # $CheckPackage.AddCheck($Check); + # $CheckPackage.AddCheck($Check2); + + # Return our checkresult for the provided check and compile it + # This function will take care to write the plugin output and + # with return we will return the exit code to determine if our + # check is Ok, Warning, Critical or Unknown + return (New-IcingaCheckResult -Check $CheckPackage -NoPerfData $NoPerfData -Compile) +} +``` + +If we now call our script plugin again, we will see two output for performance data + +```powershell +powershell -C { Use-Icinga; Invoke-IcingaCheckTutorial -Warning 20 -Critical 30 } +``` + +```test +[OK] Check package "Tutorial Package" +| 'tutorial'=63;20;30 'tutorial_2'=37;20;30 +0 +``` + +### Package Operators + +As you see, the plugin output is `Ok` while clearly it should throw `Critical`. What we are missing is a comparing operator, telling the package how to count each assiged check. We have several operators on our hand: + +* `-OperatorMin ` with `` amount of checks require to be ok for the package to be ok +* `-OperatorMax ` with `` amount of checks require to be ok for the package to be ok +* `-OperatorAnd` for all checks requiring to be ok for the package to be ok +* `-OperatorOr` for atleast one check requiring to be ok for the package to be ok +* `-OperatorNone` for all checks to be `not` ok for the package to be ok + +You can only use one operator per check package, a combination is not possible. + +On our example we will use the `-OperatorAnd` to ensure all checks have to be ok for the package to be ok + +```powershell +function Invoke-IcingaCheckTutorial() +{ + # Create our arguments we can use to parese thresholds + # Example: Invoke-IcingaCheckTutorial -Warning 10 -Critical 30 + param ( + $Warning = $null, + $Critical = $null, + [switch]$NoPerfData = $FALSE + ); + + # Create a new object we can check on. This will include + # comparing values and checking if they are between a + # range is Unknown + $Check = New-IcingaCheck ` + -Name 'Tutorial' ` + -Value ( + Get-Random -Minimum 10 -Maximum 100 + ); + # Add another check objects with a different name for identifying + # which check is holding which value + $Check2 = New-IcingaCheck ` + -Name 'Tutorial 2' ` + -Value ( + Get-Random -Minimum 10 -Maximum 100 + ); + # Each compare function within our check object will return the + # object itself, allowing us to write a nested call like below + # to compare multiple values at once. + # IMPORTANT: We have to output the last call either to Out-Null + # or store the result inside a variable, as the check + # object is otherwise written into our plugin output + $Check.WarnOutOfRange($Warning).CritOutOfRange($Critical) | Out-Null; + # Dont forget to add our comparison for the second check with + # the identical tresholds. If you want to, you could compare + # them to different arguments + $Check2.WarnOutOfRange($Warning).CritOutOfRange($Critical) | Out-Null; + + # Now lets define a check package we can combine our checks into. + # Check packages have names themself and provide a function to + # add checks into. We can either add them directly during creation + # or later + $CheckPackage = New-IcingaCheckPackage ` + -Name 'Tutorial Package' ` + -Checks @( + $Check, + $Check2 + ) ` + -OperatorAnd; + + # Alternatively we can also call the method AddCheck + # $CheckPackage.AddCheck($Check); + # $CheckPackage.AddCheck($Check2); + + # Return our checkresult for the provided check and compile it + # This function will take care to write the plugin output and + # with return we will return the exit code to determine if our + # check is Ok, Warning, Critical or Unknown + return (New-IcingaCheckResult -Check $CheckPackage -NoPerfData $NoPerfData -Compile) +} +``` + +Now lets see how the output changes + +```powershell +powershell -C { Use-Icinga; Invoke-IcingaCheckTutorial -Warning 20 -Critical 30 } +``` + +```text +[CRITICAL] Check package "Tutorial Package" - [CRITICAL] Tutorial, Tutorial 2 +\_ [CRITICAL] Tutorial: Value "52" is greater than threshold "30" +\_ [CRITICAL] Tutorial 2: Value "60" is greater than threshold "30" +| 'tutorial'=52;20;30 'tutorial_2'=60;20;30 +2 +``` + +As you can see our package is now critical, outputting each check which is `not` Ok. In addition the functions will add + +```text +[CRITICAL] Tutorial, Tutorial 2 +``` + +inside the short plugin output to ensure we have a quick overview within Icinga Web 2, telling us which checks are failling. + +### Increasing Verbosity + +In case our checks are ok, they are not printed by default to keep the view as little as possible. We can test this by executing the plugin without tresholds + +```powershell +powershell -C { Use-Icinga; Invoke-IcingaCheckTutorial } +``` + +```text +[OK] Check package "Tutorial Package" +| 'tutorial'=63;; 'tutorial_2'=51;; +0 +``` + +In case we want to make it configurable if every single `check object` and `check package` is printed, we can add a `Verbosity` flag. This will also introduce another method for the `params` of the module, as we will only allow certain input values for the `Verbosity` argument. + +In addition, we will parse the new `$Verbosity` as argument to our `check package` + +```powershell +function Invoke-IcingaCheckTutorial() +{ + # Create our arguments we can use to parese thresholds + # Example: Invoke-IcingaCheckTutorial -Warning 10 -Critical 30 + param ( + $Warning = $null, + $Critical = $null, + [switch]$NoPerfData = $FALSE, + # Ensure only 0-2 values are allowed for Verbosity + [ValidateSet(0, 1, 2)] + [int]$Verbosity = 0 + ); + + # Create a new object we can check on. This will include + # comparing values and checking if they are between a + # range is Unknown + $Check = New-IcingaCheck ` + -Name 'Tutorial' ` + -Value ( + Get-Random -Minimum 10 -Maximum 100 + ); + # Add another check objects with a different name for identifying + # which check is holding which value + $Check2 = New-IcingaCheck ` + -Name 'Tutorial 2' ` + -Value ( + Get-Random -Minimum 10 -Maximum 100 + ); + # Each compare function within our check object will return the + # object itself, allowing us to write a nested call like below + # to compare multiple values at once. + # IMPORTANT: We have to output the last call either to Out-Null + # or store the result inside a variable, as the check + # object is otherwise written into our plugin output + $Check.WarnOutOfRange($Warning).CritOutOfRange($Critical) | Out-Null; + # Dont forget to add our comparison for the second check with + # the identical tresholds. If you want to, you could compare + # them to different arguments + $Check2.WarnOutOfRange($Warning).CritOutOfRange($Critical) | Out-Null; + + # Now lets define a check package we can combine our checks into. + # Check packages have names themself and provide a function to + # add checks into. We can either add them directly during creation + # or later + $CheckPackage = New-IcingaCheckPackage ` + -Name 'Tutorial Package' ` + -Checks @( + $Check, + $Check2 + ) ` + -OperatorAnd ` + -Verbose $Verbosity; + + # Alternatively we can also call the method AddCheck + # $CheckPackage.AddCheck($Check); + # $CheckPackage.AddCheck($Check2); + + # Return our checkresult for the provided check and compile it + # This function will take care to write the plugin output and + # with return we will return the exit code to determine if our + # check is Ok, Warning, Critical or Unknown + return (New-IcingaCheckResult -Check $CheckPackage -NoPerfData $NoPerfData -Compile) +} +``` + +If we now exectue the plugin with `Verbosity` and the value `2`, every single check will be printed, even when the check itself is Ok + +```powershell +powershell -C { Use-Icinga; Invoke-IcingaCheckTutorial -Verbosity 2 } +``` + +```text +[OK] Check package "Tutorial Package" (Match All) +\_ [OK] Tutorial: 70 +\_ [OK] Tutorial 2: 36 +| 'tutorial'=70;; 'tutorial_2'=36;; +0 +``` + +The following `Verbose` options are available + +* `0`: Default - only `not` Ok values will be printed +* `1`: Only `not` Ok values will be printed including package `operator` config +* `2`: Everything will be printed + +### More Complex Checks + +We will not provide an example in this guide, but we would like to add that this is not the final complexity level of plugins. Each `check package` for example could contain multiple `check packages` with `checks` and even more `check packages`. + +You simply have to ensure you are adding `checks` and `check packages` correctly into each object and parse your primary `check package` to the `check result Cmdlet`. The Framework will then deal with the entire operation and calculation itself + +### Icinga Configuration + +Now as we are done with writing our plugin, it is time to test it inside Icinga 2. Instead of having to write an `Icinga Director` command configuration yourself, we can use an integrated Framework Cmdlet to generate a `Basket` file for us which can be imorted into the `Icinga Director`. + +```powershell +Get-IcingaCheckCommandConfig -CheckName 'Invoke-IcingaCheckTutorial' -OutDirectory 'C:\users\public'; +``` + +```text +The following commands have been exported: +- 'Invoke-IcingaCheckTutorial' +JSON export created in 'C:\users\public\PowerShell_CheckCommands_03-31-2020-17-34-5367.json' +``` + +This is the reason why it is `mandatory` to place plugin Cmdlets within the `Invoke-IcingaCheck` "namespace". Calling `Get-IcingaCheckCommandConfig` without the `CheckName` argument will automatically lookup every command with this naming schema and export all of them inside the `Basket` file. + +### General Guidelines + +To ensure the later import into the `Icinga Director` and usage within Icinga 2 is as easy as possible, it is recommended to write a proper plugin documentation which is understood by the `Get-Help` Cmdlet of Windows. By doing so, arguments are described directly inside the `Icinga Director`. + +Another important note are correct `data types` for values. Each `data type` is translated properly into `Icinga Director` language, resulting in the following behaviour: + +* `[string]` will be translated to text values on check input fields +* `[int]` will be translated to numeric values on check input fields +* `[bool]` will be translated to yes/no values on check input fields +* `[switch]` will be translated to yes/no values on check input fields +* `[array]` will be translated to array values on check input fields + +By using the `ValidateSet` feature of PowerShell (as we did for our `Verbosity`) we will automatically generate a `custom variable` as `datalist`, only allowing the valid input values in a `drop down list` diff --git a/doc/service/01-Install-Service.md b/doc/service/01-Install-Service.md index aebcb6e..a6d4e57 100644 --- a/doc/service/01-Install-Service.md +++ b/doc/service/01-Install-Service.md @@ -11,36 +11,12 @@ In order to make this work, you will require the Icinga Windows Service which ca Benefits --- -Running the PowerShell Framework as background service will add the possibility to register certain functions which are executed depending on their configuration / coding. One example would be to frequently collect monitoring metrics from the installed plugins, allowing you to receice an average of time for the CPU load for example. +Running the PowerShell Framework as background service will add the possibility to register certain functions which are executed depending on their configuration / coding. One example would be to frequently collect monitoring metrics from the installed plugins, allowing you to receive an average of time for the CPU load for example. Install the Service --- -At first you will require the Service Binary from the [Icinga Windows Service GitHub Repository](https://github.com/Icinga/icinga-powershell-service) and copy the binary locally to your system. A recommended path would be your Program Files / Program Files (x86) directory. - -Any other custom location is fully supported, has to be however accessible from the Windows Service Environment. - -Once you have found a location, the PowerShell Module will assist you with setting up the service itself. In this documentation we will assume the path you have chosen to copy the binary to is - -```powershell -C:\Program Files\Icinga-Framework-Service -``` - -and the binary name is - -```powershell -icinga-service.exe -``` - -Now lets install the service with the help of the PowerShell Module: - -```powershell -Install-IcingaFrameworkService -Path 'C:\Program Files\Icinga-Framework-Service\icinga-service.exe' -``` - -You can validate if the service has been installed properly by using the Get Service Cmdlet: - -Each enabled background daemon component is afterwards being started and executed. +A detailed documentation on how to download and install the service and be found directly on the services [installation guide](https://icinga.com/docs/windows/latest/service/doc/02-Installation/). Register Functions --- diff --git a/lib/apis/Get-IcingaDirectorSelfServiceConfig.psm1 b/lib/apis/Get-IcingaDirectorSelfServiceConfig.psm1 index f934f26..e6614c4 100644 --- a/lib/apis/Get-IcingaDirectorSelfServiceConfig.psm1 +++ b/lib/apis/Get-IcingaDirectorSelfServiceConfig.psm1 @@ -1,3 +1,27 @@ +<# +.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( diff --git a/lib/apis/Get-IcingaDirectorSelfServiceTicket.psm1 b/lib/apis/Get-IcingaDirectorSelfServiceTicket.psm1 index 48fca58..f4c1b85 100644 --- a/lib/apis/Get-IcingaDirectorSelfServiceTicket.psm1 +++ b/lib/apis/Get-IcingaDirectorSelfServiceTicket.psm1 @@ -1,29 +1,52 @@ +<# +.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 - ); + param( + $DirectorUrl, + $ApiKey = $null + ); - if ([string]::IsNullOrEmpty($DirectorUrl)) { - Write-Host 'Unable to fetch host ticket. No Director url has been specified'; - return; - } + if ([string]::IsNullOrEmpty($DirectorUrl)) { + Write-IcingaConsoleError 'Unable to fetch host ticket. No Director url has been specified'; + return; + } - if ([string]::IsNullOrEmpty($ApiKey)) { - Write-Host 'Unable to fetch host ticket. No API key has been specified'; - return; - } + if ([string]::IsNullOrEmpty($ApiKey)) { + Write-IcingaConsoleError 'Unable to fetch host ticket. No API key has been specified'; + return; + } - [string]$url = Join-WebPath -Path $DirectorUrl -ChildPath ([string]::Format('/self-service/ticket?key={0}', $ApiKey)); + [string]$url = Join-WebPath -Path $DirectorUrl -ChildPath ([string]::Format('/self-service/ticket?key={0}', $ApiKey)); - $response = Invoke-WebRequest -Uri $url -UseBasicParsing -Headers @{ 'accept' = 'application/json'; 'X-Director-Accept' = 'application/json' } -Method 'POST'; + $response = Invoke-WebRequest -Uri $url -UseBasicParsing -Headers @{ 'accept' = 'application/json'; 'X-Director-Accept' = 'application/json' } -Method 'POST'; - if ($response.StatusCode -ne 200) { - throw $response.Content; - } + if ($response.StatusCode -ne 200) { + throw $response.Content; + } - $JsonContent = ConvertFrom-Json -InputObject $response.Content; + $JsonContent = ConvertFrom-Json -InputObject $response.Content; - return $JsonContent; + return $JsonContent; } diff --git a/lib/apis/Register-IcingaDirectorSelfServiceHost.psm1 b/lib/apis/Register-IcingaDirectorSelfServiceHost.psm1 index f5503d5..adcee02 100644 --- a/lib/apis/Register-IcingaDirectorSelfServiceHost.psm1 +++ b/lib/apis/Register-IcingaDirectorSelfServiceHost.psm1 @@ -1,3 +1,33 @@ +<# +.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( @@ -47,7 +77,7 @@ function Register-IcingaDirectorSelfServiceHost() Set-IcingaPowerShellConfig -Path 'IcingaDirector.SelfService.ApiKey' -Value $JsonContent; - Write-Host 'Host was successfully registered within Icinga Director'; + Write-IcingaConsoleNotice 'Host was successfully registered within Icinga Director'; return $JsonContent; } diff --git a/lib/config/Get-IcingaConfigTreeCount.psm1 b/lib/config/Get-IcingaConfigTreeCount.psm1 index a295d52..67f76a9 100644 --- a/lib/config/Get-IcingaConfigTreeCount.psm1 +++ b/lib/config/Get-IcingaConfigTreeCount.psm1 @@ -1,3 +1,22 @@ +<# +.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( diff --git a/lib/config/Get-IcingaPowerShellConfig.psm1 b/lib/config/Get-IcingaPowerShellConfig.psm1 index 65abd70..4aed09d 100644 --- a/lib/config/Get-IcingaPowerShellConfig.psm1 +++ b/lib/config/Get-IcingaPowerShellConfig.psm1 @@ -1,3 +1,22 @@ +<# +.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( diff --git a/lib/config/New-IcingaPowerShellConfigItem.psm1 b/lib/config/New-IcingaPowerShellConfigItem.psm1 index ddff776..2de7a6a 100644 --- a/lib/config/New-IcingaPowerShellConfigItem.psm1 +++ b/lib/config/New-IcingaPowerShellConfigItem.psm1 @@ -1,3 +1,24 @@ +<# +.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( diff --git a/lib/config/Read-IcingaPowerShellConfig.psm1 b/lib/config/Read-IcingaPowerShellConfig.psm1 index cf989f2..84d74af 100644 --- a/lib/config/Read-IcingaPowerShellConfig.psm1 +++ b/lib/config/Read-IcingaPowerShellConfig.psm1 @@ -1,3 +1,18 @@ +<# +.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; diff --git a/lib/config/Remove-IcingaPowerShellConfig.psm1 b/lib/config/Remove-IcingaPowerShellConfig.psm1 index a6c0dfd..a9a9ab6 100644 --- a/lib/config/Remove-IcingaPowerShellConfig.psm1 +++ b/lib/config/Remove-IcingaPowerShellConfig.psm1 @@ -1,3 +1,20 @@ +<# +.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( diff --git a/lib/config/Set-IcingaPowerShellConfig.psm1 b/lib/config/Set-IcingaPowerShellConfig.psm1 index 195d6e1..c5b6069 100644 --- a/lib/config/Set-IcingaPowerShellConfig.psm1 +++ b/lib/config/Set-IcingaPowerShellConfig.psm1 @@ -1,3 +1,22 @@ +<# +.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( diff --git a/lib/config/Test-IcingaPowerShellConfigItem.psm1 b/lib/config/Test-IcingaPowerShellConfigItem.psm1 index 95c3fe4..e910ef1 100644 --- a/lib/config/Test-IcingaPowerShellConfigItem.psm1 +++ b/lib/config/Test-IcingaPowerShellConfigItem.psm1 @@ -1,3 +1,24 @@ +<# +.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( diff --git a/lib/config/Write-IcingaPowerShellConfig.psm1 b/lib/config/Write-IcingaPowerShellConfig.psm1 index 3dfbdda..5375c8d 100644 --- a/lib/config/Write-IcingaPowerShellConfig.psm1 +++ b/lib/config/Write-IcingaPowerShellConfig.psm1 @@ -1,3 +1,20 @@ +<# +.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( diff --git a/lib/core/cache/Get-IcingaCacheData.psm1 b/lib/core/cache/Get-IcingaCacheData.psm1 index 27b09d9..19225a2 100644 --- a/lib/core/cache/Get-IcingaCacheData.psm1 +++ b/lib/core/cache/Get-IcingaCacheData.psm1 @@ -1,3 +1,29 @@ +<# +.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// +.PARAMETER KeyName + This is the actual cache file located under icinga-powershell-framework/cache///.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( diff --git a/lib/core/cache/Set-IcingaCacheData.psm1 b/lib/core/cache/Set-IcingaCacheData.psm1 index bdf3a36..bb6c81b 100644 --- a/lib/core/cache/Set-IcingaCacheData.psm1 +++ b/lib/core/cache/Set-IcingaCacheData.psm1 @@ -1,3 +1,30 @@ +<# +.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// +.PARAMETER KeyName + This is the actual cache file located under icinga-powershell-framework/cache///.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( diff --git a/lib/core/framework/Copy-ItemSecure.psm1 b/lib/core/framework/Copy-ItemSecure.psm1 index 9641a29..f5ccb96 100644 --- a/lib/core/framework/Copy-ItemSecure.psm1 +++ b/lib/core/framework/Copy-ItemSecure.psm1 @@ -1,3 +1,30 @@ +<# +.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( @@ -23,7 +50,7 @@ function Copy-ItemSecure() } return $TRUE; } catch { - Write-Host ([string]::Format('Failed to copy items from path "{0}" to "{1}": {2}', $Path, $Destination, $_.Exception)) -ForegroundColor Red; + Write-IcingaConsoleError -Message 'Failed to copy items from path "{0}" to "{1}": {2}' -Objects $Path, $Destination, $_.Exception; } return $FALSE; } diff --git a/lib/core/framework/Expand-IcingaZipArchive.psm1 b/lib/core/framework/Expand-IcingaZipArchive.psm1 index 658e63a..5359971 100644 --- a/lib/core/framework/Expand-IcingaZipArchive.psm1 +++ b/lib/core/framework/Expand-IcingaZipArchive.psm1 @@ -1,3 +1,24 @@ +<# +.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( @@ -6,7 +27,7 @@ function Expand-IcingaZipArchive() ); if ((Test-Path $Path) -eq $FALSE -Or (Test-Path $Destination) -eq $FALSE) { - Write-Host 'The path to the zip archive or the destination path do not exist'; + Write-IcingaConsoleError 'The path to the zip archive or the destination path do not exist'; return $FALSE; } diff --git a/lib/core/framework/Get-IcingaFrameworkServiceBinary.psm1 b/lib/core/framework/Get-IcingaFrameworkServiceBinary.psm1 index 96552b8..0274a00 100644 --- a/lib/core/framework/Get-IcingaFrameworkServiceBinary.psm1 +++ b/lib/core/framework/Get-IcingaFrameworkServiceBinary.psm1 @@ -1,3 +1,29 @@ +<# +.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( @@ -19,7 +45,7 @@ function Get-IcingaFrameworkServiceBinary() } if ([string]::IsNullOrEmpty($FrameworkServiceUrl)) { - Write-Host 'No Url to download the Icinga Service Binary from has been specified. Please try again.'; + Write-IcingaConsoleError 'No Url to download the Icinga Service Binary from has been specified. Please try again.'; return Get-IcingaFrameworkServiceBinary; } @@ -40,7 +66,7 @@ function Get-IcingaFrameworkServiceBinary() try { Invoke-WebRequest -Uri $FrameworkServiceUrl -UseBasicParsing -OutFile $ZipArchive; } catch { - Write-Host ([string]::Format('Failed to download the Icinga Service Binary from "{0}". Please try again.', $FrameworkServiceUrl)); + Write-IcingaConsoleError -Message 'Failed to download the Icinga Service Binary from "{0}". Please try again.' -Objects $FrameworkServiceUrl; return Get-IcingaFrameworkServiceBinary; } diff --git a/lib/core/framework/Get-IcingaPowerShellModuleArchive.psm1 b/lib/core/framework/Get-IcingaPowerShellModuleArchive.psm1 index 36a8afc..a5eded2 100644 --- a/lib/core/framework/Get-IcingaPowerShellModuleArchive.psm1 +++ b/lib/core/framework/Get-IcingaPowerShellModuleArchive.psm1 @@ -1,3 +1,39 @@ +<# +.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' -Stable 1; +.EXAMPLE + PS>Get-IcingaPowerShellModuleArchive -ModuleName 'Plugins' -Repository 'icinga-powershell-plugins' -Stable 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 Stable + Download the latest stable 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( @@ -46,7 +82,7 @@ function Get-IcingaPowerShellModuleArchive() $CurrentVersion = Get-IcingaPowerShellModuleVersion $Repository; if ($null -ne $CurrentVersion -And $CurrentVersion -eq $Tag) { - Write-Host ([string]::Format('Your "{0}" is already up-to-date', $ModuleName)); + Write-IcingaConsoleNotice -Message 'Your "{0}" is already up-to-date' -Objects $ModuleName; return @{ 'DownloadUrl' = $DownloadUrl; 'Version' = $Tag; @@ -76,15 +112,15 @@ function Get-IcingaPowerShellModuleArchive() try { $DownloadDirectory = New-IcingaTemporaryDirectory; $DownloadDestination = (Join-Path -Path $DownloadDirectory -ChildPath ([string]::Format('{0}.zip', $Repository))); - Write-Host ([string]::Format('Downloading "{0}" into "{1}"', $ModuleName, $DownloadDirectory)); + Write-IcingaConsoleNotice ([string]::Format('Downloading "{0}" into "{1}"', $ModuleName, $DownloadDirectory)); Invoke-WebRequest -UseBasicParsing -Uri $DownloadUrl -OutFile $DownloadDestination; } catch { - Write-Host ([string]::Format('Failed to download "{0}" into "{1}". Starting cleanup process', $ModuleName, $DownloadDirectory)); + 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-Host 'Starting to re-run the download wizard'; + Write-IcingaConsoleNotice 'Starting to re-run the download wizard'; return Get-IcingaPowerShellModuleArchive -ModuleName $ModuleName -Repository $Repository; } diff --git a/lib/core/framework/Get-IcingaPowerShellModuleVersion.psm1 b/lib/core/framework/Get-IcingaPowerShellModuleVersion.psm1 index 14d9d4c..7a9e74e 100644 --- a/lib/core/framework/Get-IcingaPowerShellModuleVersion.psm1 +++ b/lib/core/framework/Get-IcingaPowerShellModuleVersion.psm1 @@ -1,3 +1,24 @@ +<# +.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( diff --git a/lib/core/framework/Install-IcingaFrameworkPlugins.psm1 b/lib/core/framework/Install-IcingaFrameworkPlugins.psm1 index 124d0ea..d4cd8ed 100644 --- a/lib/core/framework/Install-IcingaFrameworkPlugins.psm1 +++ b/lib/core/framework/Install-IcingaFrameworkPlugins.psm1 @@ -1,3 +1,29 @@ +<# +.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( diff --git a/lib/core/framework/Install-IcingaFrameworkService.psm1 b/lib/core/framework/Install-IcingaFrameworkService.psm1 index dd67ec1..81607dc 100644 --- a/lib/core/framework/Install-IcingaFrameworkService.psm1 +++ b/lib/core/framework/Install-IcingaFrameworkService.psm1 @@ -1,3 +1,29 @@ +<# +.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-IcingaFrameworkService -Path C:\Program Files\icinga-service\icinga-service.exe; +.EXAMPLE + PS>Install-IcingaFrameworkService -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-IcingaFrameworkService() { param( @@ -7,7 +33,7 @@ function Install-IcingaFrameworkService() ); if ([string]::IsNullOrEmpty($Path)) { - Write-Host 'No path specified for Framework service. Service will not be installed'; + Write-IcingaConsoleWarning 'No path specified for Framework service. Service will not be installed'; return; } @@ -17,10 +43,10 @@ function Install-IcingaFrameworkService() if ((Test-Path $UpdateFile)) { - Write-Host 'Updating Icinga PowerShell Service binary'; + Write-IcingaConsoleNotice 'Updating Icinga PowerShell Service binary'; if ($ServiceStatus -eq 'Running') { - Write-Host 'Stopping Icinga PowerShell service'; + Write-IcingaConsoleNotice 'Stopping Icinga PowerShell service'; Stop-IcingaService 'icingapowershell'; Start-Sleep -Seconds 1; } @@ -47,7 +73,7 @@ function Install-IcingaFrameworkService() throw ([string]::Format('Failed to install Icinga PowerShell Service: {0}{1}', $ServiceCreation.Message, $ServiceCreation.Error)); } } else { - Write-Host 'The Icinga PowerShell Service is already installed'; + 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 @@ -60,7 +86,7 @@ function Install-IcingaFrameworkService() Stop-IcingaService 'icingapowershell'; if ($ServiceStatus -eq 'Running') { - Write-Host 'Starting Icinga PowerShell service'; + Write-IcingaConsoleNotice 'Starting Icinga PowerShell service'; Start-IcingaService 'icingapowershell'; Start-Sleep -Seconds 1; } diff --git a/lib/core/framework/Install-IcingaFrameworkUpdate.psm1 b/lib/core/framework/Install-IcingaFrameworkUpdate.psm1 index b2cb4ba..6906ce9 100644 --- a/lib/core/framework/Install-IcingaFrameworkUpdate.psm1 +++ b/lib/core/framework/Install-IcingaFrameworkUpdate.psm1 @@ -1,3 +1,27 @@ +<# +.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( @@ -13,7 +37,7 @@ function Install-IcingaFrameworkUpdate() }; } - Write-Host ([string]::Format('Installing module into "{0}"', ($Archive.Directory))); + 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; @@ -26,12 +50,12 @@ function Install-IcingaFrameworkUpdate() } } - Write-Host ([string]::Format('Using content of folder "{0}" for updates', $ModuleContent)); + Write-IcingaConsoleNotice ([string]::Format('Using content of folder "{0}" for updates', $ModuleContent)); $ServiceStatus = (Get-Service 'icingapowershell' -ErrorAction SilentlyContinue).Status; if ($ServiceStatus -eq 'Running') { - Write-Host 'Stopping Icinga PowerShell service'; + Write-IcingaConsoleNotice 'Stopping Icinga PowerShell service'; Stop-IcingaService 'icingapowershell'; Start-Sleep -Seconds 1; } @@ -39,13 +63,13 @@ function Install-IcingaFrameworkUpdate() $ModuleDirectory = (Join-Path -Path $Archive.ModuleRoot -ChildPath $RepositoryName); if ((Test-Path $ModuleDirectory) -eq $FALSE) { - Write-Host 'Failed to update the component. Module Root-Directory was not found'; + Write-IcingaConsoleError 'Failed to update the component. Module Root-Directory was not found'; return; } $Files = Get-ChildItem $ModuleDirectory -File '*'; - Write-Host 'Removing files from framework'; + Write-IcingaConsoleNotice 'Removing files from framework'; foreach ($ModuleFile in $Files) { Remove-ItemSecure -Path $ModuleFile -Force | Out-Null; @@ -55,7 +79,7 @@ function Install-IcingaFrameworkUpdate() 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-Host 'Copying new files to framework'; + 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; @@ -63,16 +87,16 @@ function Install-IcingaFrameworkUpdate() Unblock-IcingaPowerShellFiles -Path $ModuleDirectory; - Write-Host 'Cleaning temporary content'; + Write-IcingaConsoleNotice 'Cleaning temporary content'; Start-Sleep -Seconds 1; Remove-ItemSecure -Path $Archive.Directory -Recurse -Force | Out-Null; - Write-Host 'Framework update has been completed. Please start a new PowerShell instance now to complete the update'; + 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-Host 'Starting Icinga PowerShell service'; + Write-IcingaConsoleNotice 'Starting Icinga PowerShell service'; Start-IcingaService 'icingapowershell'; } } diff --git a/lib/core/framework/Remove-ItemSecure.psm1 b/lib/core/framework/Remove-ItemSecure.psm1 index 6c97c90..bf88070 100644 --- a/lib/core/framework/Remove-ItemSecure.psm1 +++ b/lib/core/framework/Remove-ItemSecure.psm1 @@ -1,3 +1,32 @@ +<# +.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( @@ -22,7 +51,7 @@ function Remove-ItemSecure() } return $TRUE; } catch { - Write-Host ([string]::Format('Failed to remove items from path "{0}": {1}', $Path, $_.Exception)) -ForegroundColor Red; + Write-IcingaConsoleError ([string]::Format('Failed to remove items from path "{0}": {1}', $Path, $_.Exception)); } return $FALSE; } diff --git a/lib/core/framework/Restart-IcingaService.psm1 b/lib/core/framework/Restart-IcingaService.psm1 index 4fc26e7..1e18e4e 100644 --- a/lib/core/framework/Restart-IcingaService.psm1 +++ b/lib/core/framework/Restart-IcingaService.psm1 @@ -1,3 +1,23 @@ +<# +.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( @@ -5,7 +25,9 @@ function Restart-IcingaService() ); if (Get-Service $Service -ErrorAction SilentlyContinue) { - Write-Host ([string]::Format('Restarting service "{0}"', $Service)); + Write-IcingaConsoleNotice ([string]::Format('Restarting service "{0}"', $Service)); Restart-Service $Service; + } else { + Write-IcingaConsoleWarning -Message 'The service "{0}" is not installed' -Objects $Service; } } diff --git a/lib/core/framework/Start-IcingaService.psm1 b/lib/core/framework/Start-IcingaService.psm1 index ec4b5a7..63487cb 100644 --- a/lib/core/framework/Start-IcingaService.psm1 +++ b/lib/core/framework/Start-IcingaService.psm1 @@ -1,3 +1,23 @@ +<# +.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( @@ -5,6 +25,9 @@ function Start-IcingaService() ); if (Get-Service $Service -ErrorAction SilentlyContinue) { + Write-IcingaConsoleNotice -Message 'Starting service "{0}"' -Objects $Service; Start-Service $Service; + } else { + Write-IcingaConsoleWarning -Message 'The service "{0}" is not installed' -Objects $Service; } } diff --git a/lib/core/framework/Stop-IcingaService.psm1 b/lib/core/framework/Stop-IcingaService.psm1 index ef91fa8..8daaf52 100644 --- a/lib/core/framework/Stop-IcingaService.psm1 +++ b/lib/core/framework/Stop-IcingaService.psm1 @@ -1,3 +1,23 @@ +<# +.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( @@ -5,6 +25,9 @@ function Stop-IcingaService() ); if (Get-Service $Service -ErrorAction SilentlyContinue) { + Write-IcingaConsoleNotice -Message 'Stopping service "{0}"' -Objects $Service; Stop-Service $Service; + } else { + Write-IcingaConsoleWarning -Message 'The service "{0}" is not installed' -Objects $Service; } } diff --git a/lib/core/framework/Test-IcingaZipBinaryChecksum.psm1 b/lib/core/framework/Test-IcingaZipBinaryChecksum.psm1 index 94612fa..652a79f 100644 --- a/lib/core/framework/Test-IcingaZipBinaryChecksum.psm1 +++ b/lib/core/framework/Test-IcingaZipBinaryChecksum.psm1 @@ -1,3 +1,26 @@ +<# +.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( diff --git a/lib/core/framework/Unblock-IcingaPowerShellFiles.psm1 b/lib/core/framework/Unblock-IcingaPowerShellFiles.psm1 index 9f6ef5c..acd2229 100644 --- a/lib/core/framework/Unblock-IcingaPowerShellFiles.psm1 +++ b/lib/core/framework/Unblock-IcingaPowerShellFiles.psm1 @@ -1,3 +1,25 @@ +<# +.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( @@ -5,10 +27,10 @@ function Unblock-IcingaPowerShellFiles() ); if ([string]::IsNullOrEmpty($Path)) { - Write-Host 'The specified directory was not found'; + Write-IcingaConsoleError 'The specified directory was not found'; return; } - Write-Host 'Unblocking Icinga PowerShell Files'; + Write-IcingaConsoleNotice 'Unblocking Icinga PowerShell Files'; Get-ChildItem -Path $Path -Recurse | Unblock-File; } diff --git a/lib/core/framework/Uninstall-IcingaFrameworkService.psm1 b/lib/core/framework/Uninstall-IcingaFrameworkService.psm1 index 5c703b2..1d13f10 100644 --- a/lib/core/framework/Uninstall-IcingaFrameworkService.psm1 +++ b/lib/core/framework/Uninstall-IcingaFrameworkService.psm1 @@ -1,3 +1,21 @@ +<# +.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-IcingaFrameworkService; +.INPUTS + System.String +.OUTPUTS + System.Object +.LINK + https://github.com/Icinga/icinga-powershell-framework +#> + function Uninstall-IcingaFrameworkService() { Stop-IcingaService 'icingapowershell'; @@ -7,10 +25,10 @@ function Uninstall-IcingaFrameworkService() switch ($ServiceCreation.ExitCode) { 0 { - Write-Host 'Icinga PowerShell Service was successfully removed'; + Write-IcingaConsoleNotice 'Icinga PowerShell Service was successfully removed'; } 1060 { - Write-Host 'The Icinga PowerShell Service is not installed'; + 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)); diff --git a/lib/core/icingaagent/firewall/Disable-IcingaFirewall.psm1 b/lib/core/icingaagent/firewall/Disable-IcingaFirewall.psm1 index 749d17c..0502a5d 100644 --- a/lib/core/icingaagent/firewall/Disable-IcingaFirewall.psm1 +++ b/lib/core/icingaagent/firewall/Disable-IcingaFirewall.psm1 @@ -9,9 +9,9 @@ function Disable-IcingaFirewall() 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-Host ([string]::Format('Failed to remove legacy firewall: {0}{1}', $Firewall.Message, $Firewall.Error)); + Write-IcingaConsoleError ([string]::Format('Failed to remove legacy firewall: {0}{1}', $Firewall.Message, $Firewall.Error)); } else { - Write-Host 'Successfully removed legacy Firewall rule'; + Write-IcingaConsoleNotice 'Successfully removed legacy firewall rule'; } } @@ -22,9 +22,9 @@ function Disable-IcingaFirewall() if ($FirewallConfig.IcingaFirewall) { $Firewall = Start-IcingaProcess -Executable 'netsh' -Arguments 'advfirewall firewall delete rule name="Icinga Agent Inbound"'; if ($Firewall.ExitCode -ne 0) { - Write-Host ([string]::Format('Failed to remove Icinga firewall: {0}{1}', $Firewall.Message, $Firewall.Error)); + Write-IcingaConsoleError ([string]::Format('Failed to remove Icinga firewall: {0}{1}', $Firewall.Message, $Firewall.Error)); } else { - Write-Host 'Successfully removed Icinga Firewall rule'; + Write-IcingaConsoleNotice 'Successfully removed Icinga firewall rule'; } } } diff --git a/lib/core/icingaagent/firewall/Enable-IcingaFirewall.psm1 b/lib/core/icingaagent/firewall/Enable-IcingaFirewall.psm1 index 88b353c..1f8a18c 100644 --- a/lib/core/icingaagent/firewall/Enable-IcingaFirewall.psm1 +++ b/lib/core/icingaagent/firewall/Enable-IcingaFirewall.psm1 @@ -8,7 +8,7 @@ function Enable-IcingaFirewall() $FirewallConfig = Get-IcingaFirewallConfig -NoOutput; if ($FirewallConfig.IcingaFirewall -And $Force -eq $FALSE) { - Write-Host 'Icinga Firewall is already enabled' + Write-IcingaConsoleNotice 'Icinga Firewall is already enabled' return; } @@ -28,8 +28,8 @@ function Enable-IcingaFirewall() $FirewallResult = Start-IcingaProcess -Executable 'netsh' -Arguments $FirewallRule; if ($FirewallResult.ExitCode -ne 0) { - Write-Host ([string]::Format('Failed to open Icinga firewall for port "{0}": {1}[2}', $IcingaPort, $FirewallResult.Message, $FirewallResult.Error)); + Write-IcingaConsoleError ([string]::Format('Failed to open Icinga firewall for port "{0}": {1}[2}', $IcingaPort, $FirewallResult.Message, $FirewallResult.Error)); } else { - Write-Host ([string]::Format('Successfully enabled firewall for port "{0}"', $IcingaPort)); + Write-IcingaConsoleNotice ([string]::Format('Successfully enabled firewall for port "{0}"', $IcingaPort)); } } diff --git a/lib/core/icingaagent/firewall/Get-IcingaFirewallConfig.psm1 b/lib/core/icingaagent/firewall/Get-IcingaFirewallConfig.psm1 index 6caa144..1048b88 100644 --- a/lib/core/icingaagent/firewall/Get-IcingaFirewallConfig.psm1 +++ b/lib/core/icingaagent/firewall/Get-IcingaFirewallConfig.psm1 @@ -11,7 +11,7 @@ function Get-IcingaFirewallConfig() if ($LegacyFirewall.ExitCode -eq 0) { if ($NoOutput -eq $FALSE) { - Write-Host 'Legacy firewall configuration has been detected.'; + Write-IcingaConsoleWarning 'Legacy firewall configuration has been detected.'; } $LegacyFirewallPresent = $TRUE; } @@ -20,12 +20,12 @@ function Get-IcingaFirewallConfig() if ($IcingaFirewall.ExitCode -eq 0) { if ($NoOutput -eq $FALSE) { - Write-Host 'Icinga firewall is present.'; + Write-IcingaConsoleNotice 'Icinga firewall is present.'; } $IcingaFirewallPresent = $TRUE; } else { if ($NoOutput -eq $FALSE) { - Write-Host 'Icinga firewall is not present'; + Write-IcingaConsoleError 'Icinga firewall is not present'; } } diff --git a/lib/core/icingaagent/getters/Get-IcingaAgentInstallerAnswerInput.psm1 b/lib/core/icingaagent/getters/Get-IcingaAgentInstallerAnswerInput.psm1 index 6f5473b..eaac48d 100644 --- a/lib/core/icingaagent/getters/Get-IcingaAgentInstallerAnswerInput.psm1 +++ b/lib/core/icingaagent/getters/Get-IcingaAgentInstallerAnswerInput.psm1 @@ -16,7 +16,7 @@ function Get-IcingaAgentInstallerAnswerInput() $DefaultAnswer = ' (y/N)'; } elseif ($Default -eq 'v') { if ([string]::IsNullOrEmpty($DefaultInput) -eq $FALSE) { - $DefaultAnswer = [string]::Format(' (Default: "{0}")', $DefaultInput); + $DefaultAnswer = [string]::Format(' (Defaults: "{0}")', $DefaultInput); } } diff --git a/lib/core/icingaagent/getters/Get-IcingaAgentMSIPackage.psm1 b/lib/core/icingaagent/getters/Get-IcingaAgentMSIPackage.psm1 index 5a48b7d..580c6ff 100644 --- a/lib/core/icingaagent/getters/Get-IcingaAgentMSIPackage.psm1 +++ b/lib/core/icingaagent/getters/Get-IcingaAgentMSIPackage.psm1 @@ -25,7 +25,6 @@ function Get-IcingaAgentMSIPackage() foreach ($line in $Content) { if ($line -like '*.msi*' -And $line -like "*$Architecture*") { - #Write-Host '#####' $line $MSIPackage = $line.SubString( $line.IndexOf('Icinga2-'), $line.IndexOf('.msi') - $line.IndexOf('Icinga2-') @@ -43,7 +42,7 @@ function Get-IcingaAgentMSIPackage() break; } } elseif ($Version -eq 'latest') { - if ($line -like '*snapshot*') { + if ($line -like '*snapshot*' -Or $line -like '*-rc*') { continue; } $UsePackage = $MSIPackage; @@ -61,13 +60,13 @@ function Get-IcingaAgentMSIPackage() if ($SkipDownload -eq $FALSE) { $DownloadPath = Join-Path $Env:TEMP -ChildPath $UsePackage; - Write-Host ([string]::Format('Downloading Icinga 2 Agent installer "{0}" into temp directory "{1}"', $UsePackage, $DownloadPath)); + Write-IcingaConsoleNotice ([string]::Format('Downloading Icinga 2 Agent installer "{0}" into temp directory "{1}"', $UsePackage, $DownloadPath)); Invoke-WebRequest -Uri (Join-WebPath -Path $Source -ChildPath $UsePackage) -OutFile $DownloadPath; } return @{ 'InstallerPath' = $DownloadPath; - 'Version' = ($UsePackage).Replace('Icinga2-v', '').Replace($Architecture, '').Replace('.msi', '').Replace('-', ''); + 'Version' = ($UsePackage).Replace('Icinga2-v', '').Replace([string]::Format('-{0}.msi', $Architecture), '') 'LastUpdate' = $LastUpdate; } } diff --git a/lib/core/icingaagent/installer/Install-IcingaAgent.psm1 b/lib/core/icingaagent/installer/Install-IcingaAgent.psm1 index 7490a12..613faa6 100644 --- a/lib/core/icingaagent/installer/Install-IcingaAgent.psm1 +++ b/lib/core/icingaagent/installer/Install-IcingaAgent.psm1 @@ -8,12 +8,12 @@ function Install-IcingaAgent() ); if ([string]::IsNullOrEmpty($Version)) { - Write-Host 'No Icinga Agent version specified. Skipping installation.'; + Write-IcingaConsoleError 'No Icinga Agent version specified. Skipping installation.'; return $FALSE; } if ($IcingaData.Installed -eq $TRUE -and $AllowUpdates -eq $FALSE) { - Write-Host 'The Icinga Agent is already installed on this system. To perform updates or downgrades, please add the "-AllowUpdates" argument'; + Write-IcingaConsoleWarning 'The Icinga Agent is already installed on this system. To perform updates or downgrades, please add the "-AllowUpdates" argument'; return $FALSE; } @@ -24,12 +24,12 @@ function Install-IcingaAgent() if ($Version -eq 'snapshot') { if ($IcingaData.InstallDate -ge $IcingaInstaller.LastUpdate -And [string]::IsNullOrEmpty($InstalledVersion.Snapshot) -eq $FALSE) { - Write-Host 'There is no new snapshot package available which requires to be installed.' + 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-Host ([string]::Format( + Write-IcingaConsoleNotice ([string]::Format( 'No installation required. Your installed version [{0}] is matching the online version [{1}]', $InstalledVersion.Full, $IcingaInstaller.Version @@ -63,7 +63,7 @@ function Install-IcingaAgent() } } - Write-Host ([string]::Format('Installing new Icinga Agent version into "{0}"', $InstallFolderMsg)); + Write-IcingaConsoleNotice ([string]::Format('Installing new Icinga Agent version into "{0}"', $InstallFolderMsg)); if ($IcingaData.Installed) { if ((Uninstall-IcingaAgent) -eq $FALSE) { @@ -74,10 +74,10 @@ function Install-IcingaAgent() $InstallProcess = Start-IcingaProcess -Executable 'MsiExec.exe' -Arguments ([string]::Format('/quiet /i "{0}" {1}', $IcingaInstaller.InstallerPath, $InstallTarget)) -FlushNewLines; if ($InstallProcess.ExitCode -ne 0) { - Write-Host ([string]::Format('Failed to install Icinga 2 Agent: {0}{1}', $InstallProcess.Message, $InstallProcess.Error)); + Write-IcingaConsoleError -Message 'Failed to install Icinga 2 Agent: {0}{1}' -Objects $InstallProcess.Message, $InstallProcess.Error; return $FALSE; } - Write-Host 'Icinga Agent was successfully installed'; + Write-IcingaConsoleNotice 'Icinga Agent was successfully installed'; return $TRUE; } diff --git a/lib/core/icingaagent/installer/Install-IcingaAgentCertificates.psm1 b/lib/core/icingaagent/installer/Install-IcingaAgentCertificates.psm1 index 71699de..a9ff5fd 100644 --- a/lib/core/icingaagent/installer/Install-IcingaAgentCertificates.psm1 +++ b/lib/core/icingaagent/installer/Install-IcingaAgentCertificates.psm1 @@ -26,7 +26,7 @@ function Install-IcingaAgentCertificates() } if (-Not (Test-IcingaAgentCertificates -CertDirectory $CertificateDirectory -Hostname $Hostname -Force $Force)) { - Write-Host ([string]::Format('Generating host certificates for host "{0}"', $Hostname)); + 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, @@ -39,31 +39,33 @@ function Install-IcingaAgentCertificates() } if ([string]::IsNullOrEmpty($Endpoint) -And [string]::IsNullOrEmpty($CACert)) { - Write-Host 'Your host certificates have been generated successfully. Please either specify an endpoint to connect to or provide the path to a valid ca.crt.'; + 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 $TRUE; } if (-Not [string]::IsNullOrEmpty($Endpoint)) { if (-Not (Test-IcingaAgentCertificates -CertDirectory $CertificateDirectory -Hostname $Hostname -TestTrustedParent -Force $Force)) { - Write-Host ([string]::Format('Fetching trusted master certificate from "{0}"', $Endpoint)); + 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}', + $arguments = [string]::Format('pki save-cert --trustedcert {0}trusted-parent.crt --host {1} --port {2}', $CertificateDirectory, - $Endpoint + $Endpoint, + $Port ); } else { - $arguments = [string]::Format('pki save-cert --key {0}{1}.key --trustedcert {0}trusted-parent.crt --host {2}', + $arguments = [string]::Format('pki save-cert --key {0}{1}.key --trustedcert {0}trusted-parent.crt --host {2} --port {3}', $CertificateDirectory, $Hostname, - $Endpoint + $Endpoint, + $Port ); } if ((Start-IcingaAgentCertificateProcess -Arguments $arguments) -eq $FALSE) { - Write-Host 'Unable to connect to your provided Icinga CA. Please verify the entered configuration is correct.' ` + 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 $TRUE; @@ -90,9 +92,9 @@ function Install-IcingaAgentCertificates() } if ([string]::IsNullOrEmpty($Ticket)) { - Write-Host 'Your certificates were generated successfully. Please sign the certificate now on your Icinga CA master. You can lookup open requests with "icinga2 ca list"'; + 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-Host 'Icinga certificates successfully installed'; + Write-IcingaConsoleNotice 'Icinga certificates successfully installed'; } } @@ -101,7 +103,7 @@ function Install-IcingaAgentCertificates() if (-Not (Copy-IcingaAgentCACertificate -CAPath $CACert -Desination $CertificateDirectory)) { return $FALSE; } - Write-Host '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"'; + 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; @@ -117,11 +119,11 @@ function Start-IcingaAgentCertificateProcess() $Process = Start-IcingaProcess -Executable $Binary -Arguments $Arguments; if ($Process.ExitCode -ne 0) { - Write-Host ([string]::Format('Failed to create certificate.{0}Arguments: {1}{0}Error:{2} {3}', "`r`n", $Arguments, $Process.Message, $Process.Error)); + 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-Host $Process.Message; + Write-IcingaConsoleNotice $Process.Message; return $TRUE; } @@ -154,20 +156,20 @@ function Test-IcingaAgentCertificates() if ($TestCACert) { if (Test-Path (Join-Path -Path $CertDirectory -ChildPath 'ca.crt')) { - Write-Host 'Your ca.crt is present. No generation or fetching required'; + Write-IcingaConsoleNotice 'Your ca.crt is present. No generation or fetching required'; return $TRUE; } else { - Write-Host 'Your ca.crt is not present. Manuall copy or fetching from your Icinga CA is required.'; + 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-Host 'Your trusted-parent.crt is present. No fetching or generation required'; + Write-IcingaConsoleNotice 'Your trusted-parent.crt is present. No fetching or generation required'; return $TRUE; } else { - Write-Host 'Your trusted master certificate is not present. Fetching from your CA server is required'; + Write-IcingaConsoleWarning 'Your trusted master certificate is not present. Fetching from your CA server is required'; return $FALSE; } } @@ -186,13 +188,13 @@ function Test-IcingaAgentCertificates() 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-Host ([string]::Format('Certificate file {0} is not matching the hostname {1}. Certificate generation is required.', $cert.Name, $Hostname)); + Write-IcingaConsoleWarning ([string]::Format('Certificate file {0} is not matching the hostname {1}. Certificate generation is required.', $cert.Name, $Hostname)); return $FALSE; } } } - Write-Host 'Icinga host certificates are present and valid. No generation required.'; + Write-IcingaConsoleNotice 'Icinga host certificates are present and valid. No generation required'; return $TRUE; } @@ -207,7 +209,7 @@ function Copy-IcingaAgentCACertificate() # 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-Host ([string]::Format('Copied ca.crt from "{0}" to "{1}', $CAPath, $Desination)); + Write-IcingaConsoleNotice ([string]::Format('Copied ca.crt from "{0}" to "{1}', $CAPath, $Desination)); } else { # It could also be a web ressource try { @@ -219,9 +221,9 @@ function Copy-IcingaAgentCACertificate() $response.RawContent.Length - $Index ); Set-Content -Path (Join-Path $Desination -ChildPath 'ca.crt') -Value $CAContent; - Write-Host ([string]::Format('Downloaded ca.crt from "{0}" to "{1}', $CAPath, $Desination)) + Write-IcingaConsoleNotice ([string]::Format('Downloaded ca.crt from "{0}" to "{1}', $CAPath, $Desination)) } catch { - Write-Host 'Failed to load any provided ca.crt ressource'; + Write-IcingaConsoleError 'Failed to load any provided ca.crt ressource'; return $FALSE; } } diff --git a/lib/core/icingaagent/installer/Uninstall-IcingaAgent.psm1 b/lib/core/icingaagent/installer/Uninstall-IcingaAgent.psm1 index cb99f8f..ef1d852 100644 --- a/lib/core/icingaagent/installer/Uninstall-IcingaAgent.psm1 +++ b/lib/core/icingaagent/installer/Uninstall-IcingaAgent.psm1 @@ -1,23 +1,35 @@ function Uninstall-IcingaAgent() { + param ( + [switch]$RemoveDataFolder = $FALSE + ); + $IcingaData = Get-IcingaAgentInstallation; if ($IcingaData.Installed -eq $FALSE) { - Write-Host 'Unable to uninstall the Icinga Agent. The Agent is not installed'; + Write-IcingaConsoleError 'Unable to uninstall the Icinga Agent. The Agent is not installed'; return; } - Write-Host 'Removing current installed Icinga Agent'; + Write-IcingaConsoleNotice 'Removing current Icinga Agent'; Stop-IcingaService 'icinga2'; $Uninstaller = Start-IcingaProcess -Executable 'MsiExec.exe' -Arguments ([string]::Format('{0} /q', $IcingaData.Uninstaller)) -FlushNewLine; if ($Uninstaller.ExitCode -ne 0) { - Write-Host ([string]::Format('Failed to remove Icinga 2 Agent: {0}{1}', $Uninstaller.Message, $Uninstaller.Error)); + Write-IcingaConsoleError ([string]::Format('Failed to remove Icinga Agent: {0}{1}', $Uninstaller.Message, $Uninstaller.Error)); return $FALSE; } - - Write-Host 'Icinga Agent was successfully removed'; + + if ($RemoveDataFolder) { + [string]$IcingaProgramData = Join-Path -Path $Env:ProgramData -ChildPath 'icinga2'; + 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; } diff --git a/lib/core/icingaagent/misc/Disable-IcingaAgentFeature.psm1 b/lib/core/icingaagent/misc/Disable-IcingaAgentFeature.psm1 index 983c340..cef5fc8 100644 --- a/lib/core/icingaagent/misc/Disable-IcingaAgentFeature.psm1 +++ b/lib/core/icingaagent/misc/Disable-IcingaAgentFeature.psm1 @@ -9,7 +9,7 @@ function Disable-IcingaAgentFeature() } if ((Test-IcingaAgentFeatureEnabled -Feature $Feature) -eq $FALSE) { - Write-Host ([string]::Format('This feature is already disabled [{0}]', $Feature)); + Write-IcingaConsoleNotice ([string]::Format('This feature is already disabled [{0}]', $Feature)); return; } @@ -20,5 +20,5 @@ function Disable-IcingaAgentFeature() throw ([string]::Format('Failed to disable Icinga Feature: {0}', $Process.Message)); } - Write-Host ([string]::Format('Feature "{0}" was successfully disabled', $Feature)); + Write-IcingaConsoleNotice ([string]::Format('Feature "{0}" was successfully disabled', $Feature)); } diff --git a/lib/core/icingaagent/misc/Enable-IcingaAgentFeature.psm1 b/lib/core/icingaagent/misc/Enable-IcingaAgentFeature.psm1 index 6721a61..0a59aa3 100644 --- a/lib/core/icingaagent/misc/Enable-IcingaAgentFeature.psm1 +++ b/lib/core/icingaagent/misc/Enable-IcingaAgentFeature.psm1 @@ -9,7 +9,7 @@ function Enable-IcingaAgentFeature() } if ((Test-IcingaAgentFeatureEnabled -Feature $Feature)) { - Write-Host ([string]::Format('This feature is already enabled [{0}]', $Feature)); + Write-IcingaConsoleNotice ([string]::Format('This feature is already enabled [{0}]', $Feature)); return; } @@ -20,5 +20,5 @@ function Enable-IcingaAgentFeature() throw ([string]::Format('Failed to enable Icinga Feature: {0}', $Process.Message)); } - Write-Host ([string]::Format('Feature "{0}" was successfully enabled', $Feature)); + Write-IcingaConsoleNotice ([string]::Format('Feature "{0}" was successfully enabled', $Feature)); } diff --git a/lib/core/icingaagent/misc/Move-IcingaAgentDefaultConfig.psm1 b/lib/core/icingaagent/misc/Move-IcingaAgentDefaultConfig.psm1 index 076761a..901d6cf 100644 --- a/lib/core/icingaagent/misc/Move-IcingaAgentDefaultConfig.psm1 +++ b/lib/core/icingaagent/misc/Move-IcingaAgentDefaultConfig.psm1 @@ -4,7 +4,7 @@ function Move-IcingaAgentDefaultConfig() $BackupFile = Join-Path -Path $ConfigDir -ChildPath 'ps_backup\backup_executed.key'; if ((Test-Path $BackupFile)) { - Write-Host 'A backup of your default configuration is not required. A backup was already made.'; + Write-IcingaConsoleNotice 'A backup of your default configuration is not required. A backup was already made'; return; } @@ -19,5 +19,5 @@ function Move-IcingaAgentDefaultConfig() New-Item (Join-Path -Path $ConfigDir -ChildPath 'zones.conf') -ItemType File | Out-Null; New-Item -Path $BackupFile -ItemType File | Out-Null; - Write-Host 'Successfully backed up Icinga 2 Agent default config'; + Write-IcingaConsoleNotice 'Successfully backed up Icinga 2 Agent default config'; } diff --git a/lib/core/icingaagent/misc/Reset-IcingaAgentConfigFile.psm1 b/lib/core/icingaagent/misc/Reset-IcingaAgentConfigFile.psm1 new file mode 100644 index 0000000..43a7590 --- /dev/null +++ b/lib/core/icingaagent/misc/Reset-IcingaAgentConfigFile.psm1 @@ -0,0 +1,30 @@ +<# +.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; + } +} diff --git a/lib/core/icingaagent/misc/Show-IcingaAgentObjects.psm1 b/lib/core/icingaagent/misc/Show-IcingaAgentObjects.psm1 index 07f4aae..b53bdaf 100644 --- a/lib/core/icingaagent/misc/Show-IcingaAgentObjects.psm1 +++ b/lib/core/icingaagent/misc/Show-IcingaAgentObjects.psm1 @@ -4,7 +4,7 @@ function Show-IcingaAgentObjects() $Output = Start-IcingaProcess -Executable $Binary -Arguments 'object list'; if ($Output.ExitCode -ne 0) { - Write-Host ([string]::Format('Failed to fetch Icinga Agent objects list: {0}{1}', $Output.Message, $Output.Error)); + Write-IcingaConsoleError ([string]::Format('Failed to fetch Icinga Agent objects list: {0}{1}', $Output.Message, $Output.Error)); return $null; } diff --git a/lib/core/icingaagent/misc/Start-IcingaAgentDirectorWizard.psm1 b/lib/core/icingaagent/misc/Start-IcingaAgentDirectorWizard.psm1 index c7f6c51..d77faf0 100644 --- a/lib/core/icingaagent/misc/Start-IcingaAgentDirectorWizard.psm1 +++ b/lib/core/icingaagent/misc/Start-IcingaAgentDirectorWizard.psm1 @@ -57,7 +57,7 @@ function Start-IcingaAgentDirectorWizard() try { $Arguments = Get-IcingaDirectorSelfServiceConfig -DirectorUrl $DirectorUrl -ApiKey $SelfServiceAPIKey; } catch { - Write-Host ([string]::Format('Failed to connect to your Icinga Director at "{0}". Please try again', $DirectorUrl)); + 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) ` @@ -88,7 +88,7 @@ function Start-IcingaAgentDirectorWizard() # Host is already registered if ($null -eq $SelfServiceAPIKey) { - Write-Host 'The wizard is unable to complete as this host is already registered but the local API key is not stored within the config' + 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; } @@ -112,6 +112,10 @@ function Start-IcingaAgentDirectorWizard() $DirectorOverrideArgs.Add( 'Ticket', $IcingaTicket ); + $DirectorOverrideArgs.Add( + 'OverrideDirectorVars', 0 + ); + if ([string]::IsNullOrEmpty($TemplateKey) -eq $FALSE) { $DirectorOverrideArgs.Add( 'SelfServiceAPIKey', $TemplateKey @@ -131,18 +135,21 @@ function Start-IcingaDirectorAPIArgumentOverride() ); $NewArguments = @{}; - Write-Host 'Please follow the wizard and manually override all entries you intend to'; - Write-Host '===='; + 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]) { - if ([string]::IsNullOrEmpty($value) -eq $FALSE) { + 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, - ([string]::Join(',', $tmpArray)) + $tmpArray ); } } diff --git a/lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 b/lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 index 1984232..5fff42d 100644 --- a/lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 +++ b/lib/core/icingaagent/misc/Start-IcingaAgentInstallWizard.psm1 @@ -16,6 +16,7 @@ function Start-IcingaAgentInstallWizard() $AcceptConnections = $null, [array]$Endpoints = @(), [array]$EndpointConnections = @(), + $ConvertEndpointIPConfig = $null, [string]$ParentZone, [array]$GlobalZones = $null, [string]$CAEndpoint, @@ -70,74 +71,75 @@ function Start-IcingaAgentInstallWizard() $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 '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 'AddFirewallRule' -Value $AddFirewallRule -InstallerArguments $InstallerArguments; - $AddFirewallRule = $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 '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 '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; } } if ([string]::IsNullOrEmpty($Hostname) -And $null -eq $AutoUseFQDN -And $null -eq $AutoUseHostname) { - if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to manually specify a hostname?' -Default 'n').result -eq 1) { - if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to automatically fetch the hostname with its FQDN?' -Default 'y').result -eq 1) { + 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; @@ -148,17 +150,24 @@ function Start-IcingaAgentInstallWizard() $AutoUseFQDN = $FALSE; $AutoUseHostname = $TRUE; } - if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to modify the hostname to only include lower case characters?' -Default 'y').result -eq 1) { + $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 { - if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to modify the hostname to only include upper case characters?' -Default 'n').result -eq 0) { + $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; @@ -171,13 +180,13 @@ function Start-IcingaAgentInstallWizard() } } - Write-Host ([string]::Format('Using hostname "{0}" for the Icinga 2 Agent configuration', $Hostname)); + 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 then "https://packages.icinga.com/windows/"?' -Default 'n').result -eq 0) { + 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 { @@ -185,15 +194,15 @@ function Start-IcingaAgentInstallWizard() $InstallerArguments += "-PackageSource '$PackageSource'"; } - Write-Host ([string]::Format('Using package source "{0}" for the Icinga 2 Agent package', $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 wish to install ("latest", "snapshot", or a version like "2.11.0")' -Default 'v' -DefaultInput 'latest').answer; + $AgentVersion = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the version you wish to install ("latest", "snapshot" or a version like "2.11.3")' -Default 'v' -DefaultInput 'latest').answer; $InstallerArguments += "-AgentVersion '$AgentVersion'"; - Write-Host ([string]::Format('Installing Icinga Version: "{0}"', $AgentVersion)); + Write-IcingaConsoleNotice ([string]::Format('Installing Icinga version: "{0}"', $AgentVersion)); } } else { $AllowVersionChanges = $FALSE; @@ -204,7 +213,7 @@ function Start-IcingaAgentInstallWizard() } } else { if ($null -eq $UpdateAgent) { - if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'The Icinga 2 Agent is already installed. Would you like to update it?' -Default 'y').result -eq 1) { + 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'; @@ -218,10 +227,10 @@ function Start-IcingaAgentInstallWizard() if ($UpdateAgent -eq 1) { if ([string]::IsNullOrEmpty($AgentVersion)) { - $AgentVersion = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the version you wish to install ("latest", "snapshot", or a version like "2.11.0")' -Default 'v').answer; + $AgentVersion = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the version you wish to install ("latest", "snapshot", or a version like "2.11.0")' -Default 'v' -DefaultInput 'latest').answer; $InstallerArguments += "-AgentVersion '$AgentVersion'"; - Write-Host ([string]::Format('Updating/Downgrading Icinga 2 Agent to version: "{0}"', $AgentVersion)); + Write-IcingaConsoleNotice ([string]::Format('Updating/Downgrading Icinga 2 Agent to version: "{0}"', $AgentVersion)); } if ([string]::IsNullOrEmpty($PackageSource)) { @@ -237,14 +246,14 @@ function Start-IcingaAgentInstallWizard() } if ($Endpoints.Count -eq 0) { - $ArrayString = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify all endpoints this Agent will report to (separated by ",")' -Default 'v').answer; + $ArrayString = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the parent node(s) separated by "," (Example: "master-icinga2a, master-icinga2b")' -Default 'v').answer; $Endpoints = ($ArrayString.Replace(' ', '')).Split(','); $InstallerArguments += ("-Endpoints " + ([string]::Join(',', $Endpoints))); } if ($null -eq $CAPort) { - if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Are you using a different port than 5665 for Icinga communications?' -Default 'n').result -eq 0) { - $CAPort = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter the port for Icinga 2 communication' -Default 'v').answer; + if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Are you using a custom port 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"; @@ -255,20 +264,25 @@ function Start-IcingaAgentInstallWizard() [bool]$CanConnectToParent = $FALSE; if ($null -eq $AcceptConnections) { - if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Is this Agent able to connect to its parent node for certificate generation and general communication?' -Default 'y').result -eq 1) { + if ((Get-IcingaAgentInstallerAnswerInput -Prompt "Is this Agent able to connect to its parent node(s)?" -Default 'y').result -eq 1) { $CanConnectToParent = $TRUE; - $AcceptConnections = 1; - $InstallerArguments += ("-AcceptConnections 1"); - } else { $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; } - } elseif ($AcceptConnections) { - $CanConnectToParent = $TRUE; - $InstallerArguments += ("-AcceptConnections $AcceptConnections"); } - if ($null -eq $AddFirewallRule) { + 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; @@ -276,9 +290,33 @@ function Start-IcingaAgentInstallWizard() $InstallerArguments += "-AddFirewallRule 0"; $AddFirewallRule = $FALSE; } + } else { + if ($CanConnectToParent -eq $TRUE) { + $InstallerArguments += "-AddFirewallRule 0"; + $AddFirewallRule = $FALSE; + } } - if ($EndpointConnections.Count -eq 0 -And $AcceptConnections -eq 1) { + 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.Split(','); + } + 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); @@ -286,13 +324,20 @@ function Start-IcingaAgentInstallWizard() 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 ","' -Default 'v' -DefaultInput $NetworkDefault).answer; + $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))); } if ([string]::IsNullOrEmpty($ParentZone)) { - $ParentZone = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the parent zone this agent will connect to' -Default 'v' -DefaultInput 'master').answer; + $ParentZone = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please specify the parent zone this Agent will connect to' -Default 'v' -DefaultInput 'master').answer; $InstallerArguments += "-ParentZone $ParentZone"; } @@ -326,10 +371,15 @@ function Start-IcingaAgentInstallWizard() 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 ","' -Default 'v').answer; - $GlobalZones = ($ArrayString.Replace(' ', '')).Split(',') - $GlobalZoneConfig += $GlobalZones; - $InstallerArguments += ("-GlobalZones " + ([string]::Join(',', $GlobalZones))); + $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 @()"); @@ -340,12 +390,12 @@ function Start-IcingaAgentInstallWizard() if ($CanConnectToParent) { if ([string]::IsNullOrEmpty($CAEndpoint)) { - $CAEndpoint = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter the IP/FQDN for either ONE of your Icinga parent nodes or your Icinga 2 CA master' -Default 'v' -DefaultInput (Get-IPConfigFromString $EndpointConnections[0]).address).answer; + $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 Icinga Ticket available to sign your certificate?' -Default 'y').result -eq 1) { - $Ticket = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter your Icinga Ticket' -Default 'v').answer; + 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 { @@ -371,7 +421,7 @@ function Start-IcingaAgentInstallWizard() } 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' -Default 'v').answer; + $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 { @@ -380,7 +430,8 @@ function Start-IcingaAgentInstallWizard() $InstallerArguments += "-CAFile '$CAFile'"; } else { $InstallerArguments += "-CAFile ''"; - $InstallerArguments += "-EmptyCA 1" + $InstallerArguments += "-EmptyCA 1"; + $EmptyCA = $TRUE; } } else { if ([string]::IsNullOrEmpty($CAFile)) { @@ -397,11 +448,11 @@ function Start-IcingaAgentInstallWizard() } if ([string]::IsNullOrEmpty($ServiceUser)) { - if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to change the user the Icinga Agent service is running with (Default: "NT Authority\NetworkService")?' -Default 'n').result -eq 0) { - $ServiceUser = (Get-IcingaAgentInstallerAnswerInput -Prompt 'Please enter the user you wish the Icinga Agent service to run with' -Default 'v').answer; + 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 Service user require a password to login (not required for System users)?' -Default 'y').result -eq 1) { + 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 { @@ -428,10 +479,14 @@ function Start-IcingaAgentInstallWizard() $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 PowerShell Framework as a Service?' -Default 'y').result -eq 1) { + if ((Get-IcingaAgentInstallerAnswerInput -Prompt 'Do you want to install the PowerShell Framework as a service?' -Default 'y').result -eq 1) { $result = Get-IcingaFrameworkServiceBinary; $InstallerArguments += "-InstallFrameworkService 1"; $InstallerArguments += [string]::Format("-FrameworkServiceUrl '{0}'", $result.FrameworkServiceUrl); @@ -450,23 +505,23 @@ function Start-IcingaAgentInstallWizard() if ($InstallerArguments.Count -ne 0) { $InstallerArguments += "-RunInstaller"; - Write-Host 'The wizard is complete. These are the configured settings:'; + Write-IcingaConsoleNotice 'The wizard is complete. These are the configured settings:'; - Write-Host '========' - Write-Host ($InstallerArguments | Out-String); - Write-Host '========' + 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-Host 'To execute your Icinga Agent installation based on your answers again on this or another machine, simply run this command:' + 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-Host 'To execute your Icinga Agent installation based on your answers, simply run this command:' + Write-IcingaConsoleNotice 'To execute your Icinga Agent installation based on your answers, simply run this command:'; } } else { - Write-Host 'Please run the wizard again to modify your answers or modify the command below:' + Write-IcingaConsoleNotice 'Please run the wizard again to modify your answers or modify the command below:'; } } Get-IcingaAgentInstallCommand -InstallerArguments $InstallerArguments -PrintConsole; @@ -474,26 +529,139 @@ function Start-IcingaAgentInstallWizard() if ($RunInstaller) { if ((Install-IcingaAgent -Version $AgentVersion -Source $PackageSource -AllowUpdates $AllowVersionChanges) -Or $Reconfigure) { + Reset-IcingaAgentConfigFile; Move-IcingaAgentDefaultConfig; Set-IcingaAgentNodeName -Hostname $Hostname; Set-IcingaAgentServiceUser -User $ServiceUser -Password $ServicePass -SetPermission | Out-Null; - Install-IcingaFrameworkService -Path $ServiceBin -User $ServiceUser -Password $ServicePass | Out-Null; + if ($InstallFrameworkService) { + Install-IcingaFrameworkService -Path $ServiceBin -User $ServiceUser -Password $ServicePass | Out-Null; + } Register-IcingaBackgroundDaemon -Command 'Start-IcingaServiceCheckDaemon'; Install-IcingaAgentBaseFeatures; Install-IcingaAgentCertificates -Hostname $Hostname -Endpoint $CAEndpoint -Port $CAPort -CACert $CAFile -Ticket $Ticket | Out-Null; Write-IcingaAgentApiConfig -Port $CAPort; + if ($EmptyCA -eq $TRUE) { + 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; - Restart-IcingaService 'icingapowershell'; + 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( @@ -505,11 +673,12 @@ function Set-IcingaWizardArgument() ); if ($DirectorArgs.Overrides.ContainsKey($WizardArg)) { - $Override = $DirectorArgs.Overrides[$WizardArg]; - if ($Value -is [array]) { - $Override = [string]::Join(',', $Override); - } - $InstallerArguments += "-$WizardArg $Override"; + + $InstallerArguments = Add-InstallerArgument ` + -InstallerArguments $InstallerArguments ` + -Key $WizardArg ` + -Value $DirectorArgs.Overrides[$WizardArg]; + return @{ 'Value' = $DirectorArgs.Overrides[$WizardArg]; 'Args' = $InstallerArguments; @@ -522,11 +691,12 @@ function Set-IcingaWizardArgument() $RetValue = $DirectorArgs.Arguments[$WizardArg]; } else { if ($null -ne $Value -Or [string]::IsNullOrEmpty($Value) -eq $FALSE) { - $TmpValue = $Value; - if ($Value -is [array]) { - $TmpValue = [string]::Join(',', $TmpValue); - } - $InstallerArguments += "-$WizardArg $TmpValue"; + + $InstallerArguments = Add-InstallerArgument ` + -InstallerArguments $InstallerArguments ` + -Key $WizardArg ` + -Value $Value; + return @{ 'Value' = $Value; 'Args' = $InstallerArguments; @@ -540,11 +710,12 @@ function Set-IcingaWizardArgument() } if ([string]::IsNullOrEmpty($Value) -eq $FALSE) { - $TmpValue = $Value; - if ($Value -is [array]) { - $TmpValue = [string]::Join(',', $Value); - } - $InstallerArguments += "-$WizardArg $TmpValue"; + + $InstallerArguments = Add-InstallerArgument ` + -InstallerArguments $InstallerArguments ` + -Key $WizardArg ` + -Value $Value; + return @{ 'Value' = $Value; 'Args' = $InstallerArguments; @@ -571,9 +742,9 @@ function Get-IcingaAgentInstallCommand() ); if ($PrintConsole) { - Write-Host '====' - Write-Host $Installer -ForegroundColor ([System.ConsoleColor]::Cyan); - Write-Host '====' + Write-IcingaConsolePlain '====' + Write-IcingaConsolePlain $Installer; + Write-IcingaConsolePlain '====' } else { return $Installer; } diff --git a/lib/core/icingaagent/readers/Read-IcingaAgentDebugLogFile.psm1 b/lib/core/icingaagent/readers/Read-IcingaAgentDebugLogFile.psm1 index 992fb43..139dfe6 100644 --- a/lib/core/icingaagent/readers/Read-IcingaAgentDebugLogFile.psm1 +++ b/lib/core/icingaagent/readers/Read-IcingaAgentDebugLogFile.psm1 @@ -2,7 +2,7 @@ function Read-IcingaAgentDebugLogFile() { $Logfile = Join-Path -Path (Get-IcingaAgentLogDirectory) -ChildPath 'debug.log'; if ((Test-Path $Logfile) -eq $FALSE) { - Write-Host 'Icinga 2 debug logfile not present. Unable to load it'; + Write-IcingaConsoleError 'Icinga 2 debug logfile not present. Unable to load it'; return; } diff --git a/lib/core/icingaagent/readers/Read-IcingaAgentLogFile.psm1 b/lib/core/icingaagent/readers/Read-IcingaAgentLogFile.psm1 index 8ce56bf..a277265 100644 --- a/lib/core/icingaagent/readers/Read-IcingaAgentLogFile.psm1 +++ b/lib/core/icingaagent/readers/Read-IcingaAgentLogFile.psm1 @@ -2,7 +2,7 @@ function Read-IcingaAgentLogFile() { $Logfile = Join-Path -Path (Get-IcingaAgentLogDirectory) -ChildPath 'icinga2.log'; if ((Test-Path $Logfile) -eq $FALSE) { - Write-Host 'Icinga 2 logfile not present. Unable to load it'; + Write-IcingaConsoleError 'Icinga 2 logfile not present. Unable to load it'; return; } diff --git a/lib/core/icingaagent/setters/Set-IcingaAgentNodeName.psm1 b/lib/core/icingaagent/setters/Set-IcingaAgentNodeName.psm1 index 4956b41..6262823 100644 --- a/lib/core/icingaagent/setters/Set-IcingaAgentNodeName.psm1 +++ b/lib/core/icingaagent/setters/Set-IcingaAgentNodeName.psm1 @@ -31,5 +31,5 @@ function Set-IcingaAgentNodeName() Set-Content -Path $ConstantsConf -Value $ConfigContent; - Write-Host ([string]::Format('Your hostname was successfully changed to "{0}"', $Hostname)); + Write-IcingaConsoleNotice ([string]::Format('Your hostname was successfully changed to "{0}"', $Hostname)); } diff --git a/lib/core/icingaagent/setters/Set-IcingaAgentServicePermission.psm1 b/lib/core/icingaagent/setters/Set-IcingaAgentServicePermission.psm1 index a166b26..fd63c13 100644 --- a/lib/core/icingaagent/setters/Set-IcingaAgentServicePermission.psm1 +++ b/lib/core/icingaagent/setters/Set-IcingaAgentServicePermission.psm1 @@ -1,7 +1,7 @@ function Set-IcingaAgentServicePermission() { if (Test-IcingaAgentServicePermission -Silent) { - Write-Host 'The Icinga Service User already has permission to run as service'; + Write-IcingaConsoleNotice 'The Icinga Service User already has permission to run as service'; return; } @@ -12,7 +12,7 @@ function Set-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'; + Write-IcingaTestOutput -Severity 'Failed' -Message 'There is no user assigned to the Icinga 2 service or the service is not yet installed'; return $FALSE; } diff --git a/lib/core/icingaagent/setters/Set-IcingaAgentServiceUser.psm1 b/lib/core/icingaagent/setters/Set-IcingaAgentServiceUser.psm1 index 5c1ef0b..c4d79e2 100644 --- a/lib/core/icingaagent/setters/Set-IcingaAgentServiceUser.psm1 +++ b/lib/core/icingaagent/setters/Set-IcingaAgentServiceUser.psm1 @@ -32,10 +32,10 @@ function Set-IcingaAgentServiceUser() Set-IcingaUserPermissions; } - Write-Host 'Service User successfully updated' + Write-IcingaConsoleNotice 'Service User successfully updated' return $TRUE; } else { - Write-Host ([string]::Format('Failed to update the service user: {0}', $Output.Message)); + Write-IcingaConsoleError ([string]::Format('Failed to update the service user: {0}', $Output.Message)); return $FALSE; } } diff --git a/lib/core/icingaagent/tests/Test-IcingaAcl.psm1 b/lib/core/icingaagent/tests/Test-IcingaAcl.psm1 index b69cb3c..68a950e 100644 --- a/lib/core/icingaagent/tests/Test-IcingaAcl.psm1 +++ b/lib/core/icingaagent/tests/Test-IcingaAcl.psm1 @@ -38,14 +38,14 @@ function Test-IcingaAcl() [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)); + 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-Host "\_ Please run the following command to fix this issue: Set-IcingaAcl -Directory '$Directory'"; + 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-Host "\_ Please run the following command to fix this issue: Set-IcingaAcl -Directory '$Directory'"; + 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'"; } } diff --git a/lib/core/icingaagent/tests/Test-IcingaAgent.psm1 b/lib/core/icingaagent/tests/Test-IcingaAgent.psm1 index 32ffdee..1c6cbaf 100644 --- a/lib/core/icingaagent/tests/Test-IcingaAgent.psm1 +++ b/lib/core/icingaagent/tests/Test-IcingaAgent.psm1 @@ -1,18 +1,18 @@ function Test-IcingaAgent() { if (Get-Service 'icinga2' -ErrorAction SilentlyContinue) { - Write-IcingaTestOutput -Severity 'PASSED' -Message 'Icinga Agent Service is installed'; + 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.' + 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' + Write-IcingaTestOutput -Severity 'Passed' -Message 'Icinga Agent debug log is disabled' } } else { - Write-IcingaTestOutput -Severity 'FAILED' -Message 'Icinga Agent Service is not installed'; + Write-IcingaTestOutput -Severity 'Failed' -Message 'Icinga Agent service is not installed'; } } diff --git a/lib/core/icingaagent/tests/Test-IcingaAgentConfig.psm1 b/lib/core/icingaagent/tests/Test-IcingaAgentConfig.psm1 index 42b78a6..5fbab5c 100644 --- a/lib/core/icingaagent/tests/Test-IcingaAgentConfig.psm1 +++ b/lib/core/icingaagent/tests/Test-IcingaAgentConfig.psm1 @@ -8,12 +8,12 @@ function Test-IcingaAgentConfig() $ConfigResult = Start-IcingaProcess -Executable $Binary -Arguments 'daemon -C'; if ($ConfigResult.ExitCode -eq 0) { - Write-IcingaTestOutput -Severity 'PASSED' -Message 'Icinga Agent configuration is valid'; + Write-IcingaTestOutput -Severity 'Passed' -Message 'Icinga Agent configuration is valid'; return $TRUE; } else { - Write-IcingaTestOutput -Severity 'FAILED' -Message 'Icinga Agent configuration is containing errors. Run this command for getting a detailed error report: "Test-IcingaAgentConfig -WriteStackTrace | Out-Null"'; + 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-Host $ConfigResult.Message; + Write-IcingaConsolePlain $ConfigResult.Message; } return $FALSE; } diff --git a/lib/core/icingaagent/tests/Test-IcingaAgentServicePermission.psm1 b/lib/core/icingaagent/tests/Test-IcingaAgentServicePermission.psm1 index 6b53163..b99bebc 100644 --- a/lib/core/icingaagent/tests/Test-IcingaAgentServicePermission.psm1 +++ b/lib/core/icingaagent/tests/Test-IcingaAgentServicePermission.psm1 @@ -15,7 +15,7 @@ function Test-IcingaAgentServicePermission() 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'; + Write-IcingaTestOutput -Severity 'Failed' -Message 'There is no user assigned to the Icinga 2 service or the service is not yet installed'; } return $FALSE; } @@ -40,9 +40,9 @@ function Test-IcingaAgentServicePermission() if (-Not $Silent) { if ($FoundSID) { - Write-IcingaTestOutput -Severity 'PASSED' -Message ([string]::Format('The specified user "{0}" is allowed to run as service.', $ServiceUser)); + 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)); + Write-IcingaTestOutput -Severity 'Failed' -Message ([string]::Format('The specified user "{0}" is not allowed to run as service', $ServiceUser)); } } diff --git a/lib/core/icingaagent/writers/Write-IcingaAgentApiConfig.psm1 b/lib/core/icingaagent/writers/Write-IcingaAgentApiConfig.psm1 index 50a235f..0d51505 100644 --- a/lib/core/icingaagent/writers/Write-IcingaAgentApiConfig.psm1 +++ b/lib/core/icingaagent/writers/Write-IcingaAgentApiConfig.psm1 @@ -16,5 +16,5 @@ function Write-IcingaAgentApiConfig() $ApiConf = $ApiConf.Substring(0, $ApiConf.Length - 4); Set-Content -Path (Join-Path -Path (Get-IcingaAgentConfigDirectory) -ChildPath 'features-available\api.conf') -Value $ApiConf; - Write-Host 'Api configuration has been written successfully'; + Write-IcingaConsoleNotice 'Api configuration has been written successfully'; } diff --git a/lib/core/icingaagent/writers/Write-IcingaAgentZonesConfig.psm1 b/lib/core/icingaagent/writers/Write-IcingaAgentZonesConfig.psm1 index 4729226..bd0ff6f 100644 --- a/lib/core/icingaagent/writers/Write-IcingaAgentZonesConfig.psm1 +++ b/lib/core/icingaagent/writers/Write-IcingaAgentZonesConfig.psm1 @@ -74,5 +74,5 @@ function Write-IcingaAgentZonesConfig() $ZonesConf = $ZonesConf.Substring(0, $ZonesConf.Length - 4); Set-Content -Path (Join-Path -Path (Get-IcingaAgentConfigDirectory) -ChildPath 'zones.conf') -Value $ZonesConf; - Write-Host 'Icinga Agent zones.conf has been written successfully'; + Write-IcingaConsoleNotice 'Icinga Agent zones.conf has been written successfully'; } diff --git a/lib/core/icingaagent/writers/Write-IcingaTestOutput.psm1 b/lib/core/icingaagent/writers/Write-IcingaTestOutput.psm1 index bfb8110..345db68 100644 --- a/lib/core/icingaagent/writers/Write-IcingaTestOutput.psm1 +++ b/lib/core/icingaagent/writers/Write-IcingaTestOutput.psm1 @@ -1,7 +1,7 @@ function Write-IcingaTestOutput() { param( - [ValidateSet('PASSED', 'WARNING', 'FAILED')] + [ValidateSet('Passed', 'Warning', 'Failed')] $Severity, $Message ); @@ -9,15 +9,15 @@ function Write-IcingaTestOutput() $Color = 'Green'; Switch ($Severity) { - 'PASSED' { + 'Passed' { $Color = 'Green'; break; }; - 'WARNING' { + 'Warning' { $Color = 'Yellow'; break; }; - 'FAILED' { + 'Failed' { $Color = 'Red'; break; }; diff --git a/lib/core/logging/Write-IcingaConsoleDebug.psm1 b/lib/core/logging/Write-IcingaConsoleDebug.psm1 new file mode 100644 index 0000000..717d950 --- /dev/null +++ b/lib/core/logging/Write-IcingaConsoleDebug.psm1 @@ -0,0 +1,34 @@ +<# +.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 + ); + + Write-IcingaConsoleOutput ` + -Message $Message ` + -Objects $Objects ` + -ForeColor 'Blue' ` + -Severity 'Debug'; +} diff --git a/lib/core/logging/Write-IcingaConsoleError.psm1 b/lib/core/logging/Write-IcingaConsoleError.psm1 new file mode 100644 index 0000000..895a6b1 --- /dev/null +++ b/lib/core/logging/Write-IcingaConsoleError.psm1 @@ -0,0 +1,34 @@ +<# +.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'; +} diff --git a/lib/core/logging/Write-IcingaConsoleNotice.psm1 b/lib/core/logging/Write-IcingaConsoleNotice.psm1 new file mode 100644 index 0000000..44939fa --- /dev/null +++ b/lib/core/logging/Write-IcingaConsoleNotice.psm1 @@ -0,0 +1,34 @@ +<# +.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'; +} diff --git a/lib/core/logging/Write-IcingaConsoleOutput.psm1 b/lib/core/logging/Write-IcingaConsoleOutput.psm1 new file mode 100644 index 0000000..6a51bdc --- /dev/null +++ b/lib/core/logging/Write-IcingaConsoleOutput.psm1 @@ -0,0 +1,58 @@ +<# +.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('Black', 'DarkBlue', 'DarkGreen', 'DarkCyan', 'DarkRed', 'DarkMagenta', 'DarkYellow', 'Gray', 'DarkGray', 'Blue', 'Green', 'Cyan', 'Red', 'Magenta', 'Yellow', 'White')] + [string]$ForeColor = 'White', + [string]$Severity = 'Notice' + ); + + $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; +} diff --git a/lib/core/logging/Write-IcingaConsolePlain.psm1 b/lib/core/logging/Write-IcingaConsolePlain.psm1 new file mode 100644 index 0000000..35c1de7 --- /dev/null +++ b/lib/core/logging/Write-IcingaConsolePlain.psm1 @@ -0,0 +1,34 @@ +<# +.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 + ); + + Write-IcingaConsoleOutput ` + -Message $Message ` + -Objects $Objects ` + -ForeColor 'Blue' ` + -Severity $null; +} diff --git a/lib/core/logging/Write-IcingaConsoleWarning.psm1 b/lib/core/logging/Write-IcingaConsoleWarning.psm1 new file mode 100644 index 0000000..b7f7097 --- /dev/null +++ b/lib/core/logging/Write-IcingaConsoleWarning.psm1 @@ -0,0 +1,34 @@ +<# +.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 'Yellow' ` + -Severity 'Warning'; +} diff --git a/lib/core/tools/Convert-IcingaEndpointsToIP.psm1 b/lib/core/tools/Convert-IcingaEndpointsToIP.psm1 new file mode 100644 index 0000000..f5201c7 --- /dev/null +++ b/lib/core/tools/Convert-IcingaEndpointsToIP.psm1 @@ -0,0 +1,63 @@ +<# +.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; + }; +} diff --git a/lib/core/tools/ConvertTo-Integer.psm1 b/lib/core/tools/ConvertTo-Integer.psm1 new file mode 100644 index 0000000..8c195b8 --- /dev/null +++ b/lib/core/tools/ConvertTo-Integer.psm1 @@ -0,0 +1,65 @@ +<# +.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; +} diff --git a/lib/core/tools/Expand-IcingaIPv6String.psm1 b/lib/core/tools/Expand-IcingaIPv6String.psm1 index 8637b89..423a7ed 100644 --- a/lib/core/tools/Expand-IcingaIPv6String.psm1 +++ b/lib/core/tools/Expand-IcingaIPv6String.psm1 @@ -41,7 +41,7 @@ function Expand-IcingaIPv6String() } if ($RelV -lt 0 -and $Counter -ne 7) { - Write-Host "Invalid IP was provided!"; + Write-IcingaConsoleError "Invalid IP was provided!"; return $null; } diff --git a/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 b/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 index 8e52e0f..668c4fc 100644 --- a/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 +++ b/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 @@ -320,19 +320,19 @@ function Get-IcingaCheckCommandConfig() Set-Content -Path $OutDirectory -Value $output; # Output-Text - Write-Host "The following commands have been exported:" + Write-IcingaConsoleNotice "The following commands have been exported:" foreach ($check in $CheckName) { - Write-Host "- '$check'"; + Write-IcingaConsoleNotice "- '$check'"; } - Write-Host "JSON export created in '${OutDirectory}'" + Write-IcingaConsoleNotice "JSON export created in '${OutDirectory}'" return; } - Write-Host "Check Command JSON for the following commands:" + Write-IcingaConsoleNotice "Check Command JSON for the following commands:" foreach ($check in $CheckName) { - Write-Host "- '$check'" + Write-IcingaConsoleNotice "- '$check'" } - Write-Host '############################################################'; + Write-IcingaConsoleNotice '############################################################'; return $output; } diff --git a/lib/core/tools/Get-IcingaNetworkInterface.psm1 b/lib/core/tools/Get-IcingaNetworkInterface.psm1 index ad72151..7fa0d7b 100644 --- a/lib/core/tools/Get-IcingaNetworkInterface.psm1 +++ b/lib/core/tools/Get-IcingaNetworkInterface.psm1 @@ -32,14 +32,14 @@ function Get-IcingaNetworkInterface() ); if ([string]::IsNullOrEmpty($IP)) { - Write-Host 'Please specify a valid IP-Address or FQDN'; + Write-IcingaConsoleError 'Please specify a valid IP-Address or FQDN'; return $null; } try { [array]$IP = ([System.Net.Dns]::GetHostAddresses($IP)).IPAddressToString; } catch { - Write-Host 'Invalid IP was provided!'; + Write-IcingaConsoleError 'Invalid IP was provided!'; return $null; } diff --git a/lib/core/tools/New-IcingaCheckCommand.psm1 b/lib/core/tools/New-IcingaCheckCommand.psm1 index f3a1787..042c5b7 100644 --- a/lib/core/tools/New-IcingaCheckCommand.psm1 +++ b/lib/core/tools/New-IcingaCheckCommand.psm1 @@ -25,16 +25,30 @@ function New-IcingaCheckCommand() ); [string]$CommandFile = [string]::Format( - '{0}.psm1', - $CommandName + 'icinga-powershell-{0}.psm1', + $Name.ToLower() + ); + [string]$PSDFile = [string]::Format( + 'icinga-powershell-{0}.psd1', + $Name.ToLower() ); - [string]$ScriptFile = Join-Path -Path (Get-IcingaCustomPluginDir) -ChildPath $CommandFile; + [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.'; + throw 'This check command does already exist.'; } + New-Item -Path $ModuleFolder -ItemType Directory | Out-Null; + Add-Content -Path $ScriptFile -Value 'Import-IcingaLib icinga\plugin;'; foreach ($Library in $ImportLib) { @@ -82,16 +96,26 @@ function New-IcingaCheckCommand() Add-Content -Path $ScriptFile -Value "}"; - Write-Host ([string]::Format('The Check-Command "{0}" was successfully added.', $CommandName)); + 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 ((Get-Command $DefaultEditor -ErrorAction SilentlyContinue) -eq $null) -And ((Test-Path $DefaultEditor) -eq $FALSE)) { - Write-Host 'No default editor for .psm1 files found. Specify a default editor to automaticly open the newly generated check plugin.'; + 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 automaticly open the newly generated check plugin.'; return; } diff --git a/lib/core/tools/Remove-IcingaDirectorSelfServiceKey.psm1 b/lib/core/tools/Remove-IcingaDirectorSelfServiceKey.psm1 index 6f30b34..3aa608a 100644 --- a/lib/core/tools/Remove-IcingaDirectorSelfServiceKey.psm1 +++ b/lib/core/tools/Remove-IcingaDirectorSelfServiceKey.psm1 @@ -6,9 +6,9 @@ function Remove-IcingaDirectorSelfServiceKey() Remove-IcingaPowerShellConfig 'IcingaDirector.SelfService.ApiKey'; $Value = Get-IcingaPowerShellConfig $Path; if ($null -eq $Value) { - Write-Host 'Icinga Director Self-Service Api key was successfully removed. Please dont forget to drop it within the Icinga Director as well'; + 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-Host 'There is no Self-Service Api key configured on this system'; + Write-IcingaConsoleWarning 'There is no Self-Service Api key configured on this system'; } } diff --git a/lib/core/tools/Show-IcingaDirectorSelfServiceKey.psm1 b/lib/core/tools/Show-IcingaDirectorSelfServiceKey.psm1 index 806ad98..94103c6 100644 --- a/lib/core/tools/Show-IcingaDirectorSelfServiceKey.psm1 +++ b/lib/core/tools/Show-IcingaDirectorSelfServiceKey.psm1 @@ -4,8 +4,8 @@ function Show-IcingaDirecorSelfServiceKey() $Value = Get-IcingaPowerShellConfig $Path; if ($null -ne $Value) { - Write-Host ([string]::Format('Self-Service Key: "{0}"', $Value)); + Write-IcingaConsoleNotice ([string]::Format('Self-Service Key: "{0}"', $Value)); } else { - Write-Host 'There is no Self-Service Api key configured on this system'; + Write-IcingaConsoleWarning 'There is no Self-Service Api key configured on this system'; } } diff --git a/lib/daemon/Register-IcingaBackgroundDaemon.psm1 b/lib/daemon/Register-IcingaBackgroundDaemon.psm1 index 83aa6b7..3a47438 100644 --- a/lib/daemon/Register-IcingaBackgroundDaemon.psm1 +++ b/lib/daemon/Register-IcingaBackgroundDaemon.psm1 @@ -18,5 +18,5 @@ function Register-IcingaBackgroundDaemon() Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.Command', $Path)) -Value $Command; Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.Arguments', $Path)) -Value $Arguments; - Write-Host ([string]::Format('Background daemon Cmdlet "{0}" has been configured', $Command)); + Write-IcingaConsoleNotice ([string]::Format('Background daemon Cmdlet "{0}" has been configured', $Command)); } diff --git a/lib/daemon/Unregister-IcingaBackgroundDaemon.psm1 b/lib/daemon/Unregister-IcingaBackgroundDaemon.psm1 index a836b11..19fa89c 100644 --- a/lib/daemon/Unregister-IcingaBackgroundDaemon.psm1 +++ b/lib/daemon/Unregister-IcingaBackgroundDaemon.psm1 @@ -13,5 +13,5 @@ function Unregister-IcingaBackgroundDaemon() Remove-IcingaPowerShellConfig -Path $Path; - Write-Host 'Background daemon has been removed'; + Write-IcingaConsoleNotice 'Background daemon has been removed'; } diff --git a/lib/daemons/ServiceCheckDaemon/Register-IcingaServiceCheck.psm1 b/lib/daemons/ServiceCheckDaemon/Register-IcingaServiceCheck.psm1 index 2492950..9dd1ed3 100644 --- a/lib/daemons/ServiceCheckDaemon/Register-IcingaServiceCheck.psm1 +++ b/lib/daemons/ServiceCheckDaemon/Register-IcingaServiceCheck.psm1 @@ -19,5 +19,5 @@ function Register-IcingaServiceCheck() Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.Interval', $Path)) -Value $Interval; Set-IcingaPowerShellConfig -Path ([string]::Format('{0}.TimeIndexes', $Path)) -Value $TimeIndexes; - Write-Host 'Icinga Service Check has been configured'; + Write-IcingaConsoleNotice 'Icinga Service Check has been configured'; } diff --git a/lib/daemons/ServiceCheckDaemon/Set-IcingaRegisteredServiceCheckConfig.psm1 b/lib/daemons/ServiceCheckDaemon/Set-IcingaRegisteredServiceCheckConfig.psm1 index 9edc6b5..7e7e25d 100644 --- a/lib/daemons/ServiceCheckDaemon/Set-IcingaRegisteredServiceCheckConfig.psm1 +++ b/lib/daemons/ServiceCheckDaemon/Set-IcingaRegisteredServiceCheckConfig.psm1 @@ -10,7 +10,7 @@ function Set-IcingaRegisteredServiceCheckConfig() $Services = Get-IcingaRegisteredServiceChecks; if ($Services.ContainsKey($ServiceId) -eq $FALSE) { - Write-Host 'Service Id was not found'; + Write-IcingaConsoleError 'Service Id was not found'; return; } @@ -31,8 +31,8 @@ function Set-IcingaRegisteredServiceCheckConfig() } if ($Modified) { - Write-Host 'Service configuration was successfully updated'; + Write-IcingaConsoleNotice 'Service configuration was successfully updated'; } else { - Write-Host 'No arguments were specified to update the service configuraiton'; + Write-IcingaConsoleWarning 'No arguments were specified to update the service configuration'; } } diff --git a/lib/daemons/ServiceCheckDaemon/Show-IcingaRegisteredServiceChecks.psm1 b/lib/daemons/ServiceCheckDaemon/Show-IcingaRegisteredServiceChecks.psm1 index 69af178..6dc248c 100644 --- a/lib/daemons/ServiceCheckDaemon/Show-IcingaRegisteredServiceChecks.psm1 +++ b/lib/daemons/ServiceCheckDaemon/Show-IcingaRegisteredServiceChecks.psm1 @@ -3,8 +3,8 @@ function Show-IcingaRegisteredServiceChecks() $Services = Get-IcingaRegisteredServiceChecks; foreach ($service in $Services.Keys) { - Write-Host ([string]::Format('Service Id: {0}', $service)); - Write-Host ( + Write-IcingaConsoleNotice ([string]::Format('Service Id: {0}', $service)); + Write-IcingaConsoleNotice ( $Services[$service] | Out-String ); } diff --git a/lib/daemons/ServiceCheckDaemon/Unregister-IcingaServiceCheck.psm1 b/lib/daemons/ServiceCheckDaemon/Unregister-IcingaServiceCheck.psm1 index 9285a11..02f4a96 100644 --- a/lib/daemons/ServiceCheckDaemon/Unregister-IcingaServiceCheck.psm1 +++ b/lib/daemons/ServiceCheckDaemon/Unregister-IcingaServiceCheck.psm1 @@ -12,5 +12,5 @@ function Unregister-IcingaServiceCheck() Remove-IcingaPowerShellConfig -Path $Path; - Write-Host 'Icinga Service Check has been configured'; + Write-IcingaConsolePlain 'Icinga Service Check has been configured'; } diff --git a/lib/help/help/Get-IcingaHelpThresholds.psm1 b/lib/help/help/Get-IcingaHelpThresholds.psm1 index eb79706..388e8b4 100644 --- a/lib/help/help/Get-IcingaHelpThresholds.psm1 +++ b/lib/help/help/Get-IcingaHelpThresholds.psm1 @@ -14,7 +14,7 @@ function Get-IcingaHelpThresholds() return; } - Write-Host + 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. diff --git a/lib/icinga/enums/Icinga_IcingaEnums.psm1 b/lib/icinga/enums/Icinga_IcingaEnums.psm1 index 0ffac3d..1b11ac1 100644 --- a/lib/icinga/enums/Icinga_IcingaEnums.psm1 +++ b/lib/icinga/enums/Icinga_IcingaEnums.psm1 @@ -18,6 +18,13 @@ 3 = '[UNKNOWN]'; }; +[hashtable]$IcingaExitCodeColor = @{ + 0 = 'Green'; + 1 = 'Yellow'; + 2 = 'Red'; + 3 = 'Magenta'; +}; + [hashtable]$IcingaMeasurementUnits = @{ 's' = 'seconds'; 'ms' = 'milliseconds'; @@ -41,6 +48,7 @@ [hashtable]$IcingaEnums = @{ IcingaExitCode = $IcingaExitCode; IcingaExitCodeText = $IcingaExitCodeText; + IcingaExitCodeColor = $IcingaExitCodeColor; IcingaMeasurementUnits = $IcingaMeasurementUnits; } diff --git a/lib/icinga/exception/Exit-IcingaThrowException.psm1 b/lib/icinga/exception/Exit-IcingaThrowException.psm1 index b7a1304..b9b8027 100644 --- a/lib/icinga/exception/Exit-IcingaThrowException.psm1 +++ b/lib/icinga/exception/Exit-IcingaThrowException.psm1 @@ -5,7 +5,7 @@ function Exit-IcingaThrowException() [string]$StringPattern, [string]$CustomMessage, [string]$ExceptionThrown, - [ValidateSet('Permission','Input','Unhandled')] + [ValidateSet('Permission','Input','Configuration','Unhandled','Custom')] [string]$ExceptionType = 'Unhandled', [switch]$Force ); @@ -32,9 +32,16 @@ function Exit-IcingaThrowException() $ExceptionTypeString = 'Invalid Input'; $ExceptionMessageLib = $IcingaExceptions.Inputs; }; + 'Configuration' { + $ExceptionTypeString = 'Invalid Configuration'; + $ExceptionMessageLib = $IcingaExceptions.Configuration; + }; 'Unhandled' { $ExceptionTypeString = 'Unhandled'; }; + 'Custom' { + $ExceptionTypeString = 'Custom'; + }; } [string]$ExceptionName = ''; @@ -47,9 +54,10 @@ function Exit-IcingaThrowException() } } } else { - $ExceptionName = 'Unhandled Exception'; + $ExceptionName = [string]::Format('{0} Exception', $ExceptionTypeString); $ExceptionThrown = [string]::Format( - 'Unhandled exception occured:{0}{1}', + '{0} exception occured:{1}{2}', + $ExceptionTypeString, "`r`n", $InputString ); @@ -71,7 +79,7 @@ function Exit-IcingaThrowException() ); if ($global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE) { - Write-Host $OutputMessage; + Write-IcingaConsolePlain $OutputMessage; exit $IcingaEnums.IcingaExitCode.Unknown; } } diff --git a/lib/icinga/exception/Icinga_IcingaExceptionEnums.psm1 b/lib/icinga/exception/Icinga_IcingaExceptionEnums.psm1 index 5422093..35158d4 100644 --- a/lib/icinga/exception/Icinga_IcingaExceptionEnums.psm1 +++ b/lib/icinga/exception/Icinga_IcingaExceptionEnums.psm1 @@ -5,17 +5,22 @@ #> [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 Log 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."; + 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 Log 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."; }; [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".'; + 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".'; }; +[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 is error is caused when mandatory or required arguments are missing from a plugin call and the operation is unable to process without them.'; +} + <# # Once we defined a new enum hashtable above, simply add it to this list # to make it available within the entire module. @@ -24,8 +29,9 @@ # $IcingaExceptionEnums.IcingaExecptionHandlers.PerformanceCounter #> [hashtable]$IcingaExceptions = @{ - Permission = $Permission; - Inputs = $Inputs; + Permission = $Permission; + Inputs = $Inputs; + Configuration = $Configuration; } Export-ModuleMember -Variable @( 'IcingaExceptions' ); diff --git a/lib/icinga/plugin/New-IcingaCheck.psm1 b/lib/icinga/plugin/New-IcingaCheck.psm1 index 89d8bf7..78f071b 100644 --- a/lib/icinga/plugin/New-IcingaCheck.psm1 +++ b/lib/icinga/plugin/New-IcingaCheck.psm1 @@ -94,6 +94,22 @@ function New-IcingaCheck() return $this.unknownchecks; } + $Check | Add-Member -membertype ScriptMethod -name 'SetUnknown' -value { + $this.AddInternalCheckMessage( + $IcingaEnums.IcingaExitCode.Unknown, + $null, + $null + ); + } + + $Check | Add-Member -membertype ScriptMethod -name 'SetWarning' -value { + $this.AddInternalCheckMessage( + $IcingaEnums.IcingaExitCode.Warning, + $null, + $null + ); + } + $Check | Add-Member -membertype ScriptMethod -name 'WarnOutOfRange' -value { param($warning); @@ -147,6 +163,8 @@ function New-IcingaCheck() ); } + $this.warning = $warning; + return $this; } @@ -161,6 +179,8 @@ function New-IcingaCheck() ); } + $this.warning = $warning; + return $this; } @@ -175,6 +195,8 @@ function New-IcingaCheck() ); } + $this.warning = $warning; + return $this; } @@ -189,6 +211,8 @@ function New-IcingaCheck() ); } + $this.warning = $warning; + return $this; } @@ -203,6 +227,8 @@ function New-IcingaCheck() ); } + $this.warning = [string]::Format('{0}:{1}', $min, $max); + return $this; } @@ -217,6 +243,8 @@ function New-IcingaCheck() ); } + $this.warning = [string]::Format('{0}:{1}', $min, $max); + return $this; } @@ -231,6 +259,8 @@ function New-IcingaCheck() ); } + $this.warning = $warning; + return $this; } @@ -245,6 +275,8 @@ function New-IcingaCheck() ); } + $this.warning = $warning; + return $this; } @@ -259,6 +291,8 @@ function New-IcingaCheck() ); } + $this.warning = $warning; + return $this; } @@ -273,9 +307,19 @@ function New-IcingaCheck() ); } + $this.warning = $warning; + return $this; } + $Check | Add-Member -membertype ScriptMethod -name 'SetCritical' -value { + $this.AddInternalCheckMessage( + $IcingaEnums.IcingaExitCode.Critical, + $null, + $null + ); + } + $Check | Add-Member -membertype ScriptMethod -name 'CritOutOfRange' -value { param($critical); @@ -329,6 +373,8 @@ function New-IcingaCheck() ); } + $this.critical = $critical; + return $this; } @@ -343,6 +389,8 @@ function New-IcingaCheck() ); } + $this.critical = $critical; + return $this; } @@ -357,6 +405,8 @@ function New-IcingaCheck() ); } + $this.critical = $critical; + return $this; } @@ -371,6 +421,8 @@ function New-IcingaCheck() ); } + $this.critical = $critical; + return $this; } @@ -385,6 +437,8 @@ function New-IcingaCheck() ); } + $this.critical = [string]::Format('{0}:{1}', $min, $max); + return $this; } @@ -399,6 +453,8 @@ function New-IcingaCheck() ); } + $this.critical = [string]::Format('{0}:{1}', $min, $max); + return $this; } @@ -413,6 +469,8 @@ function New-IcingaCheck() ); } + $this.critical = $critical; + return $this; } @@ -427,6 +485,8 @@ function New-IcingaCheck() ); } + $this.critical = $critical; + return $this; } @@ -441,6 +501,8 @@ function New-IcingaCheck() ); } + $this.critical = $critical; + return $this; } @@ -455,6 +517,8 @@ function New-IcingaCheck() ); } + $this.critical = $critical; + return $this; } @@ -494,17 +558,25 @@ function New-IcingaCheck() } $this.SetExitCode($state); - $this.AddMessage( - [string]::Format( - '{0}: Value "{1}{4}" is {2} threshold "{3}{4}"', + + if ($null -eq $value -And $null -eq $type) { + $this.AddMessage( $this.name, - $this.TranslateValue($this.value), - $type, - $this.TranslateValue($value), - $this.unit - ), - $state - ); + $state + ); + } else { + $this.AddMessage( + [string]::Format( + '{0}: Value "{1}{4}" is {2} threshold "{3}{4}"', + $this.name, + $this.TranslateValue($this.value), + $type, + $this.TranslateValue($value), + $this.unit + ), + $state + ); + } switch ($state) { $IcingaEnums.IcingaExitCode.Warning { @@ -721,14 +793,17 @@ function New-IcingaCheck() $this.completed = $TRUE; [string]$LabelName = (Format-IcingaPerfDataLabel $this.name); + $value = ConvertTo-Integer -Value $this.value -NullAsEmpty; + $warning = ConvertTo-Integer -Value $this.warning -NullAsEmpty; + $critical = ConvertTo-Integer -Value $this.critical -NullAsEmpty; $perfdata = @{ 'label' = $LabelName; 'perfdata' = ''; 'unit' = $this.unit; - 'value' = (Format-IcingaPerfDataValue $this.value); - 'warning' = (Format-IcingaPerfDataValue $this.warning); - 'critical' = (Format-IcingaPerfDataValue $this.critical); + 'value' = (Format-IcingaPerfDataValue $value); + 'warning' = (Format-IcingaPerfDataValue $warning); + 'critical' = (Format-IcingaPerfDataValue $critical); 'minimum' = (Format-IcingaPerfDataValue $this.minimum); 'maximum' = (Format-IcingaPerfDataValue $this.maximum); 'package' = $FALSE; diff --git a/lib/icinga/plugin/Write-IcingaPluginOutput.psm1 b/lib/icinga/plugin/Write-IcingaPluginOutput.psm1 index c9a8746..ab593bc 100644 --- a/lib/icinga/plugin/Write-IcingaPluginOutput.psm1 +++ b/lib/icinga/plugin/Write-IcingaPluginOutput.psm1 @@ -5,7 +5,7 @@ function Write-IcingaPluginOutput() ); if ($global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE) { - Write-Host $Output; + Write-IcingaConsolePlain $Output; } else { if ($global:IcingaDaemonData.IcingaThreadContent.ContainsKey('Scheduler')) { $global:IcingaDaemonData.IcingaThreadContent['Scheduler']['PluginCache'] += $Output; diff --git a/lib/icinga/plugin/Write-IcingaPluginPerfData.psm1 b/lib/icinga/plugin/Write-IcingaPluginPerfData.psm1 index be86233..ddb4a83 100644 --- a/lib/icinga/plugin/Write-IcingaPluginPerfData.psm1 +++ b/lib/icinga/plugin/Write-IcingaPluginPerfData.psm1 @@ -17,7 +17,7 @@ function Write-IcingaPluginPerfData() if ($global:IcingaDaemonData.FrameworkRunningAsDaemon -eq $FALSE) { [string]$PerfDataOutput = (Get-IcingaPluginPerfDataContent -PerfData $PerformanceData -CheckResultCache $CheckResultCache); - Write-Host ([string]::Format('| {0}', $PerfDataOutput)); + Write-IcingaConsolePlain ([string]::Format('| {0}', $PerfDataOutput)); } else { [void](Get-IcingaPluginPerfDataContent -PerfData $PerformanceData -CheckResultCache $CheckResultCache -AsObject $TRUE); }