From 9a42c9efa1afbb29e64c8ff494e3c8efe7a6af24 Mon Sep 17 00:00:00 2001 From: Yonas Habteab Date: Fri, 9 Oct 2020 21:49:01 +0200 Subject: [PATCH] Check whether or not a specific wmi class exists Tests if a specific WMI class including the Namespace can be accessed and returns status codes for possible errors/exceptions taht might occure. Returns binary operator values for easier comparison. In case no errors occured it will return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.Ok --- doc/31-Changelog.md | 1 + .../Test-IcingaWindowsInformation.psm1 | 73 +++++++++++++++++++ lib/core/tools/Test-IcingaBinaryOperator.psm1 | 68 +++++++++++++++++ .../enums/Test-IcingaWindowsInfoEnums.psm1 | 40 ++++++++++ .../exception/Get-IcingaLastExceptionId.psm1 | 19 +++++ 5 files changed, 201 insertions(+) create mode 100644 lib/core/framework/Test-IcingaWindowsInformation.psm1 create mode 100644 lib/core/tools/Test-IcingaBinaryOperator.psm1 create mode 100644 lib/icinga/enums/Test-IcingaWindowsInfoEnums.psm1 create mode 100644 lib/icinga/exception/Get-IcingaLastExceptionId.psm1 diff --git a/doc/31-Changelog.md b/doc/31-Changelog.md index b83b44b..8beeda4 100644 --- a/doc/31-Changelog.md +++ b/doc/31-Changelog.md @@ -17,6 +17,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic * [#137](https://github.com/Icinga/icinga-powershell-framework/issues/137) Adds Cmdlet to compare a DateTime object with the current DateTime and return the offset as Integer in seconds * [#139](https://github.com/Icinga/icinga-powershell-framework/pull/139) Add Cmdlet `Start-IcingaShellAsUser` to open an Icinga Shell as different user for testing * [#141](https://github.com/Icinga/icinga-powershell-framework/pull/141) Adds Cmdlet `Convert-IcingaPluginThresholds` as generic approach to convert Icinga Thresholds with units to the lowest unit of this type. +* [#134](https://github.com/Icinga/icinga-powershell-framework/pull/134) Adds Cmdlet `Test-IcingaWindowsInformation` to check if a WMI class exist and if we can fetch data from it. In addition we add support for binary value comparison with the new Cmdlet `Test-IcingaBinaryOperator` ### Bugfixes diff --git a/lib/core/framework/Test-IcingaWindowsInformation.psm1 b/lib/core/framework/Test-IcingaWindowsInformation.psm1 new file mode 100644 index 0000000..a3a5374 --- /dev/null +++ b/lib/core/framework/Test-IcingaWindowsInformation.psm1 @@ -0,0 +1,73 @@ +<# +.SYNOPSIS + Tests if a specific WMI class including the Namespace can be accessed and returns status codes for possible errors/exceptions taht might occure. + Returns binary operator values for easier comparison. In case no errors occured it will return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.Ok +.DESCRIPTION + Tests if a specific WMI class including the Namespace can be accessed and returns status codes for possible errors/exceptions taht might occure. + Returns binary operator values for easier comparison. In case no errors occured it will return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.Ok +.ROLE + ### WMI Permissions + + No special permissions required as this Cmdlet will validate all input data and reports back the result. +.OUTPUTS + Name Value + ---- ----- + Ok 1 + EmptyClass 2 + PermissionError 4 + ObjectNotFound 8 + InvalidNameSpace 16 + UnhandledException 32 + NotSpecified 64 + CimNotInstalled 128 +.LINK + https://github.com/Icinga/icinga-powershell-framework +#> +function Test-IcingaWindowsInformation() +{ + param ( + [string]$ClassName, + [string]$NameSpace = 'Root\Cimv2' + ); + + if ([string]::IsNullOrEmpty($ClassName)) { + return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.EmptyClass; + } + + # Check with Get-CimClass for the specified WMI class and in the specified namespace default root\cimv2 + if ((Test-IcingaFunction 'Get-CimInstance') -eq $FALSE ) { + return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.CimNotInstalled; + } + + # We clear all previous errors so that we can catch the last error message from this try/catch in the plugins. + $Error.Clear(); + + try { + Get-CimInstance -ClassName $ClassName -Namespace $NameSpace -ErrorAction Stop | Out-Null; + } catch { + + Write-IcingaConsoleDebug ` + -Message "WMIClass: '{0}' : Namespace : {1} {2} {3}" ` + -Objects $ClassName, $NameSpace, (New-IcingaNewLine), $_.Exception.Message; + + if ($_.CategoryInfo.Category -like 'MetadataError') { + return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.InvalidNameSpace; + } + + if ($_.CategoryInfo.Category -like 'ObjectNotFound') { + return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.ObjectNotFound; + } + + if ($_.CategoryInfo.Category -like 'NotSpecified') { + return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.NotSpecified; + } + + if ($_.CategoryInfo.Category -like 'PermissionDenied') { + return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.PermissionError; + } + + return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.UnhandledException; + } + + return $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo.Ok; +} diff --git a/lib/core/tools/Test-IcingaBinaryOperator.psm1 b/lib/core/tools/Test-IcingaBinaryOperator.psm1 new file mode 100644 index 0000000..a4020f7 --- /dev/null +++ b/lib/core/tools/Test-IcingaBinaryOperator.psm1 @@ -0,0 +1,68 @@ +<# +.SYNOPSIS + Tests for binary operators with -band if a specific Value contains binary + operators within a Compare array. In addition you can use a Namespace + argument to provide a hashtable in which your key values are included to + reduce the amount of code to write +.DESCRIPTION + Tests for binary operators with -band if a specific Value contains binary + operators within a Compare array. In addition you can use a Namespace + argument to provide a hashtable in which your key values are included to + reduce the amount of code to write +.EXAMPLE + PS>Test-IcingaBinaryOperator -Value Ok -Compare EmptyClass, InvalidNameSpace, PermissionError, Ok -Namespace $TestIcingaWindowsInfoEnums.TestIcingaWindowsInfo; + True +.EXAMPLE + PS>Test-IcingaBinaryOperator -Value 2 -Compare 1,4,8,16,32,64,128,256; + False +.PARAMETER Value + The value to check if it is included within the compare argument. This can either be + the name of the key for a Namespace or a numeric value +.PARAMETER Compare + An array of values to compare for and check if the value matches with the -band operator + The array can either contain the key names of your Namespace, numeric values or both cominbed +.PARAMETER Namespace + A hashtable object containing values you want to compare for. By providing a hashtable here + you can use the key names for each value on the Value and Compare argument +.LINK + https://github.com/Icinga/icinga-powershell-framework +#> + +function Test-IcingaBinaryOperator() +{ + param ( + $Value = $null, + [array]$Compare = @(), + [hashtable]$Namespace = $null + ); + + [long]$BinaryValue = 0; + + foreach ($entry in $Compare) { + if ($null -ne $Namespace) { + if ($Namespace.ContainsKey($entry)) { + $BinaryValue += $Namespace[$entry]; + } else { + if (Test-Numeric $entry) { + $BinaryValue += $entry; + } + } + } else { + $BinaryValue += $entry; + } + } + + if ($null -ne $Value -and (Test-Numeric $Value)) { + if (($Value -band $BinaryValue) -eq $Value) { + return $TRUE; + } + } + + if ($null -ne $Namespace -and $Namespace.ContainsKey($Value)) { + if (($Namespace[$Value] -band $BinaryValue) -eq $Namespace[$Value]) { + return $TRUE; + } + } + + return $FALSE; +} diff --git a/lib/icinga/enums/Test-IcingaWindowsInfoEnums.psm1 b/lib/icinga/enums/Test-IcingaWindowsInfoEnums.psm1 new file mode 100644 index 0000000..6a85d48 --- /dev/null +++ b/lib/icinga/enums/Test-IcingaWindowsInfoEnums.psm1 @@ -0,0 +1,40 @@ +[hashtable]$TestIcingaWindowsInfo = @{ + 'Ok' = 1; + 'EmptyClass' = 2; + 'PermissionError' = 4; + 'ObjectNotFound' = 8; + 'InvalidNameSpace' = 16; + 'UnhandledException' = 32; + 'NotSpecified' = 64; + 'CimNotInstalled' = 128; +} + +[hashtable]$TestIcingaWindowsInfoText = @{ + 1 = 'Everything is fine.'; + 2 = 'No class specified to check'; + 4 = 'Unable to query data from your Windows Cluster. You are either missing permissions or your cluster is not running properly'; + 8 = 'The specified WMI Class could not be found in the specified NameSpace.'; + 16 = 'No namespace with the specified name could be found on this system.'; + 32 = 'Windows unhandled exception is thrown. Please enable frame DebugMode for information.'; + 64 = 'The Cluster Service is Stopped or you are not authorized to access the Cluster Service'; + 128 = 'The Cmdlet Get-CimClass is not available on your system.'; +} + +[hashtable]$TestIcingaWindowsInfoExceptionType = @{ + 1 = 'OK'; + 2 = 'EmptyClass'; + 4 = 'PermissionError'; + 8 = 'ObjectNotFound'; + 16 = 'InvalidNameSpace'; + 32 = 'UnhandledException'; + 64 = 'NotSpecified'; + 128 = 'CimNotInstalled'; +} + +[hashtable]$TestIcingaWindowsInfoEnums = @{ + TestIcingaWindowsInfo = $TestIcingaWindowsInfo; + TestIcingaWindowsInfoText = $TestIcingaWindowsInfoText; + TestIcingaWindowsInfoExceptionType = $TestIcingaWindowsInfoExceptionType; +} + +Export-ModuleMember -Variable @( 'TestIcingaWindowsInfoEnums' ); diff --git a/lib/icinga/exception/Get-IcingaLastExceptionId.psm1 b/lib/icinga/exception/Get-IcingaLastExceptionId.psm1 new file mode 100644 index 0000000..94d62a0 --- /dev/null +++ b/lib/icinga/exception/Get-IcingaLastExceptionId.psm1 @@ -0,0 +1,19 @@ +<# +.SYNOPSIS + This function returns the HRESULT unique value thrown by the last exception +.DESCRIPTION + This function returns the HRESULT unique value thrown by the last exception +.OUTPUTS + System.String +#> +function Get-IcingaLastExceptionId() +{ + if ([string]::IsNullOrEmpty($Error)) { + return ''; + } + + [string]$ExceptionId = ([string]($Error.FullyQualifiedErrorId)).Split(',')[0].Split(' ')[1]; + $Error.Clear(); + + return $ExceptionId; +}