diff --git a/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 b/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 new file mode 100644 index 0000000..6ddf2d7 --- /dev/null +++ b/lib/core/tools/Get-IcingaCheckCommandConfig.psm1 @@ -0,0 +1,500 @@ +<# +.SYNOPSIS + Exports command as JSON for icinga director + +.DESCRIPTION + Get-IcingaCheckCommandConfig returns a JSON-file of one or all 'Invoke-IcingaCheck'-Commands, which can be imported via Icinga-Director + When no single command is specified all commands will be exported, and vice versa. + + More Information on https://github.com/LordHepipud/icinga-module-windows + +.FUNCTIONALITY + This module is intended to be used to export one or all PowerShell-Modules with the namespace 'Invoke-IcingaCheck'. + The JSON-Export, which will be egenerated through this module is structured like an Icinga-Director-JSON-Export, so it can be imported via the Icinga-Director the same way. + +.EXAMPLE + PS>Get-IcingaCheckCommandConfig + Check Command JSON for the following commands: + - 'Invoke-IcingaCheckBiosSerial' + - 'Invoke-IcingaCheckCPU' + - 'Invoke-IcingaCheckProcessCount' + - 'Invoke-IcingaCheckService' + - 'Invoke-IcingaCheckUpdates' + - 'Invoke-IcingaCheckUptime' + - 'Invoke-IcingaCheckUsedPartitionSpace' + - 'Invoke-IcingaCheckUsers' +############################################################ + +.EXAMPLE + Get-IcingaCheckCommandConfig -OutFile 'C:\Users\icinga\config-exports' + The following commands have been exported: + - 'Invoke-IcingaCheckBiosSerial' + - 'Invoke-IcingaCheckCPU' + - 'Invoke-IcingaCheckProcessCount' + - 'Invoke-IcingaCheckService' + - 'Invoke-IcingaCheckUpdates' + - 'Invoke-IcingaCheckUptime' + - 'Invoke-IcingaCheckUsedPartitionSpace' + - 'Invoke-IcingaCheckUsers' + JSON export created in 'C:\Users\icinga\config-exports\PowerShell_CheckCommands_09-13-2019-10-55-1989.json' + +.EXAMPLE + Get-IcingaCheckCommandConfig Invoke-IcingaCheckBiosSerial, Invoke-IcingaCheckCPU -OutFile 'C:\Users\icinga\config-exports' + The following commands have been exported: + - 'Invoke-IcingaCheckBiosSerial' + - 'Invoke-IcingaCheckCPU' + JSON export created in 'C:\Users\icinga\config-exports\PowerShell_CheckCommands_09-13-2019-10-58-5342.json' + +.PARAMETER CheckName + Used to specify an array of commands which should be exported. + Seperated with ',' + +.INPUTS + System.Array + +.OUTPUTS + System.String + +.LINK + https://github.com/LordHepipud/icinga-module-windows + +.NOTES +#> + +function Get-IcingaCheckCommandConfig() +{ + param( + [Parameter(ValueFromPipeline)] + [array]$CheckName, + [string]$OutFile + ); + + # Check whether all Checks will be exported or just the ones specified + if ([string]::IsNullOrEmpty($CheckName) -eq $true) { + $CheckName = (Get-Command Invoke-IcingaCheck*).Name + } + + [int]$FieldID = 2; # Starts at '2', because '0' and '1' are reserved for 'Verbose' and 'NoPerfData' + [hashtable]$Basket = @{}; + + # Define basic hashtable structure by adding fields: "Datafield", "DataList", "Command" + $Basket.Add('Datafield', @{}); + $Basket.Add('DataList', @{}); + $Basket.Add('Command', @{}); + + + # "NoPerfData" gets added to all checks build and exported no matter what, so we add it from the start + if ($Basket.DataList.ContainsKey('PowerShell NoPerfData') -eq $FALSE) { + + # DataList Content for NoPerfData + $Basket.DataList.Add( + 'PowerShell NoPerfData', @{ + 'list_name' = 'PowerShell NoPerfData'; + 'owner' = $env:username; + 'originalId' = '1'; + 'entries' = @( + @{ + 'entry_name' = '0'; + 'entry_value:' = "yes"; + 'format' = 'string'; + 'allowed_roles' = $NULL; + }, + @{ + 'entry_name' = '1'; + 'entry_value:' = "no"; + 'format' = 'string'; + 'allowed_roles' = $NULL; + } + ); + } + ); + } + + # "Verbose" gets added to all Checks build and exported no matter what, so we add it from the start + if ($Basket.DataList.ContainsKey('PowerShell Verbose') -eq $FALSE) { + $Basket.DataList.Add( + 'PowerShell Verbose', @{ + 'list_name' = 'PowerShell Verbose'; + 'owner' = $env:username; + 'originalId' = '2'; + 'entries' = @( + @{ + 'entry_name' = '0'; + 'entry_value:' = "Show Default"; + 'format' = 'string'; + 'allowed_roles' = $NULL; + }, + @{ + 'entry_name' = '1'; + 'entry_value:' = "Show Operator"; + 'format' = 'string'; + 'allowed_roles' = $NULL; + }, + @{ + 'entry_name' = '2'; + 'entry_value:' = "Show Problems"; + 'format' = 'string'; + 'allowed_roles' = $NULL; + }, + @{ + 'entry_name' = '3'; + 'entry_value:' = "Show All"; + 'format' = 'string'; + 'allowed_roles' = $NULL; + } + ); + } + ); + } + + # Loop through ${CheckName}, to get information on every command specified/all commands. + foreach ($check in $CheckName) { + + [int]$FieldNumeration = 0; + + # Get necessary syntax-information and more through cmdlet "Get-Help" + $Data = (Get-Help $check) + + # Add command Structure + $Basket.Command.Add( + $Data.Syntax.syntaxItem.Name, @{ + 'arguments'= @{ + # Gets set for every command as default + '-C' = @{ + 'value' = [string]::Format('Use-Icinga; {0}', $Data.Syntax.syntaxItem.Name); + 'order' = '0'; + } + } + 'command' = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"; + 'disabled' = $FALSE; + 'fields' = @{}; + 'imports' = @(); + 'is_string' = $NULL; + 'methods_excute' = 'PluginCheck'; + 'object_name' = $Data.Syntax.syntaxItem.Name; + 'object_type' = 'object'; + 'timeout' = '180'; + 'vars' = @{}; + 'zone' = $NULL; + } + ); + + # Loop through parameters of a given command + foreach ($parameter in $Data.Syntax.syntaxItem.parameter) { + + # Filter for Parameter 'core', because its set by default + if ($parameter.name -ne 'core') { + + # IsNumeric-Check on position to determine the order-value + If (Test-Numeric($parameter.position) -eq $TRUE) { + [string]$Order = [int]$parameter.position + 1; + } else { + [string]$Order = 99 + } + + $IcingaCustomVariable = [string]::Format('$PowerShell_{0}_{1}$', $parameter.type.name, $parameter.Name); + + # Add arguments to a given command + if ($parameter.type.name -eq 'switch') { + $Basket.Command[$Data.Syntax.syntaxItem.Name].arguments.Add( + [string]::Format('-{0}', $parameter.Name), @{ + 'set_if' = $IcingaCustomVariable; + 'set_if_format' = 'string'; + 'order' = $Order; + } + ); + + $Basket.Command[$Data.Syntax.syntaxItem.Name].vars.Add($parameter.Name, "0"); + + # Conditional whether type of parameter is array + } elseif ($parameter.type.name -eq 'array') { + $Basket.Command[$Data.Syntax.syntaxItem.Name].arguments.Add( + [string]::Format('-{0}', $parameter.Name), @{ + 'value' = @{ + 'type' = 'Function'; + 'body' = [string]::Format( + 'var arr = macro("{0}");{1}if (len(arr) == 0) {2}{1}return "$null";{1}{3}{1}return arr.join(",");', + $IcingaCustomVariable, + "`r`n", + '{', + '}' + ); + } + 'order' = $Order; + } + ); + } else { + # Default to Object + $Basket.Command[$Data.Syntax.syntaxItem.Name].arguments.Add( + [string]::Format('-{0}', $parameter.Name), @{ + 'value' = $IcingaCustomVariable; + 'order' = $Order; + } + ); + + if ($parameter.name -ne 'Verbose') { + $Basket.Command[$Data.Syntax.syntaxItem.Name].vars.Add($parameter.Name, '$$null'); + } else { + $Basket.Command[$Data.Syntax.syntaxItem.Name].vars.Add($parameter.Name, "0"); + } + } + + # Determine wether a parameter is required based on given syntax-information + if ($parameter.required -eq $TRUE) { + $Required = 'y'; + } else { + $Required = 'n'; + } + + $IcingaCustomVariable = [string]::Format('PowerShell_{0}_{1}', $parameter.type.name, $parameter.Name); + + $DataListName = [string]::Format('PowerShell {0}', $parameter.Name) + + if ($parameter.type.name -eq 'switch') { + $IcingaDataType='Datalist'; + if ($Basket.DataList.ContainsKey($DataListName) -eq $FALSE) { + $Basket.DataList.Add( + $DataListName, @{ + 'list_name' = $DataListName; + 'owner' = $env:username; + 'originalId' = '50'; #Gehört noch geändert + 'entries' = @{}; + } + ); + } + } elseif ($parameter.type.name -eq 'Object') { + if ($parameter.Name -eq 'Verbose') { + $IcingaDataType='Datalist' + } + + $IcingaDataType='String'; + + } elseif ($parameter.type.name -eq 'Array') { + $IcingaDataType='Array'; + } else { + $IcingaDataType='String'; + } + + if($Basket.Datafield.ContainsKey('0') -eq $FALSE){ + $Basket.Datafield.Add( + '0', @{ + 'varname' = 'PowerShell_switch_NoPerfData'; + 'caption' = 'NoPerfData'; + 'description' = 'Specifies if the plugin will return performance data output or not'; + 'datatype' = 'Icinga\\Module\\Director\\DataType\\DataTypeDatalist'; + 'format' = $NULL; + 'originalId' = '0'; + 'settings' = @{ + 'datalist' = 'PowerShell NoPerfData'; + 'datatype' = 'string'; + 'behavior' = 'strict'; + } + } + ); + } + + if($Basket.Datafield.ContainsKey('1') -eq $FALSE){ + $Basket.Datafield.Add( + '1', @{ + 'varname' = 'PowerShell_switch_NoPerfData'; + 'caption' = 'Verbose'; + 'description' = 'Specifies if the plugin will return performance data output or not'; + 'datatype' = 'Icinga\\Module\\Director\\DataType\\DataTypeString'; + 'format' = $NULL; + 'originalId' = '1'; + 'settings' = @{ + 'datalist' = 'PowerShell Verbose'; + 'datatype' = 'string'; + 'behavior' = 'strict'; + } + } + ); + } + + $IcingaDataType = [string]::Format('Icinga\Module\Director\DataType\DataType{0}', $IcingaDataType) + + if ($Basket.Datafield.Values.varname -eq $IcingaCustomVariable) { + } else { + $Basket.Datafield.Add( + [string]$FieldID, @{ + 'varname' = $IcingaCustomVariable; + 'caption' = $parameter.Name; + 'description' = $parameter.Description.Text; + 'datatype' = $IcingaDataType; + 'format' = $NULL; + 'originalId' = [string]$FieldID; + } + ); + + if ($parameter.type.name -eq 'switch' -or $parameter.Name -eq 'Verbose') { + $Basket.Datafield[[string]$FieldID].Add( + 'settings', @{ + 'behavior' = 'strict'; + 'datatype' = 'string'; + 'datalist' = $DataListName; + } + ); + } elseif ($parameter.type.name -eq 'Object') { + $Basket.Datafield[[string]$FieldID].Add( + 'settings', @{ + 'visbility' = 'visible'; + } + ); + } else { + $Basket.Datafield[[string]$FieldID].Add( + 'settings', @{ + 'visbility' = 'visible'; + } + ); + } + + # Increment FieldID, so unique datafields are added. + [int]$FieldID = [int]$FieldID + 1; + } + } + + # Increment FieldNumeation, so unique fields for a given command are added. + [int]$FieldNumeration = [int]$FieldNumeration + 1; + } + + # Check whether or not noperfdata and verbose is set and add it if necessary + if ($Basket.Command[$Data.Syntax.syntaxItem.Name].arguments.ContainsKey('-Verbose') -eq $FALSE) { + $Basket.Command[$Data.Syntax.syntaxItem.Name].arguments.Add( + '-Verbose', @{ + 'value' = '$PowerShell_Object_Verbose$'; + 'order' = '99'; + } + ); + + $Basket.Command[$Data.Syntax.syntaxItem.Name].vars.Add( + 'PowerShell_Object_Verbose', "0" + ); + + if ($Basket.Datafield.Values.varname -eq $IcingaCustomVariable) { + } else { + $Basket.Datafield.Add( + [string]$FieldID, @{ + 'varname' = 'PowerShell_Object_Verbose'; + 'caption' = 'Verbose'; + 'description' = 'Increase the plugin output for more information on the received result.'; + 'datatype' = 'Icinga\Module\Director\DataType\DataTypeDatalist'; + 'format' = $NULL; + 'originalId' = [string]$FieldID; + 'settings' = @{ + 'behavior' = 'strict'; + 'data_type' = 'string'; + 'datalist' = 'PowerShell Verbose' + } + } + ); + } + } + + if ($Basket.Command[$Data.Syntax.syntaxItem.Name].arguments.ContainsKey('-NoPerfData') -eq $FALSE) { + $Basket.Command[$Data.Syntax.syntaxItem.Name].arguments.Add( + '-NoPerfData', @{ + 'set_if' = '$PowerShell_switch_NoPerfData$'; + 'set_if_format' = 'string'; + 'order' = '99'; + } + ); + $Basket.Command[$Data.Syntax.syntaxItem.Name].vars.Add('PowerShell_switch_NoPerfData', "0"); + + if ($Basket.Datafield.Values.varname -eq $IcingaCustomVariable) { + } else { + $Basket.Datafield.Add( + [string]$FieldID, @{ + 'varname' = 'PowerShell_switch_NoPerfData'; + 'caption' = 'Perf Data'; + 'description' = 'Specifies if the plugin will return performance data output or not'; + 'datatype' = 'Icinga\Module\Director\DataType\DataTypeDatalist'; + 'format' = $NULL; + 'originalId' = [string]$FieldID; + 'settings' = @{ + 'behavior' = 'strict'; + 'data_type' = 'string'; + 'datalist' = 'PowerShell NoPerfData' + } + } + ); + } + } + } + + foreach ($check in $CheckName) { + [int]$FieldNumeration = 0; + + $Data = (Get-Help $check) + + foreach ($parameter in $Data.Syntax.syntaxItem.parameter){ + $IcingaCustomVariable = [string]::Format('PowerShell_{0}_{1}', $parameter.type.name, $parameter.Name); + + # Hashtable for Matching Command.Name.Fields to DataFields (and there given IDs) + [hashtable]$TranslationDataField = @{} + + # Looping through IDs of existing DataFields + foreach ($DataFieldID in $Basket.Datafield.Keys) + { + # Ignore Default-Set Deatafield "NoPerfData" + if ($TranslationDataField.Contains('PowerShell_switch_NoPerfData') -eq $TRUE){ + }else{ + $TranslationDataField.Add($Basket.Datafield.$DataFieldID.varname, $DataFieldID); + } + } + + foreach($key in $TranslationDataField.Keys) + { + if ([string]$IcingaCustomVariable -eq [string]$key) { + $MatchedDataFieldID = $TranslationDataField[$IcingaCustomVariable]; + } else {} + } + + $Basket.Command[$Data.Syntax.syntaxItem.Name].fields.Add( + [string]$FieldNumeration, @{ + 'datafield_id' = [int]$MatchedDataFieldID; + 'is_required' = $Required; + 'var_filter' = $NULL; + } + ); + + [int]$FieldNumeration = [int]$FieldNumeration + 1; + } + } + + # Build Filename with given Timestamp + $TimeStamp = (Get-Date -Format "MM-dd-yyyy-HH-mm-ffff"); + $FileName = "PowerShell_CheckCommands_$TimeStamp.json"; + + # Generate JSON Output from Hashtable + $output = ConvertTo-Json -Depth 100 $Basket -Compress; + + # Determine whether json output via powershell or in file (based on param -OutFile) + if ([string]::IsNullOrEmpty($OutFile) -eq $false) { + $OutFile = (Join-Path -Path $OutFile -ChildPath $FileName); + if ((Test-Path($OutFile)) -eq $false) { + New-Item -Path $OutFile -Force | Out-Null; + } + + if ((Test-Path($OutFile)) -eq $false) { + throw 'Failed to create specified directory. Please try again or use a different target location.'; + } + + Set-Content -Path $OutFile -Value $output; + + # Output-Text + Write-Host "The following commands have been exported:" + foreach ($check in $CheckName) { + Write-Host "- '$check'"; + } + Write-Host "JSON export created in '${OutFile}'" + return; + } + + Write-Host "Check Command JSON for the following commands:" + foreach ($check in $CheckName) { + Write-Host "- '$check'" + } + Write-Host '############################################################'; + + return $output; +} diff --git a/lib/plugins/Invoke-IcingaCheckService.psm1 b/lib/plugins/Invoke-IcingaCheckService.psm1 index 86cc058..3b2c323 100644 --- a/lib/plugins/Invoke-IcingaCheckService.psm1 +++ b/lib/plugins/Invoke-IcingaCheckService.psm1 @@ -2,13 +2,69 @@ Import-IcingaLib provider\services; Import-IcingaLib provider\enums; Import-IcingaLib icinga\plugin; +<# +.SYNOPSIS + Checks if a service has a specified status. + +.DESCRIPTION + Invoke-icingaCheckService returns either 'OK' or 'CRITICAL', if a service status is matching status to be checked. + + More Information on https://github.com/LordHepipud/icinga-module-windows + +.FUNCTIONALITY + This module is intended to be used to check whether one or more services have a certain status. + As soon as one of the specified services does not match the status, the function returns 'CRITICAL' instead of 'OK'. + +.EXAMPLE + PS>Invoke-IcingaCheckService -Service WiaRPC, Spooler -Status '1' -Verbose 3 + [CRITICAL]: Check package "Services" is [CRITICAL] (Match All) + \_ [OK]: Service "Ereignisse zum Abrufen von Standbildern (WiaRPC)" is Stopped + \_ [CRITICAL]: Service "Druckwarteschlange (Spooler)" Running is not matching Stopped + +.PARAMETER Service + Used to specify an array of services which should be checked against the status. + Seperated with ',' + +.PARAMETER Status + Status for the specified service or services to check against. + +.INPUTS + System.Array + +.OUTPUTS + System.String + +.LINK + https://github.com/LordHepipud/icinga-module-windows + +.NOTES +#> + function Invoke-IcingaCheckService() { param( + [array]$Service, [string]$Status, - [string]$Service + [int]$Verbose ); + $ServicesPackage = New-IcingaCheckPackage -Name 'Services' -OperatorAnd -Verbose $Verbose; + + if ($Service.Count -ne 1) { + foreach ($services in $Service) { + $IcingaCheck = $null; + + $FoundService = Get-IcingaServices -Service $services; + $ServiceName = Get-IcingaServiceCheckName -ServiceInput $services -Service $FoundService; + $ConvertedStatus = ConvertTo-ServiceStatusCode -Status $Status; + $StatusRaw = $FoundService.Values.configuration.Status.raw; + + $IcingaCheck = New-IcingaCheck -Name $ServiceName -Value $StatusRaw -ObjectExists $FoundService -Translation $ProviderEnums.ServiceStatusName; + $IcingaCheck.CritIfNotMatch($ConvertedStatus) | Out-Null; + $ServicesPackage.AddCheck($IcingaCheck) + } + } else { + $FoundService = Get-IcingaServices -Service $Service; $ServiceName = Get-IcingaServiceCheckName -ServiceInput $Service -Service $FoundService; $Status = ConvertTo-ServiceStatusCode -Status $Status; @@ -16,6 +72,8 @@ function Invoke-IcingaCheckService() $IcingaCheck = New-IcingaCheck -Name $ServiceName -Value $StatusRaw -ObjectExists $FoundService -Translation $ProviderEnums.ServiceStatusName; $IcingaCheck.CritIfNotMatch($Status) | Out-Null; + $ServicesPackage.AddCheck($IcingaCheck); - exit (New-IcingaCheckResult -Check $IcingaCheck -NoPerfData $TRUE -Compile); + } + exit (New-IcingaCheckResult -Name 'Services' -Check $ServicesPackage -NoPerfData $TRUE -Compile); }