Executing PowerShell scripts from C#

Executing PowerShell scripts from C#

In today’s post, I will demonstrate how to execute PowerShell scripts from a C# application.

Requirements

  • PowerShell 2.0

References

In the solution explorer, add a project reference to the System.Management.Automation assembly. Then, you have to add the following using statements to import the required types:

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

Create and populate a PowerShell pipeline

The first step is to create an empty PowerShell pipeline by using the static method PowerShell.Create().

using (PowerShell powershell= PowerShell.Create())
{
    ...
}

Next, we can add both scripts or commands to execute.

  • AddScript(): Add a piece of script to construct a command pipeline. 
  • AddCommand(): Add a cmdlet to construct a command pipeline.

If your script has parameters, you can easily add a string or an object for the parameter value with the AddParameter() method.

using (PowerShell powershell = PowerShell.Create())
{
    ...
    powershell.AddScript("param($param1$d = get-date; $s = 'test string value'; " + "$d$s$param1; get-service");
    powershell.AddParameter("param1""parameter 1 value!");
    ...
}

Execution

There are two ways we can call PowerShell to execute it: synchronously and asynchronously.

Synchronously execution

For synchronous execution, we call PowerShell.Invoke(). The caller waits until the script or commands have finished executing completely before returning from the call to Invoke().

using (PowerShell powershell = PowerShell.Create())
{
    ...
    powershell.Invoke();
    ...
}

The return object from Invoke() is a collection of PSObject instances that were written to the output stream during execution. Inside the PSObject is a member called BaseObject, which contains an object reference to the base type you are working with.

Besides the standard output stream, there are also dedicated streams for warnings, errors, debug, progress, and verbose logging. If any cmdlets leverage those streams, or you call them directly (write-error, write-debug, etc.), then those items will appear in the streams collections.

using (PowerShell powershell = PowerShell.Create())
{
    ...
    Collection<PSObject> psOutput = powershell.Invoke();
    foreach (PSObject output in psOutput)
    {
        if (output != null)
        {
            Console.WriteLine(outputItem.BaseObject.GetType().FullName);           
        }
    }
    ...
    if (powershell.Streams.Error.Count > 0)
    {
        // error records were written to the error stream.
        // do something with the items found.
    }
}

Asynchronous execution

For asynchronous execution, we call PowerShell.BeginInvoke(). BeginInvoke() immediately returns to the caller an IAsyncResult object (used to monitor the status of the execution pipeline) and the script execution begins in the background.

using (PowerShell powershell = PowerShell.Create())
{
    ...
    powershell.AddScript("start-sleep -s 7; get-service");
    IAsyncResult result = PowerShellInstance.BeginInvoke();
    while (result.IsCompleted == false)
    {
        Console.WriteLine("Waiting for pipeline to finish...");
        Thread.Sleep(1000);
    }
    Console.WriteLine("Finished!");
    ...
}

By wrapping the PowerShell instance in a using block and don't wait for execution to complete, the pipeline will close itself, and will abort script execution, when it reaches the closing brace of the using block. To avoid this and wait remove the using block and manually calling Dispose() the instance.

Execution Policy

When you invoke cmdlets through the PowerShell class in C#, the execution policy behavior is subject to the policy restrictions of the machine. In order to get around this is, you can set the execution policy for the scope of the application process by runing Set-ExecutionPolicy and specify the scope to be Process. This should allow you to invoke secondary scripts without altering the machine/user policies.

To view or add a comment, sign in

More articles by Ivan Porta

  • How to create and configure your bot to work in Microsoft Teams

    This article is a step-by-step guide on how to create a Bot from scratch using Microsoft Bot Framework and how to…

  • Move your SharePoint On-Premise to Teams

    With the Covid-19 pandemic, remote working has become a must more than a luxury. Many companies decided to adopt…

  • Continuous testing and integration with GitHub repo and CircleCI

    In this article, I'll show you how to use two patterns that have penetrated all aspects of software development:…

  • Partial classes and methods

    In this article, I'm going to explain what partial classes and partial methods are, and how to implement them in C#. In…

  • How to create a web application using NPM and Docker in 5 minutes or less

    In this article, I will show first how to build a Docker image and then download it from Docker Hub and use it to…

    3 Comments
  • Sealed modifiers

    In this article, I will discuss what is a sealed modifier, how to use it and what's its impact on your application's…

  • Data types and memory management in C#

    Before explaining the different data types available in C#, it's important to mention that C# is a strongly-typed…

  • What is a virtual member?

    We can't talk about virtual members without referring to polymorphism. In fact, a function, property, indexer or event…

  • State Management in ASP.NET

    Whenever you visit a web application, your browser will communicate with the respective server through HTTP or HTTPs…

  • What is CTS?

    .NET is language agnostic which allows programmers to write code in different languages (which can be compiled to IL)…

Insights from the community

Others also viewed

Explore topics