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.
Related
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.
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.
I am using Visual C# as UI and Python in the background.
Enter the details on a visual C# form.
Clicking a button should run a Python program which should embed the details given in the form into an XML file.
Python should process the XML and ingest into a system.
Python should monitor for the success from logs and return back the value to be displayed in C# form.
Is this possible?
You could start your python in a new process in the background and pass the form items as arguments in the process start information as if you were running the python script from the command line, like so:
var start = new ProcessStartInfo
{
FileName = _pathToPythonExecutable,
Arguments = string.Format(" {0} --arg1 {1}",_pathToYourPythonScript, //formItemValue),
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = true,
RedirectStandardError = true,
WorkingDirectory = _currentWorkingDirectory
};
using (Process process = Process.Start(start))
{
// Do stuff
}
You'll see that in my start information, I have told the process to Redirect StandardInput, Standard Output and Standard Error. This is another way that you can pass data between the processes.
You would write to standard input like so:
process.StandardInput.Write(input);
process.StandardInput.Close();
Standard output and Standard Errors are streams, so you can read them like so
// This would be the same for standard error
using (StreamReader reader = process.StandardOutput)
{
result = reader.ReadToEnd();
}
I am trying to execute a batch file server-side in IIS to add a printer using the printuientry call.
The problem I am facing is that I am using the Copy To Output Directory - Copy Always and the following code:
var path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
var processInfo = new ProcessStartInfo(Path.Combine(path, "AddPrinter.bat"))
{
CreateNoWindow = true,
UseShellExecute = false,
WorkingDirectory = path,
Arguments = ipAddress,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true
};
var process = Process.Start(processInfo);
process.WaitForExit(10000);
process.Close();
Now when deugging, I have checked the values of path and its set to
file:\C:\_Projects\PrinterServerV2\bin
and I have checked to see if the file and directory exist which they do.
But I get the exception:
System.ComponentModel.Win32Exception (0x80004005): The directory name is invalid
Any ideas please??
Check if the user you had set in the iis configuration does have all privileges to run, access, write and read what you wanna do with your batch file.
Also try to change your ProcessStartInfo like the process will be cmd.exe and your batch file the argument.
I had a similar issue How to execute multiples .BAT files in C#
try AppDomain.CurrentDomain.BaseDirectory as path.
I am trying to understand why, when I call the above function, I am getting hex 0D0A every 80th column on the output I am reading.
I have a powershell script, for testing that has two lines in it for brevity's sake:
$xmlSpew = "<IISAppPoolConfig><DefaultWebSite><ApplicationPoolName>DefaultAppPool</ApplicationPoolName></DefaultWebSite><AuthN>Basic</AuthN></IISAppPoolConfig>"
Write-Output $xmlSpew
I am calling the script using the Process object with ProcessStartInfo as follows:
var psi = new ProcessStartInfo
{
WorkingDirectory = Path.GetDirectoryName(FileToRun),
FileName = FileToRun,
Arguments = Arguments,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
};
var process = new Process
{
StartInfo = psi,
EnableRaisingEvents = true,
};
FileToRun value is:
C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe
Arguments value is:
-File "C:\Program Files\MyTest\MyProgInputs\read.d\IISAppPoolConfig.ps1"
The script runs fine and I get back exit code 0, but I have this mysterious (to me) 0D0A newline every 80th char in standard out that I capture using:
var Stdout = new List<string>;
...
Stdout.Add(process.StandardOutput.ReadToEnd());
This is wreaking havoc on my XML efforts once I have standard out stored in a string var. I expected to get exactly what I write to the stdout in the ps1 script, not the extra newline.
What am I missing? I've looked for others with this issue, but I have not found an answer. Hopefully it is not me being search-challenged.
Follow this P/Invoke method and set dwXCountChars to a very large value. Don't forget to include STARTF_USECOUNTCHARS in the flags as well.
Final and tested resolution for now (because I need to ship something), is to have output from powershell come from the Write-Host cmdlet instead of Write-Output. The process for obtaining stdout remained the same as in my original post. Hope this helps others. Thanks for all the inputs.