ProcessUtils 0.1.3

dotnet add package ProcessUtils --version 0.1.3
                    
NuGet\Install-Package ProcessUtils -Version 0.1.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ProcessUtils" Version="0.1.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ProcessUtils" Version="0.1.3" />
                    
Directory.Packages.props
<PackageReference Include="ProcessUtils" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ProcessUtils --version 0.1.3
                    
#r "nuget: ProcessUtils, 0.1.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ProcessUtils@0.1.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ProcessUtils&version=0.1.3
                    
Install as a Cake Addin
#tool nuget:?package=ProcessUtils&version=0.1.3
                    
Install as a Cake Tool

ProcessUtils

A lightweight .NET utility library for running external processes with proper argument escaping and output capture.

CI Build NuGet NuGet Downloads

Features

  • ✅ Safe process execution with proper argument escaping
  • ✅ Capture standard output and error streams
  • ✅ Cross-platform support (.NET 8.0+)
  • ✅ Simple, clean API
  • ✅ Originally derived from the NUnit3TestAdapter project

Installation

Install via NuGet:

dotnet add package ProcessUtils

Cancellation and timeouts

You can cancel a running process using a CancellationToken, for example to enforce a timeout. When cancelled, the process is terminated and the task will be cancelled (you may observe TaskCanceledException, which derives from OperationCanceledException).

using ProcessUtils;
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2));

try
{
    var result = await ProcessRunner.Run(
        workingDirectory: string.Empty,
        scriptPath: OperatingSystem.IsWindows() ? "python" : "python3",
        arguments: new[] { "./long_running_script.py" },
        cancellationToken: cts.Token
    );
    Console.WriteLine($"Output: {result.StdOut}");
}
catch (OperationCanceledException)
{
    Console.WriteLine("Process timed out and was cancelled.");
}

Or via Package Manager Console:

Install-Package ProcessUtils

Usage

using ProcessUtils;

// Run a process and capture output
var result = await ProcessRunner.Run(
    workingDirectory: @"C:\MyApp",
    scriptPath: "myapp.exe",
    arguments: new[] { "--option", "value with spaces" }
);

// Check the results
if (result.ExitCode == 0)
{
    Console.WriteLine("Success!");
    Console.WriteLine($"Output: {result.StdOut}");
}
else
{
    Console.WriteLine($"Error: {result.StdErr}");
}

Azure/Cloud scenarios

When you don't control the working directory (for example in Azure Functions, App Service, or containerized environments), you can pass an empty string for the working directory. ProcessUtils will use the current directory of the running process (typically the bin folder). You can then pass a relative script path like "./pythonscript.py".

using ProcessUtils;

// Assume pythonscript.py is deployed next to your binaries (bin folder)
// We'll call Python and pass a relative path to the script
var result = await ProcessRunner.Run(
    workingDirectory: string.Empty,     // Use current directory automatically
    scriptPath: OperatingSystem.IsWindows() ? "python" : "python3",
    arguments: new[] { "./pythonscript.py" }
);

if (result.ExitCode == 0)
{
    Console.WriteLine($"Script output: {result.StdOut}");
}
else
{
    Console.WriteLine($"Script error: {result.StdErr}");
}

Working with binary data (PDF via Base64)

When a child process needs to return binary data (like a PDF) over stdout, a common pattern is to base64-encode the bytes in the script and decode them in .NET.

Python (pdf_to_base64.py):

#!/usr/bin/env python3
import sys, base64

pdf_path = sys.argv[1] if len(sys.argv) > 1 else "./document.pdf"
with open(pdf_path, "rb") as f:
    data = f.read()

# Print base64 to stdout (no extra text)
print(base64.b64encode(data).decode("ascii"))

.NET usage:

// Invoke the Python script to get a base64-encoded PDF on stdout
var result = await ProcessRunner.Run(
    workingDirectory: string.Empty,
    scriptPath: OperatingSystem.IsWindows() ? "python" : "python3",
    arguments: new[] { "./pdf_to_base64.py", "./document.pdf" }
);

if (result.ExitCode != 0)
    throw new InvalidOperationException($"Process failed: {result.StdErr}");

// Convert base64 back to bytes
// Note: Convert.FromBase64String ignores whitespace (including newlines)
string base64 = result.StdOut;
byte[] pdfBytes = Convert.FromBase64String(base64);

// Persist or stream as needed
await File.WriteAllBytesAsync("./output.pdf", pdfBytes);

API Reference

ProcessRunner.Run()

Executes a process and returns the result.

Parameters:

  • workingDirectory (string): The working directory for the process. Must be an absolute path.
  • scriptPath (string): The path to the executable or script to run.
  • arguments (IEnumerable<string>, optional): Command-line arguments to pass to the process.

Returns: ProcessRunResult containing:

  • ExitCode: The exit code of the process
  • StdOut: Captured standard output
  • StdErr: Captured standard error
ProcessRunner.EscapeProcessArguments()

Escapes a collection of argument values for safe process execution.

Parameters:

  • literalValues (IEnumerable<string>): The argument values to escape
  • alwaysQuote (bool, optional): Whether to always quote arguments

Returns: A properly escaped command-line string

Building from Source

# Restore dependencies
dotnet restore

# Build
dotnet build --configuration Release

# Run tests
dotnet test --configuration Release

# Create NuGet package
dotnet pack --configuration Release

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License.

Acknowledgments

This library is derived from the NUnit3TestAdapter project.

Support

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.3 172 10/27/2025
0.1.1 162 10/26/2025
0.1.0 145 10/26/2025

Initial release of ProcessUtils library.