Question
Run Command Prompt Commands from C# with ProcessStartInfo
Question
Is it possible to run Command Prompt commands from a C# application? If so, how can I automate the following Windows command?
copy /b Image1.jpg + Archive.rar Image2.jpg
This command concatenates a JPG file and an RAR archive into a new file. I would like to perform this operation automatically from C#.
Short Answer
You can start Command Prompt or another executable from C# with System.Diagnostics.Process and ProcessStartInfo. For this particular task, however, C# file streams are usually a better choice: they copy binary bytes directly, avoid shell-specific syntax, and make errors easier to handle.
Concept
Process lets a C# program start another program, such as cmd.exe, git, dotnet, or a custom command-line tool.
When you need Command Prompt syntax—such as copy /b, pipes (|), redirection (>), or shell built-ins—start cmd.exe and pass the command after /c:
cmd.exe /c "your command here"
cmd.exeis the Windows Command Prompt executable./cmeans “run this command, then exit.”- The command itself is passed as an argument.
For operations that are already easy in .NET, prefer the .NET API instead of launching a shell. Concatenating files is one example: FileStream can copy bytes from each input file into one output file. This is more portable within .NET, avoids command quoting issues, and does not depend on the behavior of a shell command.
The /b option in copy /b means binary mode. It is important for non-text files because binary data must be copied without text-oriented transformations.
Mental Model
Think of Process as asking your C# application to hire another worker.
- Your application is the manager.
cmd.exeis a worker that understands Command Prompt instructions.ProcessStartInfois the work order: it says which worker to start, which arguments to give it, whether to show a window, and whether to return its output.
For file concatenation, using FileStream is like doing the work inside your own application instead of hiring Command Prompt. It is often simpler because your application controls every byte that is read and written.
Syntax and Examples
Use ProcessStartInfo to configure a process before starting it.
using System.Diagnostics;
var startInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = "/c echo Hello from Command Prompt",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
using Process process = Process.Start(startInfo)!;
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
Console.WriteLine(output);
Console.WriteLine($"Exit code: {process.ExitCode}");
FileName identifies the program to run. Arguments contains arguments for that program. Here, Command Prompt receives /c echo Hello from Command Prompt.
For the original command, use paths surrounded by quotes so names containing spaces work:
using System.Diagnostics;
string imagePath = @"C:\Files\Image1.jpg";
string archivePath = @"C:\Files\Archive.rar";
string outputPath = @"C:\Files\Image2.jpg";
string command = $"copy /b \"{imagePath}\" + \"{archivePath}\" \"{outputPath}\"";
var startInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = $"/c \"{command}\"",
UseShellExecute = false,
CreateNoWindow = true
};
using Process process = Process.Start(startInfo)!;
process.WaitForExit();
if (process.ExitCode != 0)
{
throw new InvalidOperationException($"The copy command failed with exit code {process.ExitCode}.");
}
Only build shell command strings from paths your application controls or has validated. If untrusted user input is inserted into a shell command, it can alter the command that is executed.
Step by Step Execution
Consider this smaller example:
using System.Diagnostics;
var startInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = "/c dir C:\\Temp",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
using Process process = Process.Start(startInfo)!;
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
Console.WriteLine(output);
Step by step:
- A
ProcessStartInfoobject is created. FileName = "cmd.exe"selects Windows Command Prompt.Arguments = "/c dir C:\\Temp"tells Command Prompt to listC:\Tempand then close.UseShellExecute = falseallows C# to redirect the program's output.RedirectStandardOutput = truesends Command Prompt's normal text output back to the C# program.Process.Startlaunches Command Prompt.ReadToEnd()reads its output. Reading before waiting is useful when output is redirected.WaitForExit()waits until the command has finished.Console.WriteLinedisplays the captured directory listing.
For binary file concatenation, no textual output needs to be captured unless you want diagnostics. You should still wait for completion and inspect the exit code when launching an external command.
Real World Use Cases
Common uses of Process in C# include:
- Running build tools such as
dotnet build,npm, orgitfrom a desktop tool or CI helper. - Calling an image, video, or document converter that provides a command-line interface.
- Running system maintenance scripts in an internal Windows application.
- Executing database migration tools during deployment.
- Automating existing command-line utilities when no suitable .NET library exists.
- Capturing a tool's standard output and error output for logs or a user-facing status screen.
For normal file tasks, .NET APIs are usually preferable:
File.Copyfor copying one file.Directory.CreateDirectoryfor folders.FileStreamfor streaming or combining binary data.System.IO.Compressionfor ZIP archives when ZIP is appropriate.
An RAR archive requires an RAR-capable library or command-line program if you need to inspect, create, or extract its contents. Concatenating an existing archive is only a byte-copy operation.
Real Codebase Usage
In production code, process launching is commonly wrapped in a helper method that handles logging, output, errors, and cancellation.
A robust pattern is:
- Validate file paths and verify that input files exist.
- Prefer direct .NET APIs when they can perform the task.
- Use
ProcessStartInfo.ArgumentListfor normal executable arguments rather than manually joining quoted strings. - Redirect both standard output and standard error when diagnostics matter.
- Check
ExitCodeafter the process finishes. - Treat nonzero exit codes as failures unless the tool documents otherwise.
For this operation, a direct streaming implementation is clearer and avoids the shell entirely:
using System;
using System.IO;
static void CombineFiles(string imagePath, string archivePath, string outputPath)
{
if (!File.Exists(imagePath))
throw new FileNotFoundException("Image file was not found.", imagePath);
if (!File.Exists(archivePath))
throw new FileNotFoundException("Archive file was not found.", archivePath);
using var output = new FileStream(outputPath, FileMode.Create, FileAccess.Write);
using (var image = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
image.CopyTo(output);
}
using (var archive = new FileStream(archivePath, FileMode.Open, FileAccess.Read))
{
archive.CopyTo(output);
}
}
This is equivalent to writing the bytes from the JPG first and the bytes from the RAR second. It does not require cmd.exe, and it works even if Command Prompt is unavailable or restricted.
Common Mistakes
Forgetting /c
Without /c, Command Prompt starts but does not receive the instruction to run one command and exit.
// Incomplete for a one-time command
FileName = "cmd.exe";
Arguments = "dir";
Use:
Arguments = "/c dir";
Not quoting paths with spaces
This breaks when a file is in a directory such as C:\My Files.
string command = "copy /b C:\My Files\Image1.jpg + C:\My Files\Archive.rar output.jpg";
Quote each path:
string command = "copy /b \"C:\\My Files\\Image1.jpg\" + \"C:\\My Files\\Archive.rar\" \"C:\\My Files\\output.jpg\"";
Treating a command as an executable
copy is a Command Prompt built-in, not a standalone copy.exe program that C# can reliably start directly. Start cmd.exe for shell built-ins, or use FileStream instead.
Ignoring errors and exit codes
A process can start successfully but the command can still fail because a file is missing or the destination is unwritable. Call WaitForExit() and inspect ExitCode.
Redirecting output but not reading it
A process can block if it writes enough redirected output and your program never reads it. Read redirected standard output and standard error before or while waiting for the process to exit.
Building shell commands from untrusted input
Do not insert arbitrary text entered by a user into cmd.exe /c .... Shell metacharacters such as &, |, and > can change the command. Prefer direct .NET APIs; otherwise validate inputs strictly.
Assuming the resulting file is a normal image everywhere
Appending bytes does not change the JPG's original image data, but different viewers, scanners, upload services, or security tools may handle trailing data differently. Do not rely on this format for storing application data. Store attachments separately or use a documented container format when the data must be reliably exchanged.
Comparisons
| Approach | Best for | Advantages | Limitations |
|---|---|---|---|
FileStream and CopyTo | Copying or concatenating binary files | No shell quoting, direct byte control, easy validation | You implement the operation yourself |
File.Copy | Copying one file to another location | Very simple .NET API | Does not append a second file |
Process with cmd.exe | Command Prompt built-ins and shell syntax | Reuses existing Windows commands | Windows-specific and sensitive to quoting |
Process with a tool executable | Tools such as git.exe or ffmpeg.exe | Automates a specialized external tool | Requires the tool to be installed and handled correctly |
ProcessStartInfo.Arguments is appropriate when passing one complete shell command to cmd.exe. For a normal executable, prefer ArgumentList:
var startInfo = new ProcessStartInfo
{
FileName = "git",
UseShellExecute = false
};
startInfo.ArgumentList.Add("status");
ArgumentList avoids many quoting mistakes, but it does not replace cmd.exe when you specifically need Command Prompt features such as copy /b or |.
Cheat Sheet
using System.Diagnostics;
var startInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = "/c echo Hello",
UseShellExecute = false,
CreateNoWindow = true
};
using Process process = Process.Start(startInfo)!;
process.WaitForExit();
int exitCode = process.ExitCode;
- Use
cmd.exe /cto run one Command Prompt command and exit. - Quote file paths that might contain spaces.
- Set
UseShellExecute = falseto redirect output or error streams. - Use
RedirectStandardOutputandRedirectStandardErrorwhen you need diagnostics. - Read redirected streams to avoid blocked processes.
- Call
WaitForExit()before using the exit code. - Exit code
0commonly means success, but consult the tool's documentation. - Prefer
System.IOAPIs for file operations that .NET can perform directly. - Never concatenate untrusted input into a command string passed to a shell.
FAQ
Can C# run Command Prompt commands?
Yes. Start cmd.exe through System.Diagnostics.Process and pass /c followed by the command.
What does /c mean in cmd.exe /c?
It tells Command Prompt to execute the supplied command and then terminate.
Can I run copy /b directly with Process.Start?
Not reliably. copy is a Command Prompt built-in. Start cmd.exe /c copy /b ..., or use FileStream to concatenate the files directly.
How do I hide the Command Prompt window in C#?
Set UseShellExecute = false and CreateNoWindow = true. This does not make a console application disappear; it prevents a new Command Prompt window for the child process.
How can I get error messages from a command?
Set RedirectStandardError = true, read process.StandardError, wait for the process to finish, and check ExitCode.
Is FileStream better than calling copy /b?
For combining files in a C# application, usually yes. It avoids a shell, works directly with bytes, and gives your code clearer control over validation and exceptions.
Does adding an archive after a JPG make it a valid RAR file?
The output begins as a JPG and contains the archive bytes after it. Whether a particular program recognizes or accepts the trailing archive data depends on that program; this is not a general-purpose archive or attachment format.
Mini Project
Description
Build a small console utility that combines two binary files by writing the bytes of the first file followed by the bytes of the second file. This demonstrates the .NET alternative to the Windows copy /b command and includes basic path validation.
Goal
Create an output file containing a JPG file's bytes followed by an archive file's bytes.
Requirements
Provide three command-line arguments: the first input path, the second input path, and the output path.
Verify that both input files exist before creating the output.
Write the first file completely before writing the second file.
Display the output path and final file size after a successful operation.
Return a nonzero exit code when input is invalid or the operation fails.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Access Modifiers and static: public, private, protected, and Defaults
Learn how C# public, private, protected, and default access control visibility, and how static differs from instance members.