So I am trying to automate the output from DxDiag in C# and I have run into a problem. The program runs but doesn't produce any output file. It might be that I am not passing parameters correctly or that I am misunderstanding something.
When running DxDiag in the normal command line I do this and it works as expected:
dxdiag -64bit -x C:\dxFromCode.xml
And this is how I am trying to do it in code:
//Create process
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
pProcess.StartInfo.FileName = "dxdiag";
pProcess.StartInfo.Arguments = #"64bit x C:\dxFromCode.xml";
pProcess.StartInfo.UseShellExecute = false;
//Set output of program to be written to process output stream
pProcess.StartInfo.RedirectStandardOutput = false;
//Start the process
pProcess.Start();
//Wait for process to finish
pProcess.WaitForExit();
EDIT:
Ok, so I changed my code to build for x64. This makes dxdiag automatically start the as the 64-bit version. Then I could just take away the 64bit switch and suddenly everything works as I would expect.
DxDiag is quite cranky on a 64-bit OS. The 32-bit version and the 64-bit version accept different command line switches and it doesn't give a peep when you use the wrong one. The /x option simply does not work when you try to use the /64bit option on the 32-bit version. And the 64-bit version does not accept /64bit. You'll have to start the 64-bit version explicitly when you run on a 64-bit OS and your program runs in 32-bit mode.
This worked well on my Win81 x64 machine:
private string RunDxDiag() {
var psi = new ProcessStartInfo();
if (IntPtr.Size == 4 && Environment.Is64BitOperatingSystem) {
// Need to run the 64-bit version
psi.FileName = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Windows),
"sysnative\\dxdiag.exe");
}
else {
// Okay with the native version
psi.FileName = System.IO.Path.Combine(
Environment.SystemDirectory,
"dxdiag.exe");
}
string path = System.IO.Path.GetTempFileName();
try {
psi.Arguments = "/x " + path;
using (var prc = Process.Start(psi)) {
prc.WaitForExit();
if (prc.ExitCode != 0) {
throw new Exception("DXDIAG failed with exit code " + prc.ExitCode.ToString());
}
}
return System.IO.File.ReadAllText(path);
}
finally {
System.IO.File.Delete(path);
}
}
Try adding /user:Administrator cmd /K to the arguments statement. Like this:
Arguments = "/user:Administrator \"cmd /K " + command + "\""
Command being 64bit x C:\dxFromCode.xml. I think your problem might be that you need to run cmd as Administrator.
Weirdly, Hans's code didn't work for me. I found that the WaitForExit() call would return before the file could be read. As a workaround, I added this:
int nTries = 0;
do
{
string szText = System.IO.File.ReadAllText(path);
if (szText.Length != 0)
{
return szText;
}
else
{
System.Threading.Thread.Sleep(1000);
}
} while (nTries++ < 10);
return "";
Related
Mostly just as a curiosity, I wrote a little app to start up Terminator shell on Windows, using Ubuntu/WSL and Xming window server.
Doing things manually from the shell, I can run Firefox, gedit, Terminator, etc on Windows, it's pretty cool.
So I checked the location of bash.exe using where bash and it returned...
C:\Windows\System32\bash.exe
However when I tried to run this code...
using (var xminProc = new Process())
{
xminProc.StartInfo.FileName = #"C:\Program Files (x86)\Xming\Xming.exe";
xminProc.StartInfo.Arguments = ":0 -clipboard -multiwindow";
xminProc.StartInfo.CreateNoWindow = true;
xminProc.Start();
}
using (var bashProc = new Process())
{
bashProc.StartInfo.FileName = #"C:\Windows\System32\bash.exe";
bashProc.StartInfo.Arguments = "-c \"export DISPLAY=:0; terminator; \"";
bashProc.StartInfo.CreateNoWindow = true;
bashProc.Start();
}
I get the error...
System.ComponentModel.Win32Exception: 'The system cannot find the file specified'
And checking my entire system for bash.exe reveals it really be in another place altogether...
I'm not sure if this location is one that I can rely on, I'm worried it's ephemeral and can change during a Windows Store update, although I may be wrong about that.
Why does the command prompt show bash.exe to be in System32 but it's really in another location altogether?
Can I get C# to also use the System32 location?
As #Biswapriyo stated first set the platafrom to x64 on your solution:
Then you may run on your ubuntu machine from c# as:
Console.WriteLine("Enter command to execute on your Ubuntu GNU/Linux");
var commandToExecute = Console.ReadLine();
// if command is null use 'ifconfig' for demo purposes
if (string.IsNullOrWhiteSpace(commandToExecute))
{
commandToExecute = "ifconfig";
}
// Execute wsl command:
using (var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = #"cmd.exe",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = true,
CreateNoWindow = true,
}
})
{
proc.Start();
proc.StandardInput.WriteLine("wsl " + commandToExecute);
System.Threading.Thread.Sleep(500); // give some time for command to execute
proc.StandardInput.Flush();
proc.StandardInput.Close();
proc.WaitForExit(5000); // wait up to 5 seconds for command to execute
Console.WriteLine(proc.StandardOutput.ReadToEnd());
Console.ReadLine();
}
I eventually want to be able to return a DataFrame from Python to C#. At the moment I am running a very simple console app to try and run a basic Python script. This script compiles and runs in Canopy fine however when I run it from C# I get the error relating to non-ASCII chars.
I have read many articles relating to this but none of them seem to resolve the issue I have.
Error
SyntaxError: Non-ASCII character '\x90' in file C:\Program Files\Enthought\Canop
y32\App\appdata\canopy-1.5.2.2785.win-x86\python.exe on line 1, but no encoding
declared; see http://www.python.org/peps/pep-0263.html for details
Thx in advance for any help!
static int test_python_canopy()
{
string cmd;
string args;
args = "C:\\Share\\Python\\test.py";
cmd = #"C:\Program Files\Enthought\Canopy32\App\appdata\canopy-1.5.2.2785.win-x86\python.exe";
cmd = "\"" + cmd + "\"";
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = cmd;
start.Arguments = string.Format("{0} {1}", cmd, args);
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
string result = reader.ReadToEnd();
Console.Write(result);
}
}
return 0;
}
For ProcessStartInfo, FileName should be set to the executable that you wish to run and Arguments should be set to the arguments that you want to pass to that executable.
In your code, FileName is set correctly to the Python interpreter. Arguments, however, the first argument is being set to Python interpreter. The net result is that C# is trying to execute this command:
C:\Program Files\Enthought\Canopy32\App\appdata\canopy-1.5.2.2785.win-x86\python.exe C:\Program Files\Enthought\Canopy32\App\appdata\canopy-1.5.2.2785.win-x86\python.exe C:\Share\Python\test.py
which means that Python is trying to use the Python executable as a script, which is not going to work. Changing the line that sets the arguments should fix the problem:
start.Arguments = args;
When i try to run BCDEDIT from my C# application i get the following error:
'bcdedit' is not recognized as an internal or external
command,
operable program or batch file.
when i run it via elevated command line i get as expected.
i have used the following code:
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.FileName = #"CMD.EXE";
p.StartInfo.Arguments = #"/C bcdedit";
p.Start();
string output = p.StandardOutput.ReadToEnd();
String error = p.StandardError.ReadToEnd();
p.WaitForExit();
return output;
i have also tried using
p.StartInfo.FileName = #"BCDEDIT.EXE";
p.StartInfo.Arguments = #"";
i have tried the following:
Checking path variables - they are fine.
running visual studio from elevated command prompt.
placing full path.
i am running out of ideas,
any idea as to why i am getting this error ?
all i need is the output of the command if there is another way that would work as well.
thanks
There is one explanation that makes sense:
You are executing the program on a 64 bit machine.
Your C# program is built as x86.
The bcdedit.exe file exists in C:\Windows\System32.
Although C:\Windows\System32 is on your system path, in an x86 process you are subject to the File System Redirector. Which means that C:\Windows\System32 actually resolves to C:\Windows\SysWOW64.
There is no 32 bit version of bcdedit.exe in C:\Windows\SysWOW64.
The solution is to change your C# program to target AnyCPU or x64.
If you are stuck with x86 application on both 32it/64bit Windows and You need to call bcdedit command, here is a way how to do that:
private static int ExecuteBcdEdit(string arguments, out IList<string> output)
{
var cmdFullFileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows),
Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess
? #"Sysnative\cmd.exe"
: #"System32\cmd.exe");
ProcessStartInfo psi = new ProcessStartInfo(cmdFullFileName, "/c bcdedit " + arguments) { UseShellExecute = false, RedirectStandardOutput = true };
var process = new Process { StartInfo = psi };
process.Start();
StreamReader outputReader = process.StandardOutput;
process.WaitForExit();
output = outputReader.ReadToEnd().Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList();
return process.ExitCode;
}
usage:
var returnCode = ExecuteBcdEdit("/set IgnoreAllFailures", out outputForInvestigation);
Inspiration was from this thread and from How to start a 64-bit process from a 32-bit process and from http://www.samlogic.net/articles/sysnative-folder-64-bit-windows.htm
I'm trying to create a small program to run on a centralized device. This program will run
"psexec \server(s) netstat -na | findstr "LISTENING""
to collect netstat data from remote nodes (should redirect output to string), then parse the data and compare against a known list. I can run the psexec cmd above without any issues from the cmd line, but when I try to run the same command as a process within my C# program, no data is returned to be parsed. I can see that the netstat is being run (cmd window flashes with netstat results), but the process.standardoutput is not catching the stream. If I use ping or pretty much anything other than psexec as an argument, the stream is caught and the results are shown in my text box. I've also tried setting the filename to psexec.exe and specifying the arguments but I get the same results. Last but not least, if I run psexec without any arguments, I get the help kickback info returned in my textbox. This is true if I'm running psexec.exe as the filename OR if I run cmd.exe as filename with "/c psexec" specified as args.
I'm just trying to get psexec output to be caught when executing locally at this point. I'll worry about psexec to remote machines later. Any help would be MUCH appreciated.
Here's the code:
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
pProcess.StartInfo.FileName = "cmd.exe";
pProcess.StartInfo.Arguments = "/c psexec netstat";
pProcess.StartInfo.UseShellExecute = false;
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.Start();
string strOutput = pProcess.StandardOutput.ReadToEnd();
pProcess.WaitForExit();
if (pProcess.HasExited)
{
textBox1.Text = strOutput;
}
else
{
textBox1.Text = "TIMEOUT FAIL";
}
I would recommend also capturing the standard error output in case anything is being reported there.
Also, you may have a disconnect between "bitness" of psexec and your application if you are running on a 64-bit OS. If this is the case, change the platform for the project to match that of psexec rather than building as Any CPU.
Came across a few things to be changed but your recommendation of capturing standard error output was dead on and a good start. Turns out some info was being sent to the error output (even though really wasn't error, just run status 0 from psexec) so I knew at that point psexec wasn't just eating ALL the output. Once I started trying to pass remote hosts as args, I started getting user/pass error data back. Also needed to catch standard input if I wanted to supply credentials for proc run. Threw in some str literals and credentials for the remote exec, works perfectly. Thanks for the help. Here is the updated code--
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
pProcess.StartInfo.Domain = "domain";
pProcess.StartInfo.UserName = "user with priv";
pProcess.StartInfo.Password = new System.Security.SecureString();
char [] pass = textBox3.Text.ToArray();
for (int x = 0; x < pass.Length; ++x)
{
pProcess.StartInfo.Password.AppendChar(pass[x]);
}
pProcess.StartInfo.FileName = #"psexec.exe";
pProcess.StartInfo.Arguments = #"\\remoteHost netstat -ano";
pProcess.StartInfo.UseShellExecute = false;
pProcess.StartInfo.RedirectStandardInput = true;
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.StartInfo.RedirectStandardError = true;
pProcess.Start();
pProcess.WaitForExit(30000);
if (!pProcess.HasExited)
{
pProcess.Kill();
}
string strOutput = pProcess.StandardOutput.ReadToEnd();
string errOutput = pProcess.StandardError.ReadToEnd();
textBox1.Text = strOutput;
textBox2.Text = errOutput;
I am writing a program that needs to run a java.jar server. I need to run the process directly so I can rewrite the output to a textbox and all-in-all have complete control of it. I tried just doing it through CMD.exe, but that wouldnt work because CMD.exe would just call a new process java.exe and I wouldn't have control of it. I need to call java.exe directly so I can have the control and get the output. Can any of you tell me how to convert this command so I could create a process in C# and call it?
I need this CMD command converted:
"java -Xmx1024m -cp ./../libs/*;l2jserver.jar net.sf.l2j.gameserver.GameServer"
into
a command line I can put into the Process.Arguments so I can call Java.exe directly.
I've tried to do it... and it just won't work.
I've been looking at this for hours and hours... please someone help!
Part of the problem might be that despite what the Framework documentation says using Process doesn't always resolve things against the PATH environment variable properly. If you know the name of the folder Java is in then use the full path to Java.exe, otherwise use a function like the following:
private void LocateJava()
{
String path = Environment.GetEnvironmentVariable("path");
String[] folders = path.Split(';');
foreach (String folder in folders)
{
if (File.Exists(folder + "java.exe"))
{
this._javadir = folder;
return;
}
else if (File.Exists(folder + "\\java.exe"))
{
this._javadir = folder + "\\";
return;
}
}
}
It's somewhat hacky but it will find java.exe provided the Java Runtime is installed and it's folder is in the windows PATH variable. Make a call to this function the first time your program needs to find Java and then subsequently start Java using the following:
//Prepare the Process
ProcessStartInfo start = new ProcessStartInfo();
if (!_javadir.Equals(String.Empty)) {
start.FileName = this._javadir + "java.exe";
} else {
start.FileName = "java.exe";
}
start.Arguments = "-Xmx1024m -cp ./../libs/*;l2jserver.jar net.sf.l2j.gameserver.GameServer";
start.UseShellExecute = false;
start.RedirectStandardInput = true;
start.RedirectStandardOutput = true;
//Start the Process
Process java = new Process();
java.StartInfo = start;
java.Start();
//Read/Write to/from Standard Input and Output as required using:
java.StandardInput;
java.StandardOutput;