I can in C# do the following:
var pSpawn = new Process
{
StartInfo = { WorkingDirectory = #"C:\temp", FileName = fileToRun, CreateNoWindow = true }
};
pSpawn.Start();
and this works fine.... however I am wondering if there is a way to run a command (ie: "dir /b") without having to encapsulate it in a batch file?
Just start the cmd.exe and pass the arguments required
var pSpawn = new Process
{
StartInfo =
{
WorkingDirectory = #"C:\temp",
FileName = "cmd.exe",
Arguments ="/K dir /b" }
};
pSpawn.Start();
I have added the parameter /K to leave the command window open so, it is possible to see the output of the command dir.
Of course I think that you are really interested to catch the output of the command.
In this case you could work with something like this:
StringBuilder sb = new StringBuilder();
var pSpawn = new Process
{
StartInfo =
{
WorkingDirectory = #"C:\temp",
FileName = "cmd.exe",
Arguments ="/c dir /b",
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardInput = true,
UseShellExecute = false
}
};
pSpawn.OutputDataReceived += (sender, args) => sb.AppendLine(args.Data);
pSpawn.Start();
pSpawn.BeginOutputReadLine();
pSpawn.WaitForExit();
Console.WriteLine(sb.ToString());
You can call something like this:
ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
info.Arguments = "/c dir /b";
Process.Start(info);
Related
I have read several question on how to read the standard output from a process such as these ones:
https://stackoverflow.com/a/285841/637142
https://stackoverflow.com/a/9730455/637142
and all of them work great. But for some reason when using it against tcpdump it does not work.
When I run this on Linux I get this output:
~ /usr/bin/tcpdump -n
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
16:34:36.190659 IP 192.168.157.221.56683 > 8.8.8.8.53: 29151+ A? google.com. (28)
16:34:36.190665 IP 192.168.157.221.56683 > 8.8.8.8.53: 39646+ AAAA? google.com. (28)
16:34:36.219305 IP 8.8.8.8.53 > 192.168.157.221.56683: 29151 1/0/0 A 142.250.64.206 (44)
16:34:40.891435 ARP, Request who-has 192.168.157.221 (00:15:5d:fb:8f:dd) tell 192.168.144.1, length 28
... etc
Now on C# this is what am I doing hoping to do the same thing:
var process = new Process();
process.StartInfo = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = "/usr/bin/tcpdump",
Arguments = "-n",
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
};
process.OutputDataReceived += (a, b) =>
{
if (b.Data is null) return;
Console.WriteLine(b.Data); // <--- trying to hit this line
};
process.ErrorDataReceived += (a, b) =>
{
if (b.Data is null) return;
Console.WriteLine(b.Data);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
await process.WaitForExitAsync();
Why is it that when I run that I get no output? If I run on another terminal the command /usr/bin/tcpdump -n I see output but not on the c# application why?
I have also tried a synchronous attempt:
var process = new Process();
process.StartInfo = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = "/usr/bin/tcpdump",
Arguments = "-n",
RedirectStandardOutput = true,
CreateNoWindow = true,
};
process.Start();
while (process.HasExited == false)
{
Span<char> buf = new char[1024].AsSpan();
var i = process.StandardOutput.Read(buf);
if (i > 0)
{
var str = new string(buf); // I never hit this line
Console.WriteLine(str);
}
}
If I run both programs at the same time one works (top) and the other does not (c#):
As you can see from the output both programs are listening on interface eth0 they both show the same output. But for some reason the c# one does not capture any traffic.
This answer solved my problem: https://unix.stackexchange.com/a/16484/281179
I needed to pass the argument -l for buffered. In other works this is how my c# code looks like now:
process.StartInfo = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = "/usr/bin/tcpdump",
Arguments = "-l -n", // <--------- append -l flag
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
};
// ... etc
My question is literally, how do I execute a Shell command from my application. There is a similar Post, but that shows how to execute a script file and requires the path to that file.
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = command, // Path required here
Arguments = args,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
Why I want to pass the command as a string?
Because I want to interpolate it. Otherwise, I would have to create a script, with some input parameters. Since I'm not that good with Shell, I prefer the easy way.
Assume you want to run echo hello in bash, then
Process process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "bash",
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
}
};
process.Start();
await process.StandardInput.WriteLineAsync("echo hello");
var output = await process.StandardOutput.ReadLineAsync();
Console.WriteLine(output);
I want to print a PDF file from C# code without user interaction.
I tried this accepted answer but it is not working for me.
This is the code I tried:
Process p = new Process();
p.StartInfo = new ProcessStartInfo()
{
CreateNoWindow = true,
Verb = "print",
FileName = #"G:\Visual Studio Projects\PrintWithoutGUI\PrintWithoutGUI\Courses.pdf" //put the correct path here
};
p.Start();
I get this exception :
System.ComponentModel.Win32Exception: 'The specified executable is not a valid application for this OS platform.'`
try this by add UseShellExecute=true it will print to default printer but if you want to print to a specific print change the verb print to verb printTo by spefiying the name of the printer Arguments proprety.
private static void PrintByProcess()
{
using (Process p = new Process())
{
p.StartInfo = new ProcessStartInfo()
{
CreateNoWindow = true,
UseShellExecute=true,
Verb = "print",
FileName = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\doc.pdf"
};
p.Start();
}
this is the correct way to write your code
Process p = new Process();
p.StartInfo = new ProcessStartInfo()
{
CreateNoWindow = true,
Verb = "print",
FileName = "PDfReader.exe", //put the path to the pdf reading software e.g. Adobe Acrobat
Arguments = "PdfFile.pdf" // put the path of the pdf file you want to print
};
p.Start();
I´m trying to make a program. that will find a programs PID number.
so far i got it to work with notepad.
Code:
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = "/C for /f \"tokens=1,2\" %a in " + "('Tasklist /fi \"imagename eq notepad.exe\" /nh') do #echo %b",
RedirectStandardOutput = true,
UseShellExecute = false,
}
};
Its not going to be a Notepad it was just for testing purposes.
I want it to be a string that stands there instead of notepad.
Like this
String myProgram = #"[insert program name]";
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = "/C for /f \"tokens=1,2\" %a in " + "('Tasklist /fi \"imagename eq MyProgram\" /nh') do #echo %b",
RedirectStandardOutput = true,
UseShellExecute = false,
}
};
I don't know how to change it from the text "notepad" to my string.
Maybe it can work?
Arguments = string.Format("/C for /f \"tokens=1,2\" %a in " + "('Tasklist /fi \"imagename eq {0}\" /nh') do #echo %b",myProgram ),
This will give you the PIDs of all running notepad instances:
foreach (var notepad in Process.GetProcessesByName("notepad"))
{
Console.WriteLine(notepad.Id);
}
There is no need to start a batch processor and fiddle with it's parameters.
Simplest way would be to use the string.Format shorthand:
string myProgram = #"[insert program name]";
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = $"/C for /f \"tokens=1,2\" %a in ('Tasklist /fi \"imagename eq {myProgram}\" /nh') do #echo %b",
RedirectStandardOutput = true,
UseShellExecute = false,
}
};
Edit: Per Ian's suggestion, the $ shorthand operator for string.Format is only available in C# 6. This won't work for earlier versions.
i'm developing an application to get backup from my postgreSQL database with C#.
i,m using code below to execute and get out put from pg_dump.exe.
ProcessStartInfo startinfo = new ProcessStartInfo
{
FileName = "\"C:\\Program Files (x86)\\pgAdmin III\\1.16\\pg_dump.exe\"",
Arguments = "--host XXX.XXX.XXX.XXX --port 5432 --username \"USERNAME\" --no-password --format plain --verbose --file \"D:\\MYBACKUP.backup\" \"MYDBNAME\"",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process proc = new Process();
proc.StartInfo = startinfo;
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
var r = proc.StandardOutput.ReadLine();
}
proc.WaitForExit();
Console.WriteLine(proc.ExitCode);
Console.ReadLine();
but proc.StandardOutput.ReadLine always returns null!!!
i try to put pg_dump.exe output to a file with command propt like this:
C:\Program Files (x86)\pgAdmin III\1.16>pg_dump.exe > d:\log.txt
but again log.txt is empty!!
thanks in advance.
Replace RedirectStandardOutput with RedirectStandardError.
My working code is:
ProcessStartInfo startinfo = new ProcessStartInfo
{
FileName = "Path to pg_dump.exe",
Arguments = "Arguments",
UseShellExecute = false,
RedirectStandardError = true,
CreateNoWindow = true
};
using (Process process = Process.Start(startinfo))
{
using (StreamReader reader = process.StandardError)
{
StreamWriter sw = new StreamWriter(#"C:\log.txt");
sw.WriteLine(reader.ReadToEnd());
sw.Close();
}
}