' ' ' Check files under a given path ' ============================== ' ' based on example scripts found in nsclient++/scripts directory ' ' Author: werner.fuerst@assmann.at 2010-12-21 ' ' uses NagiosPlugin.vbs from nsclient++/scripts/lib ' - NagiosPlugin.vbs which came with nsclient++ vers. 0.3.9 (earlier version needed adaptation) ' - compares bounds to double values, so 10 comes after 9 (numeric sorting) ' - bounds definition conforms to nagios plugin guidelines (http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT) ' ' modifications in NSC.ini: ' ========================= ' ' ' in [modules]: ' CheckExternalScripts.dll ' ' in [NRPE]: ' allow_arguments=1 ' allow_nasty_meta_chars=1 ' allowed_hosts=x.x.x.x ' ' in [External Script]: ' allow_arguments=1 ' allow_nasty_meta_chars=1 ' ' in [Script Wrappings]: ' obsolet, as modifications in wrapperCDbl.vbs are included since version 0.3.9: vbs=cscript.exe //T:30 //NoLogo scripts\lib\wrapperCDbl.vbs %SCRIPT% %ARGS% ' ' in [Wrapped Scripts]: ' check_files=check_files.vbs $ARG1$ $ARG2$ $ARG3$ $ARG4$ $ARG5$ $ARG6$ $ARG7$ $ARG8$ $ARG9$ $ARG10$ $ARG11$ $ARG12$ $ARG13$ $ARG14$ ' ' ' nagios usage: ' ============= ' ' define command{ ' command_name check_nrpe_external ' command_line $USER1$/check_nrpe -H $HOSTADDRESS$ -c $ARG1$ -a $ARG2$ ' } ' ' define service{ ' use generic-service ' host_name windowsxx ' service_description Backup DB2 ' check_command check_nrpe_external!check_files!/path:"e:\\BACKUP\\DB" /namefilter:"DB2\.DAT" /expectmatch:1 /age:3 /selage:hour /warning:1: /critical:1: /size:9000000000 /weekdays:"2,3" ' } ' give alarm when file DB2.DAT in e:\BACKUP\DB was not written until 3 o clock on Monday or Tuesday (alarm if count is less than 1, so threshold is set to 1:) ' ' ' ' check_command check_nrpe_external!check_files!/path:"d:\\journal" /searchdepth:1 /selage:ignore /warning:30 /critical:40 ' give alarm if there are more than 30 files under d:\journal ' ' ' check_command check_nrpe_external!check_files!/path:"T:\\nfs\\interface1" /searchdepth:2 /age:2d /warning:5: /critical:3: /selage:newer /seldat:created ' give alarm if there are fewer than 3 files which are newer than 2 days under t:\nfs\interface1, search only 1 subdir down, use the creation date for comparison ' ' ' ' args: ' ===== ' ' ' warning: threshold warning ' alert if x... ' 10 < 0 or > 10, (outside the range of {0 .. 10}) ' 10: < 10, (outside {10 .. 8}) ' ~:10 > 10, (outside the range of {-8 .. 10}) ' 10:20 < 10 or > 20, (outside the range of {10 .. 20}) ' @10:20 >= 10 and <= 20, (inside the range of {10 .. 20}) ' critical: threshold critical ' namefilter: regular expressionon on which files have to match ' age: files have to be older/newer (see selage) than age ' e.g.: 5d: 5 days, 4h: 4 hours, 10n: 10 Minutes, 90s: 90 seconds ' selage: older/newer/hour/ignore ' older/newer: count only files if the are older/newer ' hour: alert if file is not written until hour ' ignore: count files independent of their age ' searchdepth: search down x subdirs (searchdepth:1 - do not go down in directory hierarchy) ' seldat: modified/created ' modified: date, when file was written ' created: date, when file was created ' size: if file is smaller than given size give a warning ' expectmatch: if less than expectmatch files correspond to namefilter give a warning ' weekdays: ' if selage:hour files have to be written only on weekdays (1:sunday, 2:monday, ...) ' if selage:newer or selage:older and the timeunit of age is d (days), we add as many days to age as the last weekday is back ' e.g.: weekdays:23456 files are written on Monday, Tuesday, Wednesday, Thursday, Friday ' Const PROGNAME = "check_files" Const VERSION = "0.1.3" ' ver 0.1.3 2011-10-06 ' Comment in header ' ver 0.1.2 2011-06-15 ' start with 1 and not with 0 when trying to find the last day when the file should have been written according to weekdays ' fixed some typos in the coments ' ver 0.1.1 2011-01-07 ' replaced Testing... with Checking... Dim verbose verbose = 0 Dim lastfile Dim lastdat Dim lastsize Dim intdif Dim warnsize Dim matchcount Dim weekdays Dim ageint Dim ageunit Dim agestring Dim inlevel ' Default settings for script. threshold_warning = 10 threshold_critical = 20 alias = "default" agestring = "5d" '5 days ageint = 5 ageunit = "d" selage = "newer" namefilter = "" searchdepth = 0 seldat = "modified" size = 0 expectmatch = 0 weekdays = "1,2,3,4,5,6,7" ' Create the NagiosPlugin object Set np = New NagiosPlugin ' Define what args should be used np.add_arg "path", "Path", 1 np.add_arg "namefilter", "Filename Filter", 0 np.add_arg "age", "Age", 0 np.add_arg "selage", "newer, older, hour, ignore", 0 np.add_arg "searchdepth", "depth of subdirs to search", 0 np.add_arg "seldat", "modified or created", 0 np.add_arg "size", "size", 0 np.add_arg "warning", "warning threshold", 0 np.add_arg "critical", "critical threshold", 0 np.add_arg "expectmatch", "expect at least x matches", 0 np.add_arg "weekdays", "1,2,3,... 1-Sun 2-Mon 3-Tue...", 0 np.add_arg "alias", "Alias", 0 ' If we have no args or arglist contains /help or not all of the required arguments are fulfilled show the usage output,. If Args.Count < 1 Or Args.Exists("help") Or np.parse_args = 0 Then WScript.Echo Args.Count np.Usage End If ' If we define /warning /critical on commandline it should override the script default. If Args.Exists("warning") Then threshold_warning = Args("warning") If Args.Exists("critical") Then threshold_critical = Args("critical") If Args.Exists("namefilter") Then namefilter = Args("namefilter") If Args.Exists("age") Then agestring = Args("age") If Args.Exists("selage") Then selage = Args("selage") If Args.Exists("searchdepth") Then searchdepth = Cint(Args("searchdepth")) If Args.Exists("seldat") Then seldat = Args("seldat") If Args.Exists("size") Then size = CDbl(Args("size")) If Args.Exists("expectmatch") Then expectmatch = CInt(Args("expectmatch")) If Args.Exists("weekdays") Then weekdays = Args("weekdays") If Args.Exists("alias") Then alias = Args("alias") ' Set the msg output to be used (OK/WARNING/CRITICAL/UNKNOWN will be applied automaticly) np.set_thresholds threshold_warning, threshold_critical ' Set ageint and ageunit Set reage = New RegExp reage.IgnoreCase = False reage.Pattern = "^([0-9]+)([dhns]*)$" 'd: days h:hours n:minutes s:seconds Set ages = reage.Execute(agestring) For Each age In ages pt age & " > " & age.SubMatches(0) & " > " & age.SubMatches(1) ageint = CInt(age.SubMatches(0)) ageunit = age.SubMatches(1) If ageunit = "" Then If selage = "hour" Then ageunit = "h" Else ageunit = "d" End If End If Next ' add some days if this and the days before do not belong to the weekdays If ageunit="d" And (selage="newer" Or selage="older") Then date1 = Now() date00 = DateValue(Now) ' start with 1 and not with 0 when trying to find the last day when the file should have been written according to weekdays ' if a machine is saved only on mondays, and we start with 0, 0 is added to age, and we get an alarm every monday mornung until the copy is started ' if we start with 1, and it is monday, we add 7 to age ' drawback: we add always at least 1 to age (we could count how many weekdays are defined, ...) For i = 1 To 7 ' datex: last day when the file should have been written according to weekdays datex = SubtractDate(date00,i) wdnowx = WeekDay(datex) If Instr(weekdays,wdnowx) Then ' exit for if we found the youngest weekday Exit For End If Next datex0 = DateValue(datex) diffd = DateDiff("d",datex0,date00) ageint = ageint + diffd End If intdif=0 matchcount=0 warnsize = 0 ' go down the hierarchy, in intdif we get the number of corresponding files CheckSubdirs Args("path") ' get return code according to intdif files return_code = np.check_threshold(CDbl(intdif)) last = "" If Len(namefilter) Then last = "filter: " & namefilter End If ' if there was only one file... If matchcount = 1 Then last = last & " found one: " & lastfile & " " & lastdat & " " & lastsize End If ' warning message if file too small or too few of them message = "" If warnsize = matchcount And warnsize > 0 Then If return_code = 0 Then return_code = 1 End If message = " TOO SMALL!!! " End If If matchcount < expectmatch Then If return_code = 0 Then return_code = 1 End If message = " NOT FOUND!!! " End If If selage = "ignore" Then agemessage = " count: " ElseIf selage = "newer" Or selage ="older" Then agemessage = selage & " than " & ageint & " " & ageunit & " : " ElseIf selage = "hour" Then agemessage = " written before " & ageint & " o-clock on " & weekdays & " : " Else agemessage = selage & ": " & age & " " & ageunit & " " End If ' for the performance data format warning and critical thresholds (no :@~) cintw=np.get_threshold_perfdat("warning") 'PerfDat(np.get_threshold("warning")) cintc=np.get_threshold_perfdat("critical") ' if we watch only a single file we will see the size in the performance data If expectmatch = 1 and matchcount = 1 Then perfdata = "size=" & lastsize Else perfdata = "count=" & Cint(intdif) & ";" & cintw & ";" & cintc End If msg = "Checking " & Replace(Args("path"),"\","/") & " " & last & " " & agemessage & intdif & " w:" & np.get_threshold("warning") & " c: " & np.get_threshold("critical") & " " & message & " |" & perfdata ' Nice Exit with msg and exitcode np.nagios_exit msg, return_code Sub CheckSubdirs(StartDir) Set FSO = CreateObject("Scripting.FileSystemObject") inlevel = 0 ' go down hierarchy ShowSubfolders FSO.GetFolder(StartDir) 'Clean up Set FSO = Nothing End Sub Sub ShowSubFolders(Folder) 'inlevel: we start with 1, so the startdir has level 1! inlevel = inlevel + 1 pt "level: " & inlevel & " Folder: " & Folder.Name & " searchdepth: " & searchdepth If (inlevel > searchdepth) And (searchdepth > 0) Then ' we are too deep! inlevel = inlevel - 1 pt "level2: " & inlevel & " Folder: " & Folder.Name Exit sub End If pt "level3: " & inlevel & " Folder: " & Folder.Name ListFiles Folder If ((inlevel < searchdepth) And (searchdepth > 0)) Or (searchdepth = 0) Then For Each Subfolder in Folder.SubFolders ' go further down ShowSubFolders Subfolder Next End If ' leave level inlevel = inlevel - 1 End Sub Sub ListFiles(Folder) Set colFiles = Folder.Files pt "in folder " & Folder.Name For Each File in colFiles matched = true 'pt "namefilter: " & namefilter & " len:" & Len(namefilter) ' if we defined a namefilter, use it (regexp!) If Len(namefilter) > 0 Then filename = File.Name 'pt "namefilter1: " & filename Set re = new regexp re.IgnoreCase = True re.Pattern = namefilter 'pt "namefilter2: " & namefilter & " len:" & Len(namefilter) If re.Test(filename) <> true Then matched = false End If End If ' now test the matched files against the age If matched = true Then ' count the matched files (we warn later if there are fewer the expectmatch files) matchcount = matchcount + 1 pt "match: " & matchcount & " file: " & File.name ' Date2 can be the DateCreated (backup of old machine, which is not time synchronized, so the created date is the date when the file was backed up to our server) Date1 = Now() If seldat = "created" Then Date2 = File.DateCreated Else Date2 = File.DateLastModified End If ' time difference between file and now dif = Cint(DateDiff(ageunit,Date2,Date1)) 'remember the last file checked (we use it later in the message) lastfile = File.name lastdat = Date2 lastsize = File.Size ' remember the count of files which where too small If CDbl(File.Size) < CDbl(size) Then warnsize = warnsize + 1 End If 'pt "c0 dif: " & dif & " age: " & age & " selage: " & selage & " seldat: " & seldat ' count the numer of files which are newer/older than given age If dif < ageint And selage = "newer" Then intdif = intdif + 1 ElseIf dif > ageint And selage = "older" Then intdif = intdif + 1 ElseIf selage = "ignore" Then intdif = intdif + 1 ElseIf selage = "hour" Then ' if selage:hour check if file has been written not after age (here age is the hour) If isnotolder(File) Then intdif = intdif + 1 End If End If End If Next End Sub Function isnotolder(File) date1 = Now() date2 = File.DateLastModified date00 = DateValue(Now) date10 = DateValue(Now) date20 = DateValue(date2) For i = 0 To 7 ' datex: last day when the file should have been written according to weekdays datex = SubtractDate(date00,i) 'date00 = DateValue(datex) wdnowx = WeekDay(datex) If Instr(weekdays,wdnowx) Then ' exit for if we found the youngest weekday Exit For End If Next ' we also need the second youngest weekday, when the file should have been written (is this english?) date00 = datex For i = 1 To 7 datex2 = SubtractDate(date00,i) wdnowx2 = WeekDay(datex2) If Instr(weekdays,wdnowx2) Then Exit For End If Next diffdx = DateDiff("d",datex,Now) ' days between expected write date and today diffh0 = DateDiff("h",date10,Now) ' hours since midnight diffd = DateDiff("d",date20,datex) ' days between written and expect to be written diffd2 = DateDiff("d",date20,datex2) ' days between second oldest expected write day and today diff1 = DateDiff("h",date20,date2) ' hour of write (we currently do not use it) ' we expect the best iswritten = 1 ' today to be written an hour passed: should be written today! If diffdx = 0 And diffh0 > ageint And diffd > 0 Then pt "if1: diffdx=0 and diffh0>0ageint and diffd>0: diffdx: " & diffdx & " diffh0: " & diffh0 & " diffd: " & diffd iswritten = 0 End If ' today to be written an hour not passed: should be written at least on second oldest expected day If diffdx = 0 And diffh0 <= ageint And diffd2 > 0 Then pt "if2: diffdx=0 and diffh0<= ageint and diffd2>0: diffdx: " & diffdx & " diffh0: " & diffh0 & " diffd2: " & diffd2 iswritten = 0 End If ' it should have been written on a day before, diffd gives a positive value: expected day passed If diffdx > 0 And diffd > 0 Then pt "if3: diffdx>0 and diffd>0 diffdx: " & diffdx & " diffd: " & diffd iswritten = 0 End If ' older the 7 days! If diffd > 7 Then pt "if4: diffd>7 diffd: " & diffd iswritten = 0 End If ' if none of the bad conditions matched, we still have iswritten=1 isnotolder = iswritten End Function Function SubtractDate(datea,ii) dateb = DateAdd("d",-ii,datea) SubtractDate = dateb End Function Function pt(strMsg) If verbose = 1 Then wscript.echo strMsg End If End Function