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
Related
I want to run a gpu accelerated python script on windows using conda environment (dlwin36).
I’m trying to activate dlwin36 and execute a script:
1) activate dlwin36
2) set KERAS_BACKEND=tensorflow
3) python myscript.py
If I manually open cmd on my machine and write:"activate dlwin36"
it works.
But when I try opening a cmd from c# I get:
“activate is not recognized as an internal or external command, operable program or batch file.”
I tried using the following methods:
Command chaining:
var start = new ProcessStartInfo();
start.FileName = "cmd.exe";
start.Arguments = "/c activate dlwin36&&set KERAS_BACKEND=tensorflow&&python myscript.py";
Process.Start(start).WaitForExit();
(I’ve tested several variations of UseShellExecute, LoadUserProfile and WorkingDirectory)
Redirect standard input:
var commandsList = new List<string>();
commandsList.Add("activate dlwin36");
commandsList.Add("set KERAS_BACKEND=tensorflow");
commandsList.Add("python myscript.py");
var start = new ProcessStartInfo();
start.FileName = "cmd.exe";
start.UseShellExecute = false;
start.RedirectStandardInput = true;
var proc = Process.Start(start);
commandsList.ForEach(command => proc.StandardInput.WriteLine(command));
(I’ve tested several variations of LoadUserProfile and WorkingDirectory)
In both cases, I got the same error.
It seems that there is a difference between manually opening cmd and opening it from c#.
The key is to run activate.bat in your cmd.exe before doing anything else.
// Set working directory and create process
var workingDirectory = Path.GetFullPath("Scripts");
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
RedirectStandardInput = true,
UseShellExecute = false,
RedirectStandardOutput = true,
WorkingDirectory = workingDirectory
}
};
process.Start();
// Pass multiple commands to cmd.exe
using (var sw = process.StandardInput)
{
if (sw.BaseStream.CanWrite)
{
// Vital to activate Anaconda
sw.WriteLine("C:\\PathToAnaconda\\anaconda3\\Scripts\\activate.bat");
// Activate your environment
sw.WriteLine("activate your-environment");
// Any other commands you want to run
sw.WriteLine("set KERAS_BACKEND=tensorflow");
// run your script. You can also pass in arguments
sw.WriteLine("python YourScript.py");
}
}
// read multiple output lines
while (!process.StandardOutput.EndOfStream)
{
var line = process.StandardOutput.ReadLine();
Console.WriteLine(line);
}
You need to use the python.exe from your environment. For example:
Process proc = new Process();
proc.StartInfo.FileName = #"C:\path-to-Anaconda3\envs\tensorflow-gpu\python.exe";
or in your case:
start.Arguments = "/c activate dlwin36&&set KERAS_BACKEND=tensorflow&&\"path-to-Anaconda3\envs\tensorflow-gpu\python.exe\" myscript.py";
I spent a bit of time working on this and here's the only thing that works for me: run a batch file that will activate the conda environment and then issue the commands in python, like so. Let's call this run_script.bat:
call C:\Path-to-Anaconda\Scripts\activate.bat myenv
set KERAS_BACKEND=tensorflow
python YourScript.py
exit
(Note the use of the call keyword before we invoke the activate batch file.)
After that you can run it from C# more or less as shown above.
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = "cmd.exe";
start.Arguments = "/K c:\\path_to_batch\\run_script.bat";
start.UseShellExecute = false;
start.RedirectStandardOutput = true;
start.RedirectStandardError = true;
start.WorkingDirectory = "c:\\path_to_batch";
string stdout, stderr;
using (Process process = Process.Start(start))
{
using (StreamReader reader = process.StandardOutput)
{
stdout = reader.ReadToEnd();
}
using (StreamReader reader = process.StandardError)
{
stderr = reader.ReadToEnd();
}
process.WaitForExit();
}
I am generating the batch file on the fly in C# to set the necessary parameters.
If this is gonna help anyone in the future. I found that you must run the activation from C:\ drive.
I am trying to run the process with different user. When I run normal "notepad.exe" it works fine. But when I change the file to any other executable with full path(C:\\Program Files\\Microsoft Office\\Office15\\Excel.exe) or (C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroRd32.exe) it doesn't work. Instead gives errors like attached in pic.
Any suggestions...??
static void Main(string[] args)
{
SecureString securePwd = new SecureString();
string password = "P#ssw0rd";
SecureString sec_pass = new SecureString();
Array.ForEach(password.ToArray(), sec_pass.AppendChar);
sec_pass.MakeReadOnly();
Process p = new Process();
ProcessStartInfo ps = new ProcessStartInfo();
p.StartInfo.FileName = "notepad.exe";
p.StartInfo.Arguments = "C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\welcome.pdf";
p.StartInfo.WorkingDirectory = "C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\";
p.StartInfo.ErrorDialog = true;
p.StartInfo.EnvironmentVariables.Add("TempPath", "C:\\Temp");
p.StartInfo.Domain = "testdom";
p.StartInfo.UserName = "testuser";
p.StartInfo.Password = sec_pass;
p.StartInfo.RedirectStandardError = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.Start();
StreamReader myStreamReader = p.StandardOutput;
// Read the standard error of net.exe and write it on to console.
Console.WriteLine(myStreamReader.ReadLine());
p.Close();
}
Notepad doesn't store any user-specific settings. I'm certain all of the Office products do, and it wouldn't surprise me if Acrobat does too.
So, first thing to fix is to make sure that your ProcessStartInfo sets LoadUserProfile to true. That may be sufficient.
However, sometimes applications also act quite differently when run for the first time versus any subsequent launches, so I'd also make sure that you have, at least once, launched each of these applications as the intended target user, whilst you're actually logged onto the machine as that user (versus just launching a single process as that user).
In your code example your trying to open a pdf document in notepad.
Just checking, what happens when you change the file name to the adobe exe (you may need to add the path to the exe) instead of notepad.exe
I'm running PSExec Microsoft tool with Process class executing a remote command with its own output like this:
Process p = new Process();
string args = #"\\remotemachine -u someuser -p somepass wmic product get name";
ProcessStartInfo ps = new ProcessStartInfo();
ps.Arguments = args;
ps.FileName = psExecFileName;
ps.UseShellExecute = false;
ps.CreateNoWindow = true;
ps.RedirectStandardOutput = true;
ps.RedirectStandardError = true;
p.StartInfo = ps;
p.Start();
StreamReader output = p.StandardOutput;
string output = output.ReadToEnd();
where wmic product get name is WMI tool running remotely with its own output listing all installed applications on the remote machine.
So, in the output I don't see the output of wmic, at the same time when I'm running PSExec in the command line locally, I can fully see the output of both PSExec and started remotely WMIC.
The question is, how can I capture all the output on the local machine? Should I run it in a separate console and try to attach to the console to capture all the output?
More generally, if put plainly, why is the output in the process StandardOutput and in the console when running PSExec directly not the same?
ReadToEnd will wait till the process exit. e.g. a Console.ReadLine() in the psExecFile could block your reading. But you can get the already written stream,
StreamReader output = p.StandardOutput;
string line;
while ((line = output.ReadLine()) != null)
{
Console.WriteLine(line);
}
In the console, data written to both StandardOutput and StandardError is displayed in the console.
Within your program you need to look at each individually...try adding something like this at the end:
string error = p.StandardError.ReadToEnd();
I'd like to execute a batch file without showing terminal window
and I need to get the standard output contents.
Here is the batch file:
timeout /T 5
exit 0
Below is my partial C# code:
static void Main(string[] args)
{
bool ShowTerminal = true;
Process proc = new Process();
proc.StartInfo.FileName = "cmd.exe";
string ExecContent = "\"" + args[0] + "\"";
proc.StartInfo.Arguments = "/c " + ExecContent;
proc.StartInfo.UseShellExecute = ShowTerminal;
proc.StartInfo.RedirectStandardError = !ShowTerminal;
proc.StartInfo.RedirectStandardInput = !ShowTerminal;
proc.StartInfo.RedirectStandardOutput = !ShowTerminal;
proc.Start();
proc.WaitForExit();
}
I found that variable ShowTerminal set true, then everything is going well
except I can not get standard output contents
But if variable ShowTerminal set false, timeout command will be skipped
Is there any solution for this problem? Thanks!
If you specify "redirect" options you should also provide their redirection streams (STDIN, STDOUT) and ensure they are being emptied/read/processed as CMD would expect.
Chances are good that 'timeout' is failing to detect any STDIN/STDOUT and therefore performs a noop.
I´m trying to create a small console app in c#. I want to run the program and save all pending changes in TFS to a .txt file. But I cant get the arguments to work. Can someone help me?
Here is my code i haved done so far:
string argument = "#tf.exe status /collection:http://tiffany:8080/tfs/ /user:* /format:detailed >c:\\Status\\Detailed.txt";
try
{
Process process = new Process();
process.StartInfo.Arguments = "#call" + " " + "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\Tools\\VsDevCmd.bat";
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Verb = "runas";
process.StartInfo.Arguments = argument;
process.StartInfo.CreateNoWindow = false;
process.Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadKey();
}
aI'm not really sure that I understand what you're trying to call, exactly.
Let's assume you want to run the following command line from a C# application, as if you would call it from a command line:
tf.exe status /collection:http://tiffany:8080/tfs/ /user:* /format:detailed >c:\\Status\\Detailed.txt"
I would use this code:
string arguments = #"/C tf.exe status /collection:http://tiffany:8080/tfs/ /user:* /format:detailed >c:\\Status\\Detailed.txt";
this.process = new Process();
this.process.StartInfo.FileName = #"cmd.exe";
this.process.StartInfo.Arguments = arguments;
this.process.Start();
Edit:
If that's all your console app does, why not consider creating a batch (.BAT / .CMD) file instead of a C# application?
Instead of running a command line tool you could leverage the TFS API.
There are many articles out there, e.g. Code project article on topic
and
Sample code directly from the MSDN
I suppose you have to read standard error and output from process started:
Process process = new Process();
process.StartInfo.Arguments = #"status PATH /recursive";
process.StartInfo.FileName = "tf.exe";
process.StartInfo.CreateNoWindow = false;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
var st = process.StandardOutput.ReadToEnd();
var err = process.StandardError.ReadToEnd();
But parsing tf output is not easy and I'd like to suggest to use TFS API as #Mare said
You do not need to create an application in C # to save in a text file. Just use the parameters (...) > [file name].txt at the end of the command.
The ">" symbol send the result of any command to a file.