I want to execute a batch command and save the output in a string, but I can only execute the file and am not able to save the content in a string.
Batch file:
#echo off
"C:\lmxendutil.exe" -licstatxml -host serv005 -port
6200>C:\Temp\HW_Lic_XML.xml notepad C:\Temp\HW_Lic_XML.xml
C# code:
private void btnShowLicstate_Click(object sender, EventArgs e)
{
string command = "'C:\\lmxendutil.exe' -licstatxml -host lwserv005 -port 6200";
txtOutput.Text = ExecuteCommand(command);
}
static string ExecuteCommand(string command)
{
int exitCode;
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
// *** Redirect the output ***
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
process = Process.Start(processInfo);
process.WaitForExit();
// *** Read the streams ***
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
exitCode = process.ExitCode;
process.Close();
return output;
}
I want the output in a string and do this directly in C# without a batch file, is this possible?
Don't need to use "CMD.exe" for execute a commandline application or retreive the output, you can use "lmxendutil.exe" directly.
Try this:
processInfo = new ProcessStartInfo();
processInfo.FileName = "C:\\lmxendutil.exe";
processInfo.Arguments = "-licstatxml -host serv005 -port 6200";
//etc...
Do your modifications to use "command" there.
I hope this helps.
It doesn't look to me like your batch file will produce any output. If you run it in the command line, do you see an output? You have the redirection > operator in your bat file line, so it seems like you're sending output to the xml file.
If you have saved the output to an xml file, maybe you should just load that using C# once your process exits.
Related
I have a batch file I want to run from a C# windows form. the Batch file is very basic and accepts one parameter
cd C:\Program Files (x86)\Advent\ApxClient
AdvScriptRunner REPRUN -mrgainloss -p%1 -vf -t\\myserver\apx$\pdf\myReport
If i call it in a command prompt, this works fine
C:\Program Files (x86)\Locations\blah>realizedgainloss 123456
that will run just fine, and i get the expected result (it outputs a report run on a third party peice of software). However I cannot for the life of me figure this out with c#. I have the following.
private void button1_Click(object sender, EventArgs e)
{
ExecuteCommand(getCommand());
}
public string getCommand()
{
return "realizedgainloss.bat";
}
static void ExecuteCommand(string command)
{
int exitCode;
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo(command);
//processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
// *** Redirect the output ***
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
processInfo.Arguments = String.Format("{0} {1}", command, "123456");
process = Process.Start(processInfo);
process.WaitForExit();
// *** Read the streams ***
// Warning: This approach can lead to deadlocks, see Edit #2
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
exitCode = process.ExitCode;
Console.WriteLine("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
Console.WriteLine("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
Console.WriteLine("ExitCode: " + exitCode.ToString(), "ExecuteCommand");
process.Close();
}
Its worth noting that if i do not provide a parameter, and change the bat file to be static, with 12345 in place of it's %1, then it runs from C#, so there is something incorrect about how i'm getting the parameters into the bat file...
any thoughts?
You have your batch file name as the command to run and the first parameter of your script. I find it easier and more reliable to use cmd.exe as the command to run and invoke it with the /C argument. Doing it this way you should make sure your working directory is set correctly as well.
processInfo = new ProcessStartInfo("cmd.exe");
processInfo.Arguments = String.Format("/C {0} {1}", command, "123456");
processInfo.WorkingDirectory = yourWorkingDirectory;
I'm having some difficulty doing this without using a batch file. What I want to do is when a button is clicked, run the command line with a simple argument that I specify.
Here's my code so far:
ProcessStartInfo startInfo = new ProcessStartInfo("cmd.exe");
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.UseShellExecute = true;
startInfo.Arguments = "dir";
Process.Start(startInfo);
string output = Process.StandardOutput.ReadToEnd();
txtblkOutput.Text = output;
However, this just opens a cmd window and nothing happens. The text box remains blank.
However I can do this:
var process = new Process();
process.StartInfo.FileName = "C:/Users/user/Documents/SUB-20 Tool/commands.bat";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
string output = process.StandardOutput.ReadToEnd();
txtblkOutput.Text = output;
Inside the batch file it just says dir. And this works, I get the output sent to my textbox.
Why does this work only with a batch file? Can I do this without it, with just using the argument property?
This is the excepted behaviour. When you execute cmd.exe with the argument dir, it does not execute the command.
As an exemple, see the screenshot below :
The correct way to execute a command in the arguments is the following :
cmd.exe /C <command>
I have a batch file that copy file from one folder to another folder. So I would like to run this file from a C# windows services then I would like to read if the script generate an error or it works correctly.
This is my code for lunch it but I don't Know how to read the message of the script:
SCRIPT CODE:
REM
REM This script moves files with results from GOLD server and saves them on MES06 server on .
REM IMPORT folder.
REM
REM Robocopy Options:
REM /R:2 Two retries on failed copies (default is 1 million)
REM /W:5 Wait 5 seconds between retries (default is 30 sec).
REM
REM GOLD QAS Inbound Folder: \\goldqas01.app.pmi\limscihome$\RootDirectory
REM
for /f "delims=: tokens=2,3" %%j in (F:\MES2GOLD\copy_list_test.txt) do ROBOCOPY.EXE %%j %%j\..\BACKUP *.* /R:2 /W:5 /log+:%%j\..\LOGS\MES2GOLD.log & ROBOCOPY.EXE %%j %%k *.* /R:2 /W:5 /MOV /log+:%%j\..\LOGS\MES2GOLD.log
PAUSE
C# Code:
public void execute(string workingDirectory, string command)
{
// create the ProcessStartInfo using "cmd" as the program to be run, and "/c " as the parameters.
// Incidentally, /c tells cmd that we want it to execute the command that follows, and then exit.
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd.exe", #"/c C:\Users\mcastrio\Desktop\GOLD2MES.bat");
procStartInfo.WorkingDirectory = workingDirectory;
//This means that it will be redirected to the Process.StandardOutput StreamReader.
procStartInfo.RedirectStandardOutput = true;
//This means that it will be redirected to the Process.StandardError StreamReader. (same as StdOutput)
procStartInfo.RedirectStandardError = true;
procStartInfo.UseShellExecute = false;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
//This is importend, else some Events will not fire!
proc.EnableRaisingEvents = true;
// passing the Startinfo to the process
proc.StartInfo = procStartInfo;
// The given Funktion will be raised if the Process wants to print an output to consol
proc.OutputDataReceived += DoSomething;
// Std Error
proc.ErrorDataReceived += DoSomethingHorrible;
// If Batch File is finished this Event will be raised
proc.Exited += Exited;
}
Can we help me?
You can use the code below inside your loop:
var startInfo = p.StartInfo;
startInfo.CreateNoWindow = true;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.UseShellExecute = false;
startInfo.StandardOutputEncoding = Encoding.GetEncoding("ibm850");
startInfo.RedirectStandardOutput = true;
startInfo.FileName = filebatch;
startInfo.Arguments = arguments;
p.Start();
var output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Or just use ProcessHelper.Run from TestSharp library:
ProcessHelper.Run(string exePath, string arguments = "", bool waitForExit = true)
Use case: I am checking certain credentials on a remote system by running commands via PsExec (i.e. for this example, I am trying to retrieve the KB articles currently installed on the remote system).
I have the following to retrieve command output:
public string GetCmDOutput(string cmd)
ProcessStartInfo startInfo = new ProcessStartInfo("control", cmd)
{
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
string output = string.Empty;
Process process = Process.Start(startInfo);
process.OutputDataReceived += (sender, e) => output = string.Concat(output, e.Data);
process.BeginOutputReadLine();
process.Start();
process.WaitForExit();
Delay.Milliseconds(1500) //API-specific delay
return output;
}
Whenever I use GetCmdOutput() to run a command locally it works like a charm, but if I try to run a command with PsExec, my output is empty.
For instance, I ran the following:
string cmd = #"\psexec.exe \\remoteComputerName -u username -p password -c cmd /c wmic qfe";
GetCmdOutput(cmd);
Report.Info(cmd); //API-specific reporting
And an empty string was returned.
After playing around with this for a couple of hours, I feel I may need a second set of eyes. What might be causing this issue?
I have run into this same problem. My solution was to run cmd and have it call psexec. I have psexec's output saved to a temp file for further manipulation. My code is returning a List.
public List<string> ExecutePSExec(string hostname)
{
List<string> recordNames = new List<string>();
string command = #"\\path\to\psexec.exe /accepteula \\" + hostname + ". exe-to-run-remotely";
try
{
string location = AppDomain.CurrentDirectory.BaseDirectory;
string cmdWithFileOutput = string.Format("{0} >{1}temp.log", command, location);
procStartInfo.UseShellExecute = true;
procStartInfo.CreateNoWindow = true;
procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process proc = new Process();
proc.StartInfo = procStartInfo;
proc.Start();
proc.WaitForExit();
// Read file contents, manipulate data and then delete temp file here
}
catch (Exception e)
{
Console.WriteLine("Failure to run psexec: {0}", e.Message);
}
return recordNames;
}
NOTE: I ran into another problem and found out that running psexec this way requires the remote hostname (not IP Address) in the command to end in a period \\" + hostname + ".
This code assumes you can run psexec on the remote machine as your current user.
I have a user, let's call it "MyUser". It has a password, suppose it is "Password". This user has an SSH key for git. I try to run from my ASP.NET application a batch file which issues git commands, it is at a location which is passed as a parameter. My function is as follows:
private void ExecuteCommand(string path, int timeout)
{
Process process = new Process();
process.StartInfo = new ProcessStartInfo();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "\"" + path + "\"";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
//processInfo.WorkingDirectory = Config.GitHubRepoPath;
process.StartInfo.UserName = "MyUser";
process.StartInfo.Password = new System.Security.SecureString();
process.StartInfo.Password.AppendChar('P');
process.StartInfo.Password.AppendChar('a');
process.StartInfo.Password.AppendChar('s');
process.StartInfo.Password.AppendChar('s');
process.StartInfo.Password.AppendChar('w');
process.StartInfo.Password.AppendChar('o');
process.StartInfo.Password.AppendChar('r');
process.StartInfo.Password.AppendChar('d');
// *** Redirect the output ***
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
// *** Read the streams ***
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
if (timeout <= 0)
{
process.WaitForExit();
}
else
{
process.WaitForExit(timeout);
}
int exitCode = process.ExitCode;
process.Close();
return new ShellCommandReturn { Error = error, ExitCode = exitCode, Output = output };
}
But when I run this function, the ExitCode is -1073741502 and error and output are empty. How can I fix this behavior?
Please help me, I have tried to solve this literally for days.
I think redirecting both standard error and standard output & attempts to consume both synchronously is wrong. Please see this link:
http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput%28v=vs.100%29.aspx
Allow me to copy excerpt:
A deadlock condition results if the parent process calls p.StandardOutput.ReadToEnd followed by p.StandardError.ReadToEnd and the child process writes enough text to fill its error stream. The parent process would wait indefinitely for the child process to close its StandardOutput stream. The child process would wait indefinitely for the parent to read from the full StandardError stream.
The other thing is ... when you invoke a cmd.exe instance, try adding a "/c" argument too.