Call shell vs Wscript.Shell using cmd.exe - vba

I am using the following code and it is working fine.
path = "cd C:\Program Files\bin & AppX File.txt"
Call Shell("cmd.exe /k " & path, vbNormalFocus)
However, I have to use the waitOnreturn so I changed to the following code and it is not working anymore.
path = "cd C:\Program Files\bin & AppX File.txt"
Dim wsh As Object
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
Set wsh = VBA.CreateObject("WScript.Shell")
wsh.Run ("cmd.exe /k " & path & ", windowStyle, waitOnReturn")
The error is " couldn't read file "File.txt,": no such file or directory " but the file is there.
The Filename is File.txt.
The program's name is AppX. The program allows me to run the file using cmd.exe if I first change the direction to the AppX path. Then, to run the file using cmd.exe, I need to run "AppX File.txt"
Is there something running with the WScript.Shell code

Because the file has spaces in its name, you need to enclose the path in quotation marks. So something like:
path = "cd \"C:\Program Files\bin & AppX File.txt\""

I changed
wsh.Run ("cmd.exe /k " & path & ", windowStyle, waitOnReturn")
to
wsh.Run "cmd.exe /k " & path, windowStyle, waitOnReturn
and it is working now

Related

Using Excel VBA to run a CMD command

I would like to use Excel VBA to run a CMD command.
The basic cmd command is:
"C:\Program Files\example program.exe" -w C:\Program files\outputfile.file "dir1" "dir2" "dir n+1"
The first part is the location of the program that will merge the files together.
The second part is the file location of the outputted merged files.
And the "dir1".... is the files that will be merged together.
I have code that lists the files to be merged but struggling to get the CMD code to get it so it does what I want as mentioned above. I have tried the following:
Sub RunCMD()
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
Dim locationofprogram as string
'dir of program that will do the merge
Dim outputfolder as string
'dir of where the merged file will go
Dim listoffiles as string
'list of files to be merged
wsh.Run "cmd.exe /S /C locationofprogram & " " & "-w" & " " & outputfolder & " " & listoffiles, windowStyle, waitOnReturn
End Sub
Thanks for the help!
You can always create a .bat file, run the file, then delete it.
MyFile = "C:\Bat-File\Bat-File.bat"
fnum = FreeFile()
Open MyFile For Output As #fnum
Print #fnum, "C:\Program Files\example program.exe -w C:\Program files\outputfile.file dir1 dir2 dir n+1"
Close #fnum
Shell MyFile, vbNormalFocus
' wait 10 seconds to let bat file finnish
newHour = Hour(Now())
newMinute = Minute(Now())
newSecond = Second(Now()) + 10
waitTime = TimeSerial(newHour, newMinute, newSecond)
Application.Wait waitTime
' delete bat-file
kill MyFile
I can't test that example program runs without the " around the dirĀ“s so you have to see what happens.
But if it does not work you need to double enclose the " or use & CHR(34) &
If in doubt, send the text to the Immediate Window to see if it still matches the syntax using:
Debug.Print "cmd.exe /S /C " & locationofprogram & " " & "-w" & " " & outputfolder & " " & listoffiles
If that works, use:
wsh.Run "cmd.exe /S /C " & locationofprogram & " " & "-w" & " " & outputfolder & " " & listoffiles, windowStyle, waitOnReturn

Running dir in command prompt from vba

Trying to get VBA to run dir in command prompt using a shell command:
Call Shell("Dir \\rtserver\controlleddocuments\""incoming reports""\" & Left(cmbComponent.Column(1), 3) & "\20" & Left(lstComponentLots.Column(1), 2) & "\*" & lstComponentLots.Column(1) & "* /b /a-d > C:\users\public\tmpcomponentsearch.txt", vbNormalFocus)
DoCmd.TransferText acImportDelim, "pathImport", "z_tmpcomponentsearch",
"C:\users\public\tmpcomponentsearch.txt"
Me.listScannedRecords.Requery
If I debug.print the string in the shell command I get:
Dir \\rtserver\controlleddocuments\"incoming reports"\019\2017\*1702-1015* /b /a-d > C:\users\public\tmpcomponentsearch.txt
which runs fine in command prompt, but I get a 'file not found' error when I try to run it in VBA. I'd rather not create a batch file to do this.
Thanks in advance.
Why use shell at all? Have a play with the FileSystemObject (add a reference to Microsoft Scripting Runtime). Try something along the lines of:
Dim fso As New FileSystemObject
Dim oFolder As Folder
Dim oFile As File
Dim strFolderName As String
strFolderName = "\\rtserver\controlleddocuments\""incoming reports""\019\2017"
Set oFolder = fso.GetFolder(strFolderName)
For Each oFile In oFolder.Files
If oFile.Name Like "*1702-1015*" Then
CurrentDb.Execute "INSERT INTO z_tmpcomponentsearch (col_name) " & _
"VALUES ('" & Replace(oFile.Name, "'", "''") & "')"
End If
Next oFile
Set oFile = Nothing
Set oFolder = Nothing
Set fso = Nothing
I found an answer - sort of. Basically create the batch file with the dir command in it on the fly and then run it:
Public Function search_with_batch_file(searchStr As String)
Const my_filename = "C:\Users\Public\qsd_search.bat"
Dim FileNumber As Integer
Dim wsh As Object
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
FileNumber = FreeFile
'creat batch file
Open my_filename For Output As #FileNumber
Print #FileNumber, "Dir " & searchStr & " /b /a-d >
C:\users\public\tmpcomponentsearch.txt"
Print #FileNumber, "exit"
Close #FileNumber
'run batch file and wait to complete
Set wsh = VBA.CreateObject("WScript.Shell")
wsh.Run my_filename, windowStyle, waitOnReturn
'Delete batch file
Kill my_filename
End Function
The FSO method was taking about 4-5 seconds to search each time but this method was executing in less than 1 second. It would still be nice to dynamically feed commands right into command prompt without creating a batch file each time, but this works for now.
This question is (almost) already answered here.
To run a DOS command from within VBA using Shell, the command line needs to begin with cmd.exe with the /c parameter, followed by your DOS command, like this:
Shell "cmd.exe /c [your DOS command here]".
For example, to use DOS's ever-efficient DIR command to find a file (the Common Controls Library in this case), putting the (bare) results into a text file:
Shell "cmd.exe /c dir ""C:\Program Files (x86)\mscomctl.ocx"" /b /s > ""C:\MyResults.txt"""
Note that the Shell command returns control immediately to VBA and does not wait for the DOS command to complete, so we need to wait for the file to be created, and the write lock released, before using it.
For example:
Sub ShellTest()
'Uses VBA Shell command to run DOS command, and waits for completion
Dim Command As String
Dim FileName As String
Dim FileHan As Long
Dim ErrNo As Long
'Set output file for results (NB folder must already exist)
FileName = "C:\Temp\Test.txt"
'Remove output file if already exists
If Dir(FileName) > "" Then Kill FileName
'Set command string
Command = "cmd.exe /c dir ""C:\Program Files (x86)\mscomctl.ocx"" /b /s >""" & FileName & """"
'Shell out to DOS to perform the DIR command
Shell Command
'Wait for file creation
Do While Dir(FileName) = ""
Debug.Print "Waiting for file creation...", Time
DoEvents
Loop
'Wait for write lock release
ErrNo = -1
Do While ErrNo <> 0
FileHan = FreeFile 'Find an available file handle
On Error Resume Next 'Disable error trapping while attempting to gain write lock
Open FileName For Append As #FileHan 'Attempt to gain write lock - will fail with error while write lock is held by DOS
ErrNo = Err.Number 'Save error number
On Error GoTo 0 'Re-enable error trapping
Close #FileHan 'Release write lock just obtained (if successful) - fails with no error if lock not obtained
Debug.Print "Waiting for write lock release...", Time
DoEvents
Loop
'Now we can use the results file, eg open it in Notepad
Command = "cmd.exe /c notepad.exe """ & FileName & """"
Shell Command
Debug.Print "Done"
End Sub
The WScript.Shell object has a Run method that runs a DOS command and waits for completion, which leads to simpler code (but you can't do anything in VBA while waiting for completion).
Sub ShellTest2()
'Uses WScript.Shell object to run DOS command and wait for completion
Dim Command As String
Dim FileName As String
Dim FileHan As Long
Dim ErrNo As Long
'Set output file for results (NB folder must already exist)
FileName = "C:\Temp\Test.txt"
'Remove output file if already exists
If Dir(FileName) > "" Then Kill FileName
'Set command string
Command = "cmd.exe /c dir ""C:\Program Files (x86)\mscomctl.ocx"" /b /s >""" & FileName & """"
'Use the WScript shell to perform the DOS command (waits for completion)
CreateObject("WScript.Shell").Run Command, 1, True 'Change 2nd parameter to 0 to hide window
'Now we can use the results file, eg open it in Notepad
Command = "cmd.exe /c notepad.exe """ & FileName & """"
Shell Command
Debug.Print "Done"
End Sub

Run bat file from Excel using VBA

I have test.bat file contains script:
copy host_name table_name -p table_name -t "file.csv"
Normally when I click on it, it's working fine. Now, I want to run test.bat file from Excel using vba.
strPath = ws1.Range("G2").value & "\" 'Directory to folder with bat
Shell strPath & "\test.bat", vbNormalFocus
something is wrong, because I see only snapshot/clip: like something is open and close into one sec...
just resolved it:
ChDir ThisWorkbook.Path & "\folder\"
Shell ThisWorkbook.Path & "\folder\test.bat", vbNormalFocus
im not sure with VBA and shell you using, but try something like this
Dim winShell As Object: Set winShell = CreateObject("WScript.Shell")
Dim WaitOnReturn As Boolean: WaitOnReturn = False
Dim windowStyle As Integer: windowStyle = 1
'Run the desired pair of shell commands in command prompt.
Call winShell.Run("cmd /k " & command1 & " & " & command2, windowStyle, WaitOnReturn)
'Release pointer to the command prompt.
Set winShell = Nothing
just replace my commands with your command(s) and lets see if its works
edit: just for completion my commands looks like this
Dim command1 As String: command1 = "cd /d" & projectDirectoryCell.Value
Dim command2 As String: command2 = "create_sensi.bat"

Robocopy in VBA while using strings

I have a spreadsheet that we run to copy over a list of files/folders based on what we select. In each of these row's we have a few other formula's that with gather other information. What we are trying to do is use robocopy based on a cell's data using strings. Below is currently how we have it setup in VBA, but it does not seem to work.
sSource = Sheets("Sheet1").Range("A2").Value
sFile = Sheets("Sheet1").Range("F2").Value
sPath = Sheets("Sheet2").Range("C2").Value
Shell "cmd /c robocopy sSource sPath sFile"
sSource is a network drive with the full folder path (i.e. \server1\stuff\stuff2\files)
sPath is a local folder on the computer
sFile is just as it sounds, the file name
It appears that it runs successfully, but when I go to the sPath location, there are no files there, just an empty folder.
Your code is very close. You need to concatenate your variables. All that needs to change is the final line to be:
Shell "cmd /c robocopy " & sSource & " " & sPath & " " & sFile
strParms = " /s /xo /mir /zb /R:5 /W:5"
Shell "cmd /c robocopy " & sSource & " " & sPath & sFile & strParms
Replace your code line (Shell "cmd /c robocopy " & sSource & " " & sPath & " " & sFile) with above 2 lines and you'll find files in your destination folder
Actually you're missing "strParms" in your statement which I have added. I have tested and it will definitely work.

Execute .bat file from Excel VBA Macro

Im having a problem with my excel vba macro. I need it to execute a batch file which is in the same folder as the excel workbook. The code works well sometimes. I don't know whats causing the error. Here's the code:
Sub writebatch()
Sheets("code").Select
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs FileName:=ThisWorkbook.path & "\code.bat",
FileFormat:=xlTextPrinter, CreateBackup:=False
Application.DisplayAlerts = True
ThisWorkbook.Saved = True
Shell "cmd.exe /k cd " & ThisWorkbook.path & "&&code.bat"
Application.Quit
End Sub
It writes the batch file, but then doesn't execute it. Only once I got the command window to not close and it said the code.bat file could not be found. So the changedir command worked. Is it possible to run cmd.exe and run the code.bat with the relative path without having to changedir?
First of all, when you launch a CMD instance you need to enclose the entire CMD argument if you use any type of operators (&):
CMD /K "command1 & command2"
And then enclose the sub-internal arguments, like this:
CMD /K "command "path with spaces" & command"
So you need to do something like this:
Shell "cmd.exe /k ""cd " & """ & ThisWorkbook.path & """ & " && code.bat"""
Notice I've used """ to escape a quote, but I don't know the way to escape a quote in VBA.
PS: remember to also enclose the code.bat if you have spaces, but ONLY if you have spaces.
I'm pretty sure the problem is down to this line
Shell "cmd.exe /k cd " & ThisWorkbook.path & "&&code.bat"
You need a space in front of the && to separate it from the cd command and after it to separate it from the code.bat.
Shell "cmd.exe /k cd " & ThisWorkbook.path & " && code.bat"
Shell "cmd.exe /k cd /d" & ThisWorkbook.path & "&& code.bat"
here, without /d cmd will open in document folder.
by /d it will open in d drive, you may change this as per your easy.
One way to insert a quote(") into a string is by using the character code conversion function Chr(34), 34 being the ASCII value for quotes(")
I hope it will useful for you.
Dim sfilename, fileName As String
Sub Run_file_bat()
fileName = "" & ThisWorkbook.Path & "\code.bat" & ""
VBA.Shell "Explorer.exe " & fileName, vbNormalFocus
End Sub