How to run batch commands with dynamic statements? - vb.net

I am writing code in VB.NET 2.0 and want to run batch commands for FTP using FTP -s:filename command.
I have a Batch file FTP.TXT for FTP Upload. It has the following statements:
OPEN <FPT SERVER IP>
USERNAME
PASSWORD
ASC
CD FOLDERNAME
PUT D:\DRFT000009.TXT FTPDRFTIN.DRFT000009
BYE
I have to dynamically change the filename in the Batch File. Now either I can create a Batch file at runtime and then read it or I got a code to set the input stream of the Process object. But its not working as desired.
This code runs fine but here I read a static batch file FTP.TXT from the computer:
Public Sub FTP4()
Dim psi As ProcessStartInfo
Dim totalerror As String = ""
psi = New ProcessStartInfo()
psi.FileName = "FTP.EXE"
psi.Arguments = " -s:D:\FTP.TXT"
psi.RedirectStandardError = True
psi.RedirectStandardOutput = True
psi.CreateNoWindow = True
psi.WindowStyle = ProcessWindowStyle.Hidden
psi.UseShellExecute = False
Dim process As Process = process.Start(psi)
Dim error2 As String = process.StandardError.ReadToEnd()
totalerror = totalerror & error2
process.WaitForExit()
Response.Write(totalerror)
End Sub
But I want somehow to get the FTP done with custom file name for each request. This is what I tried which is not working:
Public Sub FTP5()
Dim totalerror As String = ""
Dim BatchScriptLines(6) As String
Dim process As New Process
process.StartInfo.FileName = "FTP.EXE"
process.StartInfo.UseShellExecute = False
process.StartInfo.CreateNoWindow = True
process.StartInfo.RedirectStandardInput = True
process.StartInfo.RedirectStandardOutput = True
process.StartInfo.RedirectStandardError = True
process.Start()
process.BeginOutputReadLine()
Using InputStream As System.IO.StreamWriter = process.StandardInput
InputStream.AutoFlush = True
BatchScriptLines(0) = "OPEN <FPT IP ADDRESS>"
BatchScriptLines(1) = "USERNAME"
BatchScriptLines(2) = "PASSWORD"
BatchScriptLines(3) = "ASC"
BatchScriptLines(4) = "CD SFCD40DAT"
BatchScriptLines(5) = "PUT D:\DRFT000006.TXT FTPDRFTIN.DRFT000006"
BatchScriptLines(6) = "BYE"
For Each ScriptLine As String In BatchScriptLines
InputStream.Write(ScriptLine & vbCrLf)
Next
End Using
Dim error2 As String = process.StandardError.ReadToEnd()
totalerror = totalerror & error2
process.WaitForExit()
Response.Write(totalerror)
End Sub
Please advise how I can get the "FTP -s:filename" command executed in this case. Basically I want to do something similar to single line batch file execution which I not able to do.

Being a simple text file with a clear format, you could rewrite the file passing the parameters that need to be dynamically changed
Public Sub FTP4()
' Of course I assume that, at this point your program knows the exact values '
' to pass at the procedure that rebuilds the file'
PrepareFTPFile("D:\DRFT000006.TXT", "USERNAME", "PASSWORD")
' Now you call the original code.....
Dim psi As ProcessStartInfo
Dim totalerror As String = ""
psi = New ProcessStartInfo()
psi.FileName = "FTP.EXE"
psi.Arguments = " -s:D:\FTP.TXT"
....
End Sub
Public Sub PrepareFTPFile(fileToUpload as String, username as string, userpass as string)
Using sw = new StreamWriter("D:\FTP.TXT", False)
sw.WriteLine("OPEN <FPT IP ADDRESS>")
sw.WriteLine(username)
sw.WriteLine(userpass)
sw.WriteLine("ASC")
sw.WriteLine("CD SFCD40DAT")
sw.WriteLine("PUT " + fileToUpload + " FTPDRFTIN." + Path.GetFileNameWithoutExtension(fileToUpdload))
sw.WriteLine("BYE")
End Using
End Sub

Related

Run CMD in VB.Net using files as StandardInput and StandardOutput

I'm trying to run a command in VB.Net such as:
my_program.exe < input_commands.txt > console_outputs.txt
I tried using the RedirectStandardInput :
myProcessStartInfo.FileName = programPath
myProcessStartInfo.RedirectStandardInput = True
myprocess.StartInfo = myProcessStartInfo
myprocess.Start()
And a StreamWriter to input my text file :
Dim myStreamWriter As StreamWriter = myprocess.StandardInput
For Each Line As String In System.IO.File.ReadLines(processInputFile)
myStreamWriter.WriteLine(Line)
Next
myStreamWriter.Close()
And a similar approach to get the ouputs to a file text :
startInfo.RedirectStandardOutput = True
Dim output As String = Process.StandardOutput.ReadToEnd()
But results are quite limited...
Could you please guide me toward a proper solution?
What I would do is, first read all the lines from the input_commands.txt file into mem:
Private Sub ReadInputFile(programPath as String, processInputFile as String, processOuputFile as String)
' Open the file to read from.
Dim readText() As String = File.ReadAllLines(processInputFile)
For Each s As String In readText
' Run the command through the cmd process
OutPutResults(programPath, s, processOuputFile)
Next
End Sub
and output (append) the results to console_output.txt:
Private Sub OutPutResults(programPath as String, strArgument as String, processOuputFile as String)
Dim p As New Process()
' Set it to run hidden from user
With p.StartInfo
.RedirectStandardOutput = True
.RedirectStandardError = True
.FileName = programPath
.Arguments = strArgument
.UseShellExecute = False
.CreateNoWindow = True
End With
p.Start()
' Save all output to the variable "strOutput"
Dim strOutput As String = p.StandardOutput.ReadToEnd()
' Wait for programPath .exe to finish before we handle it's output:
' (Sync method, meaning the thread won't continue until this one is finished. Use .exited if wanting to do Async)
' Also note that you can add a timeout in milliseconds to this if wanted. i.e. .WaitForExit(1000)
p.WaitForExit()
' Save the output to console_output.txt
File.AppendAllText(processOuputFile, strOutput)
End Sub
Note the above code is completely untested; I just whipped it up to give you the idea.
I wrote the following function that does the trick :
Sub runProgrammCommandsInputFileResultsOutputFile(ByVal myProcessStartInfo As ProcessStartInfo, ByVal myProcess As Process, ByVal programPath As String, ByVal commandsInputFile As String, ByVal resultsOutputFile As String)
myProcessStartInfo.FileName = programPath
myProcessStartInfo.RedirectStandardInput = True
myProcessStartInfo.RedirectStandardOutput = True
myProcessStartInfo.RedirectStandardError = True
myProcessStartInfo.UseShellExecute = False
myProcessStartInfo.CreateNoWindow = True
myProcess.StartInfo = myProcessStartInfo
myProcess.Start()
' Read commands from text file
Dim readCommandsInputFile() As String = System.IO.File.ReadAllLines(commandsInputFile)
' Open StreamWriter to StandardInput
Dim myStreamWriter As StreamWriter = myProcess.StandardInput
' Write read commands to Streamwriter openned to StandardInput
For Each s As String In readCommandsInputFile
myStreamWriter.WriteLine(s)
Next
myStreamWriter.Close()
'Read StandardOutput
Dim resultsOutputStrings As String = myProcess.StandardOutput.ReadToEnd()
' Write StandardOutput read to text file
System.IO.File.AppendAllText(resultsOutputFile, resultsOutputStrings)
End Sub

Using cmd in VB, using commands and receiving output

I need to know, if you could help me, how to insert commands in vb then they run in cmd and i get the output.
I need to do "net localgroup Administradores a58465 /add" and get the error message if there is one.
Solution: `Dim myProcess As Process = New Process
Dim s As String
myProcess.StartInfo.FileName = "c:\windows\system32\cmd.exe"
myProcess.StartInfo.UseShellExecute = False
myProcess.StartInfo.CreateNoWindow = True
myProcess.StartInfo.RedirectStandardInput = True
myProcess.StartInfo.RedirectStandardOutput = True
myProcess.StartInfo.RedirectStandardError = True
myProcess.Start()
Dim sIn As System.IO.StreamWriter = myProcess.StandardInput
Dim sOut As System.IO.StreamReader = myProcess.StandardOutput
Dim sErr As System.IO.StreamReader = myProcess.StandardError
'sIn.AutoFlush = True
sIn.Write("cls" & System.Environment.NewLine)
sIn.Write("net user" & System.Environment.NewLine)
sIn.Write("exit" & System.Environment.NewLine)
s = sOut.ReadToEnd()
If Not myProcess.HasExited Then
myProcess.Kill()
End If
LB1.Text = s
LB1.Visible = True
sIn.Close()
sOut.Close()
sErr.Close()
myProcess.Close()`
Check out Process.Start. http://msdn.microsoft.com/en-us/library/0w4h05yb(v=vs.110).aspx
Also look for the ProcessStartInfo class, which will give you options on how to kick off an external process.
Console input and output can be made available to your program through ProcessStartInfo.

How to start a visible process

I have the following code to start the program R (even though I think that the program is not relevent for the problem here) and run a script:
Public Shared Sub RunRScript(rCodeFilePath As String, rScriptExecutablePath As String, args As String)
Dim file As String = rCodeFilePath
Dim result As String = String.Empty
Try
Dim info = New ProcessStartInfo()
info.FileName = rScriptExecutablePath
info.WorkingDirectory = Path.GetDirectoryName(rScriptExecutablePath)
info.Arguments = rCodeFilePath & " " & args
info.RedirectStandardInput = False
info.RedirectStandardOutput = True
info.UseShellExecute = False
info.CreateNoWindow = True
Using proc = New Process()
proc.StartInfo = info
proc.Start()
result = proc.StandardOutput.ReadToEnd()
proc.Close()
End Using
Catch ex As Exception
Throw New Exception("R Script failed: " & result, ex)
End Try
End Sub
Problem is, if there is an error in the script I run within R I dont get an error message because the instance is invisible. I tried to make it visible with
.WindowStyle = ProcessWindowStyle.Normal
in all combinations of .UseShellExcecute and .CreateNoWindow but this is not working. Could anyone help me to can make my process visible?
Since you are redirecting StandardInput and StandardOutput, you should now redirect StandardError to trap the errors also.
More info available on MSDN

How to Copy CMD Results into Textbox on VB.Net Project

I'm working on a Project by VB.net and i'm using CMD to excute commands i want to Know how to copy the Results of the CMD into a textbox on my Main Form
Take a look at the accepted answer here: Get the output of a shell Command in VB.net. That is probably what you need.
Also, here is a version of the code that puts the result into the textbox:
Dim oProcess As New Process()
Dim oStartInfo As New ProcessStartInfo("ApplicationName.exe", "arguments")
oStartInfo.UseShellExecute = False
oStartInfo.RedirectStandardOutput = True
oProcess.StartInfo = oStartInfo
oProcess.Start()
Dim sOutput As String
Using oStreamReader As System.IO.StreamReader = oProcess.StandardOutput
sOutput = oStreamReader.ReadToEnd()
End Using
txtOutput.Text = sOutput 'txtOutput being the output textbox.
I hope this helps.
Dim proc As New Process
proc.StartInfo.FileName = "C:\ipconfig.bat"
proc.StartInfo.UseShellExecute = False
proc.StartInfo.RedirectStandardOutput = True
proc.Start()
proc.WaitForExit()
Dim output() As String = proc.StandardOutput.ReadToEnd.Split(CChar(vbLf))
For Each ln As String In output
RichTextBox1.AppendText(ln & vbNewLine)
lstScan.Items.Add(ln & vbNewLine)
Next
'Created a file in batch with 2 lines as shown below:
echo off
ipconfig
' save this file as ipconfig.bat or whatever name u want.
' if you didn't want that you could use any command on there like this:
echo off
dir/s
or
echo off
cd\
dir/s
pause

Any way to PGP encrypt data stream and save it directly to the FTP without having to save it locally?

I have to send PGP encrypted file in asc format to FTP folder via sFTP. Is there a way to PGP encrypt a stream (which is CSV formatted stream) and push it to the sFTP without having to save it on local machine.
Below is the function I use for PGP encryption which takes file name as param:
Private Function PGPEncrypt(ByVal FileName As String) As Boolean
Dim errorHappened As Boolean = False
Dim encodedFileName As String = String.Format("{0}{1}", FileName, ".asc")
Dim pgpRecipient As String = System.Configuration.ConfigurationManager.AppSettings.Get("PgpRecipient")
Dim psi As System.Diagnostics.ProcessStartInfo
Dim ErrorResult As String = ""
Dim Result As String = ""
Try
psi = New ProcessStartInfo(System.Configuration.ConfigurationManager.AppSettings.Get("PgpPath"))
psi.CreateNoWindow = True
psi.UseShellExecute = False
psi.Arguments = String.Format(" --armor --yes --recipient ""{0}"" --output ""{1}"" --encrypt ""{2}""", _
pgpRecipient, encodedFileName, FileName)
psi.RedirectStandardInput = True
psi.RedirectStandardOutput = True
psi.RedirectStandardError = True
ProcessPGP = System.Diagnostics.Process.Start(psi)
ProcessPGP.StandardInput.Write(m_Passphrase)
Result = ProcessPGP.StandardError.ReadToEnd()
ProcessPGP.WaitForExit()
Catch ex As Exception
errorHappened = True
Dim ReadError As New StringBuilder()
ReadError.Append(vbCrLf & "Error Detail:")
ReadError.Append(vbCrLf & ex.ToString())
OurEventLog.WriteEntry(ReadError.ToString(), EventLogEntryType.Error)
End Try
Return errorHappened
End Function
Again, the main requirement is not to save the PGP encrypted file locally and then send to FTP but PGP encrypted file must be created through a stream.
Any ideas?
UPDATE:
FTP Code:
ftp.ConnectMode = FTPConnectMode.PASV
ftp.RemoteHost = Csla.ConfigurationManager.AppSettings("FTPRemoteHost")
If _blnDiagnostics Then DiagnosticsManager.Publish("STREAM_TO_FTP: CONNECT TO FTP", DiagnosticsManager.EntryType.SuccessAudit)
ftp.Connect()
ftp.Login(strUser, strPassword)
ftp.TransferType = FTPTransferType.BINARY 'ASCII
ftp.Put(OUTBOUNDMESSAGE, pFilename)
ftp.Quit()
ftp = Nothing
OUTBOUNDMESSAGE is the System.IO.Stream.
Instead of taking the filename as an option on the command line, you can pass - to --output which directly exposes the output to the console. You can stream this data directly.
Your Arguments property would then look like this:
psi.Arguments = String.Format(" --armor --yes --recipient ""{0}"" --output - --encrypt ""{1}""", _
pgpRecipient, FileName)
When you execute the process, ProcessPGP.StandardOutput should yield the stream you need.