Process.StandardOutput.ReadToEnd() and extraneous newline chars - c#

I am trying to understand why, when I call the above function, I am getting hex 0D0A every 80th column on the output I am reading.
I have a powershell script, for testing that has two lines in it for brevity's sake:
$xmlSpew = "<IISAppPoolConfig><DefaultWebSite><ApplicationPoolName>DefaultAppPool</ApplicationPoolName></DefaultWebSite><AuthN>Basic</AuthN></IISAppPoolConfig>"
Write-Output $xmlSpew
I am calling the script using the Process object with ProcessStartInfo as follows:
var psi = new ProcessStartInfo
{
WorkingDirectory = Path.GetDirectoryName(FileToRun),
FileName = FileToRun,
Arguments = Arguments,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
};
var process = new Process
{
StartInfo = psi,
EnableRaisingEvents = true,
};
FileToRun value is:
C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe
Arguments value is:
-File "C:\Program Files\MyTest\MyProgInputs\read.d\IISAppPoolConfig.ps1"
The script runs fine and I get back exit code 0, but I have this mysterious (to me) 0D0A newline every 80th char in standard out that I capture using:
var Stdout = new List<string>;
...
Stdout.Add(process.StandardOutput.ReadToEnd());
This is wreaking havoc on my XML efforts once I have standard out stored in a string var. I expected to get exactly what I write to the stdout in the ps1 script, not the extra newline.
What am I missing? I've looked for others with this issue, but I have not found an answer. Hopefully it is not me being search-challenged.

Follow this P/Invoke method and set dwXCountChars to a very large value. Don't forget to include STARTF_USECOUNTCHARS in the flags as well.

Final and tested resolution for now (because I need to ship something), is to have output from powershell come from the Write-Host cmdlet instead of Write-Output. The process for obtaining stdout remained the same as in my original post. Hope this helps others. Thanks for all the inputs.

Related

Run Python script with imports in C#

Lets say I have this super Python script that needs to run cv2 in the future...
import cv2
def method():
print("Hello")
parameter = "l"
return "OOPS"
method()
And in C# something like this.
Process p = new Process();
p.StartInfo = new ProcessStartInfo(#"D:\Programming\Python\python.exe", fileName)
{
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
p.Start();
string output = p.StandardOutput.ReadToEnd();
But this does throw an error "ImportError: DLL load failed". Alright seems like it is lookin in wrong directories for libraries since I have about 4 Python interpreters. Follows quick fix.
string path = #"D:\Programming\Python;" + Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine);
Environment.SetEnvironmentVariable("PATH", path, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PYTHONHOME", #"D:\Programming\Python;", EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PYTHONPATH ", #"D:\Programming\Python\Lib; D:\Programming\Python\DLLs", EnvironmentVariableTarget.Process);
string fileName = #"..\Python\hello.py";
Process p = new Process();
p.StartInfo = new ProcessStartInfo(#"D:\Programming\Python\python.exe", fileName)
{
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
p.Start();
string output = p.StandardOutput.ReadToEnd();
Import DLL is fixed now, but another wild bug appeared named,
Fatal Python error: initfsencoding: unable to load the file system codec
ModuleNotFoundError: No module named 'encodings'
At this point I am lost and dont know what should I do next... any ideas are welcome, have a nice day.
UPDATE:
Deleted all other python interpretors aside from anaconda and one virtual env and tried following:
Run Python script from Visual Studio Code with given interpretor, works fine.
Run it from Anaconda prompt, aswell.
Added manually to system environment variables
PATH=D:\Programming\Python
PYTHONHOME=D:\Programming\Python
PYTHONPATH=D:\Programming\Python\Lib;D:\Programming\Python\DLLs;D:\Programming\Python\Lib\site-packages
So now I can successfully call "python" from cmd, like that and check version, the virtual env is python 3.6 and this is the right one.
Python is correct
But this is where all the fun begins you would expect "hello" in your console...
hell incarnate
Did not find correct answer to this problem, but discovered workaround in p2exe or pyinstaller.
Simply call pyinstaller.py --onefile xx.py and create exe file and pass that into process.

Process.StandardOutput stops reading

I am trying to run a process, hide its window and then print its output in my program. I am achieving it with this code:
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = path,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
Verb = "runas"
}
};
proc.Start();
while(!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
Console.WriteLine(line);
}
It works with other programs but for this one it's stopping at some point. My guess is that it sends too much messages, because before actually loading it spams a ton of messages that say: "Initializing... n%". It reads it until it reaches around 90-95% and then stops reading. My guess is that it can't read anymore because it sent too much messages. What can I do to read the whole output?
I found out how to make a workaround. It turns out the program actually needed input inbetween the initialization and the actual result. Thanks to #Alexandru Clonțea I decided that I would not run the process, but create a .bat file, which contains the following command:
program.exe > output.txt < input.txt
Where program.exe is the executable, output.txt is the file that is going to contain the output of the program and input.txt in my case is just an empty text file so I can just get some kind of an input and make the program finish.

Calling ProcessStartInfo with a path with spaces always breaks

I'm calling a command line program with the following configuration:
var processStartInfo = new ProcessStartInfo {
FileName = mainCommand,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
};
And when I'm running it with mainCommand being a path that has no spaces it always works, if there is a space on the path to the command it fails with:
Could not find the command file at C:\Users\Some
Where the actual path would be:
C:\Users\Some User\AppData\Local\Temp\Process.exe
So, why isn't it being escaped and is there a way I can escape this path name to prevent this error?
Try wrapping it with quotes:
string targetExe = "\"C:\\this path with spaces\\helloWorld.exe\"";
It works like such, but it also work without having to worry about it as Patrick Hofman said. Something's different on your system it seems.
If you want to pass arguments, do it trough Arguments in ProcessStartInfo. Obviously, if these have spaces too (ie: /arg1 "An Argument"), you will have to wrap them in quotes as above.

Process.Start starts a shell then quickly exits

I am writing a C# application that uses WinForms.
I want to launch my own shell as an Admin then use Stream Writer to run some commands.
I am not doing any thing malicious. It's to fix the connection issues with another internal application (for work). The other team isn't willing to fix their program so they provided us with a command line fix. However I have to run this on many PC's so I am learning C# and trying to build something that I would use.
As soon as myProcess.Start executes, a black box appears then quickly disappears before going to the next line.
public void ProcessStartAsAdmin(string command)
{
string cname = Environment.UserDomainName + "\\" + Environment.UserName;
Process myProcess = new Process();
myProcess.StartInfo.FileName = #"C:\Windows\System32\CMD.exe";
myProcess.StartInfo.Verb = #"runas";
//myProcess.StartInfo.Arguments = command;
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.RedirectStandardError = true;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.Start();
StreamWriter myStreamWriter = myProcess.StandardInput;
String inputText;
string resetConnection = "C:\\APP\\application.exe /reset /server:example.com /uid:" + cname + " /pwd:" + textBoxPassword.Text.Trim();
myStreamWriter.WriteLine(resetConnection);
myStreamWriter.Close();
myProcess.WaitForExit();
myProcess.Close();
}
If I am doing anything wrong, please let me know. If I can use a better technique, I'm open for suggestions.
Thanks.
I don't know whether this is the only issue, but there's no space between these two arguments:
/uid:" + cname + "/pwd:"
it should be:
/uid:" + cname + " /pwd:"
string resetConnection = "C:\\APP\application.exe
\a is illegal. You should write \\ (it seems you know it, and missed).
Edit:
The screen that your see is empty, because of you chose to redirect output.
What is probably happening is that the line has some error (or it's running time is very small), and you not see that.
Cancel temporary the output redirection, and the process closing, and see what happened.
Let's take a look at how you initialize the start info:
myProcess.StartInfo.Verb = #"runas";
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.RedirectStandardError = true;
myProcess.StartInfo.RedirectStandardOutput = true;
You are redirecting the standard input, output and error streams. The documentation for this says:
You must set UseShellExecute to false if you want to set RedirectStandardOutput to true. Otherwise, reading from the StandardOutput stream throws an exception.
And likewise for the other two standard streams. So, redirection implies that you must set UseShellExecute to false.
On the other hand, you wish the new process to be elevated. Which means that you want to use the runas verb.
The documentation does not say so, but the Verb property only has impact when UseShellExecute is set to true. So, requesting elevation implies that you must set UseShellExecute to true. There is no other way to request elevation for a new process. You have to pass through the ShellExecuteEx (or its relatives) with the runas verb and that forces you to set UseShellExecute to true.
So there are two conflicting requirements here. You've got no option at all over elevation I presume. You must elevate for this task. Which means you'll have to give up on redirection. I suppose the only other option would be for you to run the calling process elevated. That would mean that any child processes would also be elevated and there would be no need for runas and so you could set UseShellExecute to false.
However, I see no reason for redirection. You are only doing that, I think, so that you can send commands to the cmd process. Instead you can pass the commands as arguments, or place them in an external .bat or .cmd file. So if I were you I would stop redirecting, and set UseShellExecute to true, and take it from there.

XCopy does not work with UseShellExecute = false

I am trying to run a Batch file from .net/c# using System.Diagnostics.Process. Somehow it does not execute xcopy command of the Batch file.
Sample Batch File:
#copy test to test2 including sub directories
xcopy c:\test\ c:\test2
C# code:
public void RunMSIBatchFile(string _workingDirectory, string batchFileName)
{
var process = new Process
{
StartInfo =
{
UseShellExecute = false,
RedirectStandardOutput = true,
WorkingDirectory = _workingDirectory,
FileName = _workingDirectory + batchFileName,
CreateNoWindow = true,
RedirectStandardError = true
}
};
process.OutputDataReceived += ProcessOutputDataReceived;
process.Start();
process.BeginOutputReadLine();
process.WaitForExit(Convert.ToInt32(CommandTimeOut.TotalMilliseconds));
}
If I change UseShellExecute to true then it works but then there seems to be no way to capture standard output.
Has anyone faced such problem?
I've tested your exact code, and appear to be able to receive data just fine. However, since the read occurs asynchronously, it is possible for WaitForExit(...) to return before you have read all of the data. It appears that the end of the data is signalled by the Data property of the DataReceivedEventArgs passed to the OutputDataReceived event handler being null.
It is also worth noting that if xcopy requests input from the user (e.g. in the case of a file with the same name existing in the destination) it appears that no data is returned. You may want to check for this in your batch file, or also handle data from the Standard Error stream.

Categories

Resources