Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / PowerShell

Enable Remote PowerShell Execution in C#

4.83/5 (19 votes)
27 Nov 2014CPOL4 min read 81.7K   2.1K  
Talks about executing PowerShell script remotely in PowerShell console; also describes how to do the same thing in C# code.

Introduction

This article introduces how to enable executing PowerShell script remotely in PowerShell console. It also describes how to execute PowerShell scripts locally or remotely in C# code.

All the introduced means are based on my real work and my intention is to manage a remote Windows Server 2008 R2 server by executing PowerShell scripts on a Windows 7 machine. Let me call the remote Windows Server 2008 R2 server as Remote Host and call the Windows 7 machine as Client.

The sample code shows how to execute PowerShell commands locally or remotely. You have to first enable PS remoting on both remote host and local client before executing PowerShell commands remotely.

Enable PowerShell Remote

To enable remote PowerShell execution, I did the following steps:

  1. Install PowerShell 4.0 on both Remote Host and Local Client. 4.0 is not mandatory. 2.0+ is OK. Actually, both Windows Server 2008 R2 and Windows 7 have PowerShell 2.0 installed by default.
  2. Add my Windows account to the Administrators group on both Remote Host and Local Client. If both machines are in the same domain, you can use your domain account; if both are in WORKGROUP, you can create one account on each machine with the same name and password, both in the Administrators group.
  3. Run the following command on Remote Host: winrm quickconfig. This command automatically analyzes and configures the WinRM service which is the core service for remote PowerShell execution.

The winrm quickconfig command is just for quick setup on experimental environment. For production environment, you should carefully configure the permission and firewall according to [2] and [3].

Note that you may encounter several issues when you execute winrm quickconfig or other comlets to enable PowerShell remoting. You can refer to [4] to find the solutions for the 3 most common issues.

Execute PowerShell Script in C#

To execute PowerShell commands in your C# code, you need to reference "C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0\System.Management.Automation.dll" in your project. Note: if your local PowerShell version is lower than 3.0, System.Management.Automation.dll could be in a different folder.

Your may need to use the following two namespaces:

C#
using System.Management.Automation; 
using System.Management.Automation.Runspaces;    

You can use the PowerShell instance directly but a better way is to create a Runspace instance. Every PowerShell instance works in a Runspace. You can have multiple Runspaces to connect to different remote hosts at the same time.

The following code piece shows how to create a local Runspace and execute a command via a PowerShell instance:

C#
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
using (PowerShell ps = PowerShell.Create())
{ 
    ps.Runspace = runspace;
    ps.AddScript("Get-Process"); 
    var results = ps.Invoke();
    // Do something with result ... 
}  
runspace.Close(); 

The following code demonstrates how to execute command remotely:

C#
WSManConnectionInfo connectionInfo = new WSManConnectionInfo();
connectionInfo.ComputerName = machineAddress;
Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);
runspace.Open();
using (PowerShell ps = PowerShell.Create())
{ 
    ps.Runspace = runspace;
    ps.AddScript("Get-Service"); 
    var results = ps.Invoke();
    // Do something with result ... 
}  
runspace.Close(); 

Note: both Runspace and PowerShell classes have implemented IDisposable. So don't forget closing or disposing their instances when you finish using them.

Most of the important methods of Runspace and PowerShell have both sync and async forms, for example, Runspace.Open and OpenAsync, Runspace.Close and CloseAsync, PowerShell.Invoke and BeginInvoke, etc.

Parse Results in C#

The return value type of PowerShell.Invoke is Collection<PSObject>. Each PSObject instance reflects the actual object properties and methods as key-value pairs in PSObject.Members. You can also use PSObject.Properties to access instance properties and use PSObject.Methods to access instance methods. Note: PSObject.BaseObject can be the actual object if the command is executed locally.

Let's take the Get-Process command as an example. When you execute Get-Process using ps.Invoke() like the previous code pieces demonstrates, you will get a Collection<PSObject>. Each PSObject instance represents a process. Then you can use the following code to retrieve process members:

C#
// Execute Get-Process and get results ...
foreach (var result in results)
{ 
    Console.WriteLine(result.Members["Id"].Value);
    Console.WriteLine(result.Members["ProcessName"].Value);
    Console.WriteLine(result.Members["PrivateMemorySize64"].Value);
    result.Methods["Kill"].Invoke();
}
// Clean up code ...  

<span style="color: rgb(17, 17, 17); font-family: 'Segoe UI', Arial, sans-serif; font-size: 14px;">The code piece above works for both local and remote scenarios. </span>Value is of the Object type. It may be a boxed value type. You can invoke the Kill method for a process and it can succeed if you have proper privileges.

If you execute your code locally, you can cast PSObject.BaseObject to the exact type instance like the following code piece does:

C#
// Code to execute Get-Process and get results ... 
foreach (var result in results) 
{ 
    var process = (System.Diagnostics.Process)result.BaseObject;
    Console.WriteLine(process.Id);
    Console.WriteLine(process.ProcessName);
    Console.WriteLine(process.PrivateMemorySize64);
    process.Kill();
}
// Clean up code ... 

If you execute a big PS script via PowerShell.AddScript and PowerShell.Invoke (or BeginInvoke), the return value will only contain the results of the last executed command in the script.

Please refer to [1] for more details.

References

Most of the knowledge can be found in the following links:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)