Having issues getting entire output from StandardOutput.ReadToEnd - c#

At work we have a large number of on-site WES09 machines that are doing controls data gathering. Because we have thousands of these, upgrades are a pain. I have been slowly evolving a better process, and am currently working on a C# application to better manage these.
The machines are running File Based Write Filter, which has the effect that if PSEXEC had not been run on the machine before, it won't let it start. So I use WMIC to disable FBWF.
I am trying to add a status feature to see if FBWF is enabled, as I haven't always had 100% success with WMIC. Anyway, FBWF gives status output in the command window, but it's multiple lines. It seems when I use StandardOutput.ReadToEnd, it only gets the first line.
So here is what it looks like when you check FBWF status from PSEXEC:
FBWFOutput
When I run the C# Application I wrote, the output only gets this:
"\r\nPsExec v2.2 - Execute processes remotely\r\nCopyright (C)
2001-2016 Mark Russinovich\r\nSysinternals -
www.sysinternals.com\r\n\r\nFile-based write filter configuration for
the current session:\r\n"
I don't know why it stops there, I can't get the rest of it that actually says if it is enabled or not (which is the next line, of course).
Here is the relevant code piece, leaving out IP/User/Pass:
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.FileName = #"C:\temp\PSTools\PsExec.exe";
p.StartInfo.Arguments = #"\\" + RemotePCName + " -u " + Username + " -p " + Password + " fbwfmgr";
p.Start();
string output = p.StandardOutput.ReadToEnd();
string errormessage = p.StandardError.ReadToEnd();
I thought my issue might be the line break, but there looks to be two between the PsExec portion and the FBWF output, but otherwise am not sure what else to try. I spent a couple hours looking through other comments on issues with getting the output, but almost all were that the application would hang which is not an issue I am having.
Thank you in advance for the assistance, I am slowly learning C# and programming in general and this community has been a huge help!

Related

How to uninstall a program using product code in C# code or via command line

I have an installer project for VS 2019 and it has a product code + update code available, so in my application I am using it to uninstall the application programatically. Everywhere I looked this appears to be the right way to call msiexec and provide the product code but all I get is a popup window with info style output for msiexec and error code 1603. Even running it myself via powershell it does the same thing so is this no longer the correct way to uninstall something via command line? I would be happy to get it working in command line and can easily update code as well but nothing is working at the moment.
Referenced several other forum posts, codeproject site solutions, maybe this info is just dated or no longer accurate? Checked here most recently How to uninstall MSI using its Product Code in c#
Process process = new Process();
process.StartInfo.FileName = "MsiExec.exe";
process.StartInfo.Arguments = " /x " + productCode + " /Qn";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.Start();
string output = process.StandardOutput.ReadToEnd();
string err = process.StandardError.ReadToEnd();
Debug.WriteLine(output);
Debug.WriteLine(err);
process.WaitForExit();
return (process.ExitCode == 0) ? true : false; //exit code 1603, popup appears from Start()

How do I force standard output on a C# Process when UseShellExecute == false?

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.

get git command line return value using c#

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();

How to run command line code from within C# Windows Form?

I am fairly new to coding, but have built a few small things. One thing I figured out on my last project was how to run 2 simple commands normally run from a console, but from within a form application instead. Simply, the form had 2 buttons and clicking one caused ipconfig to run and the other ipconfig /all. It then posted the ip information coming from the command into another form I created as a message box. That is important because I am trying to do something similar and nothing is working now.
I have a form that has a spot for user name and a spot for password. On submit, I want it to essentially run the following:
NET USE F: \\ALPHA\CLIENTAPPS /user:domain\%username% %password% /persistent:no
NET USE O: \\ALPHA\USERS /user:domain\%username% %password% /persistent:no
NET USE S: \\ALPHA\COMPANY /user:domain\%username% %password% /persistent:no
Where %username% and %password% are captured from the form and domain will be our actual domain.
Using similar methods to the aforementioned ipconfig program that is working, this is what I came up with. However, when I click the Submit button, nothing happens, no errors, nor does it actually create the network share:
private void btnSubmit_Click(object sender, EventArgs e)
{
string un = txtUsername.Text;
string pw = txtPassword.Text;
System.Diagnostics.ProcessStartInfo PR = new System.Diagnostics.ProcessStartInfo("cmd", #" /c net use W: \\\\ALPHA\\CLIENTAPPS /user:acsdish\\" + un + " " + pw + "/persistent:no");
PR.RedirectStandardOutput = true;
PR.UseShellExecute = false;
PR.CreateNoWindow = true;
System.Diagnostics.Process StartPR = new System.Diagnostics.Process();
StartPR.StartInfo = PR;
StartPR.Start();
}
What am I missing here, or is there a better way? Thanks.
Mike
System.Diagnostics.ProcessStartInfo PR = new System.Diagnostics.ProcessStartInfo("cmd", #" /c net use W: \\\\ALPHA\\CLIENTAPPS /user:acsdish\\" + un + " " + pw + "/persistent:no");
Try to remove "#" or remove escaping of "\" char
Info here (Verbatim string literals)
nothing happens, no errors, nor does it actually create the network share
You've done a lot to ensure that. "No errors" is easy to explain, you don't check for errors nor do you give a way for the user to see them because you made sure that the console window isn't visible. If the command failed that it won't be visible. Checking Process.ExitCode is a minimal requirement.
Next flaw is that you create the mapping to the share for a particular user. Which is fine, drive mappings are a per-user setting. But you are not actually logged-in as that user so you can't see those mappings. You'll have to hit Ctrl+Alt+Del and switch the user account. But that's a lost cause because you passed /persistent:no. That means "persistent while the user is logged in".
Ultimate flaw is that you leave it up to an another process to take care of it. That always loses critical information, especially errors. You should pinvoke the Windows api function that does this so you know when it doesn't work and don't burn a gazillion cycles to run another process. Pinvoke WNetAddConnection2().

Using Javac in C#?

Okay, so I've been working on this a while (and I've gone through multiple questions to get this far in the project).
Here's the C# code I'm using:
Process p = new Process();
p.StartInfo.RedirectStandardError = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = "javac";
Directory.CreateDirectory(Path.Combine(Application.StartupPath + #"\TempJavaalfgwaepfgawe"));
p.StartInfo.Arguments = "-d " + Path.Combine(Application.StartupPath + #"\TempJavaalfgwaepfgawe") + " " + files;
p.Start();
p.WaitForExit();
MessageBox.Show(p.StandardError.ReadToEnd());
In essence, I am trying to invoke the Java compiler (javac) from a C# application.
Now, when I do this, it wasn't compiling the java code correctly, so I inserted the RedirectStandardError and UseShellExecute as well as the WaitForExit and MessageBox at the end to see the error that was occurring.
Anyways, the error is as follows:
javac: invalid flag: 2010\Projects\Java
Usage: javac [options] [source files]
use -help for a list of possible options
So, what's wrong with my code?
To me, the error looks like part of the location of one of the file paths.
I suggested the fix in the comments, but I also wanted to add a formal answer for others with this problem.
When you pass in arguments to a process, strings that have spaces need to be quoted. This tells the argument parser that you really mean one argument. (different arguments are usually divided by white space)

Categories

Resources