I would like to know if there are other alternatives to capturing a process output in C#.
I have the following code
Process __process = new Process();
__process.StartInfo.Verb = "runas";
__process.StartInfo.FileName = "some file path here";
__process.StartInfo.UseShellExecute = true;
__process.Start();
__process.WaitForExit(300000);
The reason why UseShellExecute is set to true here is because that's required for the verb "runas" to run as administrator. As a result, I cannot redirect the standard output of the program anymore.
What are other ways that I can capture the output of Process if I can't use StandardOutput? I thought about making the program write to a file and then read from that file but that doesn't seem very efficient.
If you can code the actual program you're starting the process to use pipes that would probably be the best / most efficient solution. There might be a way to have the process output piped by some other command/program.
Pipe Operations in the .Net Framework
You could create a named or anonymous pipe and pass it's name/id/handle to the program as an argument. The program can then connect to the other end of the pipe and stream data back to your application that called it.
EDIT I'm assuming this is all running on a Windows environment, and I don't know if using pipes on a process started with UseShellExecute = true works..
Related
I'm trying to get the result, yes or no, that users press to answer a program when run as admin.
Example:
IMAGE
I'm trying with the following code:
var processInstall = new ProcessStartInfo();
processInstall.CreateNoWindow = true;
processInstall.FileName = "myBatchFileAddress";
processInstall.Verb = "runas";
var process = new Process();
process.StartInfo = processInstall;
process.Start();
process.WaitForExit();
//Here I must deal with the result of user, if is yes or no
Batch files are a very old technology. Literally as old as DOS. So by their nature, the ability to communicate is limited.
DOS era programms primarily communicated via "ERRORLEVEL". The return in Console programm still affects said errorlevel. 0 was returned for "no problem". Anything else for a problem. Batchfiles could check it. And I am 90% certain windows actually still uses it - if a setup returns anything but 0, it asks "should I try again with compatibility settings?" Using EXIT you can define wich ERRORLEVEL the batchfile "returns".
However there is another way to, depending on how verbose the programms are: IO redirection.
Keep in mind that batchfiles are interpreted. So you ahve to run the console programm, then give the order to run teh console (usually as a parameter with full path; see console documentation for details).
Finally executing any batchfile as adminsitrator tends to screw up the paths utterly. The batchfile needs to be designed to compensate.
Of course if those programms are written by yourself, you have options like Interprocess Communication. But I asume this was not the case right now.
Edit: It seems I missunderstood the question. If a programm asks for Adminsitrative privileges due to a Manifest or is run with runas but the elevation is denied, the execution is never done at all. The programm is not even started by Windows. It is Propably not even loaded into memory.
My question may seem as a straight forward one, because it was asked many times before.Anyway I think my case is completely different and I can't find any intuition about it. I have an exe file compiled from a code written in assembly language and I want to run this exe using another code and capture its output. I did this using C# and here is the code for it:
static string runCommand(string command, string args)
{
if (File.Exists(command))
{
Process p = new Process();
p.StartInfo.FileName = command;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.Arguments = args;
p.Start();
p.WaitForExit();
string output = p.StandardOutput.ReadToEnd();
return output;
}
return "";
}
The code for the target exe file is pretty simple (I'm using Irvine library):
INCLUDE Irvine32.inc
.data
.code
main proc
call dumpregs
exit
main ENDP
end main
Where command is the exe file path, args is the arguments passed to the exe file (be noted that no arguments required by this exe)
The output is always equal to "" !. When I run the exe using command prompt, the console output is definitely not empty.Here is what I get:
I also tried to capture the console output using python but the returned string is awlays empty.
I have done this several times but the exe file was written in C# instead of assembly language, but I think it shouldn't be any difference exist.
EDIT
Solutions attempted so far and suggested by hatchet:
Capturing console output from a .NET application (C#)
How to spawn a process and capture its STDOUT in .NET? [duplicate]
Process.start: how to get the output?
None of them worked for me
If you need any further information let me know in the comments
Your C# code is correct. The standard way of capturing the output of a console process is to redirect the standard output by setting the process object's StartInfo.RedirectStandardOutput property to true, as described here. This is exactly what you have done.
The problem, as correctly diagnosed by rkhb, is that you're using the Irvine32 library in the auxiliary process, and its implementation of dumpregs calls the Win32 WriteConsole function, which cannot be redirected. If you attempt to redirect the standard output (e.g., to a pipe or file), then WriteConsole will fail with ERROR_INVALID_HANDLE, as documented on MSDN:
ReadConsole and WriteConsole can only be used with console handles; ReadFile and WriteFile can be used with other handles (such as files or pipes). ReadConsole and WriteConsole fail if used with a standard handle that has been redirected and is no longer a console handle.
Like rkhb's comment, this except from the documentation also hints at the solution. To support redirection, you need to change the implementation of dumpregs to call WriteFile instead of WriteConsole. This is a more general function that can write to any type of handle, including the standard console output (a la WriteConsole) or any other type of object that you might redirect the output to. Once you've made this change, you will, of course, need to rebuild the Irvine32 library.
The only significant limitation of WriteFile is that it doesn't support Unicode output like WriteConsole does, but that isn't a problem in your case. The output of dumpregs is all ANSI.
I've got a process (written in C#) that runs with administrative rights and invokes dpinst.exe to perform an automated driver installation. It writes its own custom dpinst.xml file to specify things like suppressing the EULA page, suppressing the wizard, running a "quiet install," and searching in all subdirectories.
When I invoke this manually from the command line (see example below), it seems to work fine. Because of the command line switches I'm using it prints a bunch of INFO level log messages in the console.
C:\Path\To\Drivers> dpinst.exe /C /L 0x409
I want to log what gets printed in the console, so my C# code looks something like this:
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = #"C:\Path\To\Drivers\dpinst.exe",
Arguments = "/C /L 0x409",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
Verb = "runas"
}
};
string output;
process.Start();
using (var reader = process.StandardOutput)
{
output = reader.ReadToEnd();
reader.Close();
}
However, when I run that code, the value of output is always blank. So, for my next experiment, I tried using the command line directly to pipe the output to a file, like this:
C:\Path\To\Drivers> dpinst.exe /C /L 0x409 > test.log 2>&1
That created the test.log file, but it was also blank. Interestingly enough I could still see all of the console output that dpinst.exe generates in that same console window; for some reason it didn't get redirected to the file that I specified. So the symptom is the same regardless of how I invoke the dpinst executable; it doesn't want to redirect output. I'm not sure what the underlying reason for that is, nor how to solve it. How can I capture the console output?
EDIT: If anyone wants a copy of dpinst.exe to run locally and test out themselves, I've provided one at this link, bundled with the dpinst.xml file I'm using. Remember that you need to invoke it with the /C command line switch in order to generate any command line output. Alternatively, if you're paranoid and don't want to download an executable from some random Stack Overflow question, you can get the dpinst.exe utility as part of the Windows Driver Kit from Microsoft. It's a free download, but you have to extract the utility (which is only 500 KB) from the full WDK ISO (which is ~700 MB). Up to you. :)
Your code runs perfectly fine with standard tools (like "ping") for example. So maybe for some reason dpinst writes to standard error instead? You can set RedirectStandardError = true and read StandardError to check if that is the case.
UPDATED in case anyone else will hit this problem:
It seems dpinst does not write to standard output but logs messages to console in some other way. Only way to achieve your goal which comes to my mind is: remember size of "%SystemRoot%\DPINST.LOG" file, run your command, wait for exit, then read everything between remembered position and end of file. This way you will get your logs.
I my answer will help other. When you run Dpinst.exe and you add the swicth /C to dump the log to console, it also creates a log file in this directory "C:\Windows\DPINST.LOG"
You can locate the log file there..
I am trying to do the following with a VM accessed via RDP:
Launch a command prompt
thread.sleep long enough to disconnect RDP session (10 seconds, its ok if its longer)
Sendkeys to command prompt to launch an exe that works in interactive mode. A perfect example would be FTP. If you launch FTP without parameters you get an interactive prompt. Its a long story about security but command line parameters will not work, it need to be interactive.. This process will not run while connected to RDP
I have everything working except for one major problem. Once I disconnect from RDP there is no keyboard for sendkeys to work with. I don't remember the exact error offhand but it was basically 'no keyboard connected'
I had an idea that maybe I could create a virtual keyboard that would still be 'connected' when RDP session ends.
I have verified that processes, even DOS from the command prompt will continue to run after disconnecting RDP. The issue is isolated to sendkeys and the keyboard of a VM when not connected.
I have searched high and low, but this one has me stumped. I understand this is a workaround instead of tackling the problem at the source but I only have this option.
The only other alternative I could think of is if something like worked like SendKeys but will work with no keyboard attached?
edit
Just to be a little more clear. I have found many other solutions that would work, but I am left with this only idea.
The rules are:
Nothing can be installed on the VM, such as a 'test automation' tool
Everything has to be built in house from scratch using VS2012 C# .net up to 4.5.
Maybe I can find an open source test automation tool but there is no time allowed to research and convert what seems like a possibly complicated application.
Any ideas are most appreciated.
When you create your Process object set StartInfo appropriately:
var proc = new Process {
StartInfo = new ProcessStartInfo {
FileName = "program.exe",
Arguments = "command line arguments to your executable",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
then start the process and read from it:
proc.Start();
while (!proc.StandardOutput.EndOfStream) {
string line = proc.StandardOutput.ReadLine();
// do something with line
}
Taken from here
To send something you can simply use:
proc.StandardInput.WriteLine("Something");
You can simply check in the while loop for some triggers and then write some data into the stream.
I want to open SSH connections from c# via opening a process and running plink. All output should be collected and depending on the results the program will fire actions to the ssh.
My big problem is, that i am using a couple if different scripts and i need (automated) user interaction. Therefore i have to capture ALL output data (standard output, standard error AND CONSOLE).
Looking at the following test batch should make the case more clear:
1: #ECHO OFF
2: ECHO StdOut
3: ECHO StdErr 1>&2
4: ECHO Cons>CON
The code is like:
Process process;
Process process;
process = new Process();
process.StartInfo.FileName = #"cmd.exe";
process.StartInfo.Arguments = "/c test.bat";
process.StartInfo.UseShellExecute = false;
process.StartInfo.ErrorDialog = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = true;
process.Start();
process.OutputDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
process.ErrorDataReceived += new DataReceivedEventHandler(process_OutputDataReceived);
process.BeginOutputReadLine();
process.BeginErrorReadLine();
StreamWriter inputWriter = process.StandardInput;
[...]
I am able to capture lines 2+3, but not 4 (used by some programs).
I have also tried powershell (or directly plink) instead of cmd.exe as starting point, but same result.
Is there any way in c# to capture the console out as well or do you know any third party command line being able to redirect CON out to stdout or something like this?
I'm not sure that is even possible - well at least not using some plain simple API.
Please note that I have not found (although I tried) any information on the web that directly confirms that, but here is how I come to this conclusion.
The console in Windows is its own subsystem, managed by csrss.exe (and starting with Windows Vista also conhost.exe, but I digress). It has it's own set APIs (AttachConsole, WriteConsole, etc.) and you can only have one "console" per process.
CMD.EXE on the other hand is just another console mode application, that just happens to use the console and being launched it a console window. You can observe this effect, by launching a different console mode application and watch the process tree in e.g. Process Explorer: there is no CMD.EXE parent process (but rather it is Explorer or whatever you used to start it - including of course CMD.EXE).
Thus far I was trying to show the difference between "the console" and CMD.EXE, batch files, or console mode applications in general.
So when in CMD.EXE you use > CON you are actually causing the same effect as doing a write to CONOUT$ in native applications (or your typical write to /dev/console on a UNIX-like OS). There doesn't seem to be a direct equivalent for managed code, as Console.Out and Console.Error equal stdout and stderr in native applications (or 1 and 2 as file descriptors in CMD.EXE).
Having all that said, when you start a process you're only enabled to redirect it's standard output and standard error streams, but not (per se) the messages it writes to the console (or CONOUT$ handle). I guess that would be the same as trying to redirect output that a process writes to some file, which is also not (generically) possible.
You could possible achieve this using some hooking or injecting something inside the child process to grab the console output.
Being not able to easily do this, is also (one of) the reason(s) why writing a complete terminal (i.e. console window, not CMD.EXE!) replacement for Windows is not easily possible and requires some hacks or workarounds.
AFAIK know what you want (redirecting CON) is only possible by hooking/injecting which is rather complex and basically not necessary to do SSH.
For SSH you can use any number of C# libraries out there (free and commercial):
http://www.chilkatsoft.com/ssh-sftp-component.asp (commercial)
http://www.tamirgal.com/blog/page/SharpSSH.aspx (free)
http://sshnet.codeplex.com/ (free)
http://www.rebex.net/ssh-pack/default.aspx (commercial)
http://www.eldos.com/sbb/desc-ssh.php (commercial)
The main advantage of using a library is that you have much greater control over the SSH session than you could ever achieve via some redirected console AND it is much easier to implement...
UPDATE - as per comments:
To get all output from the remotely running program you need to use a library which comes with an "interactive/terminal" class for SSH - for example the one at http://www.rebex.net/ssh-pack/default.aspx comes with such a class and works really fine (not affilliated, just a happy customer), it can be used as a code-only component or as a visual control (whatever suits your needs).
Here are some CodeProject projects which do this (via native code), which AFAICT better handle redirecting all console output:
Universal Console Redirector
Redirecting an arbitrary Console's Input/Output
Also, the command freopen allows a program to redirect its streams. However, if a program does an explicit WriteConsole() I'm not sure if it is possible to redirect that.