Handling repeating return values, with individual messages - function

I have this code which works perfect for me, when running just one objShell.Run line.
Set objShell = WScript.CreateObject("WScript.Shell")
retval = objShell.Run ("cmd /c title Phase 1 & robocopy C:\this C:\that /MIR /L",1,True)
If retval < 0 Then
MsgBox "cmd aborted, return value is: " & retval
ElseIf retval > 7 Then
MsgBox "robocopy error, return value is: " & retval
Else
MsgBox "robocopy successful, return value is: " & retval
End If
How would I need to go, when I want to have multiple objShell.Run lines?
E.g.
retval = objShell.Run ("cmd /c title Phase 1 & robocopy C:\this C:\that /MIR /L",1,True)
retval = objShell.Run ("cmd /c title Phase 2 & robocopy C:\thistoo C:\thattoo /MIR /L",1,True)
retval = objShell.Run ("cmd /c title Phase 3 & robocopy C:\andthis C:\andthat /MIR /L",1,True)
I could make each retval variable unique e.g. retval1, retval2, retval3
And iterate the [If..Then..Else] statement, but that feels clunky and probably not the nicest way to go.
For me the best way would be a MsgBox showing a "report" about each individual objShell.Run line, when they are finished. Except when all lines are successful, then a MsgBox "all done" will do just fine.
In which direction do I need to start my search? Functions, arrays?

I've never used that object WScript.Shell,
but having had a look at your code, sample and explanation.
I think this is what you mean?
'-> Initialise
SequenceSteps = 3
Result = ""
ErrString = ""
MyCommandSequence(0) = "cmd /c title Phase 1 & robocopy C:\this C:\that /MIR /L"
MyCommandSequence(1) = "cmd /c title Phase 2 & robocopy C:\thistoo C:\thattoo /MIR /L"
MyCommandSequence(2) = "cmd /c title Phase 3 & robocopy C:\andthis C:\andthat /MIR /L"
'-> Process
ErrorOccurred = False
For Counta = 0 To SequenceSteps - 1
Set objShell = WScript.CreateObject("WScript.Shell")
retval = objShell.Run (MyCommandSequence(Counta), 1, True)
'-> process request result
If retval < 0 Then
ErrString = "cmd aborted, return value is: " & retval
'** NEW CODE LINE **
Exit For
ElseIf retval > 7 Then
ErrString = "robocopy error, return value is: " & retval
'** NEW CODE LINE **
Exit For
Else
Result = Result & "robocopy successful, return value is: " & retval & vbcrlf
End If
Next
'-> Display Accordingly
If Trim(ErrString) <> "" Then
MsgBox Result & vbcrlf & ErrString
Else
MsgBox "All Done"
End if
UPDATE
Re-Edited code

Related

cannot pass argument containing space to vbs function

function readFromRegistry (strRegistryKey, strDefault)
Dim WSHShell, value
On Error Resume Next
Set WSHShell = CreateObject ("WScript.Shell")
value = WSHShell.RegRead (strRegistryKey)
if err.number <> 0 then
readFromRegistry= strDefault
else
readFromRegistry=value
end if
set WSHShell = nothing
end function
function OpenWithChrome(sPage)
Dim strChrome
Dim WShellChrome
strChrome = readFromRegistry ( "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe\Path", "")
if (strChrome = "") then
strChrome = "chrome.exe"
else
strChrome = strChrome & "\chrome.exe"
end if
Set WShellChrome = CreateObject("WScript.Shell")
strChrome = """" & strChrome & """" & " " & sPage
WShellChrome.Run strChrome, 1, false
end function
OpenWithChrome "auto slides.html"
At last line i'm calling function OpenWithChrome with argument containing spaces. But it unable to open that file in my browser.
You just need to encode your space so Chrome can understand it. Change that line to:
OpenWithChrome "auto%20slides.html"
More information on encoding html files that use spaces can be found here:
HTML: href syntax : is it okay to have space in file name

cannot execute something from variable vbscript

the data of C:\highlight2.txt is :
"document.all.status1.innerText = 'component failure'"
<script>
set oFile=oFSO.OpenTextFile("C:\highlight2.txt",1)
text=oFile.ReadAll
oFile.Close
arrLines = Split(text, vbCrLf)
dim cmds
For Each strLine in arrLines
if strLine = "" Then
else
strLine
end if
next
</script>
<input value="component check progress" type="text" id="Status1" >
i need to change input field from text, but its not work, input text id was variable. thanks, the help i really appreciate it.
If you have a string containing code to execute, you need to execute it:
>> For Each s In Split("WScript.Echo 1|WScript.Echo 2", "|")
>> WScript.Echo "Statement:", s
>> Execute s
>> On Error Resume Next
>> s
>> WScript.Echo Err.Description
>> On Error GoTo 0
>> WScript.Echo "-----------"
>> Next
>>
Statement: WScript.Echo 1
1
Type mismatch
-----------
Statement: WScript.Echo 2
2
Type mismatch
-----------
>>

How to obtain last three lines content of a log file using VBScript function

Can anyone suggest me a VBscript function to get the last 3 lines of a text document (for eg: log.txt ? Below is my code which can fetch and display the entire log on my screen but I want to get only last 3 lines of the log file named log.txt.
<script type="text/Vbscript">
Option Explicit
Dim File
File = "C:\\test.txt"
'***********************************************************
Sub LoadMyFile()
myDiv.innerHTML = LoadFile(File)
End Sub
'***********************************************************
Function LoadFile(File)
On Error Resume Next
Dim fso,F,ReadMe,Tab,i,paragraphe
Set fso = CreateObject("Scripting.FileSystemObject")
Set F = fso.OpenTextFile(File,1)
LoadFile = Err.Number
If Err.Number <> 0 Then
MsgBox Err.Description,16," Error"
Exit Function
End If
ReadMe = F.ReadAll
Tab = split(ReadMe,vbcrlf)
For i = lbound(Tab) to ubound(Tab)
paragraphe=paragraphe & Tab(i) & "<br>"
Next
LoadFile = paragraphe
End Function
</script>
Code not working#Steve
<html>
<script type="text/Vbscript">
Option Explicit
Dim File
File = "C:\\test.txt"
'***********************************************************
Sub LoadMyFile()
myDiv.innerHTML = LoadFile(File)
End Sub
************************************************************
Function CheckProcesses()
dim startLine
On Error Resume Next
Dim fso,F,ReadMe,Tab,i,paragraphe
Set fso = CreateObject("Scripting.FileSystemObject")
Set F = fso.OpenTextFile(File,1)
LoadFile = Err.Number
If Err.Number <> 0 Then
MsgBox Err.Description,16," Error"
Exit Function
End If
ReadMe = F.ReadAll
Tab = split(ReadMe,vbcrlf)
For i = lbound(Tab) to ubound(Tab)
paragraphe=paragraphe & Tab(i) & "<br>"
Next
if ubound(Tab) > 2 Then
startLine = ubound(Tab) - 2
else
startLine = 0
end if
For i = startLine to ubound(Tab)
paragraphe=paragraphe & Tab(i) & "<br>"
Next
LoadFile = paragraphe
End Function
</script>
<input type="button" name="Log" id="Start" value="Log Dctm" onclick="CheckProcesses()"></html>
Thanks and regards
Deb
Another solution that avoids memory exhaustion with large files:
filename = "C:\path\to\your.txt"
numlines = 3
Set fso = CreateObject("Scripting.FileSystemObject")
'create and initialize ring buffer
ReDim buf(numlines-1)
For n = 0 To UBound(buf)
buf(n) = Null
Next
i = 0
'read lines into ring buffer
Set f = fso.OpenTextFile(filename)
Do Until f.AtEndOfStream
buf(i) = f.ReadLine
i = (i+1) Mod numlines
Loop
f.Close
'output ringbuffer content (skip null values)
For n = 1 To numlines
If Not IsNull(buf(i)) Then WScript.Echo buf(i)
i = (i+1) Mod numlines
Next
The array buf in combination with the index variable i and the modulo operation serves as a ring buffer containing the last lines read from the file (numlines at most).
At the end of the second loop (the one reading the input file), the index i points towards the array field after the one containing the last line read from the file, i.e. the beginning of the buffer.
The Null values from the array initialization let the output routine "slide" to the first content line (or the end of the buffer) if less than numlines lines were read from the file. The variable n in the output loop is just a counter so that the numlines elements from the ring buffer are read starting at index i and ending at index i-1 (modulo wrapping).
Given an array of lines (Tab), the last n lines to display start from UBound(Tab) - n + 1 and end with UBound(Tab). You should test for 'less than n lines in Tab' and for 'is last line of Tab empty (trailing EOL)'.
I am not able to test this, but If you know the UBound of the variable Tab, then the last three lines are UBound(tab)-2, UBound(tab)-1 and UBound(tab).
For i = ubound(Tab) - 2 to ubound(Tab)
paragraphe=paragraphe & Tab(i) & "<br>"
Next
Of course this requires that you have at least 3 lines in your log file, so, perhaps a little check should be done before entering the loop
dim startLine
if ubound(Tab) > 2 Then
startLine = ubound(Tab) - 2
else
startLine = 0
end if
For i = startLine to ubound(Tab)
paragraphe=paragraphe & Tab(i) & "<br>"
Next
Another solution
You can use this function :
Function ExtractLinesFromTextFile(ByRef TextFile, ByRef FromLine, ByRef ToLine)
Option Explicit
Dim Title,FromLine,ToLine,fso,Readfile,strBuff,InputFile,TotalNbLines
Title = "Extract Lines From TextFile © Hackoo 2014"
InputFile = "c:\test.txt"
Set fso = CreateObject("Scripting.FileSystemObject")
Set Readfile = Fso.OpenTextFile(InputFile,1)
strBuff = Readfile.ReadAll
TotalNbLines = Readfile.Line
Readfile.Close
MsgBox "The total number of lines in this file """& InputFile &""" = "& TotalNbLines,VbInformation,Title
'To extract the 3 last lines
MsgBox ExtractLinesFromTextFile(InputFile,TotalNbLines - 2,TotalNbLines),64,Title
'*********************************************************************************************************
Public Function ExtractLinesFromTextFile(ByRef TextFile, ByRef FromLine, ByRef ToLine) '<-- Inclusive
Const TristateUseDefault = -2 'To Open the file using the system default.
On Error Resume Next
If FromLine <= ToLine Then
With CreateObject("Scripting.FileSystemObject").OpenTextFile(TextFile,1,true,TristateUseDefault)
If Err.number <> 0 Then
MsgBox err.description,16,err.description
Exit Function
Else
Do Until .Line = FromLine Or .AtEndOfStream
.SkipLine
Loop
Do Until .Line > ToLine Or .AtEndOfStream
ExtractLinesFromTextFile = ExtractLinesFromTextFile & (.ReadLine & vbNewLine)
Loop
End If
End With
Else
MsgBox "Error to Read Line in TextFile", vbCritical,"Error to Read Line in TextFile"
End If
End Function
'*********************************************************************************************************

write lines to file and when there 5 lines in needs to execute a statement vbscript

here is a code which i wanne run on background so no windowmessages. The meaning of it is that it checks a connection. If there isn't a connection it writes a error to a file. a function reads that file if there are 5 lines it should create a event-error. The problem is that the last part doesn't work correctly.
my qeustion is can somebody fix it or help me fixing it. Here is the code:
strDirectory = "Z:\text2"
strFile = "\foutmelding.txt"
strText = "De connectie is verbroken"
strWebsite = "www.helmichbeens.com"
If PingSite(strWebsite) Then WScript.Quit 'Website is pingable - no further action required
Set objFSO = CreateObject("Scripting.FileSystemObject")
RecordSingleEvent
If EventCount >= 5 Then
objFSO.DeleteFile strDirectory & strFile
Set WshShell = WScript.CreateObject("WScript.Shell")
strCommand = "eventcreate /T Error /ID 100 /L Scripts /D " & _
Chr(34) & "Test event." & Chr(34)
WshShell.Run strcommand
End if
'------------------------------------
'Record a single event in a text file
'------------------------------------
Sub RecordSingleEvent
If Not objFSO.FolderExists(strDirectory) Then objFSO.CreateFolder(strDirectory)
Set objTextFile = objFSO.OpenTextFile(strDirectory & strFile, 8, True)
objTextFile.WriteLine(Now & strText)
objTextFile.Close
End sub
'----------------
'Ping my web site
'----------------
Function PingSite( myWebsite )
Set objHTTP = CreateObject( "WinHttp.WinHttpRequest.5.1" )
objHTTP.Open "GET", "http://" & myWebsite & "/", False
objHTTP.SetRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MyApp 1.0; Windows NT 5.1)"
On Error Resume Next
objHTTP.Send
PingSite = (objHTTP.Status = 200)
On Error Goto 0
End Function
'-----------------------------------------------
'Counts the number of lines inside the text file
'-----------------------------------------------
Function EventCount()
strData = objFSO.OpenTextFile(strDirectory & strFile,ForReading).ReadAll
arrLines = Split(strData,vbCrLf)
EventCount = UBound(arrLines)
Set objFSO = Nothing
End Function
thats the code you can copy it to see it your self. i thank you for your time and intrest
Greets helmich
It doesn't work because function EventCount sets objFSO=nothing, so,
If EventCount >= 5 Then
objFSO.DeleteFile strDirectory & strFile
fails
Use the logevent method of the Shell object
If EventCount >= 5 Then
objFSO.DeleteFile strDirectory & strFile
Set WshShell = WScript.CreateObject("WScript.Shell")
Call WshShell.LogEvent(1, "Test Event")
End if
You don't need to run a separate command
Thats not the problem is this
Windows host script gives a error
Line:41
Char:2
Translation of error: the data required for this operation are not yet available
code: 80070057
source: WinHttp.WinHttpRequest
thats the problem and i do not know how to fix it
it has something to do that he can't read the lines in the txtfile and then not execute the create event command

How to make the following code simpler with Arrays

This is by no means essential, but I would like to find out how to create more efficient code, and i'm sure this is far from efficient!
On the form disabled fields values are cleared before the form is saved.
The below code send a message to the user to inform them that they may lose some data if they leave a checkbox unchecked.
In the context of the form it all makes sense, i would just like to know a simpler methodology, i'm sure i could use an array somewhere but cant quite figure it out.
Dim couldLoseData As Boolean
Dim msgStr As String
couldLoseData = False
If (Me.chkInvSent = False) And (Not IsNull(Me.invoicedDate)) Then
couldLoseData = True
msgStr = "Invoice Sent"
End If
If (Me.chkFeePaid = False) And (Not IsNull(Me.datePaid)) Then
couldLoseData = True
If msgStr = "" Then
msgStr = "Claim Fee Paid"
Else
msgStr = msgStr & " / Claim Fee Paid"
End If
End If
If (Me.chkFeeLodged = False) And (Not IsNull(Me.lodgedDate)) Then
couldLoseData = True
If msgStr = "" Then
msgStr = "Fee Lodged"
Else
msgStr = msgStr & " / Fee Lodged"
End If
End If
If couldLoseData = True Then
If MsgBox("You will lose data in the following areas as the relevant checkboxes are unticked." & vbNewLine & vbNewLine & _
msgStr & vbNewLine & vbNewLine & "Do you wish to continue?", vbYesNo, dbNameOf) = vbNo Then
Cancel = True
End If
Else
'
'
'
' Procedure that gets carried out here
End If
No biggie but if any one could offer me a simpler solution it would be appreciated.
Cheers
Noel
I'm not sure why you think you should be using arrays. When it comes to the msgStr variable logic I would just put in the following:
msgStr = msgStr & "Invoice Sent / "
rather than the five lines of If msgstr = "" Then, etc, etc, End If lines.
Then at the end I would put in the following line
msgStr = lef(msgStr, len(msgStr) - 3) ' remove the trailing /
This then removes the trailing " / "
Purists will tell you that you should never add anything to a string you later remove. I say, so long as you leave a comment there for the next person who is reading your code, this reduces complexity of your preceding lines of code making it much easier to grasp exactly what is going on.
Whenever I'm looking for a value to be returned from a MsgBox I place the string creating in a separate line of code. Thus is much easier to see, at a glance, exactly what the code is doing.
strMsg = "You will lose data in the following areas as the relevant checkboxes are unticked." & vbNewLine & vbNewLine & _
msgStr & vbNewLine & vbNewLine & "Do you wish to continue?"
If MsgBox(strMsg, vbYesNo, dbNameOf) <> vbYes Then _
Cancel = True
If I'm only setting one value in the If statement, such as you show, I will also put in the _ and thus not require the End If.
I also prefer <> vbYes just in case something wonky should happen or if someone, not you of course, mucks with the msgbox options.
Why do you even allow the user to close the form when all the data fields have not been filled out?
Basically, to me, your logic is all in the wrong place. If you have a CLOSE button on your form (assuming you've gotten rid of the default Windows CLOSE X), you would not enable it until such time as all the data fields have been filled out appropriately.
The way I usually do this is to write a subroutine (or function) that checks all the fields that have to be filled out and enables the CLOSE button if everything is in order. Thus, the user CAN'T close the form until all the appropriate fields are filled out, except, perhaps, if you've provided a CANCEL button (in which case, you WANT to lose the data).
You don't need arrays but a simple helper method to simplify code and make it more reusable:
(just replace checkboxes and conditions in the following code)
Public Function ErrorChecker(assumption As Boolean, errorMessage As String, condition As Boolean, concatenate As Boolean) As String
Dim ret As String = [String].Empty
If Not assumption AndAlso condition Then
If concatenate Then
ret += " / "
End If
ret += errorMessage
End If
Return ret
End Function
Private Sub button1_Click(sender As Object, e As EventArgs)
Dim message As String = [String].Empty
message += ErrorChecker(checkBox1.Checked, "Error 1", value1 Is Nothing, False)
message += ErrorChecker(checkBox2.Checked, "Error 2", value2 Is Nothing, True)
message += ErrorChecker(checkBox3.Checked, "Error 3", value3 Is Nothing, True)
If message <> String.Empty Then
'messagebox
End If
End Sub
I've written a simple function to concatenate two strings that eliminates the need to worry about whether you need to strip anything off when you're done concatenating. Here's the function:
'-----------------------------------------------------------------------------
' Purpose : Concatenates two strings
' Usage : Dim MyList As String
' MyList = Conc(MyList, SomeValue)
' Notes : Eliminates the need to strip off the leading/trailing delimiter
' when building a string list
'-----------------------------------------------------------------------------
Function Conc(StartText As String, NextVal, _
Optional Delimiter As String = ", ") As String
If Len(StartText) = 0 Then
Conc = Nz(NextVal)
ElseIf Len(CStr(Nz(NextVal))) = 0 Then
Conc = StartText
Else
Conc = StartText & Delimiter & NextVal
End If
End Function
And here's how I'd rewrite your code using this function:
Dim msgStr As String
If (Me.chkInvSent = False) And (Not IsNull(Me.invoicedDate)) Then
msgStr = Conc(msgStr, "Invoice Sent", " / ")
End If
If (Me.chkFeePaid = False) And (Not IsNull(Me.datePaid)) Then
msgStr = Conc(msgStr, "Claim Fee Paid", " / ")
End If
If (Me.chkFeeLodged = False) And (Not IsNull(Me.lodgedDate)) Then
msgStr = Conc(msgStr, "Fee Lodged", " / ")
End If
If Len(msgStr) > 0 Then
If MsgBox("You will lose data in the following areas as the relevant checkboxes are unticked." & vbNewLine & vbNewLine & _
msgStr & vbNewLine & vbNewLine & "Do you wish to continue?", vbYesNo, dbNameOf) <> vbYes Then
Cancel = True
End If
Else
' Procedure that gets carried out here
End If
This is how I'd code it up
Dim couldLoseData As Boolean
Dim msgStr As String
Dim InvBoolean as boolean
Dim PaidBoolean as boolean
Dim LodgedBoolean as boolean
Dim response as integer
couldLoseData = False
InvBoolean = (Me.chkInvSent = False) And (Not IsNull(Me.invoicedDate))
PaidBoolean = (Me.chkFeePaid = False) And (Not IsNull(Me.datePaid))
LodgedBoolean = (Me.chkFeeLodged = False) And (Not IsNull(Me.lodgedDate))
couldLoseData = InvBoolean or PaidBoolean or LodgeBoolean
'if any one is true, there could be lost data.
if couldLoseData = false then
exit sub 'bail if nothing applies
'you may want a GOTO if there is stuff this sub needs to do regardless
end if
If InvBoolean = true then 'add phrase and move to new line
msgStr = msgStr & "Invoice Sent" & vbcrlf
end if
If PaidBoolean = true then 'add phrase and move to new line
msgStr = msgStr & "Claim Fee Paid" & vbcrlf
end if
If LodgedBoolean = true then 'add phrase and move to new line
msgStr = msgStr & "Fee Lodged" & vbcrlf
end if
If couldLoseData = True Then
msgStr = "You will lose data in the following areas as the relevant checkboxes are unticked." & vbcrlf & msgStr & vbcrlf
msgStr = msgStr & "Do you wish to continue?"
response = msgbox(msgstr, vbYesNo)
if response = vbno then
Cancel = True
End If
end if
If you really were looking to use an array:
Dim couldLoseData As Boolean
Dim msgStr As String
Dim ConditionsResponses(0 to 2,1)
Dim x as integer
Dim response as integer
couldLoseData = False
ConditionsResponses(0,0) = (Me.chkInvSent = False) And (Not IsNull(Me.invoicedDate))
ConditionsResponses(1,0) = (Me.chkFeePaid = False) And (Not IsNull(Me.datePaid))
ConditionsResponses(2,0) = (Me.chkFeeLodged = False) And (Not IsNull(Me.lodgedDate))
ConditionsResponses(0,1) = "Invoice Sent" & vbcrlf
ConditionsResponses(1,1) = "Claim Fee Paid" & vbcrlf
ConditionsResponses(2,1) = "Fee Lodged" & vbcrlf
couldLoseData = ConditionsResponses(0,0) or ConditionsResponses(0,0) or ConditionsResponses(0,0)
'if any one is true, there could be lost data.
for x = 0 to 2
if ConditionsResponses(x,0)= true then
msgStr = msgStr & ConditionsResponses(x,1)
end if
next x
If couldLoseData = True Then
msgStr = "You will lose data in the following areas as the relevant checkboxes are unticked." & vbcrlf & msgStr & vbcrlf
msgStr = msgStr & "Do you wish to continue?"
response = msgbox(msgstr, vbYesNo)
if response = vbno then
Cancel = True
End If
end if