As you may know, I was one of the first developers who jumped on board and started working on an alternative PowerShell host (actually, I’m also the first to create a WPF-based host, and the first to create one that was open source … but enough about me).

Recently I’ve picked back up on that project, and am just about ready to release what I hope will be the last “pre-release” of PoshConsole before I declare it to be “beta” quality and start doing more regular releases. ;-)

Trivial example of inline WPF outputThe coolest features of PoshConsole, the ones that are really revolutionary, involve exposing the WPF surface to scripts and cmdlets so that you can actually have graphical output in the console — not popups, and not just for fun… but stuff like putting bar graphs behind the size columns in Get-ChildItem for folders, and the memory columns in Get-Process, etc… anyway.

So I’ve been writing a few scripts to show off the possibilities of PoshConsole, and was thinking about even posting them on the PoshCode.org PowerShell Script Repository, but I wanted a way to make clear that they’d only work in PoshConsole.

A little investigation later, and it was clear that PowerShell has a built in feature for this: #requires -ShellId PoshConsole … except, it doesn’t work. Actually, it doesn’t work for two reasons:

  1. PowerShell always ignores #requires -ShellId Anything
  2. No other PowerShell host implements ShellId as far as I can see

The ShellId is a read-only property of the RunspaceConfiguration, so to implement it in your PowerShell host you have to create your own RunspaceConfiguration class inheriting from the abstract base class. The problem is, there are some expensive side-effects:

  1. You have to configure the available .net Assemblies, Cmdlets, Format files, Initialization Scripts, Providers, Scripts, and Type files …
  2. Having your own ShellId means you don’t inherit anything from PowerShell.exe (like for instance, the ExecutionPolicy)
  3. Some cmdlets just don’t seem to work (Add-PSSnapin is just failing on me with “Object reference not set to an instance of an object”)

So … to sum up: PowerShell ignores #require -ShellId, and I can’t find another host (including Microsoft’s “Graphical PowerShell” and the latest and greatest PowerShell Plus Professional) that bothers to set the ShellId. Can anyone tell me a reason why I should bother with this?

Oh, and, can anyone give me some information about why Add-PSSnapin might be failing when I do set the ShellId?

[new] ShellId IS too big a burden.

After further investigation, it turns out that the reason Add-PSSnapin fails is because it uses a method AddPsSnapIn which is part of the RunspaceConfiguration (that you had to create yourself to set the ShellId), and you can’t implement that method (in fact, you can’t seem to override it with “new” either, I’ll have to look into that a little more).

In any case, the method has to return a PSSnapInInfo object, and since there are no public constructors for PSSnapinInfo objects, you’re sore-out-of-luck. It appears you would literally have to reverse engineer the whole “PSSnapin” system and create your own cmdlets and functionality around it to try to keep your host compatible with the main PowerShell. No wonder nobody’s done this…

I guess I’ll just go back to using Microsoft.PowerShell as my ShellId, I don’t know what I was thinking.

Microsoft has provided some very good documentation on how to package fonts with WPF applications, and I’ve been following it in several different ways in different apps I’ve written. Recently I provided a feature in Posh Console which allows you to load the startup banner from an external file: StartupBanner.xaml.

Loading the banner from an external XAML file means that users can configure their own startup banner and make it look however they like, but it broke our default banner. The startup banner we’ve been using has a logo and some text which are all defined in pure XAML and uses several fonts which we had embedded in a FontLibrary.dll resource assembly. It worked great as long as the XAML was defined in the application, but as soon as we removed it to an external file and loaded it in using the XamlReader.Load method, the fonts all went to the fallback default fonts instead of our embedded ones.

Normally this might not be a big deal, but since our logo is based on the “Q” in a Quake-like font … it looks really lame without fonts. :D Apparently, when you load external XAML, it can’t use the Font Resource Library resources. At this point, I can’t seem to find anything to indicate why this is the case, but I suspect it has to do with the fact that the external, loaded XAML only has partial trust, and since the font is in an external assembly instead of embedded in the partial trust content, it can’t get to it. However, it might be simpler than that: it might just be that the base URI for the externally loaded XAML is an actual file location rather than one of the pack://,,,application/ type URIs, so the slightly odd font path doesn’t resolve.

In any case, I found a way around it, which is of course, why I’m writing all of this down. :) (more…)

So, I’ve been working on PoshConsole for awhile now, and with the help of some of the guys in #PowerShell@irc.freenode.net have been playing with trying to find ways to enhance output, like using ANSI escape sequences, and even creating an Out-WPF cmdlet which can output objects as databound WPF controls which look really good.

We have been trying to find a way to incorporate the colored and even bold/italic formatting in a way that would be compatible with the existing format-* cmdlets, and we’ve even looked at replacing out-default with a cmdlet that would be compatible with the default PowerShell host. But today I finally locked in on the import of this post on the PowerShell blog. It’s just not possible.

The format cmdlets (Format-List, Format-Custom, Format-Table, Format-Wide) output data in the form of undocumented .Net objects which are “subject to change without notice,” and are therefore basically useless. Of course, that means that if you want to replace Out-Default you have to not only replace the output, but you have to replace the formatting cmdlets, and of course the Update-FormatData cmdlet too — in fact, you have to either parse the largely undocumented format data files, or create some replacement for them to allow users to specify formatting for types you haven’t thought of…

All of this amounts to what many of you probably already knew: it’s a lot of work to create a complete PowerShell host, but it’s at least as much work to create a replacement PowerShell formatter.

Click for a teaser screenshot

This is actually a bit scary, because you can load sort-of … anything ;-) To prove it (you’re gonna love this … I should take a video, really, but it’s time for bed, so this will have to do): check this out Beat that! ;)

So yeah, I have this control written from an earlier project which creates a task list with live preview images. When I say “live previews” I mean actually live, like on the Vista Alt+Tab: if there’s a video playing, you can watch it in there (of course, it dies a horrible death on XP, but I have other code for that).

As a side note the TaskBar2.panel stuff is from the TINS release I made months ago, there’s several fun .panel files in there … but you have to load a bunch of the TINS assemblies first, I didn’t distinguish which ones, I just did:


cd C:\Users\Joel\Projects\TechDemos\TINS\bin\Release
ls *.dll,*.exe | % { [System.Reflection.Assembly]::LoadFrom($_) }
$Host.PrivateData.XamlUI.LoadXaml("C:\Users\Joel\Projects\TechDemos\TINS\bin\Release\Panels\TaskBar2.panel");

 

Of course, in .Net 3.5 the RichTextBox has the ability to go ContentEnabled="true" which should allow those things to be actual controls you can click to switch active task, right-click to get a task menu, etc (although I haven’t tried that yet). We might just have to upgrade ;-)

Anyway, it’s past time for bed, so I’ll preempt complaints about how this isn’t ready for release yet with this quote:

I don’t have to take this abuse from you; I’ve got hundreds of people waiting to abuse me. — Bill Murray, “Ghostbusters”

So, I’ve been practically invisible for a few weeks here, and liable to be invisible for at least one more week … this is my vacation time, so it’s hard to motivate myself to blog about anything. However, I have been spending some time working on a side project: a PowerShell Host.

Now, there are a few other hosts out there, but with PowerShell Analyzer seemingly swallowing up PowerShell IDE and going the fifty dollar route … as an open sourcer and contributor to the PowerShell Community Extensions it seemed to me that this couldn’t be that hard, so I started looking for an open source implementation of PSHostRawUserInterface and couldn’t find one. I mean, there are a couple of implementations out there, but essentially they are the PowerShell Remoting interface (which actually runs inside PowerShell.exe, and thus doesn’t seem to implement anything itself) and a half-implemented console block from a Japanese file manager called kuon

So, being myself, I stepped in an implemented it in the weirdest way I could think of: on top of a WPF RichTextBox. Yep, that’s right. I’ve made myself a ConsoleTextBox which subclasses the RichTextBox and handles keyboard input etc to behave … roughly … the way a Console should.

It’s far from finished, but it is working, so this is by way of announcing the first public alpha release of PoshConsole! The vast majority of PowerShell scripts will run without a hitch — the only time you’ll have problems is with secure string input (eg: passwords), with direct raw buffer interaction, and with running “legacy” console applications — it does not yet redirect standard input/output/error.

One small tip: if you have the PowerShell Community Extensions installed, you’ll want to remove the alias they set up to pipe help through “less” ... because less is a legacy console app — you won’t get any help at all.

Technorati Tags: , , ,