run batch file xcopy from .NET (C#) and get the result - c#

I have a simple batch file:
xcopy source1 dest1
xcopy source2 dest2
I would like to run this from a .NET application, and get the result of the process (as far as I know xcopy returns 0 on success and 1 on fail), to check whether it was successful (both files copied) or not. How can I do that?
Thanks

There are three questions in this
How do I execute an external command
How to receive the output
How do I parse the result
1: Running a DOS - Command is pretty easy:
System.Diagnostics.Process.Start("xcopy","source1 dest1");
2: Now you have two possibilities to retrieve the output. The first is to change your command to "xcopy source1 dest1 >output.txt" and read the txt-file afterwards. The second is to run the thread differently:
var proc = new Process {
StartInfo = new ProcessStartInfo {
FileName = "xcopy",
Arguments = "source1 dest1",
RedirectStandardOutput = true
}
};
proc.Start();
string response=string.Empty;
while (!proc.StandardOutput.EndOfStream) {
response += proc.StandardOutput.ReadLine();
}
now response contains the response of your copy command. Now all you have to do is to parse the return value (3).
If you got problems with the last part, search on SO or write a new question for it.

Related

Running a Curl Command from C#

I'm trying to run a curl command from a C# program. My code is below. When I run the code below, I get an exception that the file is not found. I want to be able to do this but I do not want to use a batch file as a parameter for the filename. That is because the arguments for my curl command are variable based upon other conditions in the C# code. My variable strCmdText has the arguments for the curl command (the source and destination files). There are other examples of this on Stackoverflow, but they all use a batch file which I'm trying to avoid.
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = "C:\\Windows\\System32\\curl.exe";
p.StartInfo.Arguments = strCmdText;
p.StartInfo.UseShellExecute = false;
p.Start();
p.WaitForExit();
I changed my code to the following:
System.Diagnostics.ProcessStartInfo p = new
System.Diagnostics.ProcessStartInfo();
p.UseShellExecute = true;
p.WorkingDirectory = "C:\\Windows\\System32\\";
p.FileName = "curl.exe";
p.ErrorDialog = true;
p.CreateNoWindow = true;
System.Diagnostics.Process.Start(p);
From a DOS prompt, curl does exist in this directory. But I still get the curl not found message.
Something has to be strange with the path here. When I put a break point in though, and view the Environment class, System32 is in the path.
Curl is available at the location: C:\Windows\System32\curl.exe
That only leaves the source file to be the culprit of a "File not found" issue.
As you're launching curl through a process, ensure that your paths are escaped properly in your startup arguments.
Alternatively, you could launch curl through cmd (through a process), you can try with the following, changing the command-line arguments from --help to suit your desired action.
string script = $"\"C:\\Windows\\System32\\curl.exe\" --help";
Process process = new Process()
{
StartInfo = new ProcessStartInfo()
{
FileName = "cmd",
Arguments = script
}
};
process.Start();
Please note that this is in principle, essentially using a batch file as it's just throwing some commands into a cmd.
I had the exact same problem. Just delete curl.exe from System32 and place it on another folder (dont't forget the dependences, dlls, etc.).
Then in the line
p.StartInfo.FileName = "C:\\Windows\\System32\\curl.exe";
Overwrite "C:\\Windows\\System32\\curl.exe" to "C:\\NEW PATH\\curl.exe".
Note: You MUST delete it from System32. If you just copy to the new location it will still don't work.

Process.StandardOutput stops reading

I am trying to run a process, hide its window and then print its output in my program. I am achieving it with this code:
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = path,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
Verb = "runas"
}
};
proc.Start();
while(!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
Console.WriteLine(line);
}
It works with other programs but for this one it's stopping at some point. My guess is that it sends too much messages, because before actually loading it spams a ton of messages that say: "Initializing... n%". It reads it until it reaches around 90-95% and then stops reading. My guess is that it can't read anymore because it sent too much messages. What can I do to read the whole output?
I found out how to make a workaround. It turns out the program actually needed input inbetween the initialization and the actual result. Thanks to #Alexandru Clonțea I decided that I would not run the process, but create a .bat file, which contains the following command:
program.exe > output.txt < input.txt
Where program.exe is the executable, output.txt is the file that is going to contain the output of the program and input.txt in my case is just an empty text file so I can just get some kind of an input and make the program finish.

Invoke pdftohtml.exe via C#

I want to convert a pdf file into an html file, so that I can extract the values in a table.
pdftohtml.exe can do this.
If I call the following on a command prompt I get an html page with the content from the pdf file:
pdftohtml.exe test.pdf test.html
This works as expected. Now I want to invoke this exe via C#.
I did the following:
string filename = #"C:\Temp\pdftohtml.exe";
Process proc = Process.Start(filename, "test.pdf test.html");
Unfortunately this does not work. I suspect that somehow the parameters are not past to the exe correctly.
When I call this exe via the command line with -c before the parameters I get an error:
pdftohtml.exe -c test.pdf test.html
leads to an error (rangecheck in .putdeviceprops).
Does someone know how to correctly invoke this program?
You can use the following stuff,
using System.Diagnostics;
// Prepare the process to run
ProcessStartInfo start = new ProcessStartInfo();
// Enter in the command line arguments, everything you would enter after the executable name itself
start.Arguments = arguments;
// Enter the executable to run, including the complete path
start.FileName = ExeName;
// Do you want to show a console window?
start.WindowStyle = ProcessWindowStyle.Hidden;
start.CreateNoWindow = true;
// Run the external process & wait for it to finish
using (Process proc = Process.Start(start))
{
proc.WaitForExit();
// Retrieve the app's exit code
exitCode = proc.ExitCode;
}
Usually /C will be used to execute the command and then terminate. In the above code, do modifications as required.

XCopy does not work with UseShellExecute = false

I am trying to run a Batch file from .net/c# using System.Diagnostics.Process. Somehow it does not execute xcopy command of the Batch file.
Sample Batch File:
#copy test to test2 including sub directories
xcopy c:\test\ c:\test2
C# code:
public void RunMSIBatchFile(string _workingDirectory, string batchFileName)
{
var process = new Process
{
StartInfo =
{
UseShellExecute = false,
RedirectStandardOutput = true,
WorkingDirectory = _workingDirectory,
FileName = _workingDirectory + batchFileName,
CreateNoWindow = true,
RedirectStandardError = true
}
};
process.OutputDataReceived += ProcessOutputDataReceived;
process.Start();
process.BeginOutputReadLine();
process.WaitForExit(Convert.ToInt32(CommandTimeOut.TotalMilliseconds));
}
If I change UseShellExecute to true then it works but then there seems to be no way to capture standard output.
Has anyone faced such problem?
I've tested your exact code, and appear to be able to receive data just fine. However, since the read occurs asynchronously, it is possible for WaitForExit(...) to return before you have read all of the data. It appears that the end of the data is signalled by the Data property of the DataReceivedEventArgs passed to the OutputDataReceived event handler being null.
It is also worth noting that if xcopy requests input from the user (e.g. in the case of a file with the same name existing in the destination) it appears that no data is returned. You may want to check for this in your batch file, or also handle data from the Standard Error stream.

.CMD execution in C# inexplicably failing

I'm attempting to execute a .cmd process from a C# program. When I run the process in command line, i.e.
C:\Directory\Process.cmd -x 1000 -y 1000 C:\Input\input.txt
I get an appropriate result (in this case, that means that the process writes a file to:
C:\Output\output.txt
However, When I try to run this process from a simple C# program, the output file is not created. Here are a couple of my attempts:
Attempt 1)
try
{
string processName = #"C:\Directory\Process.cmd";
string argString = #" -x 1000 -y 1000 C:\Input\input.txt"; //The extra space in front of the '-x' is here on purpose
Process prs = new Process();
prs.StartInfo.UseShellExecute = false;
prs.StartInfo.RedirectStandardOutput = false;
prs.StartInfo.FileName = processName;
prs.StartInfo.Arguments = argString;
prs.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
prs.Start()
}
catch (Exception e)
{
Console.Writeline(e.Message);
}
Attempt 2)
try
{
System.Diagnostics.Process.Start(#"C:\\Directory\\Process.cmd", " -x 1000 -y 1000 C:\\Input\\input.txt";
}
catch (Exception e)
{
Console.Writeline(e.message);
}
Now, in both cases, no exceptions are thrown, and Process.cmd is accessed (it prints status updates in a shell), but the process does not create any output files. Is there something wrong with the way I am attempting to call Process.cmd, that it works properly when run directly form the command line but does not work properly when I attempt to call it from my C# program?
Thy this one?
System.Diagnostics.Process.Start("cmd.exe", #"/c C:\Directory\Process.cmd -x 1000 -y 1000 C:\Input\input.txt");
AFAIK, '#' prepends verbatim strings, wich do not requires backslash masking )
The file may be getting created, but not where you think. Use
prs.StartInfo.WorkingDirectory = "yourpath"
http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.workingdirectory.aspx
The WorkingDirectory property must be set if UserName and Password are
provided. If the property is not set, the default working directory is
%SYSTEMROOT%\system32.
If the directory is already part of the system path variable, you do
not have to repeat the directory's location in this property.
The WorkingDirectory property behaves differently when UseShellExecute
is true than when UseShellExecute is false. When UseShellExecute is
true, the WorkingDirectory property specifies the location of the
executable. If WorkingDirectory is an empty string, the current
directory is understood to contain the executable.
When UseShellExecute is false, the WorkingDirectory property is not
used to find the executable. Instead, it is used by the process that
is started and only has meaning within the context of the new process.
I deleted this after realizing that a path is passed in as an argument and was probably using hardcoded path logic for the file it writes to, but since a comment has referenced this, I'll undelete in case it is still of assistance.
So I was finally able to get my hands on the source code, and realized that the problem was in the java code... it was interpreting the project directory as the output directory. Thank you for all of the help though, you guys gave some very useful information!

Categories

Resources