Skip to content
Archive of entries posted on October 2009

Writing your own PowerShell Hosting App (Part 3)

In the last post we started building the app, but ran into a problem with output.   We were able to get output from some scripts (dir, for example, gave incomplete output), but others didn’t give us anything useful at all (get-service, returned “System.ServiceProcess.ServiceController” over and over).

The reason for this is simple.  PowerShell cmdlets (and by extension, scripts) return objects,  not strings.  To get string output, we need to tell the script to output strings rather than ask each object that is output to give us its string representation by calling ToString() on them.

To do this, we could try to do something like surround the script that’s passed in with parentheses, and add “| out-string”, but there’s an easier solution.  The object we’re using to run our scripts is called a Pipeline.  As such, it has a method to append commands.  The “corrected” code is this:

Sub RunToolStripMenuItem1Click(sender As Object, e As EventArgs)
        Dim r As Runspace=RunspaceFactory.CreateRunspace
        r.Open
        Dim p As Pipeline=r.CreatePipeline(txtScript.Text)
        p.Commands.add(new Command("out-string"))
        Dim output As Collection(Of psobject)
        output=p.Invoke()
        For Each o As PSObject In output
            txtOutput.AppendText(o.ToString()+vbcrlf)
        Next
End Sub

The only new line is the one that contains the “out-string”.  We can even leave the ToString() calls, because we know that string objects’ ToString() will just output the string itself, or at least we hope it would.

With that, here’s the output for “get-service” (note: I changed the font to a fixed-width font):

Fixed Output

That’s much nicer and even has column headers like we’d expect.  With that change, cmdlets that output objects directly to the pipeline will work fine.  But what about cmdlets that output text to the host (like the write-* cmdlets other than write-output)?  Simply trying “Write-host ‘Hello, World.’” gives us a big fat error, but one that gives us and idea what we need to do to fix it: “System.Management.Automation.CmdletInvocationException: Cannot invoke this function because the current host does not implement it.”

That seems like a pretty good breaking point.  Implementing the host (which pretty much involves inheriting from a couple of classes and implementing some basic methods) will take some time, but most of it’s pretty easy.

One thing that I should mention.  I haven’t been specific about what version of PowerShell this series is using.  The reason is that the code so far will work on either 1.0 or 2.0 (and I anticipate that the rest of the code will as well, but I haven’t written the rest yet).  In fact, the custom host that I use at work has no problems running on either 1.0 or 2.0.  I’ve been very impressed with the PowerShell team and their commitment to making PowerShell 2.0 backwards compatible as far as possible.  I expected that this effort would end as soon as I got into the object model, but I have yet to find anything that I’ve written for 1.0 that hasn’t worked in 2.0.  Now there’s a lot of stuff that can be written for 2.0 that won’t work in 1.0, but that’s to be expected.

Speaking of 2.0, the final release of 2.0 (for XP and Win2k3) showed up today, much to my surprise.  Kudos again to the PowerShell team for a very quick release schedule following last week’s Windows 7 release.  If you haven’t already, I definitely recommend getting 2.0 downloaded and installed so you can try out all of the neat stuff that’s included.  I especially recommend trying the out-gridview cmdlet!

Mike

  • Digg
  • Slashdot
  • Reddit
  • Tumblr
  • Delicious
  • Twitter
  • Google Bookmarks
  • StumbleUpon
  • Technorati Favorites
  • Google Reader
  • Share/Bookmark

Writing your own PowerShell Hosting App (Part 2)

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.

  1. Use the PowerShell objects (in the System.Management.Automation.* namespaces) to execute scripts, and use the objects that are returned in your code.
  2. 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.

  1. Almost all example .Net code dealing with PowerShell is C#
  2. Administrators are more likely to be familiar with vbscript, so VB.NET may be more approachable.
  3. Most of the actual code for dealing with PowerShell is pretty simple, so it won’t be hard for C# folks to modify it.
  4. (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:

Screenshot 1

Screenshot 1

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:

The Finished(?) App

The Finished(?) App

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):

Not So Useful Output

Not So Useful Output

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.

  • Digg
  • Slashdot
  • Reddit
  • Tumblr
  • Delicious
  • Twitter
  • Google Bookmarks
  • StumbleUpon
  • Technorati Favorites
  • Google Reader
  • Share/Bookmark

Writing your own PowerShell Hosting App (Part 1. Introduction)

I’ve mentioned before that I use a homegrown PowerShell host in my work.  I have been more than pleasantly surprised at how easy and how rewarding this is.  In the last few weeks, I’ve seen a few articles that have gotten me thinking about writing a series of blog posts about how to get started.

Before actually writing anything, it’s good to ask yourself…why in the world would I write a host when there are so many out there already (ISE and PowerGUI are notable free examples)?  This is a really important question and one that will stop most projects in their tracks.  Most people can get what they need using an existing host.  Here are some of the reasons I chose to write  a host:

  • I wanted complete control over the environment, as I knew (hoped) that I would be spending a lot of time using it
  • I wanted to be able to interact with the environment in ways that the existing tools didn’t allow
  • I was constrained to use PowerShell 1.0 (which eliminates the ISE)

But probably the most pressing reason in reality was:

  • I had a book (link) that explained the technology and I wanted to play  :-)

Unlike most (some?) administrators, I have a development background and even have Visual Studio installed on my machine, so testing the waters of writing a host wasn’t a big investment of time, and the pleasure of seeing something like this come together was well worth it.

Here are the posts that got my mind going again:

Create your own IDE in 10 minutes

How to Host PowerShell in a WPF Application

In the next post, I’ll start the project and give you something to look at.

Let me know if there’s anything specific you’d like to see (or have experience implementing).

Mike

  • Digg
  • Slashdot
  • Reddit
  • Tumblr
  • Delicious
  • Twitter
  • Google Bookmarks
  • StumbleUpon
  • Technorati Favorites
  • Google Reader
  • Share/Bookmark