In the last post, I discussed some of the reasons why you might want to write your own PowerShell hosting app. I realized later that I didn’t define what that meant.
In general, there are 2 ways to include PowerShell technology in an application.
- Use the PowerShell objects (in the System.Management.Automation.* namespaces) to execute scripts, and use the objects that are returned in your code.
- Create a custom “host” for PowerShell, providing the PowerShell engine with the ability to interact with the environment.
With the first option, you have access to the input, output, and error streams of the PowerShell pipeline (which is how PowerShell represents a piece of running code). With the second option, you also have the ability to handle other output like debug, verbose, and warning, as well as handling prompts for things like read-host and get-credential.
In general, you can get quite a lot done with the first approach, and that’s how we’re going to start. Adding the custom host won’t involve rewriting much code, so it makes more sense to start out easy.
A few more things before we start coding: First,I’m going to use VB.NET rather than C#. I know this is probably a turn off for some of you (sorry), but there are a some good (I think) reasons to do this.
- Almost all example .Net code dealing with PowerShell is C#
- Administrators are more likely to be familiar with vbscript, so VB.NET may be more approachable.
- Most of the actual code for dealing with PowerShell is pretty simple, so it won’t be hard for C# folks to modify it.
- (the real reason) I don’t have a history of writing C#, and I don’t really want to start my efforts in that direction in a blog post. 🙂
And now, on to the code. I’m going to use SharpDevelop, because it’s possible that you want to do something like this, but don’t have the budget (as an admin) to have development tools. SharpDevelop is a free, open-source IDE for .NET languages. It is very similar to Visual Studio, and includes a lot of features. Did I mention that it’s free?
Now, on to coding. I’m envisioning a simple screen with an area to enter PowerShell code, and an area to view the output. I started by creating a new VB.NET Windows Application. I then added a menustrip, a splitter, and two textboxes (one above the splitter, and one below). I set both textboxes to multiline and set their dock property to fill. I also right-clicked on the menustrip and selected “Insert Standard Items” Clicking the Run button should give you something that looks like this:
It’s nothing spectacular, but this isn’t a post about writing a spectacular interface. This is about PowerShell in a GUI. Now to add the PowerShell.
You’re going to need to reference to System.Management.Automation (right-click on the References node in the Projects window, select Add Reference, and select System.Management.Automation from the list on the GAC tab). You will probably want to add the following to the top of the .vb file:
Imports System.Management.Automation Imports System.Management.Automation.Runspaces imports System.Collections.ObjectModel
Now, we’re going to need to add a menu item to run the code. I added a “Run” menu with an item under it called “Run Script” that has a shortcut key of F5. Double-clicking on the “Run Script” menu item brings up the code editor in the handler for the menu item. Here’s the code I put in it.
Sub RunToolStripMenuItem1Click(sender As Object, e As EventArgs) Dim r As Runspace=RunspaceFactory.CreateRunspace r.Open Dim p As Pipeline=r.CreatePipeline(txtScript.Text) Dim output As Collection(Of PSObject) output=p.Invoke() For Each o As PSObject In output txtOutput.AppendText(o.ToString()+vbcrlf) Next End Sub
With that, I clicked the run button in SharpDevelop, and behold:
Typing the simplest PowerShell script I could think of (dir) and selecting Run (or hitting F5) provides the desired output. That’s a good start, but to see a shortcoming, look what happens when I try something more adventurous (After shrinking the size of the app so the screenshots aren’t so obnoxious):
Since the System.Process.ServiceController class didn’t have a very friendly ToString() method, we’re kind of out of luck. And hey, the output from the “dir” example wasn’t anywhere close to what you would normally see in a PowerShell prompt. What’s up with that?
Tune in next time for the reason. I’ll try to get it written Saturday, but no promises.
In the meantime, play around with the code and see what you can accomplish. And let me know what you think of my choice of VB.NET and SharpDevelop.