I mentioned in my last post that the new PowerShell 2 CTP2 release includes a STA switch which lets PowerShell run in Single Threaded Apartment mode. I also mentioned that this means we can do WPF and build UIs in XAML ... but I left it at that.
I thought I should go ahead and give you a better idea what sort of things that makes possible, but I have to admit that I haven’t had a whole lot of time to play with it — and there’s still going to be threading issues unless someone can help me figure out a way to spin out a new thread for the UI. So far everything I’ve tried to get a thread has just managed to crash PowerShell. Luckily, the first couple of WPF tricks I could think of don’t really need threads at all, so they’ll work fine — lets just dive right in.
A PowerShell Splash Screen
Don’t forget to run PowerShell with the -STA switch in order to try these demos, and before you run any of these scripts, you need to have .Net 3.0 or later installed. There are lots of ways to build WPF UIs, but perhaps the simplest thing is to build it in XAML since PowerShell supports XML natively. The first thing we have to do is add a reference to the WPF library, and then we can have some fun.
Add-Type -Assembly PresentationFramework
Add-PsSnapin PoshHttp
As you can see, I’ve also loaded my PoshHttp snapin so I can use Get-Web to retrieve a web page as XML and then load the image — this is mostly about convenience (to save myself the trouble of parsing html as text) but also because if the images are remote, the WPF window has to download them, and therefore won’t work unless you ShowDialog() and give the WPF window the thread. You can just use the path to any image on your hard-drive.
Add-Type -Assembly PresentationFramework
Add-PsSnapin PoshHttp
## Download web-comic images
function Get-Comic($comic = "xkcd") {
switch($comic) {
"dilbert" { $comic = "http://dilbert.com$((Get-Web http://dilbert.com/fast/).html.body.div.img.src)" }
"xkcd" { $comic = (Get-Web "http://xkcd.com/index.html").SelectSingleNode('//img[contains(@src,"/comics/")]').src }
}
$location = Get-Location
Set-Location ([IO.Path]::GetTempPath())
Get-Web $comic -force
Set-Location $location
}
$img = (Get-Comic).FullName
$image = [system.drawing.image]::fromfile( $img )
$width = $image.Width
$image.Dispose()
[xml]$xaml = "
<Window xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
SizeToContent='WidthAndHeight' WindowStyle='None'
AllowsTransparency='True' WindowStartupLocation='CenterScreen'>
<Image Source='$img' Width='$width' />
</Window>"
$splash = [Windows.Markup.XamlReader]::Load( (New-Object System.Xml.XmlNodeReader $xaml) )
$splash.Show() # do this before you run the rest of your script
Start-Sleep 3 # imagine this is a long script ... running
$splash.Close() # and at the end, you just get rid of it
[...] WPF From PowerShell (Joel Bennett) [...]