So I have a chunk of code to call powercfg with the /requests option and get the result back from stdout.
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "powercfg";
p.StartInfo.Arguments = "/requests";
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
However when I run this code I get entirely different output than when I run the same command on the command line.
In the case of the code version I only get a load of "[DRIVER] ?" values back, but on the command line I get usually 2 or 3 properly formed responses.
I've run my code from the same command prompt window as the same user with the same environment, still no joy.
Any ideas ?
So the actual reason was that my application needed to be compiled for "Any CPU". Setting it to x86 or x64 caused issues with it loading the correct version of one of the dependent libraries.
It may have something to do with the user context your application is running in, for example if you run your app as an administrator Process.Start will attempt to start the process in the same context.
Related
I'm trying to open an external executable. I can easily open external executables by using the Process class from System.Diagnostics:
Process p = new Process()
p.StartInfo.FileName = processName;
p.Start();
This works fine with most programs, like browsers and notepad, creating a process and showing its graphical interface. However, when I try to open my desired program, the process is started (can see it in the task manager, it even takes a whole CPU core for processing) but the GUI window doesn't show. What could possibly happen to a process from Process.Start to not show its GUI?
For reference, the program I want to execute is ADOM release 60, which runs 100% fine when I open it directly in the Explorer shell or in the Powershell. This is reproducible in both console and WindowsForms applications.
Here are some other settings that did not help:
p.StartInfo.CreateNoWindow = true; // or false
p.StartInfo.ErrorDialog = false;
p.StartInfo.WindowStyle = /* any of possible values */;
p.StartInfo.UseShellExecute = true; // or false
You need to set the WorkingDirectory to the root folder where the executable is located.
var executablePath = .....;
var p = new Process();
p.StartInfo = new ProcessStartInfo(executablePath);
p.StartInfo.WorkingDirectory = Path.GetDirectoryName(executablePath);
p.Start();
The default value of WorkingDirectory is %SYSTEMROOT%\System32. Many legacy applications have hard coded relative paths that resolve to full paths with said directory and will fail miserably when trying to read (or create) files where they are not supposed to.
I am trying to use Plink to access information on a machine. I followed this tutorial:
http://www.mindfiresolutions.com/Creating-a-SSH-connection-using-plink-PuTTY-via-C-application-1760.ph
So far I am only using my program to just open up Plink, and I will be adding in the login information and such once I can at least get Plink to be openable in my program. I have this based on the tutorial:
ProcessStartInfo psi = new ProcessStartInfo(#"C:\Windows\System32\cmd");
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
psi.UseShellExecute = false;
psi.CreateNoWindow = false;
Process process = Process.Start(psi);
Thread.Sleep(3000);
string cmdForTunnel = "plink";
process.StandardInput.WriteLine(cmdForTunnel);
process.WaitForExit();
Thread.Sleep(10000);
//DoBusinessLogic();
process.StandardInput.WriteLine("logout");
Thread.Sleep(10000);
if (process.HasExited)
{
process.Close();
process.Dispose();
}
But nothing is displayed, which bothers me. The command plink is supposed to display the help information on how to use the program (I will be replacing the command with something more useful later), but the command prompt remains empty. I also experimented by replacing plink with ipconfig, which also displayed nothing.
I know how to open up cmd myself and type in plink to access it. I want to replicate this action in my program.
You have many faults in your code:
You are redirecting an output, and you are not reading/processing/printing it (that's why "nothing is displayed")
Running plink by "typing" plink to cmd.exe is insane. You can run plink directly, avoiding cmd.exe completely (and even if you needed to use the cmd.exe, you should pass plink.exe to it on a command-line: /c path\plink.exe). And no, running it directly would not cause Plink to close instantly.
Calling WaitForExit() without reading the redirected output will deadlock your code once an output buffer fills. See Remarks section for ProcessStartInfo.RedirectStandardOutput. Alternatively, use process.StandardOutput.ReadToEnd() (it's like WaitForExit, but also reads the output). It's actually what the MSDN recommends in the previous link.
If you are going to execute one command only, using Plink, it's also better to pass the command on Plink command-line, rather than "typing" it to its (redirected) input:
plink.exe -ssh user#host command
See also answer to Testing using Plink.exe to connect to SSH in C#
I'm working on a WPF application targeting .NET 3.0. I need to call an exe which requires administrative privileges. I can get the UAC to prompt for permission by using something like:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.Verb = "runas";
startInfo.UseShellExecute = true;
startInfo.FileName = "target.exe";
Process p = new Process();
p.StartInfo = startInfo;
p.Start();
My problem is I need to redirect standard output, and doing so with UseShellExecute = true results in an exception stating that:
The Process object must have the UseShellExecute property set to false
in order to redirect IO streams
However, setting it to false results in the UAC not prompting for permission and I get an exception stating:
The requested operation requires elevation
How can I redirect standard output and prompt for UAC?
I have seen this similar question, however the solution is to use the app.manifest to give my application administrative privileges. This is something I cannot do due to requirements.
UseShellExecute must be set to false to redirect IO, and to true to use the Verb property. So you can't.
But this article seems do the magic, although I haven't tested it.
It's written in C++, but a wrapper API can easily be created to be called from C# by using DllImport.
Note: If you want to pass data between the two programs and have access to the target program's source code, you can easily re-design you application to use Named Pipes instead of redirecting standard I/O.
There is another pretty simple solution:
If you want to run a child-executable elevated AND redirect the output (optionally including window hiding), then your main code must be running elevated too. This is a security requirement.
To accomplish this:
Manually edit your app.manifest in your project folder.
Find the comment regarding UAC Manifest Options, you will see the 3 examples of requestedExecutionLevel.
Under the comment, locate the tricky asInvoker which is currently enabled, and replace it with requireAdministrator.
Restart Visual Studio in order to take into effect, and after re-building your app it should have the typical UAC shield icon.
Now your code will run elevated, everything that it launches will be elevated too, and you can also capture output streams. Here is an example in VB.NET:
Dim startInfo As New ProcessStartInfo
startInfo.Verb = "runas"
startInfo.FileName = "subprocess-elevated.exe"
startInfo.Arguments = "arg1 arg2 arg3"
startInfo.WorkingDirectory = Environment.CurrentDirectory
startInfo.WindowStyle = ProcessWindowStyle.Hidden
startInfo.CreateNoWindow = True
Dim p As Process = New Process()
p.StartInfo = startInfo
p.StartInfo.UseShellExecute = False
p.StartInfo.RedirectStandardOutput = True
p.StartInfo.RedirectStandardError = True
p.Start()
Console.WriteLine(p.StandardOutput.ReadToEnd)
Console.WriteLine(p.StandardError.ReadToEnd)
p.WaitForExit()
I am new to C# and I am creating a UI for iperf(windows).
Since I could not obtain the source code for the windows version, I have to try a different method.
My aim is to create a UI which will re-direct the commands to command prompt and get the output and display it back in Visual Studio.
How do I achieve this?
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "your command here";
p.Start();
p.WaitForExit();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Now output string variable holds result of command execution.
More details here
I suggest you check out the Process class. It will allow you to start a new process and redirect the output and error streams.
EDIT:
After reading again it is not clear why you would want to redirect back to Visual Studio. I initially read this as you want to write a UI that will send commands and display the output using Visual Studio, not actually displaying in Visual Studio.
I have a custom console command, which if executed in command prompt just displays some text in the command window (similar to 'dir' command).
I'm trying to execute the command 'myCommand' from a windows service and it is always returning blank string values. However, if run the same command in a command prompt, the result is displayed in the command window. Also, if I run the below code in a windows forms application, it works fine and I get the same data which is displayed in the command screen to a string variable.
Where am I going wrong? Why is the code returning a blank string when I execute it from a windows service, where as it works in a forms application. Is there any other method to capture the result of a command to a string variable in a windows service? Please advise. Thank you.
System.Diagnostics.ProcessStartInfo procStartInfo =
new System.Diagnostics.ProcessStartInfo("cmd", "/c myCommand");
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
string result = proc.StandardOutput.ReadToEnd();
Attach the Visual Studio debugger to your running service (Debug menu, Attach to Process), put a breakpoint in the code where you execute the the command, and then execute the comand. This will enable you to debug the problem. If necessary, you can call the System.Diagnostics.Debugger.Break method in your service to force it to break into the debugger at the appropriate point, without having to attach the debugger first.
Edit:
I suggest you also capture the standard error stream:
procStartInfo.RedirectStandardError = true;
...
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
Check what you get in the error string. I use WaitForExit to wait until the command exits too.
You are not setting the working Directory (ie procStartInfo.WorkingDirectory), so if the system can not find 'myCommand' , you will get this result.
Even if 'myCommand' is in the same directory as your service exe file, that does not normally work as the working directory for a service is normally windows\system32.
I preferred this Easier way to debug a C# Windows Service
I added the conditional If to launch the debugger from the OnStart method, then put a breakpoint in my OnCustomCommand(int command) method.