Question

Run Command Prompt Commands from C# with ProcessStartInfo

csharp.netcommand-linecommandprompt

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.exe is the Windows Command Prompt executable.
  • /c means “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.exe is a worker that understands Command Prompt instructions.
  • ProcessStartInfo is 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.

Take Quiz

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:

  1. A ProcessStartInfo object is created.
  2. FileName = "cmd.exe" selects Windows Command Prompt.
  3. Arguments = "/c dir C:\\Temp" tells Command Prompt to list C:\Temp and then close.
  4. UseShellExecute = false allows C# to redirect the program's output.
  5. RedirectStandardOutput = true sends Command Prompt's normal text output back to the C# program.
  6. Process.Start launches Command Prompt.
  7. ReadToEnd() reads its output. Reading before waiting is useful when output is redirected.
  8. WaitForExit() waits until the command has finished.
  9. Console.WriteLine displays 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, or git from 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.Copy for copying one file.
  • Directory.CreateDirectory for folders.
  • FileStream for streaming or combining binary data.
  • System.IO.Compression for 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.

Take Quiz

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:

  1. Validate file paths and verify that input files exist.
  2. Prefer direct .NET APIs when they can perform the task.
  3. Use ProcessStartInfo.ArgumentList for normal executable arguments rather than manually joining quoted strings.
  4. Redirect both standard output and standard error when diagnostics matter.
  5. Check ExitCode after the process finishes.
  6. 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

ApproachBest forAdvantagesLimitations
FileStream and CopyToCopying or concatenating binary filesNo shell quoting, direct byte control, easy validationYou implement the operation yourself
File.CopyCopying one file to another locationVery simple .NET APIDoes not append a second file
Process with cmd.exeCommand Prompt built-ins and shell syntaxReuses existing Windows commandsWindows-specific and sensitive to quoting
Process with a tool executableTools such as git.exe or ffmpeg.exeAutomates a specialized external toolRequires 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 |.

Take Quiz

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 /c to run one Command Prompt command and exit.
  • Quote file paths that might contain spaces.
  • Set UseShellExecute = false to redirect output or error streams.
  • Use RedirectStandardOutput and RedirectStandardError when you need diagnostics.
  • Read redirected streams to avoid blocked processes.
  • Call WaitForExit() before using the exit code.
  • Exit code 0 commonly means success, but consult the tool's documentation.
  • Prefer System.IO APIs 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.

Take Quiz

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.

Take Quiz

Keep learning

Related questions

View more