Return error message from batch file - windows

I'm shelling to a batch file from VBA, to launch an exec file, such as Notepad.exe. I would like to return an indication or message back to VBA if the exec file wasn't found. So far, I've been doing this by having the bat write a message to a text file, then have VBA examine this file. This approach seems a bit kludgy, but so far I haven't come across an alternate method.
#echo off
set EM="C:\Msg.txt"
if exist %EM% del %EM%
set FL=%SystemRoot%\system32\xnotepad.exe
if not exist %FL% (
echo %FL% not found > %EM%
goto done
)
Start "" %FL%
:done

in VBA,
Dim oSHELL, batchname, usr, pass, exitcode
Set oSHELL = VBA.CreateObject("WScript.Shell")
usr="username"
pass="password"
batchname="batchFile.bat"
' Arguments ToRun, Style (0=hide), Waitforend
exitcode = oSHELL.Run(""""+batchname+""" """+usr+""" """+pass+"""", 0, True)
and in your batch
exit somenumber
should return somenumber to exitcode
Actual code I used:
Sub q27097252()
Dim oSHELL, batchname, usr, pass, exitcode
Set oSHELL = VBA.CreateObject("WScript.Shell")
usr = ""
pass = ""
batchname = "c:\106x\q27097252.bat"
' Arguments ToRun, Style (0=hide), Waitforend
exitcode = oSHELL.Run("""" + batchname + """ """ + usr + """ """ + pass + """", 0, True)
MsgBox (exitcode)
End Sub
With batch c:\106x\q27097252.bat
#ECHO OFF
SETLOCAL
EXIT %time:~-1%
GOTO :EOF
Ran perfectly well for me in VBA code editor/F5 (expected result: messagebox showing 0..9 at random)
Following comment/solution when using Windows XP:
It would appear the exit /b number option simply sets errorlevel whereas exit number actually sets the termination code.
Termination code is 0 under XP since cmd.exe actually terminated normally — whereas Windows 7 (and later) appears to assign the current errorlevel as exit code for the cmd.exe process.
Hence, use exit number by preference for compatibility with XP — code adjusted to suit.

You can do this with the EXIT command. Take a look at EXIT /?

Related

MSAccess VBA Shell Command - Max Length?

I've been tearing my hair out this afternoon. From Access VBA I've been issuing a Command line via a shell to FTP a file to a 3rd party server using cURL.exe.
Things were working great until I brought my code to production where it is now failing silently. I suspect the multiple unpredictable file paths producing "strCmd" are just too long to pass thru the Command shell. >> Is there a limit? <<
fShellRun (strCmd)
curl -k -T testfile.txt --ftp-ssl --ftp-pasv -u "username\$domain:password" ftp://ftp-domain.egnyte.com/Shared/testdirectory/
This is the Shell function I am using (not mine):
Function fShellRun(sCommandStringToExecute)
Dim oShellObject, oFileSystemObject, sShellRndTmpFile
Dim oShellOutputFileToRead, iErr
Set oShellObject = CreateObject("Wscript.Shell")
Set oFileSystemObject = CreateObject("Scripting.FileSystemObject")
sShellRndTmpFile = oShellObject.ExpandEnvironmentStrings("%temp%") & oFileSystemObject.GetTempName
On Error Resume Next
oShellObject.Run sCommandStringToExecute & " > " & sShellRndTmpFile, 0, True
iErr = Err.Number
'~on error goto 0
If iErr <> 0 Then
fShellRun = ""
Exit Function
End If
'~on error goto err_skip
fShellRun = oFileSystemObject.OpenTextFile(sShellRndTmpFile, 1).ReadAll
oFileSystemObject.DeleteFile sShellRndTmpFile, True
Exit Function
err_skip:
fShellRun = ""
oFileSystemObject.DeleteFile sShellRndTmpFile, True
End Function
I am noticing strCmd longer than ~200 chars fails silently.
Questions:
Is there a string length limit using a command shell?
How might I circumvent this limit?
Thanks!
Edit: The long command string (copy/paste from debug.print) works just fine in an open command window. Leads me to think there is an issue with the shell command itself. (?)

Pipeline script vbs

I created the following script, but it only returns 0, even finding errors in DNS test.
Dim consult, objShell
Set objShell = WScript.CreateObject ("WScript.shell")
consult = objShell.run ("dcdiag /test:DNS | findstr /i failed", 0)
If consult = "0" THEN
    WScript.Echo "OK"
else
    WScript.Echo "ERROR"
end If
I understand that is not running the findstr.
Thank attention.
You don't use "Option Explicit"; that's reckless.
You don't init near/immediately after your Dims; that's error prone.
You use variables (objShell) just once; that's wasteful.
You mix data types (integer vs string) in a comparison; that's stupid.
You don't read the Docs (carefully); that's impertinent.
From the Docs:
bWaitOnReturn
Optional. Boolean value indicating whether the script should wait for
the program to finish executing before continuing to the next
statement in your script. If set to true, script execution halts until
the program finishes, and Run returns any error code returned by the
program. If set to false (the default), the Run method returns
immediately after starting the program, automatically returning 0 (not
to be interpreted as an error code).
To avoid unnecessary problems caused by missing dcdiag or different versions of findstr or mis-understanding/use of those programs, I use "minimal errorlevel setters":
type ex0.vbs, ex1.vbs
ex0.vbs
WScript.Quit 0
ex1.vbs
WScript.Quit 1
and this code:
Option Explicit
Dim consult : consult = WScript.CreateObject("WScript.Shell").Run("%comspec% /c ex0.vbs | ex1.vbs", 0, True)
If consult = "0" THEN
WScript.Echo consult, "OK"
else
WScript.Echo consult, "ERROR"
end If
output:
cscript 36531325.vbs
1 ERROR
Use
.Run("ex0.vbs | ex1.vbs", 0, True)
to see that you need a shell (%comspec%) to use a shell's features (|) and
.Run("%comspec% /c ex0.vbs | ex1.vbs", 0)
for understandig the importance of the bWaitOnReturn parameter.

How to delete all files in a directory tree older than 10 days using a VBS script?

I have a server with lots of folders inside C:\data. I talk about around 5000 subfolders, whereby each folder has a random name such as sgshVSHsXx.wjwuhHHS.
Each of those folders contains a subfolder with name DB and each of those DB folders contains some database files, also with random file names and random file extensions.
I need to go through all those DB folders and delete every file that is older than 10 days.
I presume I could use some VBS for that, but have not much experience with it. Could someone throw some light on this issue?
Thanks
Of course batch or command prompt is suited to this
forfiles /p "c:\data" /m * /s /d -10 /c "cmd /c del #path"
and is one line.
Save the following as a .vbs file
set args = wscript.arguments
if args.count <> 2 then
wscript.echo "Syntax: " & wscript.scriptname & " <path> <days>"
wscript.quit
end if
path = args(0)
killdate = date() - args(1)
arFiles = Array()
set fso = createobject("scripting.filesystemobject")
SelectFiles path, killdate, arFiles, true
nDeleted = 0
for n = 0 to ubound(arFiles)
on error resume next 'in case of 'in use' files...
arFiles(n).delete true
if err.number = 0 then
nDeleted = nDeleted + 1
end if
on error goto 0
next
sub SelectFiles(sPath,vKillDate,arFilesToKill,bIncludeSubFolders)
on error resume next
set folder = fso.getfolder(sPath)
set files = folder.files
for each file in files
dtlastmodified = null
on error resume Next
dtlastmodified = file.datelastmodified
on error goto 0
if not isnull(dtlastmodified) Then
if dtlastmodified < vKillDate then
count = ubound(arFilesToKill) + 1
redim preserve arFilesToKill(count)
set arFilesToKill(count) = file
end if
end if
next
if bIncludeSubFolders then
for each fldr in folder.subfolders
SelectFiles fldr.path,vKillDate,arFilesToKill,true
next
end if
end sub
to run:
.vbs ""
example:
c:\delete.vbs "c:\test folder\" 10
Make sure you run from an admin command prompt
#
source:http://community.spiceworks.com/scripts/show/282-delete-old-files-with-recursion

wscript exec cmd.exe /c does not report error

I try several version of Wscript exec method.
If i use a cmd.exe /C MyRequest, the execution does not report an error if the MyRequest is failing but return the error if cmd.exe /c is not used.
I was thinking that cmd.exe is reporting the return code of the call to the MPyRequest but seems not. How to retreive the return code in this case.
Here is the simplified version of my test (comment direct version to have the non failure)
Environnement will be mainly windows 7 (normaly no other system, maybe XP)
' Missing.cmd does not exist to force the failure test
'version with cmd.exe (CmdDir content is a valid and working cmd.exe)
ExecCmd = CmdDir & " /c Missing.cmd 1"
' direct version
ExecCmd = "Missing.cmd 1"
Set objShell = CreateObject("WScript.Shell")
On Error Resume Next
Set oExec = objShell.exec( ExecCmd)
' -- Post treatment ---------------------------
If ( err.Number = 0) Then
If ( oExec.ExitCode = 0 ) Then
' No error
wscript.echo "Execution OK"
Else ' Exit with error
wscript.echo "Error :" & oExec.ExitCode
end if
Else ' error on exec itself
wscript.echo "Execution. Error on object at call: " & err.Number _
& " Source: " & Err.Source & " Desc: " & Err.Description
end if
Solution based on all your reply (thanks all) [ #Damien, #Ekkehard.Horner, #Hans Passant]
check error (via on error and err.Number) for vbs internal error like bad variable/method call. This should be at exec call sub level (so not at main process if exec call is in a function/subroutine)
exec.status to wait until it change to 1. Wait is a following process checking the status, not like a shell.sleep
during this wait, catch stdout/stderr with a AtEndOfStream if life info is needed (if not, read after the close of the process)
for a timeout process, use a cycle of shell.sleep with an exit (of cycle) if timeout or other event is trapped (I use a counter associate to a clock time/sleep time in this case) and exit the loop if trigger occur associate with a exec.Terminate to kill the process in this case (depending of your need ...)
You need to check the ExitCode property.
If it is actually returning an error code, perhaps you are processing exitcode to early. Maybe add in oexec.StdOut.ReadAll() to make it wait until completion.
Perhaps you could add in something like this
....
....
Set oExec = objShell.exec(ExecCmd)
oExecResult = oexec.StdOut.ReadAll()
SessionExitCode = oexec.ExitCode
' -- Post treatment ---------------------------
If ( err.Number = 0) Then
If ( SessionExitCode = 0 ) Then
' No error
wscript.echo "Execution OK"
Else ' Exit with error
wscript.echo "Error :" & SessionExitCode
end if
Else ' error on exec itself
....
....

Shell.Run with arguments

I'm trying to run a program (with argument /config) using Shell.Run from VBS. However I'm having an exit code = 87 (cannot find the file specified).
1st piece of code I've tried:
strCommand = """c:\Program Files\Test\launch.exe""" & " /config:C:\sample.xml"
intExit = objShell.Run(strCommand, 0, True)
2nd piece of code:
Dim FileExe, Argum
FileExe = "%ProgramFiles%\Test\launch.exe"
Argum = "/config:C:\sample.xml"
RunMe FileExe, Argum
Function RunMe(FileExe, Argum)
Dim Titre, ws, Command, Exec
Titre = "Execution avec argument"
Set ws = CreateObject("WScript.Shell")
command = "cmd /c "& qq(FileExe) & " " & Argum &" "
Msgbox command, 64, Titre
Exec = ws.Run(command, 0, True)
End Function
Function qq(str)
qq = chr(34)& str &chr(34)
End Function
Of course yes, the Run command is supposed to return something.
I was here because I was hesitant about the second parameter. I found it there :
Documentation of Windows Script Host Run method, on vbsedit.com
Shell.Run returns the return value of the command line that it executes, so in this case, you will find the signification of the return code in the documentation of the Launch program, in the Test folder. (Test means what it means ...)
Of course it would ease the comprehension if the Launch program respected the conventions about the significations of the codes, but for a test you do not always enter into those details. Probably because of this, 87 remains me nothing. A missing file is a quite classical error, with code 2. But perhaps 2 would be for a data file.

Resources