PROWAREtech
.NET: Create, Read from and Write to Processes
Create a new process in .NET with a simple Process.Start("notepad.exe")
but more control is had by creating a Process
object. Process.Start("http://www.bing.com")
also works. Probably, Process.Start()
is using the WinAPI ShellExecute()
function while the Process
object is using the CreateProcess()
function (at least for the Windows platform).
Learn how to kill a process or download a file from a URL using HttpClient.
Imports System.Diagnostics
Module Module1
Sub Main()
Dim pro As New Process()
pro.StartInfo.FileName = "notepad.exe"
pro.StartInfo.Arguments = "temp.txt"
' NOTE: can specify ProcessWindowStyle.Hidden for programs that do not need user input
pro.StartInfo.WindowStyle = ProcessWindowStyle.Normal
pro.Start()
pro.WaitForExit()
End Sub
End Module
C#:
using System.Diagnostics;
namespace Console1
{
class Program
{
static void Main(string[] args)
{
Process pro = new Process();
pro.StartInfo.FileName = "notepad.exe";
pro.StartInfo.Arguments = "temp.txt";
// NOTE: can specify ProcessWindowStyle.Hidden for programs that do not need user input
pro.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
pro.Start();
pro.WaitForExit();
}
}
}
Reading Console Application Output
Create a console process and read its output.
using (var proc = new System.Diagnostics.Process
{
StartInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = "/bin/executable",
Arguments = "-arguments",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
})
{
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
// NOTE: can also read one character at a time with proc.StandardOutput.Read() for more of a "real-time" effect
string line = proc.StandardOutput.ReadLine();
// NOTE: do something with this line of text
}
}
Now, read binary data from a console process.
using (var proc = new System.Diagnostics.Process
{
StartInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = "/bin/executable",
Arguments = "-arguments",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
})
{
proc.Start();
using (BinaryReader reader = new BinaryReader(proc.StandardOutput.BaseStream))
{
byte[] chunk = reader.ReadBytes(1024);
while (chunk.Length > 0)
{
// NOTE: do something with this byte array
chunk = reader.ReadBytes(1024);
}
}
}
Writing to a Console Application
In practice, if reading and writing to a console application, then it may be done on separate threads and likewise the console application may read and write on separate threads. This is because Console.ReadLine()
, proc.StandardOutput.Read()
and proc.StandardOutput.ReadLine()
are blocking.
using (var proc = new System.Diagnostics.Process
{
StartInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = Path.Combine(Environment.CurrentDirectory, "executable.exe"),
Arguments = "/command /line /arguments /go /here",
UseShellExecute = false,
RedirectStandardOutput = true, // NOTE: optional
RedirectStandardInput = true, // NOTE: required
CreateNoWindow = true, // NOTE: optional
WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden // NOTE: optional
}
})
{
proc.StandardInput.WriteLine("Hello, World!"); // NOTE: this will send "Hello, World!" to the console application's process
proc.StandardOutput.ReadLine();
}
Creating Processes on Remote Machines
Creating a process on another machine remotely from a C# application is possible, but it requires certain conditions to be met regarding network configuration, permissions, and security settings. The methods for achieving this typically involve using Windows Management Instrumentation (WMI), PowerShell remoting, or other network protocols that support remote command execution.
Windows Management Instrumentation (WMI) is a Windows feature that provides a standardized way to interact with system management data and operations. Use WMI to create processes on remote machines but ensure that both the local and remote machines are configured to allow WMI access.
using System;
using System.Management;
class Program
{
static void Main()
{
string remoteComputer = "REMOTE_COMPUTER_NAME";
string domain = "DOMAIN_NAME"; // NOTE: can be an empty string if not on a domain
string username = "USERNAME";
string password = "PASSWORD";
string processToRun = @"C:\Path\To\Executable.exe /command-line-argument";
ConnectionOptions connOptions = new ConnectionOptions();
connOptions.Username = domain + "\\" + username;
connOptions.Password = password;
connOptions.Impersonation = ImpersonationLevel.Impersonate;
connOptions.EnablePrivileges = true;
ManagementScope manScope = new ManagementScope($@"\\{remoteComputer}\root\cimv2", connOptions);
try
{
manScope.Connect();
ObjectGetOptions objectGetOptions = new ObjectGetOptions();
ManagementPath managementPath = new ManagementPath("Win32_Process");
ManagementClass processClass = new ManagementClass(manScope, managementPath, objectGetOptions);
ManagementBaseObject inParams = processClass.GetMethodParameters("Create");
inParams["CommandLine"] = processToRun;
ManagementBaseObject outParams = processClass.InvokeMethod("Create", inParams, null);
Console.WriteLine("Return Value: " + outParams["ReturnValue"]); // NOTE: return value of 0 means success, just like with any regular process
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
}
}