Thursday, September 28, 2006

Remotely Check for Memory Dumps - BSODCheck.vbs

I was working on a server the other night. I was working with a developer, trying to resolve an issue that had suddenly become business critical on a Friday night after everyone had gone home. As I was clicking away, I suddenly lost connectivity to the server. Since I was working remotely over a VPN and the internet, I thought I simply dropped the network connection.

I fired up IE and tried to go to our corporate intranet and it came right up. Well, this made me wonder why I suddenly lost connectivity to the server I was just working on. After a couple of minutes the server started responding again and when I finally got logged back into the machine it had rebooted for no apparent reason.

Since our group handed over the responsibility of monitoring CIM, I have been really insulated from monitoring server’s hardware health. So I started wondering how often these servers have been randomly be rebooting and if this has been a pattern. I thought to myself what, what would be the easiest way of checking to see if a server has crashed. I could check the event log and parse all the events to see if and events have been logged.

I thought an easier way might be just to check and see if the “memory.dmp” file was in the C:\WINNT directory. What would be really handy would be to scan a bunch of computers and if a new dump had been created, send an email to myself or just fire up a popup saying so.

So, here it is: a script that will scan a list of servers for the presence of “memory.dmp” and compare its file date. This script will use the logs of the last script run as input for its current scan. This script is really designed to be run periodically, once a day or every couple of hours. So setting it up as a scheduled task would be a great idea. The script looks for the input file to start with the name “BSODCheck-“.

The script also determines the computer name by searching for “=”. Computer names should be in the following format

Computer1=
Computer2=
Server1=
Workstation1=

If you don’t include an equals sign, the script will assume that the line you have added is a comment and it will be skipped.

'BSODCheck v1.01 - 10-11-06
'
'This script will read a log file and determine if new memory dumps
'have been created by a list of servers. The script will look for
'the last log file created and then determine if any new dumps
'have occured since the last time the list has been scanned.
'
'This script detects input files based on their filenames. Correct
'filenames will start with "BSODCheck-" followed by the date and
'".log". Your first input file needs only be named "BSODCheck-.log"
'
'The script parses out computer names based on the equals sign (=).
'Examples of correct names are as follows:
'
'computer1=
'computer2=
'computer3=
'
'If your log file contains server names that are not followed by
'the equals sign, the script will ignore them and assume they are
'administrative comments.
'
'Change Log:
'1.01 - Changed loging of "datecreated" to "datemodified" because new
'dumps weren't logging correct times.
'
'This script is provided under the Creative Commons liscense located
'at http://creativecommons.org/licenses/by-nc/2.5/ . It may not
'be used for comercial purposes with out the expressed written consent
'of NateRice.com

Const OpenAsDefault = -2
Const FailIfNotExist = 0
Const CreateIfNotExist = 1
Const ForReading = 1
Const ForWriting = 2

Set oFSO = CreateObject("Scripting.FileSystemObject")
Set WshShell = WScript.CreateObject("WScript.Shell")

sNewDumps = False

'--Find current working directory--
aScriptFilename = Split(Wscript.ScriptFullName, "\")
sScriptFilename = aScriptFileName(Ubound(aScriptFilename))
sWorkingDirectory = Replace(Wscript.ScriptFullName, sScriptFilename, "")
'----------------------------------

sInputFile = FindInputFile(sWorkingDirectory)


sNow = Replace(Replace(Now(),"/","-"),":",".")
sLogFile = sWorkingDirectory & "BSODCheck-" & sNow & ".log"
Set oResultsLog = oFSO.OpenTextFile(sLogFile, ForWriting, CreateIfNotExist)
oResultsLog.WriteLine "-----------------BSODCheck LOG FILE-------------------"
oResultsLog.WriteLine "Input File: " & sInputFile
oResultsLog.WriteLine "Start Time: " & Now()
oResultsLog.WriteLine ""
sStartTime = Now()

On Error Resume Next
Set oInputFile = oFSO.OpenTextFile(sInputFile, ForReading)

sInputFileContents = oInputFile.ReadAll
If Not Err.Number = 0 Then
  oResultsLog.WriteLine "!!!!!!Error: " & Err.Number
  oResultsLog.WriteLine "!!!!!!Error Desc: " & Err.Description
  If Err.Number = 424 Then oResultsLog.WriteLine "!!!!!! No Input Log File Found."
End If

If Not Instr(sInputFileContents,"=") > 0 And Not trim(Err.Number) = "424" Then
  oResultsLog.WriteLine "ERROR!"
  oResultsLog.WriteLine "An error occured. No system names were found in the input"
  oResultsLog.WriteLine "file. System names must be followed by an equals sign."
  oResultsLog.WriteLine ""
End If
On Error Goto 0


aInputFileContents = Split(sInputFileContents,vbCRLF)

For Each sLine In aInputFileContents
  If InStr(sLine,"=") > 0 Then
    aServerName = Split(sLine,"=")
    sServerName = aServerName(0)
 
    sCheckResults = CheckForMemoryDump(sServerName)
   
    sCurrentDump = Split(sCheckResults,"|")
    sLastDump = Split(aServerName(1),"|")
   
    If IsDate(sCurrentDump(0)) And (IsDate(sLastDump(0)) Or sLastDump(0) = "0") Then
      If DateDiff("S",sLastDump(0),sCurrentDump(0)) > 0 Then
        oResultsLog.WriteLine sServerName & "=" & sCheckResults & _
        "|New Dump Since Last Log!"
        sNewDumps = True
      Else
        oResultsLog.WriteLine sServerName & "=" & sCheckResults
      End If
    Else
      oResultsLog.WriteLine sServerName & "=" & sCheckResults
    End If
  End IF
Next

oResultsLog.WriteLine ""
oResultsLog.WriteLine "Stop Time: " & Now()
oResultsLog.WriteLine "Total Time: " & ReadableTime(DateDiff("S",sStartTime,Now()))
oResultsLog.WriteLine "---------------End BSODCheck LOG FILE-----------------"
oResultsLog.Close


If sNewDumps Then
    WScript.Echo "NEW DUMPS! Please Check: " & vbCRLF & sLogFile

'----This section could be used to send an email with the results of the log file.---
'  Set oResultsLog = oFSO.OpenTextFile(sLogFile,ForReading)
'  sLogContents = oResultsLog.ReadAll
'  oResultsLog.Close
 
'  Set oMessage = CreateObject("CDO.Message")
'  oMessage.Subject = "New Memory Dumps!"
'  oMessage.From = "somebody@naterice.com"
'  oMessage.To = "somebody@somebody.com"
'  oMessage.TextBody = sLogContents
'  oMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2 _
'  oMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "mailserver"
'  oMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
'  oMessage.Configuration.Fields.Update
'  oMessage.Send
'------------------------------------------------------------------------------------
End If 
 
Set oFSO = Nothing
 
 
Function CheckForMemoryDump(sServerName)
  'This functions checks for the existance of the file "memory.dmp"
  'on a remote computer. If the file exists, the size and date
  'are returned as a string seperated by the "|" character.
  'This script is provided under the Creative Commons liscense located
  'at http://creativecommons.org/licenses/by-nc/2.5/ . It may not
  'be used for comercial purposes with out the expressed written consent
  'of NateRice.com
 
  If oFSO.FileExists("\\" & sServerName & "\c$\winnt\memory.dmp") Then
    Set fMemoryDump = oFSO.GetFile("\\" & sServerName & "\c$\winnt\memory.dmp")
    sDateCreated = fMemoryDump.DateLastModified
    sSize = ReadableBytes(fMemoryDump.Size)
   
    CheckForMemoryDump = sDateCreated & "|" & sSize
  Else
    CheckForMemoryDump = 0
  End If
End Function

Function FindInputFile(sDirectory)
  'This function scans the current working directory for files beginning
  'with the name "bsodcheck". If the file is found, it's name is parsed
  'to find the date. If the date is the lastest found in the current
  'working directory, the file name is returned as FindInputFile.
  '
  'Format: BSODCheck-10-01-2006 10.06.21PM.log
  'This script is provided under the Creative Commons liscense located
  'at http://creativecommons.org/licenses/by-nc/2.5/ . It may not
  'be used for comercial purposes with out the expressed written consent
  'of NateRice.com
 
  Set oFileList = oFSO.GetFolder(sDirectory).Files
  For Each fFile In oFileList
    If LCase(Left(fFile.Name,9)) = "bsodcheck" And Len(fFile.Name) > 13 Then
      sFileName = Replace(fFile.Name,".log","")
      sDate = Replace(sFileName,".",":",11)     
      If DateDiff("S",sLatestLogDate,sDate) > 0 Or len(sLatestLogDate) = 0 Then
        sLatestLogDate = sDate
        sLatestLog = fFile.Name
      End If
    End If
  Next

  FindInputFile = sLatestLog
End Function

Function ReadableTime(vSeconds)
  'This function creates readable time in Years:Days:Hours:Minutes:Seconds
  'From the a value (vSeconds) passed in seconds.
  '
  'This script is provided under the Creative Commons liscense located
  'at http://creativecommons.org/licenses/by-nc/2.5/ . It may not
  'be used for comercial purposes with out the expressed written consent
  'of NateRice.com

  If Not IsNumeric(vSeconds) Then
    ReadableTime = -1
    Exit Function
  End If

  vScale = "seconds"

  If vSeconds >= 60 Then
    vSeconds1 = vSeconds Mod 60
    aMinutes = Split((vSeconds / 60), ".")
    vMinutes = aMinutes(0)
    vSeconds = "." & vSeconds1
    vScale = "mm.ss"
  End If

  If vMinutes >= 60 Then
    vMinutes1 = vMinutes Mod 60
    aHours = Split((vMinutes / 60), ".")
    vHours = aHours(0)
    vMinutes = ":" & vMinutes1
    vScale = "hh:mm.ss"
  End If

  If vHours >= 24 Then
    vHours1 = vHours Mod 24
    aDays = Split((vHours / 24), ".")
    vDays = aDays(0)
    vHours = ":" & vHours1
    vScale = "dd:hh:mm.ss"
  End If

  If vDays >= 365 Then
    vDays1 = vDays Mod 365
    aYears = Split((vDays / 365), ".")
    vYears = aYears(0)
    vDays = ":" & vDays1
    vScale = "yyyy:dd:hh:mm.ss"
  End If

  ReadableTime = vYears & vDays & vHours & vMinutes & vSeconds & " (" & vScale & ")"
End Function

Function ReadableBytes(num_bytes)
  'This function will convert a value passed in bytes to a more readable
  'format with the appropriate two character suffex. Ex:
  '       1936022345 would return 1.8 GB
  '       43112345 would return 41.12 MB
  'This script is provided under the Creative Commons liscense located
  'at http://creativecommons.org/licenses/by-nc/2.5/ . It may not
  'be used for comercial purposes with out the expressed written consent
  'of NateRice.com

  If num_bytes <= 1023 Then
    ReadableBytes = num_bytes & " B" 'Bytes!
  ElseIf num_bytes <= (1024 ^ 2) And num_bytes >= 1024 Then
    ReadableBytes = Round(num_bytes / 1024, 2) & " KB" 'Kilobytes!
  ElseIf num_bytes <= (1024 ^ 3) And num_bytes >= (1024 ^ 2) Then
    ReadableBytes = Round(num_bytes / (1024 ^ 2), 2) & " MB" 'Megabytes!
  ElseIf num_bytes <= (1024 ^ 4) And num_bytes >= (1024 ^ 3) Then
    ReadableBytes = Round(num_bytes / (1024 ^ 3), 2) & " GB" 'Gigabytes!
  ElseIf num_bytes <= (1024 ^ 5) And num_bytes >= (1024 ^ 4) Then
    ReadableBytes = Round(num_bytes / (1024 ^ 4), 2) & " TB" 'Terabytes!
  ElseIf num_bytes <= (1024 ^ 6) And num_bytes >= (1024 ^ 5) Then
    ReadableBytes = Round(num_bytes / (1024 ^ 5), 2) & " PB" 'Petabytes!
  ElseIf num_bytes <= (1024 ^ 7) And num_bytes >= (1024 ^ 6) Then
    ReadableBytes = Round(num_bytes / (1024 ^ 6), 2) & " EB" 'Exabytes!
  ElseIf num_bytes <= (1024 ^ 8) And num_bytes >= (1024 ^ 7) Then
    ReadableBytes = Round(num_bytes / (1024 ^ 7), 2) & " ZB" 'Zettabytes!
  ElseIf num_bytes <= (1024 ^ 9) And num_bytes >= (1024 ^ 8) Then
    ReadableBytes = Round(num_bytes / (1024 ^ 8), 2) & " YB" 'Yottabytes!
  End If
End Function

 

Send this to:                          

Comments

said...

Thanks for sharing this wonderful script. I will try this.

10/4/2010 2:20:36 AM

Name
URL
Email
Email address is not published
Remember Me
Comments

CAPTCHA
Write the characters in the image above