Using FTP in VBA - excel

I wrote VBA code which creates a .txt file with Job-Code for an IBM host based on Excel data (Websphere MQ Define Job).
It would be cool to have the possibility to tranfer this file to the host automatically via FTP. At this point I do this manually via:
(comment: LPAR = Host-Name)
ftp <LPAR>
'user'
'password'
put 'dateiname'
It works quite fine. But I don't know how to tranfer this to the VBA code. I found a similiar question here and there this solution was posted:
Public Sub FtpSend()
Dim vPath As String
Dim vFile As String
Dim vFTPServ As String
Dim fNum As Long
vPath = ThisWorkbook.path
vFile = "path"
vFTPServ = "<LPAR>"
'Mounting file command for ftp.exe
fNum = FreeFile()
Open vPath & "\FtpComm.txt" For Output As #fNum
Print #1, "user *******" ' your login and password"
'Print #1, "cd TargetDir" 'change to dir on server
Print #1, "bin" ' bin or ascii file type to send
Print #1, "put " & vPath & "\" & vFile & " " & vFile ' upload local filename to server file
Print #1, "close" ' close connection
Print #1, "quit" ' Quit ftp program Close
Shell "ftp -n -i -g -s:" & vPath & "\FtpComm.txt " & vFTPServ, vbNormalNoFocus
SetAttr vPath & "\FtpComm.txt", vbNormal
Kill vPath & "\FtpComm.txt"
End Sub
I'm not sure if I understand the code completely. I think I create a dummy file, FtpComm.txt, with the user data and the content and use this file to open the connection and send the data.
It works, somehow, until the point
*SetAttr vPath & "\FtpComm.txt", vbNormal*
There I get the error
Runtime-Error: 55 - File already opened.
The connection to the LPAR is set at this point. But what does "SetAttr..." do? Is this the point where the Input is done? What should I do?

Two things.
First, you are opening a file under file number #fNum obtained from fNum = FreeFile(), and then just assuming that this will return 1, as in Print #1 etc.:
Open vPath & "\FtpComm.txt" For Output As #fNum
Print #1, "user *******" ' your login and password"
Change all your Print #1 to Print #fNum.
Second, you open your file for I/O, but never close it. So of course, when you try to modify its attributes or delete it, the system will complain that it's already open and in use. The solution is to close the file -- which you should always do as soon as you're done writing to/reading from a file.
Close #fNum ' add this line
' Can now manipulate the file without risking conflict
Shell "ftp -n -i -g -s:" & vPath & "\FtpComm.txt " & vFTPServ, vbNormalNoFocus
SetAttr vPath & "\FtpComm.txt", vbNormal
Kill vPath & "\FtpComm.txt"
As for what your code is doing on a high level: if you type ftp -help at the command line, you will see what those -n -i -g -s flags mean. So yes, you're writing FTP commands to file FtpComm.txt, and then supplying that file to ftp via the -s flag.
-s:filename Specifies a text file containing FTP commands; the
commands will automatically run after FTP starts.

You're on the right path and following Jean-François's answer should get you there.
If you want something you can cut and paste, you can try the code below. It's a variation of something I wrote several years ago.
The biggest caveat is that once you shell the FTP command, you have no idea if the file actually transferred until you manually check.
But, if you're limited to strict VBA, then this is the way to go:
Option Explicit
Const FTP_ADDRESS = "ftp.yourdestination.com"
Const FTP_USERID = "anon"
Const FTP_PASSWORD = "anon"
Sub Macro1()
If Not SendFtpFile_F() Then
MsgBox "Could not ftp file"
Else
MsgBox "Sent"
End If
End Sub
Function SendFtpFile_F() As Boolean
Dim rc As Integer
Dim iFreeFile As Integer
Dim sFTPUserID As String
Dim sFTPPassWord As String
Dim sWorkingDirectory As String
Dim sFileToSend As String
Const FTP_BATCH_FILE_NAME = "myFtpFile.ftp"
Const INCREASED_BUFFER_SIZE = 20480
SendFtpFile_F = False
sWorkingDirectory = "C:\YourWorkingDirectory\"
sFileToSend = "NameOfFile.txt"
On Error GoTo FtpNECAFile_EH
'Kill FTP process file if it exists
If Dir(sWorkingDirectory & FTP_BATCH_FILE_NAME) <> "" Then
Kill sWorkingDirectory & FTP_BATCH_FILE_NAME
End If
'Create FTP process file
iFreeFile = FreeFile
Open sWorkingDirectory & FTP_BATCH_FILE_NAME For Output As #iFreeFile
Print #iFreeFile, "open " & FTP_ADDRESS
Print #iFreeFile, FTP_USERID
Print #iFreeFile, FTP_PASSWORD
Print #iFreeFile, "mput " & sWorkingDirectory & sFileToSend
Print #iFreeFile, "quit"
Close #iFreeFile
'Shell command the FTP file to the server
Shell "ftp -i -w:20480 -s:" & sWorkingDirectory & FTP_BATCH_FILE_NAME
SendFtpFile_F = True
GoTo FtpNECAFile_EX
FtpNECAFile_EH:
MsgBox "Err", Err.Name
FtpNECAFile_EX:
Exit Function
End Function
Note: While stepping through code, you could type the following command in the immediate window and then copy/paste the results into a Command Window:
? Shell "ftp -i -w:20480 -s:" & sWorkingDirectory & FTP_BATCH_FILE_NAME

SetAttr is used to set the attributes of a file (or a folder). In your case it sets it back to Normal (so not hidden, readonly, etc.). However, since your file is still open from the 'Open For Output' call it will fail with the 'File already opened' error.
I don't see any reason why the SetAttr function is called though, as you are not changing the attributes anywhere else. So feel free to remove it and see if it still works.

In the first example, after the sentence
Print #1, "quit" ' Quit ftp program Close
you must close the file used for connection with the sentence:
Close #fNum
Because this file is currently used.

Related

Record in a .txt file the generated results of an .exe

I have and Excel file which contains the data for a Python code. Python code is called from a .exe, and I can see in the PowerShell the results which that code is generating.
Sub Button()
Dim strPName As String
Dim strData As String
strPName = Range("H24").Text
strData = "--inputs"
Call Shell("""" & strPName & """ """ & strData & """", vbNormalFocus)
End Sub
When I have issues in the code or with the data input, the PowerShell is switch off and I cannot review which was the issue.
I want to include in the button code an automatic .txt file generation, which records the PowerShell text and let me review it after the stop.
I found here How to save the ouput of shell command into a text file in VBA the following command:
Shell "ftp -n -i -g -s:" & vPath & "abc.txt " & vFTPServ & " >> test.txt", vbNormalFocus
But I don't know how to connect it properly in my current button.
Could you give me some suggestions of how could I solve it?

Lotus Notes: Create a text file

I am trying to create a text file in lotus notes which I am running through the agents. The agent ran successfully but the text file is not created in the path which is specified in the lotus script.
This is the lotus script code:
Option Public
Sub Initialize
MsgBox " Agent AccessUserList"
On Error GoTo HandleError
Dim session As New NotesSession
Dim myStream As NotesStream
Dim TheDate As String, filename As String
TheDate=Format(Now(),"mmdd")
filename = "C:"+"\red"+"\color"+TheDate+".txt"
MsgBox filename
Set myStream = session.Createstream()
MsgBox "MySTREAM2"
Call myStream.Open(filename, "ASCII")
MsgBox "MySTREAM3"
Call myStream.Truncate()
MsgBox "Entered View"
closeFile:
Call myStream.Close()
MsgBox "Closed"
Exit Sub
HandleError:
MsgBox "Error - " & Error &" at line number " & Erl
Exit Sub
End Sub
I have scheduled to 5 min to check whether it creates a new file in specified folder
enter image description here
And also the privileges while scheduling I used both second and third
Allow restricted operations
Allow Restricted operations with full administrator rights
But still it shows the folder as empty but the folder time would be changed when this it gets scheduled.
To test it i scheduled the agent to run locally as well as in the server. But the error is same the text file is not created.
Agent log is not having any errors.
enter image description here
I have checked in the logs as well and there is no errors. Can anyone tell what is the mistake in the above code and why my file is not getting created when the agent executes correctly.
NotesStream doesn't work for you as you just want to create an empty file.
Call myStream.Close() always deletes just now created file if it's empty at this point.
Use traditional FreeFile()/Open/Close instead:
Sub Initialize
On Error GoTo HandleError
Dim TheDate As String
Dim filename As String
Dim fileNum As Integer
TheDate = Format(Now(),"mmdd")
filename = "C:\red\color" + TheDate + ".txt"
fileNum = FreeFile
Open filename For Output As fileNum
Close fileNum
Finally:
Exit Sub
HandleError:
MsgBox "Error - " & Error &" at line number " & Erl
Resume Finally
End Sub
When a stream is truncated, property values are: • Bytes is 0 • IsEOS
is True • Position is 0
Closing a stream with zero bytes deletes the associated file.
Your file is getting created and then deleted because it's empty.

Create text file, print cell values in text file and upload to FTP server?

I am using the following code to try and create a .txt file and upload it to my FTP server. I want to create a text file called Ref.txt and insert some cell values into the text file and then upload this to my FTP server. For some reason I do not get any errors but the text file doesn't get uploaded to my FTP server.
Could someone please show me where I am going wrong?
I want to create a temporary text file called Ref.txt on the users P:/ drive then print irange("A1").value.
Dim vPath As String
Dim vFile As String
Dim vFTPServ As String
Dim fNum As Long
vPath = "P:\"
vFile = Ref & ".txt"
vFTPServ = "********"
'Mounting file command for ftp.exe
fNum = FreeFile()
Open "P:\" & Ref & ".txt" For Output As #fNum
Print #1, "hewdenportal.co.uk" ' your login and password"
Print #1, "/public_html/ns_requests" 'change to dir on server
Print #1, "bin" ' bin or ascii file type to send
Print #1, "put " & vPath & "\" & vFile & " " & vFile ' upload local filename to server file
Print #1, "close" ' close connection
Print #1, "quit" ' Quit ftp program
Close
Shell "ftp -n -i -g -s:" & vPath & Ref & ".txt" & vFTPServ, vbNormalNoFocus
SetAttr vPath & Ref & ".txt", vbNormal
Kill vPath & Ref & ".txt"
In the code fNum is the handle to your file so you should use that when printing and closing the file. In your code change Print #1 to Print #fNum.
Also change Close to Close #fNum.
In the line Shell "ftp -n -i -g -s:" & vPath & Ref & ".txt" & vFTPServ, vbNormalNoFocus the -s parameter tells ftp to execute the contents of the file. So it looks like you are creating the file and then telling ftp to upload the file using the commands in the file?
If you want to write the value of a range to the file then Print #fNum Workbooks("book_name.xlsm").Worksheets("sheet_name").Range("A1").Value will do it. If you fully qualify the cell address in this way, you always know which workbook and worksheet you are using.

Calling BAT with VBA - CMD Loads and Closes Immediately

I'm using VBA to write a command file and a BAT file which calls PLink to log in to a server and run a script. The Plink portion is now functioning as expected thanks to some help on here. Unfortunately VBA seems to be having some difficulty with opening the cmd and finding plink as a usable command.
I've tried multiple different ways of calling it, but the results are all the same. The cmd prompt opens and then closes immediately giving me an error stating:
"plink is not recognized as an internal or external command, operable program, or batch file."
The files generate perfectly, and if I run the bat file outside of VBA, it runs as expected. With the files, I keep a copy of plink.exe on the desktop. I've even tried adding a copy of cmd.exe to the desktop with the links and plink.exe as well, but I get the same problem.
Here are some of the ways I've tried, though modified for my code: 1 2 3
Here's the most recent code for the macro:
Dim vPath As String
Dim vscript As String
UserID = Range("F1").Value
Passwd = Range("F2").Value
Server = Range("F3").Value
StartDate = Range("F4").Value
EndDate = Range("F5").Value
Set fso = CreateObject("Scripting.FileSystemObject")
fso.CopyFile "C:\Program Files (x86)\PuTTY\plink.exe", "C:\Users\MikeDesktop\"
'fso.CopyFile "C:\Windows\System32\cmd.exe", "C:\Users\Mike\Desktop\"
vPath = "C:\Users\Mike\Desktop"
Open vPath & "\pcmd.txt " For Output As #1
Print #1, "cd /opt/test/srt"
Print #1, "./srt.tool " & StartDate & " " & EndDate & " > /opt/test/srt/test.txt &"
Print #1, "rm test.txt"
Print #1, "sleep 60; exit"
Close #1
Open vPath & "\Chg.bat" For Output As #1
Print #1, "plink " & UserID & "#" & Server & " -pw " & Passwd & " < " & vPath & "\pcmd.txt"
Close #1
vscript = vPath & "\Chg.bat"
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 5
wsh.Run vscript, windowStyle, waitOnReturn
Application.Wait (Now + TimeValue("0:01:00"))
Kill vPath & "\Chg.bat"
Kill vPath & "\pcmd.txt"
Kill vPath & "\plink.exe"
If someone can tell me why the cmd isn't recognizing plink as an option, that would be much appreciated
Either pass the path to plink.exe in the batch file, or make sure that %Path% includes the folder that contains plink.exe.

File open inconsistency

I'm using code to open all the files in a folder that start with a particular prefix:
folder = "C:\Users\xxx\Documents\Exception Reports\"
pref = "blah blah prefix"
file = pref & "*.xls"
exPath = folder & file
filename = Dir(exPath)
Do While filename <> ""
Workbooks.Open (filename)
...
Workbooks(filename).Close SaveChanges:=False
filename = Dir()
Loop
The first time I run the code after opening the macro, I get "Sorry we couldn't find -filename-. Is it possible it was moved, renamed, or deleted?" But the -filename- it prints is the one I want it to open, and all I have specified is the prefix I want and the file extension, so it would seem to me like it's finding it just fine if it knows the full file name. Also if I put in a message box between declaring the filename variable and starting the Do While loop, the message box prints the correct filename that I want it to open.
If I save a new file into the folder and name it something like "AA.xls", and then just have the program loop through the folder (rather than specifying the prefix), and then go back and specify the prefix, it works just fine, and continues to work until I close the program and reopen, where the process starts all over. However, this process only works if I save a new file to that folder. If I try to leave the "AA.xls" file in the folder, I get the same error with that file that I get with the others.
Thanks for any input!
Try using a CMD approach and see if you get the same problem, if you do then it's more than likely a permissions issue:
Sub SO()
Const folder As String = "C:\Users\xxx\Documents\Exception Reports\"
Const pref As String = "blah blah prefix"
Dim file As String
Dim exPath As String
Dim fileName As Variant
file = pref & "*.xls": exPath = folder & file
For Each fileName In _
Filter(Split(CreateObject("WScript.Shell").Exec("CMD /C DIR """ & exPath & """ /B /A:-D").StdOut.ReadAll, vbCrLf), ".")
Workbooks.Open CStr(folder & fileName)
'// Do code here
Workbooks(fileName).Close False
Next fileName
End Sub

Resources