Today I will show you briefly how to build your own Powershell Modules/Plugins using icinga-powershell-framework. As you might know, we recently started writing plugins in Powershell that can be used to monitor windows-services in Icinga2 in a simple way. If you are interested in learning more about it, everything is documented here down to the smallest detail.

 

Are there any particular prerequisites?

Before we even deal with PowershellScripting, we first have to either install or clone the framework. As mentioned above, our module will depend entirely on it. If you intend to publish your custom Modules/Plugins on GitHub, I recommend that you clone it. Once you have decided to install it, I will show you a way to install it. In case you have an existing, configured and fully functional Command Install-Module in your system, you can easily install it via PowershellGallery. This can be done by starting a Powershell with administrative privileges and running the following command. Install-Module -Name icinga-powershell-framework

Alternatively, if you are stuck with it, you can install it using the Kick-Start Installation. There are several questions during the installation which you have to answer. This is mostly about where the framework should be installed and so on. After the framework is successfully installed, you will be asked if you want to perform Agent Installation.You can select yes if you want to install the agent as well but it is not relevant for us now.

 

Well, what are we going to do now?

Now we navigate to the directory where the framework is installed. When you have done it all right, the framework should be here. C: Program Files\WindowsPowershell\Modules\
In that directory we create a new folder called icinga-powershell-testmodule. This folder will be our base directory, which will be recognized as modules and in there we can build various plugins. I have two additional folder names (plugins, provider) in there. The plugins folder is used only for Plugins and in the other folder you can find all the stuff you need to build your plugin. We can now finally start writing Powershell scripts for our test plugin.

With this example we can test whether our module is loaded correctly.

function Invoke-IcingaTestModule()
{
    Write-Host "Test module was loaded";
}

If you now run the following command in a Powershell Invoke-IcingaTestModule you should be able to see the following output Test module was loaded. If not, it could be due to the execution policy and therefore that you have to unblock the module. If that is the case, you can solve it in a simple way with the Unblock-File Cmdlet.
Unblock-File -Path 'C:\Program Files\WindowsPowerShell\Modules\icinga-powershell-testmodule'
Since we can build several plugins in this module, we need a psd1 file in the root directory of our module to include them all with the NestedModules and additional files from the provider and also this file makes sure that all files in this module are loaded automatically when a new Powershell is started. With New-ModuleManifest we can generate a module manifest for our module. Then we can change everything in the psd1 file as we like except the GUID, because it is unique and must not be changed. In the following you can see how my .psd1 file looks like. File name : icinga-powershell-testmodule.psd1.

@{
    ModuleVersion     = '1.0.0'
    GUID              = '65edfb4d-09fc-4640-baee-037715b9d572'
    Author            = 'yhabteab'
    CompanyName       = 'Icinga GmbH'
    Copyright         = '(c) 2020 Icinga GmbH | GPL v2.0'
    Description       = 'A collection of test plugins to demonstrate how easy it is to create custom plugins '
    PowerShellVersion = '4.0'
    RequiredModules   = @(@{ModuleName = 'icinga-powershell-framework'; ModuleVersion = '1.2.0' })
    NestedModules     = @(
        '.\plugins\Invoke-IcingaTestModule.psm1',
        '.\provider\test\Get_IcingaTestModuleProvider.psm1'
    )
    FunctionsToExport = @('*')
    CmdletsToExport   = @('*')
    VariablesToExport = '*'
    AliasesToExport   = @()
    PrivateData       = @{}
    HelpInfoURI       = 'https://github.com/Icinga/icinga-powershell-plugins'
}

 

Now you have done everything you need to build a plugin. Here I have a prepared plugin, you can try it out. I won’t explain every single line of code here and what exactly it does but I’ve written comments all over the code so you can understand. Here you can find more examples.

Function Invoke-IcingaTutorialCheck()
{
    # Create our arguments we can use to parse thresholds
    param(
        $Warning            = $null,
        $Critical           = $null,
        [switch]$NoPerfData = $FALSE,
        [ValidateSet(0, 1, 2)]
        $Verbosity          = 0
    );

    # Create a new IcingaCheck object that will include comparing
    # values and checking if they are between a range is Unknown
    $Check = New-IcingaCheck `
                -Name 'TestModule' `
                -Value (Get-Random -Minimum 5 -Maximum 50);
    # 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;

    # 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 'TestModule Package' `
                        -Checks ($Check) `
                        -OperatorAnd `
                        -Verbose $Verbosity;

    # 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);
}

And don’t forget to add all functions you create to the NestedModules array in the .psd1 file to be loaded by the framework. If we now execute the plugin with Verbosity and the value 2, every single check will be printed, even when the check itself is Ok.
powershell -C { Use-Icinga; Invoke-IcingaTutorialCheck -Warning 30 -Critical 40 -Verbosity 2 }

So the output of this command is as follows.

[OK] Check package "TestModule Package" (Match All)
\_ [OK] TestModule: 20
| 'testmodule'=20;30;40
0

Is there anything else?

Actually, not really, but I do have one more thing I want to tell you. It is very important that you always keep your plugins clear and structured, i.e. everything that could cause an error and can be handled with try/catch etc. belongs in the provider and if you have something that is not clear in this example or would like to know more about it, please leave us a comment below.