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.
Related
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. (?)
Here is what I am trying to do:
Get a VBScript to run another VBScript.
get the second VBScript to post an error on completion, either 0 if successful or >0 if not back to the original script and then work on conditions Based on the error code returned.
Uninstall 2010 & copy office 2013
'Copy files from a network share to machine
Set FSO = CreateObject("Scripting.FileSystemObject")
WScript.Echo "Starting to uninstall Microsoft Office 2010 from the machine"
FSO.CopyFile "\\data01\Tools\WSM\Copy_2013.vbs", "C:\temp\Copy_2013.vbs"
FSO.CopyFile "\\data01\Tools\WSM\OffScrub10.vbs", "C:\Temp\OffScrub10.vbs"
FSO.CopyFile "\\data01\Tools\WSM\DeleteOffice13Package.vbs", "C:\temp\DeleteOffice13Package.vbs"
'Wait to execute rest of script where copied filed need to be in location
WScript.Sleep 5000
'Executes Office 2013 copy at the same time, do not wait to continue uninstalling office 2010
Set objShell = WScript.CreateObject("WScript.Shell")
Call objShell.Run("C:\temp\Copy_2013.vbs", 0, False)
WScript.Sleep 3000
'Run VBScript that uninstalls office 2010 (currently set to copy a non existent path for error capture test)
strRemoveOffice10 = "c:\Temp\offscrub10.vbs ALL /Quiet /NoCancel"
Call objShell.Run(strRemoveOffice10, 0, True)
WScript.Echo Err.Number
If Err.Number <> 0 Then WScript.Echo " Microsoft Office 2010 could not be uninstalled. Please uninstall again manually."
If Err.Number = 0 Then WScript.Echo "Microsoft Office 2010 has uninstalled from the machine"
Set objFileSys = Nothing
WScript.Quit
OffScrub10.vbs
Dim objFileSys
Set objFileSys = CreateObject("Scripting.FileSystemObject")
objFileSys.GetFolder("C:\Temp\Temp1\bla").Copy "C:\WSM\Test"
On Error Resume Next
If Err.Number <> 0 WScript.Quit Err
To enable error handling you need to put On Error Resume Next before the statement that may cause an error. Then you can return a status code like this:
Set fso = CreateObject("Scripting.FileSystemObject")
On Error Resume Next
fso.GetFolder("C:\Temp\Temp1\bla").Copy "C:\WSM\Test"
WScript.Quit Err.Number
However, since you said you want a return value >0 in case of an error and Err.Number is an unsigned integer that might be interpreted as a positive or negative value depending on its actual value, something like this might be a better choice:
Set fso = CreateObject("Scripting.FileSystemObject")
On Error Resume Next
fso.GetFolder("C:\Temp\Temp1\bla").Copy "C:\WSM\Test"
If Err Then WScript.Quit 1
WScript.Quit 0 'can be omitted, because it's the default
To check the returned value in the calling script you need to capture it in a variable. When using the Call statement like you do in your first script the return value is simply discarded. VBScript does not put return values of external commands in the Err object. You may also want to make sure that your script is being run with cscript.exe to avoid messages/popups blocking execution.
strRemoveOffice10 = "cscript.exe c:\Temp\offscrub10.vbs ALL /Quiet /NoCancel"
rc = objShell.Run(strRemoveOffice10, 0, True)
If rc = 0 Then
'OK
Else
'an error occurred
End If
Yes, you can return an exit code from your second script to the first as follows...
WScript.Quit(-1)
Where -1 is your exit code of choice.
Option Explicit
If WScript.Arguments.Count = 0 Then
' If we don't have any arguments, call ourselves to retrieve
' the exit code. It will be returned by the call to the
' Run method
Dim returnCode
returnCode = WScript.CreateObject("WScript.Shell").Run ( _
Chr(34) & WScript.ScriptFullName & Chr(34) & " myArgument " _
, 0 _
, True _
)
' Note ^ the "True"
' We need to wait for the "subprocess" to end to retrieve the exit code
Call WScript.Echo(CStr( returnCode ))
Else
' We have arguments, leave current process with exit code
Call WScript.Quit( 1234 )
End If
Quick sample for testing.
There are two elements to consider:
The called subprocess uses the WScript.Quit method to return the process exit code to the caller
The caller must wait for the subprocess to end to retrieve the exit code. The Run method will return the exit code of the subprocess
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 /?
I am playing with VBScript and I want to make a MsgBox which asks the user if they want to shut down their computer or not.
If the user clicks Yes they should see a MsgBox first then their computer starts to shutdown.
I am using this code but it doesn't work.
What is the problem?
result = MsgBox ("Shutdown?", vbYesNo, "Yes/No Exm")
Select Case result
Case vbYes
MsgBox("shuting down ...")
Option Explicit
Dim objShell
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "C:\WINDOWS\system32\shutdown.exe -r -t 0"
Case vbNo
MsgBox("Ok")
End Select
I have amended your code as per below:
Option Explicit
Dim result
result = MsgBox ("Shutdown?", vbYesNo, "Yes/No Exm")
Select Case result
Case vbYes
MsgBox("shuting down ...")
Dim objShell
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "C:\WINDOWS\system32\shutdown.exe -r -t 20"
Case vbNo
MsgBox("Ok")
End Select
The main issues were that "option explicit" has to be at the top, and as a result the "result" variable then must be declared using the "dim" keyword. The above code works fine when I executed it via the command line.
I also added a timeout of 20, but you can easily change this back to the original value of 0.
As documented Option Explicit must appear before any other statement in a script. Using it anywhere else in a script should raise a "Expected Statement" error pointing to the line with the Option Explicit statement. If you don't get that error, you have an On Error Resume Next in your code that you didn't show.
If you move the Option Explicit statement to the beginning of the script, but the shutdown still doesn't occur, you need to check the return value of the shutdown command:
rc = objShell.Run "C:\WINDOWS\system32\shutdown.exe -r -t 0", 0, True
If rc <> 0 Then MsgBox "shutdown failed with exit code " & rc & "."
The parentheses in your MsgBox statements shouldn't cause an issue as long as you pass just a single argument to the function, but I'd still remove them.
Try This:
Set Shell = CreateObject("WScript.Shell")
Answer = MsgBox("Do You Want To" & vbNewLine & "Shut Down Your Computer?",vbYesNo,"Shutdown:")
If Answer = vbYes Then
Shell.run "shutdown.exe -s -t 60"
Ending = 1
ElseIf Answer = vbNo Then
Stopping = MsgBox("Do You Wish To Quit?",vbYesNo,"Quit:")
If Stopping = vbYes Then
WScript.Quit 0
End If
End If
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.