Created
April 26, 2011 12:49
-
-
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#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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