WPF & PowerShell – Part 1 ( Hello World & Welcome to the Week of WPF )

WPF & PowerShell – Part 1 ( Hello World & Welcome to the Week of WPF )

Rate This
  • Comments 26

Welcome to the Week of WPF.  During the next 7 days, I’ll help show you how you can use WPF and PowerShell together.

PowerShell could always script almost everything in .NET, but, prior to the recent CTP2 you could not script Windows Presentation Foundation (WPF) in PowerShell.

Now you can script everything that WPF can do within PowerShell.

This means you can write pretty sleek looking UIs in nice little PowerShell scripts.

There are a lot of things you can do with this capability, but let’s start things off simple.

 

Windows Presentation Foundation (WPF) is a set of .NET libraries for making next-generation user interfaces.  In order to script WPF classes, you have to start them in a Single Threaded Apartment (STA).  Luckily, starting in CTP2, you can run code in an STA a few ways in PowerShell.

 

In order to script WPF, you have to do one of three things:

·         Run the Script in Graphical PowerShell, where WPF scripts will run without any changes because Graphical PowerShell runspaces are STA.

·         Run the script in PowerShell.exe and add the –STA script

·         Create a background runspace that is STA, and run the script in the background runspace

 

In this post, I’ll show you a “Hello World” script, and how to run it in each of the three modes.

 

First, let’s write our “Hello World” script.   Open up Graphical PowerShell (gPowerShell.exe) and create a new script file (CTRL + N).

 

Here’s the Hello World file:

 

$window = New-Object Windows.Window

$window.Title = $window.Content = “Hello World.  Check out PowerShell and WPF Together.”

$window.SizeToContent = “WidthAndHeight”

$null = $window.ShowDialog()

 

Now in Graphical PowerShell, you should be able to just run it and be done.

 

You can run the current script in Graphical PowerShell with F5 or the Green Run button in the upper left of the editor.

 

Now let’s run the script in STA Mode PowerShell (Run PowerShell –sta).  Save it as “HelloWorld.ps1”

 

Since PowerShell.exe –sta doesn’t load up WPF’s assemblies, lets run these three lines to add the references:

 

Add-Type –assemblyName PresentationFramework

Add-Type –assemblyName PresentationCore

Add-Type –assemblyName WindowsBase

.\HelloWorld.ps1

 

Now you have a Hello World in WPF from the console version of PowerShell.

 

Finally, you can embed scripts to generate WPF inside of an application or a background runspace.  This has some advantages over the first two approaches… namely, without a background

 

The code below will create a background runspace and set the two properties required to make WPF work in a PowerShell runspace, ApartmentState and ThreadOptions.  ApartmentState determines if the runspace PowerShell is single or multithreaded (WPF requires single threaded), and if the same thread is used every time a command is run, or if a new thread is created each time.  For WPF scripting to work in a runspace, you have to set ApartmentState to “STA” and ThreadOptions to “ReuseThread”.  In the code below, the first 3 lines set up the runspace, the next 10 lines ensure that runspace is able to load WPF classes, and the final 4 lines run our original HelloWorld.ps1

 

# Create a runspace to run Hello World

$rs = [Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()

$rs.ApartmentState, $rs.ThreadOptions = “STA”, “ReuseThread”

$rs.Open()

# Reference the WPF assemblies

$psCmd = {Add-Type}.GetPowerShell()

$psCmd.SetRunspace($rs)

$psCmd.AddParameter("AssemblyName", "PresentationCore").Invoke()

$psCmd.Command.Clear()

$psCmd = $psCmd.AddCommand("Add-Type")

$psCmd.AddParameter("AssemblyName", "PresentationFramework").Invoke()

$psCmd.Command.Clear()

$psCmd = $psCmd.AddCommand("Add-Type")

$psCmd.AddParameter("AssemblyName", "WindowsBase").Invoke()

$sb = $executionContext.InvokeCommand.NewScriptBlock(

(Join-Path $pwd "HelloWorld.ps1")

)

$psCmd = $sb.GetPowerShell()

$psCmd.SetRunspace($rs)

$null = $psCmd.BeginInvoke()

 

This is just a taste of some of the fun that PowerShell and WPF can have together, and how to get it working.  You can now use everything in WPF in a PowerShell script.

 

During the Week of WPF, I will post one script each day that will take us a little further down the rabbit hole of what PowerShell and WPF can do together.  After the week of WPF is done, keep your eyes on this space, because every Wednesday, I’ll try to post a “WPF Wednesday Widget” that uses showcase using PowerShell and WPF together.

 

Hope this Helps,

James Brundage [MSFT]

Leave a Comment
  • Please add 3 and 3 and type the answer here:
  • Post
  • Hi James,

    interesting post, it's good to see PowerShell expanding in features and capabilities.  

    It's also a good example of why I find PowerShell pretty annoying.  You've given three completely different ways of doing something, two of which aren't in the least bit intuitive and the easiest of them doesn't work.  

    When I paste the example above into gPowerShell and hit F5 it fails, with the error "the calling thread must be STA, because many UI components require this".  No doubt I've omitted some 'obvious' step such as manually setting my default gPowerShell Thursday execution policy to be green.

    I'm not even going to bother with the other two methods as no doubt some other mysterious setting needs to be changed from it's default for these to work properly.

    This is just a general example of why I find PowerShell absolutely exasperating.  There seem to be many, many ways of doing the same task, most of which have some undocumented 'miracle happens here' step completely unrelated to the task at hand.  ("You want to display a window?  Make sure you change the environment threading model first!" WTF??) How are we supposed to establish best practice and create re-usable code with such a profusion of approaches and convoluted mechanisms of making them run?

    Another bug-bear is ADSI, which I spend quite a bit of my time (normally) coding with VBScript.  I've tried to convert to PowerShell but good grief it's an irritating experience.  

    Yesterday, for example, I spent ages wrestling with a bit of pipeline code to show a table of people who had non-default mailbox size limits.  Doing the search went fine, and using (an entirely non-obvious) bit of code from the internet I got it into a table.  

    I then wanted to show the output in MB instead so did a ' / 1MB'; did it work?  "no division operator for property result set".  So, convert it a string then do it (as there's no toInt() function I take a guess it might implicitly convert a string, like it would in VBScript).  Still doesn't work, "no division operator for string".  Cast it to an int, still doesn't work, it tries to cast the propertyresult to an int before running the .toString(), not after,  and fails "can't convert propertyresult to int".  Try putting brackets round the blah.ToString(), to force it to run first.  Fails.  Give up.  Resort to copying it out from the screen and pasting it into Excel and converting it there.  Rubbish.  

    Rant over, and apologies for straying way off topic here (and directing this rant at you). I do appreciate all the effort the PowerShell guys are making to evangelise and give examples of PowerShell at work.  I'm just finding it too hard to translate the stuff I do into the PowerShell way; the balance between "effort required to make it work" versus "benefits of migrating from VBScript" to my mind isn't tipped in the right direction.

  • PingBack from http://www.alvinashcraft.com/2008/05/22/dew-drop-may-22-2008/

  • Aren't these precisely the low-level details that are supposed to be encapsulated within cmdlets?  This isn't that much easier than just doing it in C#.  I agree that it's cool to be able to do it, and I liked the article and will certainly read the rest in the series, but I doubt any of this will help to spread adoption of PowerShell among those new to it, and might even turn some of them off.  I wish Microsoft would spend more time fixing known bugs than packing in new features that will be very rarely used.  How about allowing PowerShell scripts to be directly pushed out through Group Policy without a VBScript wrapper?  Or adding Active Directory cmdlets that work?  Or supporting long file paths?  Or making the SQL cmdlets better?  Or adding support for VBScript's GetObject() method?  Or getting PowerShell to work on Server Core?  Or making powershell.exe launch as quickly as cmd.exe?

  • Andrew,

    Please detail your problems, then we can help you, and maybe help others who come along with the same issue.

    As an MVP, we tend to not always be in touch with the troubles newcomers can face, as things have changed even as of 12 months ago.

    As for the STA/gPowerShell problem...  You are running v2 CTP2 right?  v2 CTP1's gPowerShell doesn't support STA mode.

  • Andrew,

    As for the "having multiple ways to do the same thing"...

    All the methods are quite different and serve their own purpose.

    For a typicaly admin, the command-line method would likely be choice #1.  #2 can be used to actually test/develop the script by an admin, before ones copies it into a script to be run by powershell.exe.

    Option #3 is more geared for developers who could be using PowerShell *inside* their applications.

  • Now also James Brundage from the PowerShell team started a series on WPF from PowerShell, Starting with

  • I like this - look forward to the other articles.

    Shouldn't the New-Runspace (and other runspace) cmdlets be expanded to cover the use of a runspace in your third example

  • Hard Hat Area: Programmers.... Server 2008 tidbit.... PowerShell...create some real nice user interfaces

  • Ugh, I could make a peanut butter and squid sandwich, but that doesn't mean you should.

  • Interesting post but we have a simple question... how can we do to run a powershell script that shows for example a form with some controls but without the black console window in the background? how can we hide the black console window? Is it possible?

  • Richard,

    new-runspace/start-psjob only support the MTA threading model/state.

    So, one can't use these and have WPF behave correctly in all circumstances.

  • This is only meant to be MILDLY snarky.

    Thanks, just what I need, seven days of examples of how to use BETA code.  I live in a production world.  When will the new version ship?

  • > This is only meant to be MILDLY snarky.

    "Snarky" - what a GREAT word.  I just love that word.

    > Thanks, just what I need, seven days of examples of how to use BETA code.  I live in a production world.  When will the new version ship?

    It's worse than that my friend.  This is not BETA code, its CTP code.  That's a LONG way away from Beta.  V2 is a huge (compatible) release with lots of new features and we need to promulgate those features to our early adopters so they can kick the tires and tell us if we got it right, almost right, or our heads are in the wrong place of our anatomy.

    YOU benefit from this because at some point we'll ship these features and the feedback from our early adopters hopefully acts as a proxy for your needs and you get what you want without having to take the production code, file a bunch of bugs/feature requests and wait a couple of years to get them addressed.  

    Of course if these early adopters don't reflect your needs, you're screwed.  You might want to think about that when deciding whether to blow of the CTP or not.  

    This blog is going to have a content for both existing and new stuff but is probably going to lean towards the newer stuff because we want people to use it and give us feedback.  That might mean that our signal-to-noise ratio is wrong for you until we ship V2.  That's fine - no harm/no foul - we'll enjoy your company when you join us again.

    So - when will the new version ship?  Here is the deal:  We were only given permission to have a CTP if we promised never to answer that question.  That said, here is what I can say.  We are coding new features for a couple more weeks and then it has typically taken us a year plus or minus a quarter to bake the release to the point that customers tell us it is ready to ship.

    Jeffrey Snover [MSFT]

    Windows Management Partner Architect

    Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell

    Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

  • Jeffrey,

    Thanks.  I really appreciate your answer.  And I really appreciate PS.  I had been doing most of my work in Perl and I am very happy to move to this new tool.  I see PS as being a seriously big deal for me, I just can't get involved in development code right now.

    Thanks again.

  • Pablo,

    You want to get rid of the PowerShell console?  Can you be more specific?

Page 1 of 2 (26 items) 12