Powershell script

This support forum board is for support questions relating to Nagios XI, our flagship commercial network monitoring solution.
Locked
Taronga76
Posts: 6
Joined: Wed Apr 12, 2017 10:27 am

Powershell script

Post by Taronga76 »

Hi all,

I am looking for a bit of help on the below.

We have recently just launched Windows Updates via SCCM across our domain and would like to have Nagios alert us when a server has a pending reboot due to these updates, we have written the bellow powershell script in order to check this, I can run this manually on the servers and it reports correctly.

Code: Select all

Function Get-PendingReboot
{
<#
.SYNOPSIS
    Gets the pending reboot status on a local or remote computer.

.DESCRIPTION
    This function will query the registry on a local or remote computer and determine if the
    system is pending a reboot, from Microsoft updates, Configuration Manager Client SDK, Pending Computer 
    Rename, Domain Join or Pending File Rename Operations. For Windows 2008+ the function will query the 
    CBS registry key as another factor in determining pending reboot state.  "PendingFileRenameOperations" 
    and "Auto Update\RebootRequired" are observed as being consistant across Windows Server 2003 & 2008.
	
    CBServicing = Component Based Servicing (Windows 2008+)
    WindowsUpdate = Windows Update / Auto Update (Windows 2003+)
    CCMClientSDK = SCCM 2012 Clients only (DetermineIfRebootPending method) otherwise $null value
    PendComputerRename = Detects either a computer rename or domain join operation (Windows 2003+)
    PendFileRename = PendingFileRenameOperations (Windows 2003+)
    PendFileRenVal = PendingFilerenameOperations registry value; used to filter if need be, some Anti-
                     Virus leverage this key for def/dat removal, giving a false positive PendingReboot

.PARAMETER ComputerName
    A single Computer or an array of computer names.  The default is localhost ($env:COMPUTERNAME).

.PARAMETER ErrorLog
    A single path to send error data to a log file.

.EXAMPLE
    PS C:\> Get-PendingReboot -ComputerName (Get-Content C:\ServerList.txt) | Format-Table -AutoSize
	
    Computer CBServicing WindowsUpdate CCMClientSDK PendFileRename PendFileRenVal RebootPending
    -------- ----------- ------------- ------------ -------------- -------------- -------------
    DC01           False         False                       False                        False
    DC02           False         False                       False                        False
    FS01           False         False                       False                        False

    This example will capture the contents of C:\ServerList.txt and query the pending reboot
    information from the systems contained in the file and display the output in a table. The
    null values are by design, since these systems do not have the SCCM 2012 client installed,
    nor was the PendingFileRenameOperations value populated.

.EXAMPLE
    PS C:\> Get-PendingReboot
	
    Computer           : WKS01
    CBServicing        : False
    WindowsUpdate      : True
    CCMClient          : False
    PendComputerRename : False
    PendFileRename     : False
    PendFileRenVal     : 
    RebootPending      : True
	
    This example will query the local machine for pending reboot information.
	
.EXAMPLE
    PS C:\> $Servers = Get-Content C:\Servers.txt
    PS C:\> Get-PendingReboot -Computer $Servers | Export-Csv C:\PendingRebootReport.csv -NoTypeInformation
	
    This example will create a report that contains pending reboot information.

.LINK
    Component-Based Servicing:
    http://technet.microsoft.com/en-us/library/cc756291(v=WS.10).aspx
	
    PendingFileRename/Auto Update:
    http://support.microsoft.com/kb/2723674
    http://technet.microsoft.com/en-us/library/cc960241.aspx
    http://blogs.msdn.com/b/hansr/archive/2006/02/17/patchreboot.aspx

    SCCM 2012/CCM_ClientSDK:
    http://msdn.microsoft.com/en-us/library/jj902723.aspx

.NOTES
    Author:  Brian Wilhite
    Email:   bcwilhite (at) live.com
    Date:    29AUG2012
    PSVer:   2.0/3.0/4.0/5.0
    Updated: 27JUL2015
    UpdNote: Added Domain Join detection to PendComputerRename, does not detect Workgroup Join/Change
             Fixed Bug where a computer rename was not detected in 2008 R2 and above if a domain join occurred at the same time.
             Fixed Bug where the CBServicing wasn't detected on Windows 10 and/or Windows Server Technical Preview (2016)
             Added CCMClient property - Used with SCCM 2012 Clients only
             Added ValueFromPipelineByPropertyName=$true to the ComputerName Parameter
             Removed $Data variable from the PSObject - it is not needed
             Bug with the way CCMClientSDK returned null value if it was false
             Removed unneeded variables
             Added PendFileRenVal - Contents of the PendingFileRenameOperations Reg Entry
             Removed .Net Registry connection, replaced with WMI StdRegProv
             Added ComputerPendingRename
#>

[CmdletBinding()]
param(
	[Parameter(Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
	[Alias("CN","Computer")]
	[String[]]$ComputerName="$env:COMPUTERNAME",
	[String]$ErrorLog
	)

Begin {  }## End Begin Script Block
Process {
  Foreach ($Computer in $ComputerName) {
	Try {
	    ## Setting pending values to false to cut down on the number of else statements
	    $CompPendRen,$PendFileRename,$Pending,$SCCM = $false,$false,$false,$false
                        
	    ## Setting CBSRebootPend to null since not all versions of Windows has this value
	    $CBSRebootPend = $null
						
	    ## Querying WMI for build version
	    $WMI_OS = Get-WmiObject -Class Win32_OperatingSystem -Property BuildNumber, CSName -ComputerName $Computer -ErrorAction Stop

	    ## Making registry connection to the local/remote computer
	    $HKLM = [UInt32] "0x80000002"
	    $WMI_Reg = [WMIClass] "\\$Computer\root\default:StdRegProv"
						
	    ## If Vista/2008 & Above query the CBS Reg Key
	    If ([Int32]$WMI_OS.BuildNumber -ge 6001) {
		    $RegSubKeysCBS = $WMI_Reg.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\")
		    $CBSRebootPend = $RegSubKeysCBS.sNames -contains "RebootPending"		
	    }
							
	    ## Query WUAU from the registry
	    $RegWUAURebootReq = $WMI_Reg.EnumKey($HKLM,"SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\")
	    $WUAURebootReq = $RegWUAURebootReq.sNames -contains "RebootRequired"
						
	    ## Query PendingFileRenameOperations from the registry
	    $RegSubKeySM = $WMI_Reg.GetMultiStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager\","PendingFileRenameOperations")
	    $RegValuePFRO = $RegSubKeySM.sValue

	    ## Query JoinDomain key from the registry - These keys are present if pending a reboot from a domain join operation
	    $Netlogon = $WMI_Reg.EnumKey($HKLM,"SYSTEM\CurrentControlSet\Services\Netlogon").sNames
	    $PendDomJoin = ($Netlogon -contains 'JoinDomain') -or ($Netlogon -contains 'AvoidSpnSet')

	    ## Query ComputerName and ActiveComputerName from the registry
	    $ActCompNm = $WMI_Reg.GetStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName\","ComputerName")            
	    $CompNm = $WMI_Reg.GetStringValue($HKLM,"SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName\","ComputerName")

	    If (($ActCompNm -ne $CompNm) -or $PendDomJoin) {
	        $CompPendRen = $true
	    }
						
	    ## If PendingFileRenameOperations has a value set $RegValuePFRO variable to $true
	    If ($RegValuePFRO) {
		    $PendFileRename = $true
	    }

	    ## Determine SCCM 2012 Client Reboot Pending Status
	    ## To avoid nested 'if' statements and unneeded WMI calls to determine if the CCM_ClientUtilities class exist, setting EA = 0
	    $CCMClientSDK = $null
	    $CCMSplat = @{
	        NameSpace='ROOT\ccm\ClientSDK'
	        Class='CCM_ClientUtilities'
	        Name='DetermineIfRebootPending'
	        ComputerName=$Computer
	        ErrorAction='Stop'
	    }
	    ## Try CCMClientSDK
	    Try {
	        $CCMClientSDK = Invoke-WmiMethod @CCMSplat
	    } Catch [System.UnauthorizedAccessException] {
	        $CcmStatus = Get-Service -Name CcmExec -ComputerName $Computer -ErrorAction SilentlyContinue
	        If ($CcmStatus.Status -ne 'Running') {
	            Write-Warning "$Computer`: Error - CcmExec service is not running."
	            $CCMClientSDK = $null
	        }
	    } Catch {
	        $CCMClientSDK = $null
	    }

	    If ($CCMClientSDK) {
	        If ($CCMClientSDK.ReturnValue -ne 0) {
		        Write-Warning "Error: DetermineIfRebootPending returned error code $($CCMClientSDK.ReturnValue)"          
		    }
		    If ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) {
		        $SCCM = $true
		    }
	    }
            
	    Else {
	        $SCCM = $null
	    }

        $RebootPending=($CompPendRen -or $CBSRebootPend -or $WUAURebootReq -or $SCCM -or $PendFileRename)
        $rebootPending

	    ## Creating Custom PSObject and Select-Object Splat
<#	    $SelectSplat = @{
	        Property=(
	            'Computer',
	            'CBServicing',
	            'WindowsUpdate',
	            'CCMClientSDK',
	            'PendComputerRename',
	            'PendFileRename',
	            'PendFileRenVal',
	            'RebootPending'
	        )}
	    New-Object -TypeName PSObject -Property @{
	        Computer=$WMI_OS.CSName
	        CBServicing=$CBSRebootPend
	        WindowsUpdate=$WUAURebootReq
	        CCMClientSDK=$SCCM
	        PendComputerRename=$CompPendRen
	        PendFileRename=$PendFileRename
	        PendFileRenVal=$RegValuePFRO
	        RebootPending=($CompPendRen -or $CBSRebootPend -or $WUAURebootReq -or $SCCM -or $PendFileRename)
	    } | Select-Object @SelectSplat
#>
	} Catch {
	    Write-Warning "$Computer`: $_"
	    ## If $ErrorLog, log the file to a user specified location/path
	    If ($ErrorLog) {
	        Out-File -InputObject "$Computer`,$_" -FilePath $ErrorLog -Append
	    }				
	}			
  }## End Foreach ($Computer in $ComputerName)			
}## End Process

End {  }## End End

}## End Function Get-PendingReboot

Get-PendingReboot

The script will return a simple status of "True" if a reboot is complete, so I know that I can configure the notification to alert if "True" is received on the check.

We currently use NSClient++ 0.5.0.62 64bit version across all servers and our servers are a mixture of 2008R2 and 2012.

I have so far got as far as editing my nsclient.ini file to the below:

Code: Select all

# If you want to fill this file with all available options run the following command:
#   nscp settings --generate --add-defaults --load-all
# If you want to activate a module and bring in all its options use:
#   nscp settings --activate-module <MODULE NAME> --add-defaults
# For details run: nscp settings --help


; TODO
[/settings/default]

; Undocumented key
password = *Password removed*

; Undocumented key
allowed hosts = *IPs removed*


; TODO
[/settings/NRPE/server]

; Undocumented key
verify mode = none

; Undocumented key
insecure = true


; TODO
[/modules]

; Undocumented key
CheckExternalScripts = 1

; Undocumented key
CheckHelpers = 1

; Undocumented key
CheckNSCP = 1

; Undocumented key
CheckDisk = 1

; Undocumented key
CheckSystem = 1

; Undocumented key
NSClientServer = 1

; Undocumented key
CheckEventLog = 1

; Undocumented key
NSCAClient = 1

; Undocumented key
NRPEServer = 1

[/settings/external scripts/scripts]
Get-PendingReboot_ps1 = cmd /c echo scripts\\Get-PendingReboot.ps1; exit($lastexitcode) | powershell.exe -command -
I am just wandering now how I configure the command on the Nagios server in order to run this script on remote hosts as a service, if anybody is able to help, it would be greatly appreciated.

Thank-you
User avatar
mcapra
Posts: 3739
Joined: Thu May 05, 2016 3:54 pm

Re: Powershell script

Post by mcapra »

Taronga76 wrote: I am just wandering now how I configure the command on the Nagios server in order to run this script on remote hosts as a service
So you already have the command configured in your NSClient++ configuration; That's step 1:

Code: Select all

[/settings/external scripts/scripts]
Get-PendingReboot_ps1 = cmd /c echo scripts\\Get-PendingReboot.ps1; exit($lastexitcode) | powershell.exe -command -
How you call that command from Nagios XI would be to leverage the check_nrpe plugin. Nagios XI should come pre-configured with the check_nrpe command which leverages this plugin. From the CLI, it might look something like this given the command name Get-PendingReboot_ps1:

Code: Select all

/usr/local/nagios/libexec/check_nrpe -H <host_address_here> -c Get-PendingReboot_ps1
With the -c parameter telling the remote NRPE server (or in this case NSClient++ server) what command to run.
Former Nagios employee
https://www.mcapra.com/
dwhitfield
Former Nagios Staff
Posts: 4583
Joined: Wed Sep 21, 2016 10:29 am
Location: NoLo, Minneapolis, MN
Contact:

Re: Powershell script

Post by dwhitfield »

In addition to what @mcapra said, https://assets.nagios.com/downloads/nag ... ios-XI.pdf walks you through the process. Since you are using your own script you might need to change a few things, but the general process should work for you.

Please let us know if you run into any difficulty.
Taronga76
Posts: 6
Joined: Wed Apr 12, 2017 10:27 am

Re: Powershell script

Post by Taronga76 »

Perfect, thank-you all that has worked perfectly, now it's just time to get the alerts working on this check.

Once again thank-you so much for all your help :D
Taronga76
Posts: 6
Joined: Wed Apr 12, 2017 10:27 am

Re: Powershell script

Post by Taronga76 »

Hi all,

I've been working on this for most of the morning and seem to be getting nowhere, I have the script running correctly and it's returning a status correct of "True" on my test server that does require a reboot, however I can't seem to get this to trigger as a warning.

My command looks like the below

Code: Select all

$USER1$/check_nrpe -H $HOSTADDRESS$ -c Get-PendingReboot_ps1 $ARG1$
I am just not sure what to put as ARG1 for the warning and critical states, I have tried various different inputs and none seem to trigger a warning

When the check runs, it currently looks like this

Code: Select all

[nagios@*servername* ~]$ /usr/local/nagios/libexec/check_nrpe -H *hostname* -c Get-PendingReboot_ps1 
True
I had a look at the PDF linked and I couldn't see on it where the arguments were for the various states :(

I apologise if this is a silly question but any help would be greatly appreciated.
User avatar
mcapra
Posts: 3739
Joined: Thu May 05, 2016 3:54 pm

Re: Powershell script

Post by mcapra »

Taronga76 wrote:however I can't seem to get this to trigger as a warning.
That logic would have to exist in the Powershell script. The script's exit code is generally what determines OK/WARNING/CRITICAL status. Alternatively you could wrap your check_nrpe execution in something that parses True or False into something "Nagios readable", but that's pretty inefficient.

Refer to the Nagios plugin development guidelines for more information:
https://nagios-plugins.org/doc/guidelines.html

Below is a copy-paste from an old post in the "customers only" section of the forums:

OK/CRITICAL/et. al won't get appended to the status output unless you explicitly do that in the script's output (via stdout or the Windows equivalent) itself. The exit code will still be preserved though, and that's ultimately what Nagios XI cares about in terms of alerting. The status output is simply for the user's benefit.

My sample script:

Code: Select all

if ($args[0] -eq 0) {
   Write-Host "This is an ok."
   exit 0
}
if ($args[0] -eq 1) {
   Write-Host "This is a warning."
   exit 1
}
if ($args[0] -eq 2) {
   Write-Host "This is a critical."
   exit 2
}
My NSClient++ entry for the above script:

Code: Select all

test=cmd /c echo scripts\check_test.ps1 $ARG1$; exit $LastExitCode | powershell.exe -noprofile -nologo -command -
Some sample calls from check_nrpe, in which I'm only passing the exit code for demonstrative purposes. The actual exit code should be determined in your script's logic (if count > critical, exit 2 or something similar):

Code: Select all

[root@xi-stable tmp]# /usr/local/nagios/libexec/check_nrpe -H 192.168.67.99 -c test -a 0
This is an ok.
[root@xi-stable tmp]# echo $?
0
[root@xi-stable tmp]# /usr/local/nagios/libexec/check_nrpe -H 192.168.67.99 -c test -a 1
This is a warning.
[root@xi-stable tmp]# echo $?
1
[root@xi-stable tmp]# /usr/local/nagios/libexec/check_nrpe -H 192.168.67.99 -c test -a 2
This is a critical.
[root@xi-stable tmp]# echo $?
2
Former Nagios employee
https://www.mcapra.com/
bolson

Re: Powershell script

Post by bolson »

Do you have any additional questions or can we go ahead and close this topic?
Taronga76
Posts: 6
Joined: Wed Apr 12, 2017 10:27 am

Re: Powershell script

Post by Taronga76 »

Hi Brian,

I am still struggling with this if I am being honest and have attempted to modify the scripts but am not having much luck, I think I just need to spend a bit more time on the issue to get it resolved, so please feel free to close the case and once I have got it sorted, I will post up what I did to get it working and leave examples for others to use if they wish.

Thank-you
bolson

Re: Powershell script

Post by bolson »

Closing topic.

Thank you for using the Nagios Support Forum!
Locked