lib/icinga/plugin/Exit-IcingaExecutePlugin.psm1

function Exit-IcingaExecutePlugin()
{
    param (
        [string]$Command = ''
    );

    [string]$JEAProfile            = Get-IcingaJEAContext;
    [bool]$CheckByIcingaForWindows = $FALSE;
    [bool]$CheckByJEAShell         = $FALSE;

    if ($args -Contains '-IcingaForWindowsRemoteExecution') {
        $CheckByIcingaForWindows = $TRUE;
    }
    if ($args -Contains '-IcingaForWindowsJEARemoteExecution') {
        $CheckByJEAShell = $TRUE;
    }

    # We use the plugin check_by_icingaforwindows.ps1 to execute
    # checks from a Linux/Windows remote source
    if ($CheckByIcingaForWindows) {
        # First try to queue the check over the REST-Api
        $CheckResult = Invoke-IcingaInternalServiceCall -Command $Command -Arguments $args -NoExit;

        if ($null -ne $CheckResult) {
            # Seems we got a result
            Write-IcingaConsolePlain -Message $CheckResult;

            # Do not close the session, we need to read the ExitCode from Get-IcingaInternalPluginExitCode
            # The plugin itself will terminate the session
            return;
        }

        # We couldn't use our Rest-Api and Api-Checks feature, then lets execute the plugin locally
        # Set daemon true, because this will change internal handling for errors and plugin output
        $Global:Icinga.Protected.RunAsDaemon = $TRUE;

        try {
            # Execute our plugin
            (& $Command @args) | Out-Null;
        } catch {
            # Handle errors within our plugins
            # If anything goes wrong handle the error very detailed

            $Global:Icinga.Protected.RunAsDaemon = $FALSE;
            Write-IcingaExecutePluginException -Command $Command -ErrorObject $_ -Arguments $args;
            $args.Clear();

            # Do not close the session, we need to read the ExitCode from Get-IcingaInternalPluginExitCode
            # The plugin itself will terminate the session
            return;
        }

        # Disable it again - we need to write data to our shell now. Not very intuitive, but it is the easiest
        # solution to do it this way
        $Global:Icinga.Protected.RunAsDaemon = $FALSE;

        # Now print the result to shell
        Write-IcingaPluginResult -PluginOutput (Get-IcingaInternalPluginOutput) -PluginPerfData (Get-IcingaCheckSchedulerPerfData);

        # Do not close the session, we need to read the ExitCode from Get-IcingaInternalPluginExitCode
        # The plugin itself will terminate the session
        return;
    }

    # Regardless of JEA enabled or disabled, forward all checks to the internal API
    # and check if we get a result from there
    Invoke-IcingaInternalServiceCall -Command $Command -Arguments $args;

    try {
        # If the plugin is not installed, throw a good exception
        Exit-IcingaPluginNotInstalled -Command $Command;

        # In case we have JEA enabled on our system, this shell currently open most likely has no
        # JEA configuration installed. This is because a JEA shell will not return an exit code and
        # Icinga relies on that. Therefor we will try to open a new PowerShell with the JEA configuration
        # assigned for Icinga for Windows, execute the plugins there and return the result
        if ([string]::IsNullOrEmpty($JEAProfile) -eq $FALSE) {
            $ErrorHandler = ''
            $JEARun = (
                & powershell.exe -ConfigurationName $JEAProfile -NoLogo -NoProfile -Command {
                    # Load Icinga for Windows
                    Use-Icinga;

                    # Enable our JEA context
                    $Global:Icinga.Protected.JEAContext = $TRUE;

                    # Parse the arguments our previous shell received
                    $Command   = $args[0];
                    $Arguments = $args[1];
                    $Output    = '';

                    try {
                        # Try executing our checks, store the exit code and plugin output
                        $ExitCode = (& $Command @Arguments);
                        $Output   = (Get-IcingaInternalPluginOutput);
                        $ExitCode = (Get-IcingaInternalPluginExitCode);
                    } catch {
                        # If we failed for some reason, print a detailed error and use exit code 3 to mark the check as unkown
                        $Output   = [string]::Format('[UNKNOWN] Icinga Exception: Error while executing plugin in JEA context{0}{0}{1}', (New-IcingaNewLine), $_.Exception.Message);
                        $ExitCode = 3;
                    }

                    # Return the result to our main PowerShell
                    return @{
                        'Output'   = $Output;
                        'PerfData' = (Get-IcingaCheckSchedulerPerfData)
                        'ExitCode' = $ExitCode;
                    }
                } -args $Command, $args
            ) 2>$ErrorHandler;

            # If we have an exit code larger or equal 0, the execution inside the JEA shell was successfully and we can share the result
            # In case we had an error inside the JEA shell, it will returned here as well
            if ($LASTEXITCODE -ge 0) {
                Write-IcingaPluginResult -PluginOutput $JEARun.Output -PluginPerfData $JEARun.PerfData;
                exit $JEARun.ExitCode;
            } else {
                # If for some reason the PowerShell could not be started within JEA context, we can throw an exception with exit code 3
                # to mark the check as unknown including our error message
                Write-IcingaConsolePlain '[UNKNOWN] Icinga Exception: Unable to start the PowerShell.exe with the provided JEA profile "{0}" for CheckCommand: {1}' -Objects $JEAProfile, $Command;
                exit 3;
            }
        } else {
            # If we simply run the check without JEA context or from remote, we can just execute the plugin and
            # exit with the exit code received from the result
            exit (& $Command @args);
        }
    } catch {
        # If anything goes wrong handle the error
        Write-IcingaExecutePluginException -Command $Command -ErrorObject $_ -Arguments $args;
        $args.Clear();

        exit 3;
    }
}