CliInvoke 3.0.0-alpha.7
Prefix Reserveddotnet add package CliInvoke --version 3.0.0-alpha.7
NuGet\Install-Package CliInvoke -Version 3.0.0-alpha.7
<PackageReference Include="CliInvoke" Version="3.0.0-alpha.7" />
<PackageVersion Include="CliInvoke" Version="3.0.0-alpha.7" />
<PackageReference Include="CliInvoke" />
paket add CliInvoke --version 3.0.0-alpha.7
#r "nuget: CliInvoke, 3.0.0-alpha.7"
#:package CliInvoke@3.0.0-alpha.7
#addin nuget:?package=CliInvoke&version=3.0.0-alpha.7&prerelease
#tool nuget:?package=CliInvoke&version=3.0.0-alpha.7&prerelease
CliInvoke
<img src="https://github.com/alastairlundy/CliInvoke/blob/main/.assets/icon.png" width="192" height="192" alt="CliInvoke Logo">
CliInvoke is a .NET library for interacting with Command Line Interfaces and wrapping around executables.
Launch processes, redirect standard input and output streams, await process completion, and much more.
Table of Contents
- Features
- Comparison vs Alternatives
- Installing CliInvoke
- Examples
- Resource Disposal
- Documentation
- Contributing to CliInvoke
- Used By
- Roadmap
- License
- Acknowledgements
Features
- Clear separation of concerns between Process Configuration Builders, Process Configuration Models, and Invokers.
- Supports .NET 8 and newer TFMs and has few dependencies.
- Has Dependency Injection extensions to make using it a breeze.
- Support for specific specializations such as running executables or commands via Windows PowerShell or CMD on Windows <sup>1</sup>
- SourceLink support
<sup>1</sup> Specializations library distributed separately.
Comparison vs Alternatives
| Feature / Criterion | CliInvoke | CliWrap | ProcessX | .NET Process class |
|---|---|---|---|---|
| Dedicated builder, model, and invoker types (clear separation of concerns) | ✅ | ❌ | ❌ | ⚠️, offers limited separation of concerns via ProcessStartInfo model class |
| Dependency Injection registration extensions | ✅ | ❌ | ❌ | ❌ |
| Installable via NuGet | ✅ | ✅ | ✅ | ✅ , Built into .NET |
| Official cross‑platform support (advertised: Windows/macOS/Linux/BSD) | ✅ | ✅* | ❌* | ✅ |
| Buffered and non‑buffered execution modes | ✅ | ✅ | ✅ | ⚠️, can lead to deadlocks or exceptions if not careful |
| Support for Process/Command Timeout | ✅ | ⚠️, limited to cancelling via CancellationToken | ⚠️, limited to cancelling via CancellationToken | ⚠️, limited to cancelling via CancellationToken |
| Graceful Cancellation Support via SIGTERM/SIGINT Signals | ✅, 2.3.0+ | ✅ | ❌ | ❌ |
| Small surface area and minimal dependencies | ✅ | ✅ | ✅ | ✅ |
| Licensing / repository additional terms | ✅ (MPL‑2.0) | ⚠️ (MIT; test project references a source‑available library; repo contains an informal "Terms of Use" statement) | ✅ (MIT) | ✅ (.NET Runtime licensed under MIT) |
Notes:
- *Indicates not explicitly advertised for all listed OSes but may work in practice; check each project's docs.
- The CliWrap repository includes a test project that references a source‑available (non‑open source) library; that library is used for tests and is not distributed with the runtime package. The repo also contains an informal "Terms of Use" statement — review repository files if legal certainty is required.
Installing CliInvoke
CliInvoke is available on the NuGet Gallery but call be also installed via the dotnet SDK CLI.
The package(s) to install depends on your use case:
- For use in a .NET library – Install the abstractions package, your developer users can install the Implementation and Dependency Injection packages.
- For use in a .NET app – Install the implementation package and the Dependency Injection Extensions Package
| Project type / Need | Packages to install (dotnet add package ...) | Notes |
|---|---|---|
| Library author (provide abstractions only) | CliInvoke.Core |
Only the Core (abstractions) package — consumers can choose implementations. |
| Library or app that needs concrete builders / implementations | CliInvoke.Core, CliInvoke |
Implementation package plus Core for models/abstractions. |
| Desktop or Console application (common case — use DI & convenience helpers) | CliInvoke.Core, CliInvoke, CliInvoke.Extensions |
Includes DI registration and convenience extensions for easy setup. |
| Any project that needs platform‑specific or shell specializations (optional) | CliInvoke.Specializations (install in addition to the packages above as needed) |
Adds Cmd/PowerShell and other specializations; include only when required. |
Links to packages
CliInvoke.Core Nuget CliInvoke Nuget CliInvoke.Extensions Nuget CliInvoke.Specializations Nuget
Supported Platforms
CliInvoke supports Windows, macOS, Linux, FreeBSD, Android, and potentially some other operating systems.
For more details see the list of supported platforms
Design Patterns & When to Use Them
CliInvoke provides three distinct design patterns for invoking processes. See PATTERNS.md for comprehensive documentation on each pattern.
CliRun– Beginner-friendly/quickstart entrypoint. Use for basic scripting, CI/CD tasks, or simple command execution. Zero boilerplate, optional arguments with sensible defaults.IProcessInvoker– DI-centric pattern and support for end-to-end process management. Use when building applications that need testability, dependency injection integration, or custom process configuration per invocation.IExternalProcess&IExternalProcessFactory– Process-like API with DI support, rich capability, stable and predictable behaviour. Use when you need granular lifecycle control, manual start/stop sequences, or power-user scenarios similar toSystem.Diagnostics.Process.
Examples
Beginner Friendly / Quickstart
For simple use cases, the CliRun helper provides a straightforward API to execute commands with minimal boilerplate:
using CliInvoke;
using CliInvoke.Core;
// Execute a command and get the result
ProcessResult result = await CliRun.RunAsync("dotnet", "--version");
Console.WriteLine($"Exit Code: {result.ExitCode}");
For capturing output, use RunBufferedAsync:
using CliInvoke;
using CliInvoke.Core;
// Execute and capture stdout/stderr
BufferedProcessResult result = await CliRun.RunBufferedAsync("dotnet", "--info");
Console.WriteLine(result.StandardOutput);
Console.WriteLine(result.StandardError);
CliRun is ideal for scripting, quick prototypes, and basic command execution where you don't need dependency injection or advanced configuration.
For detailed documentation on all available patterns and when to use them, see PATTERNS.md.
Advanced Configuration
For fine-grained control over process execution — custom timeouts, cancellation strategies, buffered vs. non-buffered output, and builder-based configuration — see the Configuration Guide and the Choosing your Invocation Pattern guide in the documentation portal.
Resource Disposal
CliInvoke has exactly five Resource-Owning Types that implement IDisposable and must be disposed after use to avoid resource leaks (open pipe handles, kernel handles, and pinned SecureString buffers):
| # | Type | What it owns |
|---|---|---|
| 1 | ProcessConfiguration |
StreamWriter (StandardInput), optional UserCredential |
| 2 | IExternalProcess |
Underlying System.Diagnostics.Process (pipes, handles, threads) |
| 3 | PipedProcessResult |
StandardOutput and StandardError streams |
| 4 | UserCredential |
SecureString password buffer |
| 5 | UserCredentialBuilder |
SecureString password buffer staged for Build() |
No other CliInvoke type implements IDisposable. Always wrap these types in using or await using statements.
For the full disposal reference — ownership rules, disposal patterns, and a checklist — see the Resource Disposal Guide.
Documentation
Full documentation is available in the CliInvoke Developer Portal. Pick the path that fits you:
| Who you are | Start here |
|---|---|
| Beginner — "I just need to run a command" | Quickstart → Choosing your Invocation Pattern |
| Professional Developer — "I'm building a testable app with DI" | Getting Started → Configuration |
| Power User — "I need full lifecycle control" | Choosing your Invocation Pattern → IExternalProcess → Architecture |
Other guides: Troubleshooting · Migration Guides · Building from Source
How to Build CliInvoke's code
Please see building-cliinvoke.md for how to build CliInvoke from source.
How to Contribute to CliInvoke
Please see the CONTRIBUTING.md file for code and localization contributions.
If you want to file a bug report or suggest a potential feature to add, please check out the GitHub issues page to see if a similar or identical issue is already open. If there isn't already a relevant issue filed, please file one here and follow the respective guidance from the appropriate issue template.
Used By
CliInvoke is used by these projects:
- WCountLib.Providers.wc –
Implements WCountLib.Abstractions using the Unix
wccommand.
Want your project added to this list? Open an issue
CliInvoke's Roadmap
CliInvoke aims to make working with Commands and external processes easier.
Whilst there is a modest set of features are available today, there is room for more features and for modifications of existing features in future updates.
Future updates may focus on one or more of the following:
- Improved ease of use
- Improved stability
- New features
- Enhancing existing features
New vs Old Package and Namespace
CliInvoke changed it's Nuget package Id and namespace starting from the re-release of 2.0.0 (tagged as 2.0.0-v2) and has
since been published directly under the CliInvoke package ID prefix and namespace.
The previous packages Ids are marked as deprecated and will not receive future updates.
License
CliInvoke is licensed under the MPL 2.0 license. You can learn more about it here
Should your project incorporate CliInvoke, ensure that the full text of CliInvoke's LICENSE.txt is either incorporated into your third-party licenses TXT file or provided as a distinct TXT file within your project's repository.
CliInvoke Assets
CliInvoke's Icon is owned by and has all rights reserved to me (Alastair Lundy).
If you fork CliInvoke and re-distribute it, please replace the icon unless you have prior written approval from me.
Star History
<a href="https://www.star-history.com/?repos=alastairlundy%2Fcliinvoke&type=date&logscale=&legend=top-left"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=alastairlundy/cliinvoke&type=date&theme=dark&legend=top-left" /> <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=alastairlundy/cliinvoke&type=date&legend=top-left" /> <img alt="Star History Chart" src="https://api.star-history.com/chart?repos=alastairlundy/cliinvoke&type=date&legend=top-left" /> </picture> </a>
Acknowledgements
Projects
This project would like to thank the following projects for their work:
For more information, please see the THIRD_PARTY_NOTICES file.
| Product | Versions 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 is compatible. 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 is compatible. 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. |
-
net10.0
- CliInvoke.Core (>= 3.0.0-alpha.7)
-
net8.0
- CliInvoke.Core (>= 3.0.0-alpha.7)
-
net9.0
- CliInvoke.Core (>= 3.0.0-alpha.7)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on CliInvoke:
| Package | Downloads |
|---|---|
|
CliInvoke.Extensions
Adds a ``AddCliInvoke`` Dependency Injection extension method to enable easy CliInvoke setup when using the Microsoft.Extensions.DependencyInjection package. |
|
|
CliInvoke.Specializations
CliInvoke Specializations is a library for providing pre-configured Specializations of CliInvoke's ProcessConfiguration. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.0-alpha.7 | 0 | 7/28/2026 |
| 3.0.0-alpha.6 | 51 | 7/19/2026 |
| 3.0.0-alpha.5 | 132 | 6/20/2026 |
| 3.0.0-alpha.4 | 214 | 5/25/2026 |
| 3.0.0-alpha.3 | 121 | 4/26/2026 |
| 3.0.0-alpha.2 | 83 | 4/17/2026 |
| 2.9.0 | 131 | 7/19/2026 |
| 2.8.3 | 157 | 6/30/2026 |
| 2.8.2 | 208 | 6/12/2026 |
| 2.8.1 | 183 | 6/2/2026 |
| 2.7.2 | 157 | 6/2/2026 |
| 2.7.1 | 147 | 5/31/2026 |
| 2.7.0 | 212 | 5/16/2026 |
| 2.6.1 | 151 | 5/16/2026 |
| 2.6.0 | 197 | 4/29/2026 |
| 2.5.4 | 177 | 4/26/2026 |
| 2.5.3 | 239 | 4/12/2026 |
### 🆕 Additions
- **Added new `FireAndForget` methods to `CliRun`** (the static facade in `src/CliInvoke/Extensions/CliRun.cs`):
- `FireAndForget(ProcessConfiguration configuration)` — disposes the spawned `IExternalProcess` after starting it.
- `FireAndForget(string targetFilePath, string arguments = "", string? workingDirectory = null)` — builds the configuration via the new `BuildStringArgsConfig` helper and returns the spawned process ID.
### ⚙️ Modifications
- Extracted `BuildStringArgsConfig` as a private static helper in `CliRun` to eliminate the duplicated 5-line configuration-build block that previously appeared in each of the three string-argument `Run*Async` overloads.
- Routed the three configuration-argument public overloads (`RunAsync`, `RunBufferedAsync`, `RunPipedAsync`) through a single `RunInternalAsync<T>` funnel that calls the (possibly user-supplied) `IExternalProcessFactory`, starts the process, and applies the chosen capture delegate.
- Switched the default `_externalProcessFactory` field to construct an `ExternalProcessFactory` per call (capturing the current static file-path resolver), so changes to `UseFilePathResolver` take effect on subsequent calls instead of being frozen at first access.
- Implemented a synchronous `int Start()` method on `ExternalProcess` that resolves the target file path, swaps the process wrapper if needed, and starts the process; added matching `HasStarted` guards to both `StartAsync` overloads.
- **Removed** the original (broken) `FireAndForget(CancellationToken)` method implementation from `ExternalProcess`, since the FireAndForget surface has moved up to `CliRun` and the `IExternalProcess` declaration has been removed.
- Wired up the new synchronous `Start()` so that the `Started` and `Exited` events on `ExternalProcess` are raised as the process transitions through the started and exited states.
- Collapsed `ProcessWrapper`'s semaphore-driven critical section into a single `WaitForExitCoreAsync` method that owns the semaphore acquire/release pair; the two wrapper methods now delegate to it with `isGraceful: true` and `isGraceful: false`, respectively. Removed the inner `_cancellationSemaphore.WaitAsync(0)` and `Release()` calls from `CancelWithInterrupt`.
### 🐛 Bug Fixes
- Restructured `ProcessWrapper.OnStarted` with nested `try-catch-finally` blocks so that `ResumeProcess()` is always called — even when `SetResourcePolicy()` throws after `SuspendProcess()` succeeded — preventing the child process from being permanently suspended. Also fixed the suspended-resume TODO to reference the actual .NET 11 API names (`ProcessStartInfo.StartSuspended` and `SafeProcessHandle.Resume`).
- Fixed the Windows graceful-cancellation cascade in `WindowsProcessControlAdapter`: replaced `AllocConsole` with `AttachConsole` targeting the child PID, switched from `CTRL_C_EVENT` (a documented no-op for non-zero group IDs) to `CTRL_BREAK_EVENT` targeted at the correct process group, added `FreeConsole` cleanup, and used the PID directly as the process-group ID since `CreateNewProcessGroup` is not set. The fallback path now exits cleanly with `ERROR_INVALID_HANDLE` instead of sending a no-op signal.