How to Run PowerShell Script from C# Application

In this article we will look at how you can run PowerShell scripts from C#, specifically in this example we will create a simple console application to demonstrate how to call PowerShell scripts from C# application.

Problem

You have a bunch of PowerShell scripts that you have to run, some examples would be daily checks on your servers, sql instances and rebuilding dev environments after overnight batch jobs, etc.

Instead of running these scripts manually from PowerShell, you would like a C# app which will run them for you, this way you can maintain it and add additional functionality to your scripts and simply run your C# application to perform all the tasks.

Solution

Using Microsoft.PowerShell.SDK and System.Management.Automation

Microsoft provides libraries to programmatically work with PowerShell. You need to install these packages from Nuget.

  1. Microsoft.PowerShell.SDK
  2. System.Management.Automation

This code will call create PowerShell script named script01.ps1 that will invoke Get-Process -Name "msedge" command. It will look for all Microsoft Edge processes, then the Id of those processes will be printed in the console.


using System.Collections.ObjectModel;
using System.Management.Automation;

namespace ConsoleApp3
{
    internal class Program
    {
        static void Main(string[] args)
        {
            PowerShell ps = PowerShell.Create();
            ps.AddScript(File.ReadAllText(@"C:\Scripts\script01.ps1"));
            Collection<PSObject> results = ps.Invoke();
            foreach (PSObject result in results)
            {
                PSMemberInfoCollection<PSMemberInfo> memberInfos = result.Members;
                Console.WriteLine(memberInfos["Id"].Value);
            }
        }
    }
}

As of this article’s date, we use .NET 6 for C#. There are some version of both packages that works well with .NET 6. One of them is 6.2.7. If you use .NET 7, likely you have to use version 7 onwards. So, you have to be careful regarding packages version and .NET version that you are using.

call powershell script from csharp code

You can also create and run PowerShell command without writing it through the script. Below example will run the same command as previous example which is Get-Process -Name "msedge" command. It will look for all Microsoft Edge processes, then displays the Id of those processes in the console.


using System.Collections.ObjectModel;
using System.Management.Automation;

namespace ConsoleApp3
{
    internal class Program
    {
        static void Main(string[] args)
        {
            PowerShell ps = PowerShell.Create();
            ps.AddCommand("Get-Process");
            ps.AddParameter("Name", "msedge");
            Collection<PSObject> results = ps.Invoke();
            foreach (PSObject result in results)
            {
                PSMemberInfoCollection<PSMemberInfo> memberInfos = result.Members;
                Console.WriteLine(memberInfos["id"].Value);
            }
        }
    }
}

Using CliWrap Package

The CliWrap package makes working with CLIs in C# easy and powerful. It works with all CLIs, so think powershell, git, npm, docker, etc.

This example focuses on PowerShell and calls a PowerShell script which will invoke Get-Process -Name "msedge" command inside it.

First lets start with the C# app, we need to add a reference to the CliWrap package and then add the code to call our PowerShell script.


using CliWrap;
using CliWrap.Buffered;

namespace ConsoleApp2
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var dbDailyTasks = await Cli.Wrap("powershell")
                .WithWorkingDirectory(@"C:\Scripts")
                .WithArguments(new[] { @"C:\Scripts\script01.ps1" })
                .ExecuteBufferedAsync();

            Console.WriteLine(dbDailyTasks.StandardOutput);
            Console.WriteLine(dbDailyTasks.StandardError);
            Console.ReadLine();
        }
    }
}

Below is an image of the output once we run our C# application. You can see it prints out all msedge processes complete with the properties.

cliwrap-code-output

Just like in previous example, we can call the command without writing it through the script. Below example will run the same command as previous example which is Get-Process -Name "msedge" command.


using CliWrap;
using CliWrap.Buffered;

namespace ConsoleApp2
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var dbDailyTasks = await Cli.Wrap("powershell")
                .WithArguments(new string[] { "Get-Process", "-Name", "\"msedge\"" })
                .ExecuteBufferedAsync();

            Console.WriteLine(dbDailyTasks.StandardOutput);
            Console.WriteLine(dbDailyTasks.StandardError);
            Console.ReadLine();
        }
    }
}

The code above will give the same result as when we execute the command through the script.

Conclusion

This example is very simple, but also gives you an idea of what a powerful combination C# and PowerShell could be. As developers and system administrators, running PowerShell scripts is typically something we do daily, so it is nice to think of how we could create an application around these scripts which would become a powerful tool to help us with our daily tasks and perhaps make our existing PowerShell scripts more useful.