Access variable set in batch from C# application - c#

I have a batch file setEnv.bat.
#echo off
set input=C:\Program Files\Java\jdk1.8.0_131
SET MY_VAR=%input%
I want to run this batch file from C# application and want to access the newly set value of MY_VAR from c# application.
C#:
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName= "D:\\Check\\SetJavaHome.bat";
proc.StartInfo.WorkingDirectory =
System.Environment.CurrentDirectory;
proc.Start();
string myVar = Environment.GetEnvironmentVariable("MY_VAR");
Can someone help me in getting this working as expected?
Thanks in advance.

Check out this answer with the sample code:
https://stackoverflow.com/a/51189308/9630273
Getting the Environment variables directly from another process is not possible, but a simple workaround can be like:
Create a dummy bat file (env.bat) that will execute the required bat and echo the environment variable.
Get the output of this env.bat inside the process execution of C#.

The reason why you want to do this is a bit vague but if your only option is to run that batchfile from a call to Process.Start then the following trickery will let you promote the environment vars from the batch file to your own process.
This is the batch file I use:
set test1=fu
set test2=bar
The followng code opens a standard Command Prompt and then uses the StandardInput to send commands to the command prompt and receive the results with OutputDataReceived event. I basically caputure the output of the SET command and the parse over its result. For each line that contains an environment var and value I call Environment.SetEnvironmentVaruable to set the environment in our own process.
var sb = new StringBuilder();
bool capture = false;
var proc = new Process();
// we run cms on our own
proc.StartInfo.FileName = "cmd";
// we want to capture and control output and input
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardInput = true;
// get all output from the commandline
proc.OutputDataReceived += (s, e) => { if (capture) sb.AppendLine(e.Data); };
// start
proc.Start();
proc.BeginOutputReadLine(); // will start raising the OutputDataReceived
proc.StandardInput.WriteLine(#"cd \tmp"); // where is the cmd file
System.Threading.Thread.Sleep(1000); // give it a second
proc.StandardInput.WriteLine(#"setenv.cmd"); // run the cmd file
System.Threading.Thread.Sleep(1000); // give it a second
capture = true; // what comes next is of our interest
proc.StandardInput.WriteLine(#"set"); // this will list all environmentvars for that process
System.Threading.Thread.Sleep(1000); // give it a second
proc.StandardInput.WriteLine(#"exit"); // done
proc.WaitForExit();
// parse our result, line by line
var sr = new StringReader(sb.ToString());
string line = sr.ReadLine();
while (line != null)
{
var firstEquals = line.IndexOf('=');
if (firstEquals > -1)
{
// until the first = will be the name
var envname = line.Substring(0, firstEquals);
// rest is the value
var envvalue = line.Substring(firstEquals+1);
// capture what is of interest
if (envname.StartsWith("test"))
{
Environment.SetEnvironmentVariable(envname, envvalue);
}
}
line = sr.ReadLine();
}
Console.WriteLine(Environment.GetEnvironmentVariable("test2")); // will print > bar
This will bring the environment variables that are set by a command file into your process.
Do note you can achieve the same by creating a command file that first calls your batchfile and then start your program:
rem set all environment vars
setenv.cmd
rem call our actual program
rem the environment vars are inherited from this process
ConsoleApplication.exe
The latter is easier and works out of the box, no brittle parsing code needed.

Related

How to display the output from cmd in application?

I I need start acmd command in c#, for example: Echo Test.
Next I want to show the output of CMD in an messagebox like this:
MessageBox.Show(output_of_cmd_command);
Is it possible? If so, how?
This will consist of a couple of steps:
start the CMD process with the correct arguments
capture the CMD output
show it in the message box
I recently did something for Python, by using this function:
Keep in mind I explicitly suppressed the CMD dialog itself by setting UseShellExecute and CreateNoWindow. If you like you can alter those.
private string RunCommand(string fileName, string args)
{
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = fileName;
start.Arguments = string.Format("{0}", args);
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
start.UseShellExecute = false;
start.CreateNoWindow = true;
var sb = new StringBuilder();
using (Process process = new Process())
{
process.StartInfo = start;
process.OutputDataReceived += (sender, eventArgs) =>
{
sb.AppendLine(eventArgs.Data); //allow other stuff as well
};
process.ErrorDataReceived += (sender, eventArgs) => {
};
if (process.Start())
{
process.EnableRaisingEvents = true;
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
//allow std out to be flushed
Thread.Sleep(100);
}
}
return sb.ToString();
}
Usage:
var result = RunCommand("path to your cmd.exe", "/C c:\example.bat");
MessageBox.Show(result);
Here's a listing of the CMD options:
Starts a new instance of the Windows command interpreter
CMD [/A | /U] [/Q] [/D] [/E:ON | /E:OFF] [/F:ON | /F:OFF] [/V:ON | /V:OFF]
[[/S] [/C | /K] string]
/C Carries out the command specified by string and then terminates
/K Carries out the command specified by string but remains
/S Modifies the treatment of string after /C or /K (see below)
/Q Turns echo off
/D Disable execution of AutoRun commands from registry (see below)
/A Causes the output of internal commands to a pipe or file to be ANSI
/U Causes the output of internal commands to a pipe or file to be
Unicode
/T:fg Sets the foreground/background colors (see COLOR /? for more info)
/E:ON Enable command extensions (see below)
/E:OFF Disable command extensions (see below)
/F:ON Enable file and directory name completion characters (see below)
/F:OFF Disable file and directory name completion characters (see below)
/V:ON Enable delayed environment variable expansion using ! as the
delimiter. For example, /V:ON would allow !var! to expand the
variable var at execution time. The var syntax expands variables
at input time, which is quite a different thing when inside of a FOR
loop.
/V:OFF Disable delayed environment expansion.

Calling python script from C# doesn't work, without throwing error

I am writing a C# program to execute a python script with some arguments. The program is not executed(it is supposed to not only print out a message, but also to write to a file), even though there is no error and the Process ExitCode is 0(checked via the debugger). Where am I going wrong?
static private string ExecutePython(string sentence) {
// full path of python interpreter
string python = #"C:\Python27\python.exe";
// python app to call
string myPythonApp = #"C:\Users\user_name\Documents\pos_edit.py";
// Create new process start info
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo(python);
// make sure we can read the output from stdout
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardOutput = true;
myProcessStartInfo.Arguments = string.Format("{0} {1}", myPythonApp, sentence);
Process myProcess = new Process();
// assign start information to the process
myProcess.StartInfo = myProcessStartInfo;
// start process
myProcess.Start();
// Read the standard output of the app we called.
StreamReader myStreamReader = myProcess.StandardOutput;
string myString = myStreamReader.ReadToEnd();
// wait exit signal from the app we called
myProcess.WaitForExit();
// close the process
myProcess.Close();
return myString;
}
You've put myProcess.WaitForExit(); in the wrong place; wait till Python has executed the script:
...
myProcess.Start();
StreamReader myStreamReader = myProcess.StandardOutput;
// first, wait to complete
myProcess.WaitForExit();
// only then read the results (stdout)
string myString = myStreamReader.ReadToEnd();
...
Works perfectly fine with me. I think there's something with your user_name containing spaces.

C# Windows Forms - Assigning the text from a textbox in one variable within xml file

I've been working in a Windows Forms Application in C# for run the tasks of my Phing buildfile.
When I click on the button it executes the phing buildfile (runs cmd), saved the console output into a txt file and shows the output in one textbox.
The problem is I have some tasks that need user's input, like SVN commit that needs user to input the commit message.
When I executed the commit task, was showed an empty cmd for the user write the commit message, but the question is not showed, so the user have to guess what's expected to him to write in the console.
I created a input box with the question and the textbox for user answer, but how can I assign the text from the Textbox to the variable within xml file ?
Sorry for some English errors ...
Edit:
In my buildfile I've got this:
<target name="commit" description="Executa Commit">
<propertyprompt propertyName="commit_message" defaultValue="Actualizado atraves do Phing"
promptText="Introduza a mensagem do Commit: " />
<svncommit
svnpath="${svn_path}"
workingcopy="${local_dir}"
message="${commit_message} " />
<echo msg="Revisao do Commit numero: ${svn.committedrevision}"/>
</target>
So it shows the message "Introduza a mensagem do Commit" and the answer is assigned to commit_message.
In C# I've got an inputbox and I want the text from the textbox to be the value of the "commit_message" in the xml file
Edit for Kamil:
textBox1.Clear();
var startInfo = new ProcessStartInfo("phing");
startInfo.WorkingDirectory = #"C:\wamp\bin\php\php5.4.3";
startInfo.Arguments = "commit > log.txt";
string pergunta = inputbox.InputBox("Qual é a mensagem do Commit ?", "Commit", "Mensagem Commit");
// textBox1.Text = "Escreva o caminho de origem da pasta:";
Process proc = Process.Start(startInfo);
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardInput = true;
proc.WaitForExit();
using (StreamReader sr = new StreamReader(#"C:\wamp\bin\php\php5.4.3\log.txt"))
{
textBox1.Text = sr.ReadToEnd();
}
Edit number 2 to Kamil:
That way works, but the result is the same of just do this
var startInfo = new ProcessStartInfo("phing");
startInfo.WorkingDirectory = #"C:\wamp\bin\php\php5.4.3";
startInfo.Arguments = "commit ";
Process proc = Process.Start(startInfo);
my boss told me there's no problem of being like this, just want to add one thing else..
When the console closes I wanna send all the console output to one textbox or just force the console to stay open until I close it
You may use Process.OutputDataReceived event to get "the question" (from cmd script I assume).
If you want to enter data to application (cmd?) input - you have to use Process.StandardInput.WriteLine() method.
You didn't posted your C# code and I don't know if you are using Process to start cmd script or what.
Edit/added later:
textBox1.Clear();
var startInfo = new ProcessStartInfo("phing");
startInfo.WorkingDirectory = #"C:\wamp\bin\php\php5.4.3";
// startInfo.Arguments = "commit > log.txt"; // DONT PUT OUTPUT TO FILE
startInfo.Arguments = "commit"; // we will read output with event
string pergunta = inputbox.InputBox("Qual é a mensagem do Commit ?", "Commit", "Mensagem Commit");
// textBox1.Text = "Escreva o caminho de origem da pasta:";
Process proc = Process.Start(startInfo);
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardInput = true;
// not like this
// proc.WaitForExit();
// using (StreamReader sr = new StreamReader(#"C:\wamp\bin\php\php5.4.3\log.txt"))
// {
// textBox1.Text = sr.ReadToEnd();
// }
// add handler
// this will "assign" a function (proc_OutputDataReceived - you can change name)
// that will be called when proc.OutputDataReceived event will occur
// for that kind of event - you have to use DataReceivedEventHandler event type
proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
// event handler function (outside function that you pasted)
// this function is assigned to proc.OutputDataReceived event
// by code with "+= new..."
// "sender" is an object in which event occured (when it occurs - "proc" will be available as "sender" here)
// "e" is an object with event parameters (data sent from process and some more)
public void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
// cast "sender" to Process type
// "sender" is Process, but it has "object" type,
// you have to cast it to use .StandardInput.WriteLine() on "sender"
Process callerProcess = (Process)sender;
MessageBox.Show(e.Data); // this will show text that process sent
MessageBox.Show(e.Data.ToString()); // you may need to add ToString(), im not sure
if (e.Data.StartsWith("Revisao do Commit numero"))
{
MessageBox.Show("Process is talking something about Revisao numero"); // :)
callerProcess.StandardInput.WriteLine("Yes! Numero!"); // reply "Yes! Numero!" to process
}
}
If someone more experienced see some mistakes in my code - please fix it if you can. I can't test it right now.
Added later later:
You don't have to use a file and store cmd output. You can read process output directly by using event.

Executing a unix style piping command?

Is there a way to execute the following command through C#?
.\binary.exe < input > output
I am trying to use System.Diagnostics.Process but I was wondering if there is a direct exec style command in C#. Any suggestions?
Not directly, but you can redirect output from a console stream (as you may have figured out, considering you're trying to use the Process class), as noted here on MSDN: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx
There is also an example here on SO: Redirect console output to textbox in separate program
Wrap that into your own class and it will basically become an "exec" style command.
Basically you need to redirect the standard input and output to your program and write them to the files you want
ProcessStartInfo info = new ProcessStartInfo("binary.exe");
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
Process p = Process.Start(info);
string Input;
// Read input file into Input here
StreamWriter w = new StreamWriter(p.StandardInput);
w.Write(Input);
w.Dispose();
StreamReader r = new StreamReader(p.StandardOutput);
string Output = r.ReadToEnd();
r.Dispose();
// Write Output to the output file
p.WaitForExit();

how to send command and receive data in command prompt in C# GUI application

I am new to C# so please sorry if i make no sense in my question. In my application which is C# DLL need to open command prompt, give a plink command for Linux system to get a system related string and set that string as environment variable. I am able to do this when i create C# console application, using plink command to get the string on command prompt and use to set it environment variable using process class in C# to open plink as separate console process. But, in C# DLL i have to open cmd.exe 1st and then give this command which i don't know how can i achieve? I tried through opening cmd.exe as process and then trying to redirect input and output to process and give command and get string reply, but no luck. Please let me know any other way to solve this.
Thanks for answers,
Ashutosh
Thanks for your quick replys. It was my mistake in writing code sequence. Now few changes and the code is working like charm. Here is code,
string strOutput;
//Starting Information for process like its path, use system shell i.e. control process by system etc.
ProcessStartInfo psi = new ProcessStartInfo(#"C:\WINDOWS\system32\cmd.exe");
// its states that system shell will not be used to control the process instead program will handle the process
psi.UseShellExecute = false;
psi.ErrorDialog = false;
// Do not show command prompt window separately
psi.CreateNoWindow = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
//redirect all standard inout to program
psi.RedirectStandardError = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
//create the process with above infor and start it
Process plinkProcess = new Process();
plinkProcess.StartInfo = psi;
plinkProcess.Start();
//link the streams to standard inout of process
StreamWriter inputWriter = plinkProcess.StandardInput;
StreamReader outputReader = plinkProcess.StandardOutput;
StreamReader errorReader = plinkProcess.StandardError;
//send command to cmd prompt and wait for command to execute with thread sleep
inputWriter.WriteLine("C:\\PLINK -ssh root#susehost -pw opensuselinux echo $SHELL\r\n");
Thread.Sleep(2000);
// flush the input stream before sending exit command to end process for any unwanted characters
inputWriter.Flush();
inputWriter.WriteLine("exit\r\n");
// read till end the stream into string
strOutput = outputReader.ReadToEnd();
//remove the part of string which is not needed
int val = strOutput.IndexOf("-type\r\n");
strOutput = strOutput.Substring(val + 7);
val = strOutput.IndexOf("\r\n");
strOutput = strOutput.Substring(0, val);
MessageBox.Show(strOutput);
I explained the code so far..., thanks a lot

Categories