{"id":80750,"date":"2023-02-01T14:16:47","date_gmt":"2023-02-01T13:16:47","guid":{"rendered":"https:\/\/drafts.code-maze.com\/?p=80745"},"modified":"2023-02-01T14:16:47","modified_gmt":"2023-02-01T13:16:47","slug":"csharp-execute-cli-applications","status":"publish","type":"post","link":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/","title":{"rendered":"How to Execute CLI Applications From C#"},"content":{"rendered":"<p>In this article, we will learn how to execute CLI applications in C# using a built-in class called <code>Process<\/code> and using open-source libraries. We will cover how we can execute CLI, how we can check if the CLI execution was successful, and how we can react to the different outputs of CLI.<\/p>\n<div style=\"padding: 20px; border-left: 5px #dc2323 solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\">To download the source code for this article, you can visit our <a href=\"https:\/\/github.com\/CodeMazeBlog\/CodeMazeGuides\/tree\/main\/dotnet-projects\/ExecuteCli\" target=\"_blank\" rel=\"nofollow noopener\">GitHub repository<\/a>.<\/div>\n<p>Throughout this article, we will execute different dotnet CLI commands from a C# code. Additionally, we will assume the dotnet is globally available on the host machine.<\/p>\n<h2>Execute CLI Applications With a Native Class<\/h2>\n<p>.NET provides a <code>Process<\/code> class that enables us to configure, start and stop a process. There are different ways we can initiate a process and execute CLI applications in C#.<\/p>\n<p>So, let&#8217;s check the first one:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">Process proc = new();\r\nproc.StartInfo.FileName = \"&lt;application or file&gt;\";\r\nproc.StartInfo.Arguments = \"&lt;command arguments&gt;\";\r\nproc.Start();<\/pre>\n<p>Here, we create an instance of <code>Process<\/code> class, set the properties, and finally, call the start method.<\/p>\n<p>Alternatively, we can use the static <code>Start<\/code> method from <code>Process<\/code> class:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">Process.Start(\"&lt;application or file&gt;\", \"&lt;command arguments&gt;\");<\/code><\/p>\n<p>There are multiple overloads of the <code>Start<\/code> method, each with different arguments. In this article, we will use the static <code>Start<\/code> method with <code>ProcessStartInfo<\/code> as an argument to start a process.<\/p>\n<h3>What is ProcessStartInfo?<\/h3>\n<p>Throughout this article, we will use the <code>ProcessStartInfo<\/code> class. Therefore it is worth discussing what it is and what its commonly used properties mean. The <code>ProcessStartInfo<\/code> class gives us more control in configuring a process and how it should start. Some of the commonly used properties of <code>ProcessStartInfo<\/code> are:<\/p>\n<ul>\n<li><code>FileName<\/code> : Is the target application or a file with default open action(such as batch or script file). This property can not be null.<\/li>\n<li>\n<div>\n<div><code>Arguments<\/code>: Is a string we want to pass to the target application we specified using the <code>FileName<\/code> property. It is important to note that: <strong>If the arguments contain a delimiter (such as space), we should pass it in double quotes<\/strong>. Let&#8217;s take the dotnet command to create a new console project as an example:<\/div>\n<div><code class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\">dotnet new console \"Awesome Project\"<\/code><\/p>\n<p>Now, let&#8217;s inspect what this will look like when assigning it to <code>Arguments<\/code>:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">Arguments = \"new console \\\"Awesome Project\\\"\"<\/code><\/div>\n<\/div>\n<\/li>\n<li><code>CreateNoWindow<\/code>: enables us to specify whether the underlying process should start in a new window. The default value is <code>false<\/code>.<\/li>\n<li><code>RedirectStandardOutput<\/code> and <code>RedirectStandardError<\/code> are of boolean types. They enable us to specify if we want to redirect the underlying process&#8217;s standard and error outputs respectively.<\/li>\n<\/ul>\n<h3>Execute Command<\/h3>\n<p>In this section, we will execute the version command from <a href=\"https:\/\/code-maze.com\/dotnet-format-command-csharp\/\" target=\"_blank\" rel=\"noopener\">dotnet<\/a> CLI:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">dotnet --version<\/code><\/p>\n<p>This command prints the version of dotnet that is in use. Let&#8217;s take a look at how we can run this command from the code:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class DotnetNativeWrapper\r\n{\r\n    public async Task&lt;Version&gt; GetVersion()\r\n    {\r\n        ProcessStartInfo startInfo = new()\r\n        {\r\n            FileName = \"dotnet\",\r\n            Arguments = \"--version\",\r\n            CreateNoWindow = true,\r\n            RedirectStandardOutput = true,\r\n            RedirectStandardError = true,\r\n        };\r\n        var proc = Process.Start(startInfo);\r\n\r\n        ArgumentNullException.ThrowIfNull(proc);\r\n\r\n        string output = proc.StandardOutput.ReadToEnd();\r\n        await proc.WaitForExitAsync();\r\n\r\n        return Version.Parse(output);\r\n    }\r\n}<\/pre>\n<p>First, we start by creating an instance of <code>ProcessStartInfo<\/code>: we set the value of <code>FileName<\/code> to <code>dotnet<\/code>, which is the CLI application we want to use and pass <code>--version<\/code> as an argument. Next, we don&#8217;t want to create a new window to run the process; therefore, we set the <code>CreateNoWindow<\/code> to <code>true<\/code>. To retrieve both the standard and error CLI outputs, we set both <code>RedirectStandardOutput<\/code> and <code>RedirectStandardError<\/code> to <code>true<\/code>.<\/p>\n<p>At this point, we have the configuration ready. The next step is to start the process by calling the <code>Start<\/code> method. The <code>Start<\/code> method returns <code>Process<\/code> instance if starting the process was successful. <strong>This does not mean command execution was successful<\/strong>. It simply indicates the initiation of the process resource with the configuration we provide.<\/p>\n<p>If it is not successful, the <code>Start<\/code> method returns <code>null<\/code>. So, we execute the null check of the <code>proc<\/code> variable.<\/p>\n<p>Next, we use the <code>StandardOutput<\/code> property to read the output of the CLI.<strong> It is essential to call the <\/strong><code>ReadToEnd<\/code><strong> method before calling <\/strong><code>WaitForExitAsync<\/code>, because <code>WaitForExitAsync<\/code> waits until the execution of the process is complete. Finally, we use the <code>Parse<\/code> method to parse the output into <code>Version<\/code> and return the result.<\/p>\n<h3>Check Exit Code<\/h3>\n<p>Usually, a zero exit code for CLI applications indicates successful execution of the command, and non-zero exit codes indicate an error. In this section, we will run an invalid dotnet command, and yes, you will be right to question the purpose of running an invalid command as there is no real-world use case. But we&#8217;ll do that to examine how we can capture the error logs and the exit code of the underlying process.<\/p>\n<p>Let&#8217;s start by creating the <code>RunInvalidCommand<\/code> method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task&lt;(int exitCode, string? error)&gt; RunInvalidCommand()\r\n{\r\n    ProcessStartInfo startInfo = new()\r\n    {\r\n        FileName = \"dotnet\",\r\n        Arguments = \"invalid command\",\r\n        CreateNoWindow = true,\r\n        RedirectStandardOutput = true,\r\n        RedirectStandardError = true,\r\n    };\r\n    var proc = Process.Start(startInfo);\r\n\r\n    ArgumentNullException.ThrowIfNull(proc);\r\n\r\n    string errorOutput = proc.StandardError.ReadToEnd();\r\n    await proc.WaitForExitAsync();\r\n\r\n    return (proc.ExitCode, errorOutput);\r\n}<\/pre>\n<p>The <code>RunInvalidCommand<\/code> method runs an invalid command and returns the exit code and error output as a tuple.<\/p>\n<p>Again, we begin by creating an instance of <code>ProcessStartInfo<\/code> with a slight change on the <code>Arguments<\/code> property. The value of the <code>Arguments<\/code> is invalid because <code>\"invalid command\"<\/code> is an invalid command in dotnet CLI. Next, we start the process and check the <code>proc<\/code> is not null. Unlike the previous example, this time, we use the <code>StandardError<\/code> property to read from the error stream. Finally, we wait until the process completes and return the exit code and error output as a tuple.<\/p>\n<p>Let&#8217;s invoke the <code>RunInvalidCommand<\/code> method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">static async Task RunInvalidCommandExample()\r\n{\r\n    DotnetNativeWrapper native = new();\r\n    var (exitCode, errorOutput) = await native.RunInvalidCommand();\r\n\r\n    Console.WriteLine($\"ExitCode: {exitCode}\");\r\n    Console.WriteLine($\"ErrorLogs: \\n{errorOutput}\");\r\n}<\/pre>\n<p>Here we simply create an instance of the <code>DotnetNativeWrapper<\/code> class and invoke <code>RunInvalidCommand<\/code>.<\/p>\n<p>Now, we can inspect the sample output:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\">ExitCode: 1\r\nErrorLogs: \r\nCould not execute because the specified command or file was not found.\r\nPossible reasons for this include:\r\n  * You misspelled a built-in dotnet command.\r\n  * You intended to execute a .NET program, but dotnet-invalid does not exist.\r\n  * You intended to run a global tool, but a dotnet-prefixed executable with this name could not be found on the PATH.<\/pre>\n<h3>Execute Script<\/h3>\n<p>Until now, we used the CLI application to execute different commands. But what if we want to execute a file? In this section, we will look at exactly how to do that.<\/p>\n<p>Let&#8217;s start by creating an <code>info.bat<\/code> file:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">dotnet --info<\/code><\/p>\n<p>Next, let&#8217;s create <code>GetInfo<\/code> method that executes <code>info.bat<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task&lt;string&gt; GetInfo()\r\n{\r\n    ProcessStartInfo startInfo = new()\r\n    {\r\n        FileName = \"cmd\",\r\n        Arguments = \"\/c \\\"info.bat\\\"\",\r\n        CreateNoWindow = true,\r\n        RedirectStandardOutput = true,\r\n        RedirectStandardError = true,\r\n    };\r\n    \r\n    var proc = Process.Start(startInfo);\r\n\r\n    ArgumentNullException.ThrowIfNull(proc);\r\n\r\n    string output = proc.StandardOutput.ReadToEnd();\r\n    await proc.WaitForExitAsync();\r\n\r\n    return output;\r\n}<\/pre>\n<p>This time we assign the <code>FileName<\/code> property to <code>cmd<\/code> which is the command prompt on windows. This means the batch file will run on the command prompt. Next, we assign the <code>Arguments<\/code> property to a string <code>\/c<\/code> followed by the batch file&#8217;s name.<strong> The<\/strong> <code>\/c<\/code> <strong>flag in the command prompt means: run the subsequent string and terminate. <\/strong>There is another variant <code>\/k<\/code> which means: run the subsequent string and remain active.<\/p>\n<p>Because we are using a command prompt, this example code only works on Windows. But we can make slight changes to make it work on other operating systems as well.<\/p>\n<p>Let&#8217;s start by creating <code>info.sh<\/code> file:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">#!\/usr\/bin\/env bash\r\ndotnet --info<\/pre>\n<p>Next, let&#8217;s assign new values to <code>FileName<\/code> and <code>Arguments<\/code> based on the underlying OS:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task&lt;Version&gt; GetInfo()\r\n{\r\n    var isWin = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);\r\n    var args = isWin ? \"\/c \\\"info.bat\\\"\" : \"-c \\\".\/info.sh\\\"\";\r\n    var tool = isWin ? \"cmd\" : \"bash\";\r\n    ProcessStartInfo startInfo = new()\r\n    {\r\n        FileName = tool,\r\n        Arguments = args,\r\n        ...\r\n    };\r\n    \r\n    ...\r\n}<\/pre>\n<p>We first check if the OS is windows. If it is, we assign <code>FileName<\/code> to cmd and <code>Arguments<\/code> to <code>\"\/c \\\"info.bat\\\"\"<\/code> which is like saying: use the command prompt and run the <code>info.bat<\/code> batch file. But if the OS is not windows, we assign <code>FileName<\/code> to bash and <code>Arguments<\/code> to <code>\"-c \\\".\/info.sh\\\"\"<\/code> which means: use bash and run the <code>info.sh<\/code> script.<\/p>\n<h3>CLI Output as Event Stream<\/h3>\n<p>CLI applications can have different outputs that indicate the different states of the application. Also, we can have different events that correspond to the different state outputs. In this section, instead of waiting for the output from the underlying CLI process to the end, we will trigger an event whenever there are outputs from the CLI.<\/p>\n<p>Let&#8217;s start by creating a delegate:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public delegate void OnChunkStreamHandler(string chunk);<\/code><\/p>\n<p>Next, let&#8217;s create <code>CliEventStreamer<\/code>class to read outputs from the CLI and trigger event:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class CliEventStreamer\r\n{\r\n    public CliEventStreamer(StreamReader streamReader)\r\n    {\r\n        ArgumentNullException.ThrowIfNull(streamReader);\r\n        _streamReader = streamReader;\r\n        Task.Factory.StartNew(Start);\r\n    }\r\n\r\n    public event OnChunkStreamHandler? OnChunkReceived;\r\n\r\n    private readonly StreamReader _streamReader;\r\n\r\n    private async Task Start()\r\n    {\r\n        int bufferSize = 8 * 1024;\r\n        var buffer = new char[bufferSize];\r\n\r\n        while (true)\r\n        {\r\n            var chunkLength = await _streamReader.ReadAsync(buffer, 0, buffer.Length);\r\n\r\n            if (chunkLength == 0)\r\n            {\r\n                break;\r\n            }\r\n\r\n            OnChunk(new string(buffer, 0, chunkLength));\r\n        }\r\n    }\r\n\r\n    private void OnChunk(string chunk)\r\n    {\r\n        OnChunkReceived?.Invoke(chunk);\r\n    }\r\n}<\/pre>\n<p>The <code>CliEventStreamer<\/code> class contains one constructor with <code>StreamReader<\/code> as an argument. Inside the constructor, we start a new <code>Task<\/code> to read outputs from the CLI process and trigger an event. The <code>CliEventStreamer<\/code> class also contains one public <code>event<\/code> namely <code>OnChunkReceived<\/code> that we will use to invoke different methods based on the CLI output.<\/p>\n<p>The <code>Start<\/code> is where we read the CLI output from <code>StreamReader<\/code> and trigger an event. First, we create <code>char<\/code> array with an arbitrary size, and then we start an infinite loop that reads small chunks of the output from <code>_streamReader<\/code>. If there is no output, we exit from the loop. Otherwise, we call <code>OnChunk<\/code> method and pass the chunk string as an argument. The <code>OnChunk<\/code> will in turn invoke the event handler.<\/p>\n<p>The <code>CliEventStreamer<\/code> class will handle reading from the stream and invoking the event handler.<\/p>\n<p>Now, let&#8217;s add event properties into <code>DotnetNativeWrapper<\/code> class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class DotnetNativeWrapper\r\n{\r\n    public event OnChunkStreamHandler? OnStdOutput;\r\n    public event OnChunkStreamHandler? OnStdErr;\r\n\r\n    ...\r\n}<\/pre>\n<p>We can use the <code>OnStdOutput<\/code> event property to add event handlers for standard output events and <code>OnStdErr<\/code> to add event handlers for error output events.<\/p>\n<p>Next, let&#8217;s add the <code>ListProjects<\/code> method to <code>DotnetNativeWrapper<\/code> class. The <code>ListProjects<\/code> method lists the available project templates:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task ListProjects()\r\n{\r\n    ProcessStartInfo startInfo = new()\r\n    {\r\n        FileName = \"dotnet\",\r\n        Arguments = \"new list\",\r\n        CreateNoWindow = true,\r\n        RedirectStandardOutput = true,\r\n        RedirectStandardError = true,\r\n    };\r\n    var proc = Process.Start(startInfo);\r\n\r\n    ArgumentNullException.ThrowIfNull(proc);\r\n\r\n    var stdOut = new CliEventStreamer(proc.StandardOutput);\r\n    var stdErr = new CliEventStreamer(proc.StandardError);\r\n\r\n    AttachStdOutEventHandler(stdOut);\r\n    AttachStdErrEventHandler(stdErr);\r\n\r\n    await proc.WaitForExitAsync();\r\n}\r\n\r\nprivate void AttachStdOutEventHandler(CliEventStreamer stdOut)\r\n{\r\n    if (OnStdOutput is not null)\r\n    {\r\n        stdOut.OnChunkReceived += OnStdOutput;\r\n    }\r\n}\r\n\r\nprivate void AttachStdErrEventHandler(CliEventStreamer stdErr)\r\n{\r\n    if (OnStdErr is not null)\r\n    {\r\n        stdErr.OnChunkReceived += OnStdErr;\r\n    }\r\n}<\/pre>\n<p>Similar to the previous examples, we wire up the <code>ProcessStartInfo<\/code> and start the process. This time, the difference is in handling the standard and error outputs. We create two instances of <code>CliEventStreamer<\/code> one for streaming standard outputs and one for streaming error outputs, then we attach the event stream instances to the corresponding event handler: <code>AttachStdOutEventHandler<\/code> for standard output and <code>AttachStdErrEventHandler<\/code> for error output.<\/p>\n<h2>Execute CLI Applications With CliWrap<\/h2>\n<p>The native implementation works fine, but it gets complicated very quickly. To avoid that, we can use an alternative implementation with CliWrap. CliWrap is an open-source library that provides high-level API for running CLI applications. More information about CliWrap is available on <a href=\"https:\/\/github.com\/Tyrrrz\/CliWrap\" target=\"_blank\" rel=\"nofollow noopener\">GitHub<\/a>.<\/p>\n<p>In this section, we will try to understand how we can use CliWrap to execute different dotnet commands.<\/p>\n<p>Let&#8217;s start by adding the NuGet package:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">dotnet add package CliWrap<\/code><\/p>\n<h3>Execute Command<\/h3>\n<p>Let&#8217;s inspect how we can execute version commands using CliWrap:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task&lt;Version&gt; GetVersion()\r\n{\r\n    var result = await Cli.Wrap(\"dotnet\")\r\n        .WithArguments(\"--version\")\r\n        .ExecuteBufferedAsync();\r\n\r\n    return Version.Parse(result.StandardOutput);\r\n}<\/pre>\n<p>CliWrap comprises easy to understand and fluent configuration interface. Inside the <code>GetVersion<\/code> method the call to the static <code>Wrap<\/code> method defines the executable or file(batch or script) we want to execute. As its name suggests <code>WithArguments<\/code> will pass the arguments. Next, <code>ExecuteBufferedAsync<\/code> executes the CLI and returns a result that is of type <code>BufferedCommandResult<\/code> that contains both the standard and error outputs. Finally, we parse the version information from the standard output and return the result.<\/p>\n<h3>Check Exit Code<\/h3>\n<p>The default behavior in CliWrap for a non-zero exit code of the underlying process is to throw an exception, as a non-zero exit code is usually an indicator of an error. CliWrap also provides a way to suppress this default behavior. Let&#8217;s inspect how we can do that by running invalid dotnet command:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task&lt;(int exitCode, string? error)&gt; RunInvalidCommand()\r\n{\r\n    var result = await Cli.Wrap(\"dotnet\")\r\n        .WithArguments(\"invalid command\")\r\n        .WithValidation(CommandResultValidation.None)\r\n        .ExecuteBufferedAsync();\r\n\r\n    return (result.ExitCode, result.StandardError);\r\n}<\/pre>\n<p>In this example code, we are passing an invalid argument and configuring CliWrap not to throw an exception by calling <code>WithValidation<\/code> method and passing <code>CommandResultValidation.None<\/code> as an argument. Next, we return the non-zero exit code and error output as a tuple.<\/p>\n<h3>CLI Event Stream<\/h3>\n<p>Last but not least, we will look at how we can stream the different CLI process state changes and outputs as an event using CliWrap. For this example, we will use the dotnet <code>new list<\/code> command. Let&#8217;s start by declaring delegates:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public delegate void OnStart(int processId);\r\npublic delegate void OnExit(int exitCode);\r\npublic delegate void OnTextStreamHandler(string text);<\/pre>\n<p>Next, let&#8217;s add new event properties into <code>DotnetCliWrap<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class DotnetCliWrap\r\n{\r\n    public event OnTextStreamHandler? OnStdOutput;\r\n    public event OnTextStreamHandler? OnStdErr;\r\n    public event OnStart? OnStart;\r\n    public event OnExit? OnExit;\r\n\r\n    ...\r\n}<\/pre>\n<p>Now that we have the necessary event properties let&#8217;s implement the method to execute the <code>new list<\/code> command:\u00a0<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task ListProjects()\r\n{\r\n    var cmd = Cli.Wrap(\"dotnet\").WithArguments(\"new list\");\r\n\r\n    await foreach (var cmdEvent in cmd.ListenAsync())\r\n    {\r\n        switch (cmdEvent)\r\n        {\r\n            case StartedCommandEvent started:\r\n                OnStart?.Invoke(started.ProcessId);\r\n                break;\r\n            case StandardOutputCommandEvent stdOut:\r\n                OnStdOutput?.Invoke(stdOut.Text);\r\n                break;\r\n            case StandardErrorCommandEvent stdErr:\r\n                OnStdErr?.Invoke(stdErr.Text);\r\n                break;\r\n            case ExitedCommandEvent exited:\r\n                OnExit?.Invoke(exited.ExitCode);\r\n                break;\r\n        }\r\n    }\r\n}<\/pre>\n<p>We start by creating the command instance, then inside the async <code>foreach<\/code> loop we wait for events. Next, based on the concrete type of the event, we invoke the corresponding handler in the switch case.<\/p>\n<p>As we saw in the few examples, CliWarp provides a cleaner way to execute and monitor CLI processes. Moreover, CliWrap comprises several useful features that are beyond the scope of this article. Learn more about those amazing features on <a href=\"https:\/\/github.com\/Tyrrrz\/CliWrap\" target=\"_blank\" rel=\"nofollow noopener\">GitHub<\/a>.<\/p>\n<h2>Conclusion<\/h2>\n<p>In this article, we learned how to execute CLI applications, check if the execution of underlying CLI applications was successful, and stream the state and outputs of the CLI process as an event. We also saw two approaches to execute CLI applications: first, using the native <code>Process<\/code> class, and second, using an open-source library called CliWrap.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this article, we will learn how to execute CLI applications in C# using a built-in class called Process and using open-source libraries. We will cover how we can execute CLI, how we can check if the CLI execution was successful, and how we can react to the different outputs of CLI. Throughout this article, [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":62189,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[1001,12],"tags":[476,1605,1606,1607],"class_list":["post-80750","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-cli","category-csharp","tag-dotnet","tag-execute-bat-file-in-c","tag-execute-cli-application-in-c","tag-execute-dotnet-command-in-c","et-has-post-format-content","et_post_format-et-post-format-standard"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.7 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to Execute CLI Applications From C#<\/title>\n<meta name=\"description\" content=\"In this article, we&#039;ll learn how to execute CLI applications in C# using a built-in class called Process and using open-source libs\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Execute CLI Applications From C#\" \/>\n<meta property=\"og:description\" content=\"In this article, we&#039;ll learn how to execute CLI applications in C# using a built-in class called Process and using open-source libs\" \/>\n<meta property=\"og:url\" content=\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/\" \/>\n<meta property=\"og:site_name\" content=\"Code Maze\" \/>\n<meta property=\"article:published_time\" content=\"2023-02-01T13:16:47+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1100\" \/>\n\t<meta property=\"og:image:height\" content=\"620\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Code Maze\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/CodeMazeBlog\" \/>\n<meta name=\"twitter:site\" content=\"@CodeMazeBlog\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Code Maze\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/\"},\"author\":{\"name\":\"Code Maze\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/09d29b223012c8e94a68ba62861d0b04\"},\"headline\":\"How to Execute CLI Applications From C#\",\"datePublished\":\"2023-02-01T13:16:47+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/\"},\"wordCount\":1770,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png\",\"keywords\":[\"dotnet\",\"Execute .bat file in C#\",\"Execute CLI application in C#\",\"Execute dotnet command in C#\"],\"articleSection\":[\".NET CLI\",\"C#\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/\",\"url\":\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/\",\"name\":\"How to Execute CLI Applications From C#\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png\",\"datePublished\":\"2023-02-01T13:16:47+00:00\",\"description\":\"In this article, we'll learn how to execute CLI applications in C# using a built-in class called Process and using open-source libs\",\"breadcrumb\":{\"@id\":\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#primaryimage\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png\",\"width\":1100,\"height\":620,\"caption\":\"C# Development\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/code-maze.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Execute CLI Applications From C#\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/code-maze.com\/#website\",\"url\":\"https:\/\/code-maze.com\/\",\"name\":\"Code Maze\",\"description\":\"Learn. Code. Succeed.\",\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/code-maze.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/code-maze.com\/#organization\",\"name\":\"Code Maze\",\"url\":\"https:\/\/code-maze.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"width\":3511,\"height\":3510,\"caption\":\"Code Maze\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/CodeMazeBlog\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/09d29b223012c8e94a68ba62861d0b04\",\"name\":\"Code Maze\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez-150x150.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez-150x150.png\",\"caption\":\"Code Maze\"},\"description\":\"This is the standard author on the site. Most articles are published by individual authors, with their profiles, but when several authors have contributed, we publish collectively as a part of this profile.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/company\/codemaze\/\",\"https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog\"],\"url\":\"https:\/\/code-maze.com\/author\/codemazecontributor\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to Execute CLI Applications From C#","description":"In this article, we'll learn how to execute CLI applications in C# using a built-in class called Process and using open-source libs","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/","og_locale":"en_US","og_type":"article","og_title":"How to Execute CLI Applications From C#","og_description":"In this article, we'll learn how to execute CLI applications in C# using a built-in class called Process and using open-source libs","og_url":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/","og_site_name":"Code Maze","article_published_time":"2023-02-01T13:16:47+00:00","og_image":[{"width":1100,"height":620,"url":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png","type":"image\/png"}],"author":"Code Maze","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/CodeMazeBlog","twitter_site":"@CodeMazeBlog","twitter_misc":{"Written by":"Code Maze","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#article","isPartOf":{"@id":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/"},"author":{"name":"Code Maze","@id":"https:\/\/code-maze.com\/#\/schema\/person\/09d29b223012c8e94a68ba62861d0b04"},"headline":"How to Execute CLI Applications From C#","datePublished":"2023-02-01T13:16:47+00:00","mainEntityOfPage":{"@id":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/"},"wordCount":1770,"commentCount":0,"publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"image":{"@id":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png","keywords":["dotnet","Execute .bat file in C#","Execute CLI application in C#","Execute dotnet command in C#"],"articleSection":[".NET CLI","C#"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/code-maze.com\/csharp-execute-cli-applications\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/","url":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/","name":"How to Execute CLI Applications From C#","isPartOf":{"@id":"https:\/\/code-maze.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#primaryimage"},"image":{"@id":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png","datePublished":"2023-02-01T13:16:47+00:00","description":"In this article, we'll learn how to execute CLI applications in C# using a built-in class called Process and using open-source libs","breadcrumb":{"@id":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/code-maze.com\/csharp-execute-cli-applications\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#primaryimage","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/12\/social-csharp.png","width":1100,"height":620,"caption":"C# Development"},{"@type":"BreadcrumbList","@id":"https:\/\/code-maze.com\/csharp-execute-cli-applications\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/code-maze.com\/"},{"@type":"ListItem","position":2,"name":"How to Execute CLI Applications From C#"}]},{"@type":"WebSite","@id":"https:\/\/code-maze.com\/#website","url":"https:\/\/code-maze.com\/","name":"Code Maze","description":"Learn. Code. Succeed.","publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/code-maze.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/code-maze.com\/#organization","name":"Code Maze","url":"https:\/\/code-maze.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","width":3511,"height":3510,"caption":"Code Maze"},"image":{"@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/CodeMazeBlog"]},{"@type":"Person","@id":"https:\/\/code-maze.com\/#\/schema\/person\/09d29b223012c8e94a68ba62861d0b04","name":"Code Maze","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/person\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez-150x150.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez-150x150.png","caption":"Code Maze"},"description":"This is the standard author on the site. Most articles are published by individual authors, with their profiles, but when several authors have contributed, we publish collectively as a part of this profile.","sameAs":["https:\/\/www.linkedin.com\/company\/codemaze\/","https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog"],"url":"https:\/\/code-maze.com\/author\/codemazecontributor\/"}]}},"_links":{"self":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/80750","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/comments?post=80750"}],"version-history":[{"count":3,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/80750\/revisions"}],"predecessor-version":[{"id":80753,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/80750\/revisions\/80753"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media\/62189"}],"wp:attachment":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media?parent=80750"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/categories?post=80750"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/tags?post=80750"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}