I'm creating a simple C# program used to check various settings on windows 10 builds we're testing. I need to capture the output from a CMD or Powershell invoke and display the result as a string (human-readable). Specifically, I'm trying to capture the output from get-bitlockervolume to check if the drives are encrypted. The program should be able to run without using admin creds.
Get Powershell command's output when invoked through code
unfortunately doesn't quite seem to work, so I thought I'd attempt to capture the output to a txt file and read it from there, but for some reason, the txt ends up being empty. For my latest attempts, I've ditched PowerShell and attempted to get it done using simple CMD.
Process bl = new Process();
bl.StartInfo.WindowStyle = ProcessWindowStyle.Hidden ;
bl.StartInfo.FileName = "cmd.exe";
bl.StartInfo.Arguments = #"/c manage-bde -status > C:\windows\temp\bitlockerstatus.txt";
bl.StartInfo.RedirectStandardOutput = true;
bl.StartInfo.UseShellExecute = false;
bl.Start();
This seems to create the output file I was looking for in the right location, but it always turns up empty. When running the command directly from cmd, there doesn't seem to be an issue recording the output.
I'm still quite new to C#, self-learning as I go along, so any suggestions for an alternate method/way of doing this would be appreciated.
Very late edit:
I've figured out a way by using a Collection.
code:
StringBuilder str = new Stringbuilder();
using (Powershell ps = Powershell.create())
{
ps.addscript ("manage-bde -status");
Collection<PSObject> psoutp = ps.Invoke();
foreach(PSObject outp in psoutp)
{
if (outp != null)
{
str.Append(outp);
}
else str.Append ("Error");
}
return str.ToString();
}
This for a Method that returns the output of manage-bde - status from powershell back to main. If there's no output at all (not even an errormessage) , it'll simply return "error" back to main.
Here's hoping this helps someone else one day.
I think the answer is here:
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
// do something with line
}
Related
I am running processes from C# using the following code;
private static void ExecuteShellCMD(string workingDir, string commandWithArgs, bool bWait = true)
{
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "runas";
info.FileName = "cmd.exe";
info.WorkingDirectory = workingDir;
info.Arguments = "/C " + commandWithArgs;
info.UseShellExecute = false;
using (Process myProcess = Process.Start(info))
{
if (bWait)
{
myProcess.WaitForExit();
}
int ExitCode = myProcess.ExitCode;
//Log exit code here.
}
}
It loads an elevated command window and executes the code/bat file I pass it, but without logging anything to the console. This doesn't appear to be consistent on other machines, and has worked in the past on my machine, and I wondered if anyone had any ideas about how I can consistently make this Process just print logs into the command window the process makes.
I can see logs if I set UseShellExecute = true but then can't use Verb without accepting the elevation prompt which is undesirable.
I have tried looking for solutions around the web, and I am aware that I can redirect the output using other settings. Most of the questions and tutorials on this subject seem to deal with redirecting the ouput to somewhere else but I want to be able to keep track of the progress in the command window itself.
Perhaps I have missed an command line argument or similar?
Turns out this was actually a bug in Unity Hub. The process and output were working fine, however when ran from a Unity instance that was launched from Unity Hub it took control of the output and didn't release it. This was solved by just launching Unity directly and a bug report has been filed against Unity hub.
I have a file that i need to run by creating a command prompt.
Basically this is how it goes:
The file's name is UArtCMD.exe, i use it by opening a command prompt in it's directory and run commands that are programmed into it, for example "uartcmd a". What i'm trying to do is add a gui to this software externally, and when, let's say, a button is pressed on the gui, it will run a command using the command prompt.
I've managed to make it run off my computer without any hitches, but the problems occur occur when i install the software on a different computer. Because the UArtCMD is an external software, it wont be on every computer, so what i tried doing is adding it to the resources of the project and run it from there, the problem is i have no idea how to do so.
This is my code for running the command prompt on the computer which has the UArtCMD
public static string executeLine(string command)
{
string result;
try
{
Process process = Process.Start(new ProcessStartInfo("cmd.exe", "/c " + command)
{
CreateNoWindow = true,
UseShellExecute = false,
WorkingDirectory = "C:\\UArtCMD",
RedirectStandardError = true,
RedirectStandardOutput = true
});
process.WaitForExit();
string text = process.StandardOutput.ReadToEnd();
process.Close();
MainWindow.log(text);
result = text;
}
catch (Exception ex)
{
result = ex.StackTrace;
}
return result;
}
Thanks in advance!
If you need me to add any info or expand more on the question do let me know i will gladly do so.
Include a reference to the file UArtCMD.exe in your solution (can be anywhere in the solution structure).
Set its "Copy to Output Directory" property to "Always".
Set your process' "WorkingDirectory" property to
"Environment.CurrentDirectory".
Now UArtCMD.exe should always find it's way into the bin directory (even if it's built by a build agent into a strange output directory) and the code will know to look for it in the same directory as the code is running from.
Edit: The comment about removing the "WorkingDirectory" property from your process object is valid, you can do that instead of setting it to "Environment.CurrentDirectory", they both do the same thing.
There is an executable called jlink.exe that I will like to make of use on my console application. Because jlink.exe is not a .net application it is not possible for me to reference it and call it's methods. As a result I will like to use it reading it's output
When I start that exe from windows explorer this is how it looks:
It then waits for a command. If I type mem 88 2 then I get back:
Now I will like to do the same thing with my .net console application reading it's standard output but for some reason I cannot read the output. This is what I have:
// change working directory
Directory.SetCurrentDirectory(#"C:\Program Files (x86)\IAR Systems\Embedded Workbench 6.4 Evaluation\arm\bin");
Process p = new Process( )
{
StartInfo = new ProcessStartInfo( #"jlink.exe" )
{
UseShellExecute = false ,
RedirectStandardOutput = true ,
RedirectStandardInput = true
}
};
p.Start( );
StreamWriter standardInput = p.StandardInput;
StreamReader standardOutput = p.StandardOutput;
var line = string.Empty;
while ( ( line = standardOutput.ReadLine( ) ) != null )
{
Console.WriteLine( line );
}
why when I run that code I just get a black window... I do not get the same output as when running that executable. When I run that code against other executable it works great.
If I then type mem 88 2 and press ENTER nothing happens. If I press enter one more time then I finally get what I want with extra content. Why am I getting this behavior with that executable?
Edit
I have looked at similar question such as this one:
process.standardoutput.ReadToEnd() always empty?
I don't think I am doing something wrong. I guess there is something weird with that executable. To use that executable you may download it at: http://supp.iar.com/Download/SW/?item=EWARM-EVAL or at http://www.iar.com/en/Products/IAR-Embedded-Workbench/ARM/ . Then go to C:\Program Files (x86)\IAR Systems\Embedded Workbench 6.4 Evaluation\arm\bin and execute jlink.exe (If you do not have a board connected via usb you will get an error but it does not matter. the error message does not show up either).
I want to run git commands from c#. below is the coded I had written and it does execute the git command but I am not able to capture the return value. When I manually run it from command line this is the output I get.
When I run from the program the only thing I get is
Cloning into 'testrep'...
Rest of the info is not capture, but the command is executed successfully.
class Program
{
static void Main(string[] args)
{
ProcessStartInfo startInfo = new ProcessStartInfo("git.exe");
startInfo.UseShellExecute = false;
startInfo.WorkingDirectory = #"D:\testrep";
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
startInfo.Arguments = "clone http://tk1:tk1#localhost/testrep.git";
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
List<string> output = new List<string>();
string lineVal = process.StandardOutput.ReadLine();
while (lineVal != null)
{
output.Add(lineVal);
lineVal = process.StandardOutput.ReadLine();
}
int val = output.Count();
process.WaitForExit();
}
}
From the manual page for git clone:
--progress
Progress status is reported on the standard error stream by default when it is attached to
a terminal, unless -q is specified. This flag forces progress status even if the standard
error stream is not directed to a terminal.
The last three lines in the output when running git clone interactively are sent to standard error, not standard output. They won't show up there when you run the command from your program, however, since it's not an interactive terminal. You could force them to appear, but the output isn't going to be anything usable for a program to parse (lots of \rs to update the progress values).
You are better off not parsing the string output at all, but looking at the integer return value of git clone. If it's nonzero, you had an error (and there will probably be something in standard error that you can show to your user).
Have you tried libgit2sharp? The documentation is not complete, but it is pretty easy to use and there's a nuget package for it. You can always look at the test code to see about usage as well. A simple clone would be like this:
string URL = "http://tk1:tk1#localhost/testrep.git";
string PATH = #"D:\testrep";
Repository.Clone(URL, PATH);
Fetching changes is easy as well:
using (Repository r = new Repository(PATH))
{
Remote remote = r.Network.Remotes["origin"];
r.Network.Fetch(remote, new FetchOptions());
}
Once you call process.WaitForExit() and the process has terminated, you can simply use process.ExitCode which will get you the value that you want.
Your code Looks OK.
this is git problem.
git clone git://git.savannah.gnu.org/wget.git 2> stderr.txt 1> stdout.txt
stderr.txt is empty
stdout.txt:
Cloning into 'wget'...
It looks like git not uses standard console.write() like output you can see it when it writes percentage it's all in one line not like:
10%
25%
60%
100%
process.StandardError.ReadToEnd() + "\n" + process.StandardOutput.ReadToEnd();
ok this was working the other day and now it's not... i don't remember changing anything, but i can run this reg.exe command with the arguments below from CMD and it works fine and creates the output file. but running it in VC# it does not create the file test_output.txt???
System.Diagnostics.Process proc_cmd = new System.Diagnostics.Process();
proc_cmd.StartInfo.FileName = #"c:\windows\system32\reg.exe";
proc_cmd.StartInfo.Arguments = #"query ""HKLM\Software\test\test software"" /v BuildNumber >c:\test\test_output.txt";
proc_cmd.StartInfo.CreateNoWindow = true;
proc_cmd.StartInfo.RedirectStandardError = true;
proc_cmd.StartInfo.RedirectStandardOutput = true;
proc_cmd.StartInfo.RedirectStandardInput = true;
proc_cmd.StartInfo.UseShellExecute = false;
proc_cmd.Start();
proc_cmd.Close();
You should use the Registry class instead.
Your >output.txt is an instruction to the command interpreter (cmd.exe). That won't work calling reg.exe. Consider calling cmd.exe instead, or redirecting the stdout and writing it to the file yourself. See this SO answer link.
Of course, if there's no compelling reason to shell out to the Reg.exe, you should use the Registry class.