Issues in Error handling sub in VB Script - vbscript

I have written an error handling sub in my vb script
errorNumber = DoAllWork
Sub ErrorHandling (Number, Description, i)
If Number <> 0 Then
WriteLogFileLine logfile, "Error No : " & Number & " - " & Description & " has occurred !"
Else
WriteLogFileLine logfile, "Success copying files as Err.Number : " & Err.Number & "Total " & i & " files were copied ! " & vbcrlf
End If
Err.Clear
End Sub
And I am calling it in my vb script like this
Function DoAllWork
On Error Resume Next
Err.Clear
Do Until CopyFiles.AtEndOfStream
line = CopyFiles.ReadLine
For Each line In CopyFiles
If objFSO.GetFolder(line).Files.Count <> 0 then
WriteLogFileLine logfile, "Copying files FromLocation " & Chr(34) & line & Chr(34) & " to ToLocation " & Chr(34) & ToLocation & Chr(34)
Else
WriteLogFileLine logfile, "No files present in the folder " & Chr(34) & line & Chr(34) & vbcrlf
End if
i=0
For Each File In objFSO.GetFolder(line).Files
objFSO.GetFile(File).Copy ToLocation & "\" & objFSO.GetFileName(File),True
i=i+1
Next
ErrorHandling Err.Number, Err.Description, i
Next
Loop
End Function
Now the log file which is getting created has this error messages logged in it even though the files has got copied successfully. Can someone please suggest what is wrong with this error handling technique ??
2015-12-15 15:03:47 - Copying files FromLocation "\\srv10219\archive\Article\20151116_073104" to ToLocation "C:\Users\TEMPPAHIR\LearnVB\ICCdata\Article"
2015-12-15 15:03:47 - Error No : 438 - Object doesn't support this property or method has occurred !
when I place this error handling directly after the File.copy statement, it gives me such log..
2015-12-15 16:31:55 - Error No : 438 - Object doesn't support this property or method has occurred !
2015-12-15 16:31:55 - Success copying files as Err.Number : 0
2015-12-15 16:31:55 - Total 2 files were copied !
that means for the first file which is being copied it throws an error and for the second one it gives success even though both the files has been copied successfully

I implemented this to do pretty much what you asked. What the script needed to do was take a folder and its contents that was dropped into a directory, and then copy the contents to a new folder formatted correctly where there was a poller that picked up the files and entered them in our system. I needed the script to quit on any error, especially for the last thing to do. That was to delete the folder from the source directory, but I had to make sure it got copied correctly. (You could clear the error and continue as well.)
So after each important line like a folder create or a file copy I did this check. This worked for me to do error handling. Passing the Err object itself is the best way to go.
Set FolderCreate = FSO.CreateFolder(PreStagingDirectory + "\" + FolderCreateName)
ReportErrors Err,"Error creating folder: " + PreStagingDirectory + "\" + FolderCreateName
FSO.CopyFile objFile.Path, FolderCreate.Path + "\", true
ReportErrors Err,"Error copying file: " + objFile.Path + " to location: " + FolderCreate.Path
Sub ReportErrors(ErrorObject, strExtraInformation)
'This will log any errors if they happen and the script will then quit
If ErrorObject.Number <> 0 Then
OutPutFile.WriteLine(DateTimeString + " Error Number: " & ErrorObject.Number)
OutPutFile.WriteLine(DateTimeString + " Error (Hex): " & Hex(ErrorObject.Number))
OutPutFile.WriteLine(DateTimeString + " Source: " & ErrorObject.Source)
OutPutFile.WriteLine(DateTimeString + " Description: " & ErrorObject.Description)
OutPutFile.WriteLine(DateTimeString + " Other Information: " + strExtraInformation)
OutPutFile.WriteLine(DateTimeString + " Script is quitting due to the Error Condition.")
wscript.quit
End If
End Sub
I have also done code like this. In this case I needed to catch if null was returned from a SQL query to the database. If null was returned and I try to cast the value, it caused an error.
To answer the question of should you check for errors in a sub and clear them, or check for errors all through your script really depends what you need to accomplish.
First I have to say error handling in vbscipt just sucks. Using 'On Error Resume Next', is absolutely needed but be careful where you place it. I found it is not best to place it in main, at the top, just within each function. Most important is to remember the scope, if you put it in a function, you catch the error there, and can handle it. If you only have it at as the first line of your script, you can only handle an error in main. It is needed in main, sometimes.
Also to debug any vbscript, comment out any call to that, or you will never know the problem.
ExecutionString = "select Sum(cast(Frame_Count as int)) from Sop_Instance_T"
Set objRecordSet = objConnection.Execute(ExecutionString)
TotalFrames = cdbl(objRecordSet(0))
'In case null is returned catch the exception
'that happens on the above line
If Err.Number <> 0 Then
TotalFrames = 0
Err.Clear ()
End If

Related

VBScript Error "Permission Denied" But Works Anyway

I have a VBScript setup as a logon script in my GPO. I'm having an issue where every time it runs at logon, I get Permission Denied on the line:
set lf = fso.opentextfile(lfp, 2, true)
Points of interest:
Despite the error, the script completes successfully.
The script executes without error if I run it manually.
The lfp variable points to c:\folder\folder\file.log. The file is created (when necessary) and populated appropriately (overwritten, as expected when it does exist).
If the file is created, the fso is closed before trying to opentextfile.
The user logging in does have modify permission to the path and to the file being replaced when it exists via inherited Authenticated Users permission (from c:\folder1 - see below).
If I throw in a wscript.sleep 30000 just before that line, it just waits 30 seconds to throw permissions denied.
If user is a member of local administrators group on PC, I get no errors. Again, when user is not local admin, it errors, but completes successfully.
I see the same behavior under both Windows 7 and 10.
I'm at a loss here. Here's the pertinent section of code (please excuse any poor coding practice):
'notify robocopy log file location
function seelog(log)
lf.writeline "[" & now & "] " & "See log file for details: " & log
end function
'process robocopy exit codes and write log
function writeerrors(items)
docs = items(0)
retcode = items(1)
logfile = items(2)
if docs = "c" then
name = "some stuff"
else
name = "some other stuff"
end if
If retcode = 0 Then
lf.writeline "[" & now & "] " & name & " folder was already up to date."
elseif retcode = 1 then
lf.writeline "[" & now & "] " & name & " folder was updated."
seelog(logfile)
else
lf.writeline "[" & now & "] " & name & " folder update exited with robocopy error code: " & retcode
seelog(logfile)
End If
end function
'get logged in user
un = CreateObject("WScript.Network").UserName
'check for logfile, and if not exist, create
'folder1 always exists, no need to check or create
lfp = "c:\folder1\folder2\folder3\logfile1.log"
ld1 = "c:\folder1\folder2"
ld2 = "c:\folder1\folder2\folder3"
set fso = createobject("scripting.filesystemobject")
if not fso.fileexists(lfp) then
if not fso.folderexists(ld1) then
fso.createfolder(ld1)
end if
if not fso.folderexists(ld2) then
fso.createfolder(ld2)
end if
set cf = fso.createtextfile(lfp)
cf.close
end if
'open logfile (lfp variable)
'for writing (2)
'overwrite if already exists (true)
wscript.sleep 30000
'************permission denied happens on next line on lfp var*************
Set lf = fso.OpenTextFile(lfp, 2, True)
lf.writeline "[" & now & "] " & "Script started."
lf.writeline "[" & now & "] " & "Logged in user: " & un
lf.writeline "[" & now & "] " & "========================================================="
more code writing to log file and executing robocopy....
I suppose suppressing all errors is an option, but 1) I'd rather not, and 2) I'm not clear on how to accomplish that in VBScript.
ETA:
On Error Resume Next
Set lf = fso.OpenTextFile(lfp, 2, True)
On Error Goto 0
I tested this and it does break the script. lf is not set due to the error so the following lines error out with 'object required "lf"' code 800a01a8 as expected.
I don't like doing this, but my work around was to launch the .vbs from a .bat (personal preference - I like to keep everything from one job in one script so in the future I don't have to go chasing files around).
I placed a logon.bat file in my GPO as the logon script.
#echo off
echo Launching update script...
cscript c:\folder1\script.vbs
This seems to work around the (apparently false) permissions issue I was having. I'm still curious if anyone can tell me exactly why I was seeing the behavior I saw. Does the script engine write to a temp location maybe, when calling OpenTextFile (when launching directly from the GPO) that only admin users would have access to?
On Error Resume Next will ignore the error then On Error Goto 0 will turn normal error handling back on

VbScript Error Object Cleared by On Error Statement

Kind of a novice with VbScript, and trying to implement error handling. My method is to pass the error object to a HandleErr sub, but the error apparently gets cleared by the "On Error Resume Next" statement withing the sub. Using Windows 7.
On Error Resume Next
Dim x
x = 1/0
msgbox "Original Error: " & err.Number & " - " & err.Description
if err.number <> 0 then HandleErr err
Sub HandleErr(objErr)
on error resume next '### Without this On Error statement, the script runs fine.
msgbox "Error in HandleErr: " & objErr.Number & " - " & objErr.Description '### objErr.Number becomes zero.
WScript.Quit objErr.Number
End Sub
I imagine there is a simple answer for this. Any help would be greatly appreciated.
You want to stop the skipping errors with On Error Resume Next once you reach HandleErr(). Also use Err.Clear() to reset Err object.
On Error Resume Next
Dim x
x = 1/0
MsgBox "Original Error: " & Err.Number & " - " & Err.Description
if Err.Number <> 0 then HandleErr Err
'Stop skipping lines when errors occur.
On Error Goto 0
Sub HandleErr(objErr)
MsgBox "Error in HandleErr: " & objErr.Number & " - " & objErr.Description '### objErr.Number becomes zero.
'Clear current error now you have trapped it.
Err.Clear
WScript.Quit objErr.Number
End Sub
Personally though I wouldn't pass Err into your function because Err is a global built-in object so you can still check the values without passing it in.
On Error Resume Next
Dim x
x = 1/0
MsgBox "Original Error: " & Err.Number & " - " & Err.Description
Call HandleErr()
'Stop skipping lines when errors occur.
On Error Goto 0
Sub HandleErr()
'Do we need to trap an error?
If Err.Number <> 0 Then
MsgBox "Error in HandleErr: " & Err.Number & " - " & Err.Description '### Err.Number becomes zero.
'Clear current error now you have trapped it.
Err.Clear
WScript.Quit Err.Number
End If
End Sub

Cannot trap 8004020f error in VBScript

I cannot trap the 8004020f error generated by a script in Visual Basic (CDOSYS component).
I used the "on error resume next", it traps all errors except for this one.
This error is generated in this situation:
- the mailserver I use for sending hosts mailboxes belonging to #mydomain.abc
- I try to send mail to nonexistant#mydomain.abc
That is, if I try to send an email to a non-existant user of a domain hosted on the same mailserver used for sending, this action causes the error.
This is (almost) impossible to catch!! What can I do? I have a lot of databases and my old non-existant address is found in hundredths of tables and databases!
Thanks
Put in the following in order to find the real error code, which is a decimal number. For example, 13=type mismatch.
<%
response.write("err.number=" & err.number & "<br>")
%>
OR...
I looked at my own stuff and found this:
Select Case err.Number
Case -2147220973
strRet = " Failure to Send Report Message - Server Not Found" & vbCrLf & " Error: " & err.Number & " - " & err.Description
Case -2147220975
strRet = " Failure to Send Report Message - Server Authentication Failed" & vbCrLf & " Error: " & err.Number & " - " & err.Description
Case Else
strRet = " Failure to Send Report Message - Error: " & err.Number & " - " & err.Description
End Select

VB6 - How to catch exception or error during runtime

I developed an application in VB6. In client's environment it raises runtime errors which I can't reproduce under debugger. Is there any way to get the stacktrace or location of error?
I created log file and
I used
Err.Description,Err.Source
but it gives blank values.
Please help me.
my method(......
On Error GoTo Error_Handler
.........
Error_Handler :
writeToLogFile(Err.Source,Err.Description)
You've probably done something to clear the Err object before writing to the log file. This is very, very easy to do. What you'll want to do is as soon as you detect an error has occurred, grab the error message before doing anything else. Then pass the error message to whatever logging routine you're using. E.g.:
Dim sMsg As String
On Error Goto ErrHandler
' ...code here...
Exit Function
ErrHandler:
sMsg = "Error #" & Err.Number & ": '" & Err.Description & "' from '" & Err.Source & "'"
GoLogTheError sMsg
BTW, thanks for your guys' answers helping me. I'm about half a decade late to the game of VB6. I don't do windows unless forced to. ;)
Anyhow, when doing your error checking, say among 3000 individual record query insertions, I learned a couple tricks. Consider this block of code:
'----- order number 1246-------
On Error Goto EH1246:
sSql="insert into SalesReceiptLine ( CustomerRefListID,TemplateRe..."
oConnection.Execute sSQL
sSql="SELECT TxnID FROM SalesReceiptLine WHERE RefNumber='1246'..."
oRecordset.Open sSQL, oConnection
sTxnId = oRecordset(0)
oRecordset.Close
sSql="INSERT INTO SalesReceiptLine (TxnId,SalesReceiptLineDesc,Sal..."
oConnection.Execute sSQL
EH1246:
IF Err.Number<>0 THEN
sMsg = sMsg & "Order # 1246; sTxnId = " & sTxnId & _
vbCrLf & Err.Number & ": " & Err.Description & vbCrLf
sErrOrders = sErrOrders & "1246,"
End If
On Error GoTo -1
'----- order number 1247-------
On Error Goto EH1247:
When not testing for Err.Number, you'll get a 0: on every order handled. (maybe you don't want that). The On Error GoTo -1 resets the error so that it will work again. Apparently, Err only works "once".
I wrote a php script to build the VB6 source code to run some 8000 odbc queries... :P
Do you definitely, positively have an Exit Function just above the Error_Handler:?
my method(......
On Error GoTo Error_Handler
........
Exit Sub
Error_Handler :
writeToLogFile(Err.Source,Err.Description)
"Exit Sub" should be added before you handle the Error_Handler function.....

what is the better way to handle errors in VB6

I have VB6 application , I want to put some good error handling finction in it which can tell me what was the error and exact place when it happened , can anyone suggest the good way to do this
First of all, go get MZTools for Visual Basic 6, its free and invaluable. Second add a custom error handler on every function (yes, every function). The error handler we use looks something like this:
On Error GoTo {PROCEDURE_NAME}_Error
{PROCEDURE_BODY}
On Error GoTo 0
Exit {PROCEDURE_TYPE}
{PROCEDURE_NAME}_Error:
LogError "Error " & Err.Number & " (" & Err.Description & ") in line " & Erl & _
", in procedure {PROCEDURE_NAME} of {MODULE_TYPE} {MODULE_NAME}"
Then create a LogError function that logs the error to disc. Next, before you release code add Line Numbers to every function (this is also built into MZTools). From now on you will know from the Error Logs everything that happens. If possible, also, upload the error logs and actually examine them live from the field.
This is about the best you can do for unexpected global error handling in VB6 (one of its many defects), and really this should only be used to find unexpected errors. If you know that if there is the possibility of an error occurring in a certain situation, you should catch that particular error and handle for it. If you know that an error occurring in a certain section is going to cause instability (File IO, Memory Issues, etc) warn the user and know that you are in an "unknown state" and that "bad things" are probably going happen. Obviously use friendly terms to keep the user informed, but not frightened.
a simple way without additional modules, useful for class modules:
pre-empt each function/subs:
On Error Goto Handler
handler/bubbleup:
Handler:
Err.Raise Err.Number, "(function_name)->" & Err.source, Err.Description
voila, ghetto stack trace.
I use a home-grown Error.bas module to make reporting and re-raising less cumbersome.
Here's its contents (edited for length):
Option Explicit
Public Sub ReportFrom(Source As Variant, Optional Procedure As String)
If Err.Number Then
'Backup Error Contents'
Dim ErrNumber As Long: ErrNumber = Err.Number
Dim ErrSource As String: ErrSource = Err.Source
Dim ErrDescription As String: ErrDescription = Err.Description
Dim ErrHelpFile As String: ErrHelpFile = Err.HelpFile
Dim ErrHelpContext As Long: ErrHelpContext = Err.HelpContext
Dim ErrLastDllError As Long: ErrLastDllError = Err.LastDllError
On Error Resume Next
'Retrieve Source Name'
Dim SourceName As String
If VarType(Source) = vbObject Then
SourceName = TypeName(Source)
Else
SourceName = CStr(Source)
End If
If LenB(Procedure) Then
SourceName = SourceName & "." & Procedure
End If
Err.Clear
'Do your normal error reporting including logging, etc'
MsgBox "Error " & CStr(ErrNumber) & vbLf & "Source: " & ErrSource & vbCrLf & "Procedure: " & SourceName & vbLf & "Description: " & ErrDescription & vbLf & "Last DLL Error: " & Hex$(ErrLastDllError)
'Report failure in logging'
If Err.Number Then
MsgBox "Additionally, the error failed to be logged properly"
Err.Clear
End If
End If
End Sub
Public Sub Reraise(Optional ByVal NewSource As String)
If LenB(NewSource) Then
NewSource = NewSource & " -> " & Err.Source
Else
NewSource = Err.Source
End If
Err.Raise Err.Number, NewSource, Err.Description, Err.HelpFile, Err.HelpContext
End Sub
Reporting an error is as simple as:
Public Sub Form_Load()
On Error Goto HError
MsgBox 1/0
Exit Sub
HError:
Error.ReportFrom Me, "Form_Load"
End Sub
Reraising an error is as simple as calling Error.Reraise with the new source.
Although it is possible to retrieve the Source and Procedure parameters from the call stack if you compile with symbolic debug info, it's not reliable enough to use in production applications
ON ERROR GOTO
and the
Err
object.
There is a tutorial here.
Yes, take Kris's advice and get MZTools.
You can add line numbers to section off areas of complex procedures, which ERL will report in the error handler, to track down which area is causing the error.
10
...group of statements
20
...group of statements
30
...and so on
Use on
dim errhndl as string
on error goto errhndl
errhndl:
msgbox "Error"
Use the On Error statement and the Err object.

Resources