Skip to content

Instantly share code, notes, and snippets.

@kitroed
Created April 26, 2011 12:49
Show Gist options
  • Save kitroed/942201 to your computer and use it in GitHub Desktop.
Save kitroed/942201 to your computer and use it in GitHub Desktop.
Originally put together Sept. 2010 demonstrating the ability to run PowerShell scripts from C#
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
// Build Command:
// C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe PowerShellScriptExecutionDemo.cs /reference:C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
namespace PowerShellScriptExecutionDemo
{
class Program
{
static void Main(string[] args)
{
if (args.Length > 0 && System.IO.File.Exists(args[0]))
{
PowershellScriptLauncher pssl = new PowershellScriptLauncher();
string response = pssl.LaunchScriptWithRunspace(args[0]);
Console.WriteLine(response);
}
else
{
Console.WriteLine("Argument error: valid path to PowerShell script required");
}
}
}
public class PowershellScriptLauncher
{
/// LaunchScriptWithPowerShellObject() is my Preferred method of launching external
/// powershell scripts, note that this doesn't work well on systems that have PowerShell 1.0
/// installed (a rather un-catchable exception gets thrown) however, this risk is considered
/// worth it due to the ease of instantiating a "PowerShell" object and simply passing commands
/// and scripts to the object using the Invoke() method.
public string LaunchScriptWithPowerShellObject(string scriptPath)
{
PowerShell ps = PowerShell.Create();
// NOTE: Below is the way to check and enable PowerShell script execution on a machine that
// Has it set to "Restricted" (which is the default on XP)
//ps.Commands.AddCommand("Get-ExecutionPolicy");
//if (ps.AddCommand("Get-ExecutionPolicy").Invoke().First().ToString() == "Restricted")
//{
// ps.Commands.AddCommand("Set-ExecutionPolicy");
// ps.Commands.AddArgument("RemoteSigned");
// Collection<PSObject> setResults = ps.Invoke();
//}
// NOTE: Cool! AddScript() will accept either a string script (which is what I was making
// with the IO library File.ReadAllText() call, or an actual path to a physical ps1
// script file!
//string scriptText = System.IO.File.ReadAllText(scriptPath);
//ps.AddScript(scriptText);
ps.AddScript(scriptPath);
// Added command will cause what would otherwise be retured as objects to be returned as strings instead
ps.Commands.AddCommand("Out-String");
// hooking onto the error stream gives us the ability to see if anything went wrong during script execution
PSDataCollection<ErrorRecord> errorStream = ps.Streams.Error;
Collection<PSObject> results = ps.Invoke();
// convert the script result into a single string with a StringBuilder
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
if (errorStream.Count != 0)
{
stringBuilder.AppendLine("\nErrors:");
foreach (var obj in errorStream)
{
stringBuilder.AppendLine(obj.Exception.ToString());
}
}
return stringBuilder.ToString();
}
/// LaunchScriptWithRunspace() is an alternate (and apparently older) way
/// to run powershell scripts on a system
/// Note the explicit use of Runspaces, one downside to this approach is that
/// errors encountered when invoking a script materialize as thrown Exceptions
/// Thus, this may be a bit too "close to the metal" for our needs
public string LaunchScriptWithRunspace(string scriptPath)
{
// create Powershell runspace
Runspace runspace = RunspaceFactory.CreateRunspace();
// open it
runspace.Open();
// script Invoker lets us elevate priveleges
//RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
//scriptInvoker.Invoke("Set-ExecutionPolicy RemoteSigned");
// create a pipeline and feed it the script text
Pipeline pipeline = runspace.CreatePipeline();
// NOTE: Once again, script can be a file ref:
//string scriptText = System.IO.File.ReadAllText(scriptPath);
//pipeline.Commands.AddScript(scriptText);
pipeline.Commands.AddScript(scriptPath);
// add an extra command to transform the script
// output objects into nicely formatted strings
// remove this line to get the actual objects
// that the script returns. For example, the script
pipeline.Commands.Add("Out-String");
// error string
string errorMessage = "";
// execute the script
Collection<PSObject> results = new Collection<PSObject>();
try
{
results = pipeline.Invoke();
}
catch (RuntimeException re) // this should catch any script errors
{
errorMessage = re.Message;
}
// close the runspace
runspace.Close();
// convert the script result into a single string
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
if (errorMessage.Length > 0)
{
stringBuilder.AppendLine("\nScript Errors:");
stringBuilder.AppendLine(errorMessage);
}
return stringBuilder.ToString();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment