Using 'wsh.Run' in VBA with spaces in filepath - excel

I am having trouble with using the WSH.run command and escaping the spaces in the filepath - it works fine without spaces! I have tried using double, triple and quadruple quotation marks around each parameter/filepath but it does not like the filepath when the cmd shell is called from the VBA script. This is the script without any escaping:
Dim strFilePath As String
Dim xslFilePath As String
Dim RetVal
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
firstFilePath = "C:\Program Files\myprogram.exe"
secondFilePath = "C:\Program Files\stylesheet.xsl"
strfilepath = "D:\outputfiles\out.xls"
outpath = Mid(strFilePath, InStrRev(strFilePath, "\") + 1)
outfile = Left(strFilePath, InStrRev(strFilePath, ".") - 1)
logfile = outfile & "_errors.log"
cmd1 = firstFilePath & " -s:" & strFilePath & " -xsl:" & secondFilePath & " -o:" & outfile & ".csv > " & logfile & " 2>&1"
wsh.Run "cmd /c /s" & cmd1, 2, True
When I run the following via the command-line with the escaped filepaths the command completes successfully, so I am not sure why this is not working in Excel when it is called with the same escaping applied?
"C:\Program Files\myprogram.exe" -s:"D:\outputfiles\out.xls" -xsl:"C:\Program Files\stylesheet.xsl" -o:"D:\outputfiles\out.csv" > "D:\outputfiles\out_errors.log" 2>&1
Any advice or help appreciated.

Use this for your cmd1 line
cmd1 = """""" & firstFilePath & """ -s:""" & strFilePath & """ -xsl:""" & secondFilePath & """ -o:""" & outfile & ".csv"" > """ & logfile & """ 2>&1"""

Related

VBA Shell strips quotes from PowerShell command line

I'm trying to convert windows CRLF newline to UNIX LF newline with a POWERSHELL command. I would like a VBA macro to do that.
So far my code is:
Sub conversiontoUNIX()
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
Dim file As String, listfichiers As Variant, outputfolder As String, replace As String, command_shell As Variant
outputfolder = Environ("USERPROFILE") & "\Downloads\" & "run_param_" & Format(Date, "dd_mm_yy")
listfichiers = listfiles(outputfolder)
For filx = LBound(listfichiers) To UBound(listfichiers)
file = outputfolder & "\" & listfichiers(filx)
Requst = "PowerShell -noexit -Command (Get-Content " & file & ") -join ""`n"" > " & file & ""
command_shell = Shell(Requst, vbNormalFocus)
Next filx
End Sub
I run into an error:
How can i manage to run my code ?
Best regards,
Jouvzer
You need backslashes to preserve quotes around `n in command line:
Requst = "PowerShell -noexit -Command (Get-Content " & file & _
") -join \""`n\"" > " & file & ""
The error message indicates that the "" was removed and the backtick-newline character is not understood. Try adding another pair of double quotes around the
`n

VBA code to copy and replace a file directly into a .zip folder?

So I'm trying to make a macro that replaces the vbaProject.bin of a selected Excel workbook (in the "filename.zip/xl" folder), but I'm running into a problem with actually copying the update vbaProject.bin into the zip folder. The first line I tried (now commented out) was:
Call fso.CopyFile(tempBinFile, newFileName & "\xl\", True)
Which gave me an error that it couldn't find that path, which I assume is because it's within a zip file. So next I tried this line:
ShellApp.Namespace(newFileName & "\xl\").CopyHere tempBinFile, 16
Which didn't give an error, but also doesn't appear to have actually done anything. Is there a way to directly paste (and replace) into a subfolder of a zip file using VBA? I also tried unzipping the file first and then re-zipping, but I was getting different errors with that, so if anyone has a good solution for doing that instead, that would also be helpful.
Sub ReplaceVBABin()
Dim strFileName As String
Dim newFileName As String
Dim pathName As String
Dim tempBinFile As String
Dim xlFolderName As String
Dim fso As Object
Dim ShellApp As Object
Set ShellApp = CreateObject("Shell.Application")
Set fso = VBA.CreateObject("Scripting.FileSystemObject")
'Select file to patch
strFileName = Application.GetOpenFilename("Excel Macro Enabled Workbook (*.xlsm), *.xlsm")
If strFileName = "False" Then Exit Sub
'Rename file to .zip
newFileName = Replace(strFileName, ".xlsm", ".zip")
Name strFileName As newFileName
pathName = fso.GetParentFolderName(strFileName) & "\"
'Add copy of embedded vbaProject.bin to directory
tempBinFile = CreateTempBin(pathName)
'Copy and replace vbaProject.bin in folder
'Call fso.CopyFile(tempBinFile, newFileName & "\xl\", True)
ShellApp.Namespace(newFileName & "\xl\").CopyHere tempBinFile, 16
'Delete temp file
Kill tempBinFile
'Name zip file back to .xlsm
Name newFileName As strFileName
End Sub
Using the command line options for 7-Zip this shows the 3 steps extract,delete then update that you can adapt as required. It extracts the xl directory to a temporary folder, deletes the xl folder from the workbook and then replaces it with update. I think you can probably dispense with the delete, just extract, replace the vbaProject.bin file and then do update.
Sub ReplaceVBABin7z()
Const SevenZipExe = "C:\Program Files\7-Zip\7z.exe"
Const tmpDir = "c:\temp\7z\"
Dim qq As String: qq = Chr(34) '"
' check 7-zip exe exists
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.fileexists(SevenZipExe) Then
MsgBox SevenZipExe & " not found", vbCritical, "7-Zip Not found"
Exit Sub
End If
' create list of commands available
Dim cmd As String, pid As Double
'cmd = "cmd /c """ & SevenZipExe & """ >" & tmpDir & "7-Zip_Commands.txt"
'pid = Shell(cmd, vbHide)
'MsgBox "Command List see " & tmpDir & "7-Zip_Commands.txt", vbInformation, pid
Dim path As String
Dim strFileName As String, strBinName As String
' select workbook
path = ThisWorkbook.path & "\"
strFileName = Application.GetOpenFilename("Excel Macro Enabled Workbook (*.xlsm), *.xlsm")
If strFileName = "False" Then Exit Sub
strFileName = qq & strFileName & qq ' quoted for spaces in filename
ext:
' extract xl dir and sub dirs into tmpdir
cmd = qq & SevenZipExe & qq & " x -r -y -o" & qq & tmpDir & qq & " " & _
strFileName & " xl"
pid = Shell(cmd, vbHide)
Debug.Print pid, cmd
MsgBox "xl directory from " & strFileName & " extracted to " & tmpDir, vbInformation, "EXTRACT pid=" & pid
'Shell "Taskkill -pid " & pid
del:
' delete xl\vbaProject.bin dir and subdir
strBinName = "xl\vbaProject.bin"
cmd = qq & SevenZipExe & qq & " d -r " & _
strFileName & " " & strBinName
pid = Shell(cmd, vbHide)
Debug.Print pid, cmd
MsgBox strBinName & " deleted from " & strFileName, vbInformation, "DELETE pid=" & pid
'Shell "Taskkill -pid " & pid
upd:
' update xl dir and subdir
cmd = qq & SevenZipExe & qq & " u -r -y -stl " & _
strFileName & " " & qq & tmpDir & "xl" & qq
pid = Shell(cmd, vbHide)
Debug.Print pid, cmd
MsgBox strFileName & " updated from " & tmpDir, vbInformation, "UPDATE pid=" & pid
'Shell "Taskkill -pid " & pid
End Sub

Can't get WSCript.Shell object's Run method to work

I set up the following test procedure.
Private Sub TryPDF()
Dim oShell As Object
Dim App As String
Dim SrcPath As String
Dim Fn As String
App = "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe "
SrcPath = Environ("UserProfile") & "\Downloads\"
Fn = "20200509_Order_of_08_05_2020.PDF"
Shell App & SrcPath & Fn, vbNormalFocus ' opens the file
Set oShell = CreateObject("WSCript.Shell")
oShell.Run App & SrcPath & Fn, vbNormalFocus, True ' error -2147024894
Set oShell = Nothing
End Sub
The Shell command in the middle works, thereby proving that app and files exist as and where specified. However, I want the Wait property of the WSCript.Shell object and therefore want to open the file using the line oShell.Run App & SrcPath & Fn, vbNormalFocus, True. I have tested it as shown and without some and any parameters, which should just open the Acrobat Reader when totally stripped, and I always get the same error, "Method 'Run' of object 'IWshShell3' failed".
What am I doing wrong?
You have to escape the spaces in your paths (app and file) by surrounding them with double-Quotes, as the command-line uses them as argument separators. That would make
C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe
C.\Program a file named Program located on C: and that doesn't exists!
"C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"
will work as expected on command-line.
For some reasons VBA.Shell can handle the spaces in the apppath, but WScript.Shell can't.
Both will fail on not quoted paths to file, if they contain spaces.
My prefered quoting-style is the Chr(34) function
CommanQuoted = Chr(34) & "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" & Chr(34) & " " & Chr(34)
& "...\Downloads\20200509_Order_of_08_05_2020.PDF" & Chr(34)
as it is far better readable than the also useable double double-quote
CommandQuoted = """C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"" ""...\Downloads\20200509_Order_of_08_05_2020.PDF"""
Or you can create a constant that returns a double quote
Const dquote As String = """"
CommandQuoted = dquote & "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" & dquote & " " & dquote
& "...\Downloads\20200509_Order_of_08_05_2020.PDF" & dquote
Private Sub OpenPDFWithWScripShell()
Dim oShell As Object
Dim AppPathQuoted As String
Dim SrcPathQuoted As String
Dim FileName As String
Dim shellCommand As String
AppPathQuoted = Chr(34) & "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe" & Chr(34)
FileName = "20200509_Order_of_08_05_2020.PDF"
SrcPathQuoted = Chr(34) & Environ("UserProfile") & "\Downloads\" & FileName & Chr(34)
shellCommand = AppPathQuoted & " " & SrcPathQuoted
Debug.Print shellCommand
Set oShell = CreateObject("WSCript.Shell")
oShell.Run shellCommand, vbNormalFocus, True
Set oShell = Nothing
End Sub

Capture Output of WScript Shell Object

This code upload a file to a FTP Server using Putty
Dim wsh As Object
Dim waitOnReturn As Boolean
Dim windowStyle As Integer
Dim cstrSftp As String
Dim strCommand As String
Dim pUser As String
Dim pPass As String
Dim pHost As String
Dim pFile As String
Dim pRemotePath As String
Dim site As String
Dim resp As String
Set wsh = VBA.CreateObject("WScript.Shell")
'Wait the execution to finish
waitOnReturn = True
'Show the window
windowStyle = 1
'Variables
cstrSftp = """" & Application.ActiveWorkbook.Path & "\pscp.exe" & """"
site = "http://mysite/"
pUser = "user"
pPass = "password "
pHost = "ftp.mysite"
pRemotePath = "/home/"
pFile = """" & Application.ActiveWorkbook.Path & "file.png" & """"
'Command string
strCommand = "cmd /c echo n | " & cstrSftp & " -sftp -l " & pUser & " -pw " & pPass & " " & pFile & " " & pHost & ":" & pRemotePath
'Run the command
wsh.Run strCommand, windowStyle, waitOnReturn
Since the storage server is not reliable I need to capture the output to know if the upload worked. And, if it doesn't I need to know what was the message.
I thought of using the command " > C:\output.txt" to capture the output. Like this
strCommand = strCommand & " > " & """" "C:\output.txt" & """"
When the upload works my output file works too. But, when the upload doesn't work, nothing is written in the output file.
For example, when I get the message Fatal: Server unexpectedly closed network connection nothing is written in the output file. But I need to know what is the exactly messaged given.
Example for using exec to retrieve output, maybe this is useful in your case
Sub TestExec()
Dim wsh As New WshShell
Dim s As String
s = wsh.Exec("cmd /c Dir C:\ ").StdOut.ReadAll
Debug.Print s
End Sub

Access VB - Shell string problems

Trying to create the string for use with the Shell command in Access VB. The string works if written in full but if I try to use variables in the string the command does not work even if the use of variables produces exactly the full string, (in the immediate window), that works.
I suspect something is going on in the interpretation of the string version of the code but can't work out what.
Here's the code, I have used CHR(34) to produce the quotation marks that I want to show in the string. Suggestions would be so much appreciated - I don't have much hair left!
Private Sub temp()
Dim strFilePath As String
Dim strFileName As String
Dim strZipFilename As String
Dim strPDFfilename As String
Dim strShellString As String
Dim shell As Object
Dim result As Long
Set shell = CreateObject("WScript.shell")
strFilePath = "E:\Documents\Excel Spreadsheets\Roz Theremas\Access\PDFs"
strFileName = "17-03-31temp"
strZipFilename = strFilePath & "\" & strFileName & ".zip"
strZipFilename = Chr(34) & strZipFilename & Chr(34)
strPDFfilename = strFilePath & "\" & strFileName & ".pdf"
strPDFfilename = Chr(34) & strPDFfilename & Chr(34)
strShellString = Chr(34) & Chr(34) & Chr(34) & "C:\Program Files\7-Zip\7z.exe" & Chr(34) & Chr(34) & " a -tzip " & Chr(34) & strZipFilename & Chr(34) & " " & Chr(34) & strPDFfilename & Chr(34) & Chr(34)
'Non Working shell command
result = shell.Run(strShellString, 0, False)
'Working shell command
result = shell.Run("""C:\Program Files\7-Zip\7z.exe"" a -tzip ""E:\Documents\Excel Spreadsheets\Roz Theremas\Access\PDFs\17-03-31temp.zip"" ""E:\Documents\Excel Spreadsheets\Roz Theremas\Access\PDFs\17-03-31temp.pdf""", 0, False)
'Immediate Window output of strShellString
' """C:\Program Files\7-Zip\7z.exe"" a -tzip ""E:\Documents\Excel Spreadsheets\Roz Theremas\Access\PDFs\17-03-31temp.zip"" ""E:\Documents\Excel Spreadsheets\Roz Theremas\Access\PDFs\17-03-31temp.pdf"""
End Sub
My hair is saved - I worked out the answer! So, for posterity here it is.
I modified strFilePath to put quotes around the two word folder names and removed quotations from around the strZipFilename and strPDFFilename lines. I guess Shell was suffering from a surfeit of quotes.
Whilst modifying it I added a password to the zip file and changed the false to true at the end of the string command so that it would return an error code.
Thanks to anyone who spent time trying to work out what I had done.
Public Sub temp()
Dim strFilePath As String
Dim strFileName As String
Dim strZipFilename As String
Dim strPDFfilename As String
Dim strPassword As String
Dim shell As Object
Dim result As Long
Set shell = CreateObject("WScript.shell")
strPassword = "frog"
strFilePath = "E:\Documents\""Excel Spreadsheets""\""Roz Theremas""\Access\PDFs"
strFileName = "17-03-31temp"
strZipFilename = strFilePath & "\" & strFileName & ".zip"
strPDFfilename = strFilePath & "\" & strFileName & ".pdf"
result = shell.Run("""C:\Program Files\7-Zip\7z.exe"" a -tzip " & "-p" & strPassword & " " & strZipFilename & " " & strPDFfilename, 0, True)

Resources