Xcopy in C# - how to call it? - c#

Here I should copy file from nearby local ip address to my local system i have used the following code for copying using the Xcopy command and then launching the process but copying through Argumentsetting in code mentioned if I execute in command prompt it is copying but through code is not copying please tell what is the issue. Any ideas? what through code not copying.
string Porocess = String.Format("\"{0}\\xcopy.exe\"", Environment.SystemDirectory.ToString());
string SolutionSettings = string.Format("\"\\\\{0}\\C$\\Documents and Settings\\All Users\\Application Data\\Symantec\\Common Client\\settings.bak\"", IPaddress);
string TargetSettings = string.Format("\"C:\\Documents and Settings\\All Users\\Application Data\\Symantec\\settings.bak\"");
string Argumentsetting = /*"\"" +*/ SolutionSettings + " " + TargetSettings + " /Y";// parameters to launch process
int iret1 = LauncProcess(Porocess, Argumentsetting, Environment.SystemDirectory.ToString());
public static int LauncProcess(string sProcess, string sParams, string sWorkingDir)
{
int iRet = 0;
Process process = null;
try
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = sProcess;
startInfo.Arguments = sParams;
startInfo.WorkingDirectory = sWorkingDir;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
process = Process.Start(startInfo);
process.WaitForExit();
Console.WriteLine("Copy has finished.");
if (process.HasExited)
{
Console.WriteLine("Process has exited.");
if (process.ExitCode != 0)
{
iRet = 1;
}
else
{
iRet = 0;
}
}
else
{
iRet = 1;
}
}
catch (Exception ex)
{
iRet = 1;
}
finally
{
process.Dispose();
}
return iRet;
}

check whether source address and destination address are correctly given
Process process = new Process();
process.StartInfo.Arguments= #"D:\sourcePath F:\DestinationPath /e /y /I";
process.Start();

Related

How to read process Output Message from process within the process?

I am running an exe through commandline and getting following output.
C:\Users\sysadmin>C:\Users\sysadmin\Desktop\New_folder\Setup\PatchInstaller.exe
--mode=silent
C:\Users\sysadmin Begin Setup UI mode: Silent Error :
Another instance running, Only a single instance can be run at a time.
Exit Code: 11
i am running this through System.daignostics.process.
My issue is PatchInstaller.exe calling another process and the output of that nested process is what is visible with cmd. but the same result and exit code i am not able to get through Process object of PatchInstaller.exe.
Is there any way of getting output of process running within process?
Following is the code i have tired...
string command = #"C:\Users\sysadmin\Desktop\Setup\PatchInstaller.exe";
string result = string.Empty;
System.Diagnostics.ProcessStartInfo procStartInfo = new ProcessStartInfo();
procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command + " --mode=silent);
System.Diagnostics.Process proc = new Process();
procStartInfo.ErrorDialog = false;
procStartInfo.UseShellExecute = false;
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardError = true;
procStartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
if (!string.IsNullOrEmpty(domain) && !string.IsNullOrEmpty(user) && !string.IsNullOrEmpty(pwd))
{
procStartInfo.Domain = domain;
procStartInfo.UserName = user;
System.Security.SecureString ss = new System.Security.SecureString();
foreach (char c in pwd) { ss.AppendChar(c); }
procStartInfo.Password = ss;
}
proc = System.Diagnostics.Process.Start(procStartInfo);
proc.ErrorDataReceived += delegate(object sender, System.Diagnostics.DataReceivedEventArgs errorLine)
{
if (errorLine.Data != null) result += "error:" + errorLine.Data +;
};
proc.OutputDataReceived += delegate(object sender, System.Diagnostics.DataReceivedEventArgs outputLine)
{
if (outputLine.Data != null) result += outputLine.Data +;
};
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
Process[] pname = Process.GetProcessesByName("PatchInstaller");
Process[] processlist = Process.GetProcesses();
foreach (Process theprocess in processlist)
{
Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}
proc.WaitForExit();
I don't know much about ProcessStartInfo but I have used Process before and the way to get the information out of the standard output is shown as below, I assume it should be a similar way just by accessing the StandardOutput
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = false;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();
cmd.StandardInput.WriteLine(command);
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
var output = cmd.StandardOutput.ReadToEnd();
cmd.WaitForExit();
This code worked for me:
const int MAX_EXIT_WAIT_TIME = 3000;
// Fill needed data
string username = "";
string password = "";
string domain = "";
string appName = "";
var dir = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
var appFullPath = Path.Combine(dir, appName);
ProcessStartInfo psi = new ProcessStartInfo(appFullPath);
psi.UserName = username;
var securePass = new System.Security.SecureString();
foreach (var c in password)
securePass.AppendChar(c);
psi.Password = securePass;
psi.Domain = domain;
psi.LoadUserProfile = false;
psi.WorkingDirectory = dir;
psi.Arguments = "";
psi.RedirectStandardOutput = true;
// Create Process object, but not start it!
var proc = new Process();
proc.StartInfo = psi;
StringCollection values = new StringCollection();
DataReceivedEventHandler outputDataReceived = (o, e) =>
{
lock (values)
values.Add(e.Data);
};
try
{
proc.OutputDataReceived += outputDataReceived;
// Only here we start process
if (!proc.Start())
throw new InvalidOperationException("Couldn't start app");
proc.BeginOutputReadLine();
proc.WaitForExit(MAX_EXIT_WAIT_TIME);
}
finally { proc.OutputDataReceived -= outputDataReceived; }
Console.WriteLine("Read {0} ", values.Count);
foreach (var item in values)
Console.WriteLine(" {0}", item);

How to pipe output from C# application using cmd to text?

I'm running an app that uses a console app in the background
When I do this in cmd read-info.exe Myfile.file >fileinfo.txt it will create the file fileinfo.txt in the route folder.
But when I do it in code nothing happens, why?
private void button1_Click(object sender, EventArgs e)
{
FolderBrowserDialog theDialog = new FolderBrowserDialog();
theDialog.RootFolder = System.Environment.SpecialFolder.MyComputer;
if (theDialog.ShowDialog() == DialogResult.OK)
{
textBox1.Text = theDialog.SelectedPath.ToString();
string command = "read-info.exe " + textBox1.Text +"> File.txt";
string retur = CMD(command);
}
}
static string CMD(string args)
{
string cmdbat = "cd " + Application.StartupPath.Replace("\\", "/") + "\r\n";
cmdbat += args + " >> out.txt\r\n";
cmdbat += "exit\r\n";
File.WriteAllText("cmd.bat", cmdbat);
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.Arguments = "";
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = Application.StartupPath;
startInfo.CreateNoWindow = true;
startInfo.FileName = Application.StartupPath + "\\cmd.bat";
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
System.Threading.Thread.Sleep(5000);
string cmdOut = File.ReadAllText("out.txt");
File.Delete("cmd.bat");
File.Delete("out.txt");
return cmdOut;
}
See this - I tnink it is what necessary: http://www.dotnetperls.com/redirectstandardoutput
Copied from the link above:
using System;
using System.Diagnostics;
using System.IO;
class Program
{
static void Main()
{
//
// Setup the process with the ProcessStartInfo class.
//
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = #"C:\7za.exe"; // Specify exe name.
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
//
// Start the process.
//
using (Process process = Process.Start(start))
{
//
// Read in all the text from the process with the StreamReader.
//
using (StreamReader reader = process.StandardOutput)
{
string result = reader.ReadToEnd();
Console.Write(result);
}
}
}
}
use cmd /C for running console commands.
string command = "cmd /C read-info.exe " + textBox1.Text +"> File.txt";
Got It Working Thanks to #crashmstr
it outputs file as out.txt so just had to comment out File.Delete("out.txt");

how to pass html as a string using wkhtmltopdf?

how to pass html as a string instead of url in wkhtmltopdf using asp.net, c#?
STDIn and STDOut have been redirected in this example, so you shouldn't need files at all.
public static class Printer
{
public const string HtmlToPdfExePath = "wkhtmltopdf.exe";
public static bool GeneratePdf(string commandLocation, StreamReader html, Stream pdf, Size pageSize)
{
Process p;
StreamWriter stdin;
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = Path.Combine(commandLocation, HtmlToPdfExePath);
psi.WorkingDirectory = Path.GetDirectoryName(psi.FileName);
// run the conversion utility
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
// note: that we tell wkhtmltopdf to be quiet and not run scripts
psi.Arguments = "-q -n --disable-smart-shrinking " + (pageSize.IsEmpty? "" : "--page-width " + pageSize.Width + "mm --page-height " + pageSize.Height + "mm") + " - -";
p = Process.Start(psi);
try {
stdin = p.StandardInput;
stdin.AutoFlush = true;
stdin.Write(html.ReadToEnd());
stdin.Dispose();
CopyStream(p.StandardOutput.BaseStream, pdf);
p.StandardOutput.Close();
pdf.Position = 0;
p.WaitForExit(10000);
return true;
} catch {
return false;
} finally {
p.Dispose();
}
}
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0) {
output.Write(buffer, 0, read);
}
}
}
Redirecting STDIN is probably the easiest way to accomplish what you're trying to do.
One method of redirecting STDIN with wkhtmltopdf (in ASP.Net) is as follows:
private void WritePDF(string HTML)
{
string inFileName,
outFileName,
tempPath;
Process p;
System.IO.StreamWriter stdin;
ProcessStartInfo psi = new ProcessStartInfo();
tempPath = Request.PhysicalApplicationPath + "temp\\";
inFileName = Session.SessionID + ".htm";
outFileName = Session.SessionID + ".pdf";
// run the conversion utility
psi.UseShellExecute = false;
psi.FileName = "c:\\Program Files (x86)\\wkhtmltopdf\\wkhtmltopdf.exe";
psi.CreateNoWindow = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
// note that we tell wkhtmltopdf to be quiet and not run scripts
// NOTE: I couldn't figure out a way to get both stdin and stdout redirected so we have to write to a file and then clean up afterwards
psi.Arguments = "-q -n - " + tempPath + outFileName;
p = Process.Start(psi);
try
{
stdin = p.StandardInput;
stdin.AutoFlush = true;
stdin.Write(HTML);
stdin.Close();
if (p.WaitForExit(15000))
{
// NOTE: the application hangs when we use WriteFile (due to the Delete below?); this works
Response.BinaryWrite(System.IO.File.ReadAllBytes(tempPath + outFileName));
//Response.WriteFile(tempPath + outFileName);
}
}
finally
{
p.Close();
p.Dispose();
}
// delete the pdf
System.IO.File.Delete(tempPath + outFileName);
}
Note that the code above assumes that there's a temp directory available in your application directory. Also, you must explicitly enable write access to that directory for the user account used when running the IIS process.
I know this is an older post, but I want future developers to have this option. I had the same need, and the idea of having to start a background process just to get a PDF inside of a web app is terrible.
Here's another option: https://github.com/TimothyKhouri/WkHtmlToXDotNet
It's a .NET native wrapper around wkhtmltopdf.
Sample code here:
var pdfData = HtmlToXConverter.ConvertToPdf("<h1>COOOL!</h1>");
Note, it's not thread-safe as of right now - I'm working on that. So just use a monitor or something or a lock.

How to make sure a batch file is executed properly through a CMD from a c# applicaiton?

I have a c# applications which writes to a batch file and executes it. The application to be started and the path of application will be written in batch file and executed. which is working fine.
How can i make sure that the application launched successfully via my batch file run in command prompt ?
Is there any value that cmd returns after executing a batch file ? or any other ideas please...
Code i am using now :
public void Execute()
{
string LatestFileName = GetLastWrittenBatchFile();
if (System.IO.File.Exists(BatchPath + LatestFileName))
{
System.Diagnostics.ProcessStartInfo procinfo = new System.Diagnostics.ProcessStartInfo("cmd.exe");
procinfo.UseShellExecute = false;
procinfo.RedirectStandardError = true;
procinfo.RedirectStandardInput = true;
procinfo.RedirectStandardOutput = true;
System.Diagnostics.Process process = System.Diagnostics.Process.Start(procinfo);
System.IO.StreamReader stream = System.IO.File.OpenText(BatchPath + LatestFileName);
System.IO.StreamReader sroutput = process.StandardOutput;
System.IO.StreamWriter srinput = process.StandardInput;
while (stream.Peek() != -1)
{
srinput.WriteLine(stream.ReadLine());
}
stream.Close();
process.Close();
srinput.Close();
sroutput.Close();
}
else
{
ExceptionHandler.writeToLogFile("File not found");
}
}
I'm not familiar with batch files, but if there is possibility to return exit code from it, you can check it with System.Diagnostics.Process.ExitCode
Process process = Process.Start(new ProcessStartInfo{
FileName = "cmd.exe",
Arguments = "/C myfile.bat",
UseShellExecute = false,
});
process.WaitForExit();
Console.WriteLine("returned {0}", process.ExitCode);
System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo(filename);
psi.RedirectStandardOutput = true;
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
System.Diagnostics.Process listFiles;
listFiles = System.Diagnostics.Process.Start(psi);
System.IO.StreamReader myOutput = listFiles.StandardOutput;
listFiles.WaitForExit(2000);
if (listFiles.HasExited)
{
string output = myOutput.ReadToEnd();
MessageBox.Show(output);
}

Execute multiple command lines with the same process using .NET

I'm trying to execute multiple commands without create a new process each time. Basically, I want to start the DOS command shell, switch to the MySQL command shell, and execute a command. Here's how I am calling the procedure (also below). Also, how do I handle the "\"'s in the command?
ExecuteCommand("mysql --user=root --password=sa casemanager", 100, false);
ExecuteCommand(#"\. " + Environment.CurrentDirectory + #"\MySQL\CaseManager.sql", 100, true);
private void ExecuteCommand(string Command, int Timeout, Boolean closeProcess)
{
ProcessStartInfo ProcessInfo;
Process Process;
ProcessInfo = new ProcessStartInfo("cmd.exe", "/C " + Command);
ProcessInfo.CreateNoWindow = false;
ProcessInfo.UseShellExecute = false;
Process = Process.Start(ProcessInfo);
Process.WaitForExit(Timeout);
if (closeProcess == true) { Process.Close(); }
}
You can redirect standard input and use a StreamWriter to write to it:
Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "cmd.exe";
info.RedirectStandardInput = true;
info.UseShellExecute = false;
p.StartInfo = info;
p.Start();
using (StreamWriter sw = p.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
sw.WriteLine("mysql -u root -p");
sw.WriteLine("mypassword");
sw.WriteLine("use mydb;");
}
}
const string strCmdText = "/C command1&command2";
Process.Start("CMD.exe", strCmdText);
Couldn't you just write all the commands into a .cmd file in the temp folder and then execute that file?
As another answer alludes to under newer versions of Windows it seems to be necessary to read the standard output and/or standard error streams otherwise it will stall between commands. A neater way to do that instead of using delays is to use an async callback to consume output from the stream:
static void RunCommands(List<string> cmds, string workingDirectory = "")
{
var process = new Process();
var psi = new ProcessStartInfo();
psi.FileName = "cmd.exe";
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.UseShellExecute = false;
psi.WorkingDirectory = workingDirectory;
process.StartInfo = psi;
process.Start();
process.OutputDataReceived += (sender, e) => { Console.WriteLine(e.Data); };
process.ErrorDataReceived += (sender, e) => { Console.WriteLine(e.Data); };
process.BeginOutputReadLine();
process.BeginErrorReadLine();
using (StreamWriter sw = process.StandardInput)
{
foreach (var cmd in cmds)
{
sw.WriteLine (cmd);
}
}
process.WaitForExit();
}
I prefer to do it by using a BAT file.
With BAT file you have more control and can do whatever you want.
string batFileName = path + #"\" + Guid.NewGuid() + ".bat";
using (StreamWriter batFile = new StreamWriter(batFileName))
{
batFile.WriteLine($"YOUR COMMAND");
batFile.WriteLine($"YOUR COMMAND");
batFile.WriteLine($"YOUR COMMAND");
}
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmd.exe", "/c " + batFileName);
processStartInfo.UseShellExecute = true;
processStartInfo.CreateNoWindow = true;
processStartInfo.WindowStyle = ProcessWindowStyle.Normal;
Process p = new Process();
p.StartInfo = processStartInfo;
p.Start();
p.WaitForExit();
File.Delete(batFileName);
ProcessStartInfo pStartInfo = new ProcessStartInfo();
pStartInfo.FileName = "CMD";
pStartInfo.Arguments = #"/C mysql --user=root --password=sa casemanager && \. " + Environment.CurrentDirectory + #"\MySQL\CaseManager.sql"
pStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(pStartInfo);
The && is the way to tell the command shell that there is another command to execute.
A command-line process such cmd.exe or mysql.exe will usually read (and execute) whatever you (the user) type in (at the keyboard).
To mimic that, I think you want to use the RedirectStandardInput property: http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardinput.aspx
You could also tell MySQL to execute the commands in the given file, like so:
mysql --user=root --password=sa casemanager < CaseManager.sql
You need to READ ALL data from input, before send another command!
And you can't ask to READ if no data is avaliable... little bit suck isn't?
My solutions... when ask to read... ask to read a big buffer... like 1 MEGA...
And you will need wait a min 100 milliseconds... sample code...
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim oProcess As New Process()
Dim oStartInfo As New ProcessStartInfo("cmd.exe", "")
oStartInfo.UseShellExecute = False
oStartInfo.RedirectStandardOutput = True
oStartInfo.RedirectStandardInput = True
oStartInfo.CreateNoWindow = True
oProcess.StartInfo = oStartInfo
oProcess.Start()
Dim Response As String = String.Empty
Dim BuffSize As Integer = 1024 * 1024
Dim x As Char() = New Char(BuffSize - 1) {}
Dim bytesRead As Integer = 0
oProcess.StandardInput.WriteLine("dir")
Threading.Thread.Sleep(100)
bytesRead = oProcess.StandardOutput.Read(x, 0, BuffSize)
Response = String.Concat(Response, String.Join("", x).Substring(0, bytesRead))
MsgBox(Response)
Response = String.Empty
oProcess.StandardInput.WriteLine("dir c:\")
Threading.Thread.Sleep(100)
bytesRead = 0
bytesRead = oProcess.StandardOutput.Read(x, 0, BuffSize)
Response = String.Concat(Response, String.Join("", x).Substring(0, bytesRead))
MsgBox(Response)
End Sub
End Class
I'm using these methods:
public static Process StartCommand(params string[] commands) => StartCommand(commands, false);
public static Process StartCommand(IEnumerable<string> commands, bool inBackground, bool runAsAdministrator = true)
{
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
if(commands.Any()) p.StartInfo.Arguments = #"/C " + string.Join("&&", commands);
if (runAsAdministrator)
p.StartInfo.Verb = "runas";
if (inBackground)
{
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
}
p.Start();
return p;
}
Enjoy...

Categories