Tag Archives: GUI

Long-running background tasks in ShowUI GUIs from PowerShell

A lot of the time when you’re writing ShowUI user interfaces in PowerShell, you’re just asking users for inputs, prompting them for choices, or showing them the results of some calculations (whether that be dashboards, graphics, etc).

However, sometimes you need to prompt the user for input and then do some work, and you want to present the users with output as the work progresses. With any graphical user interface, when you want to do any significant amount of work, you need to do it on a background thread. The ShowUI way to do that is to use the Invoke-Background command, which gives you an event-driven way to run a script block (or command) and capture all of it’s various outputs.

I’ll show you an example here which writes output and progress events, and show you how to handle updating the user interface with both (hopefully you’ll be able to figure out the other output options, including the errors).


Import-Module ShowUI -Req 1.4

New-Grid -Columns "*","5","70" -Rows "21","Auto","5","*" -Margin 5 {
  ProgressBar -Name ProgressBar -ColumnSpan 3 -Maximum 100 -Margin "0,0,0,5"

  TextBox -Name count -Text 12 -MinWidth 150 -Row 1

  TextBox -Name output -MinHeight 100 -ColumnSpan 3 -IsReadOnly -Row 3

  Button "Start" -Name StartButton -Column 2 -Row 1 -On_Click {
    # If you need to pass values from your form to the background function
    # They need to be serializable, and go through the -Parameter hashtable:
    Invoke-Background -Parameter @{ work = [int]$count.Text } {
      param($work=10)
      # You would do real work here, but I'll just fake it
      foreach($item in 1..$work) {
        # Anything that goes to Output triggers the OutputChanged
        Write-Output "Processing item $item of $work"
        Start-Sleep -milli 500
        # And of course, progress triggers the ProgressChanged
        $progress = (([double]$item / [double]$work) * 100)
        Write-Progress "Processing" -PercentComplete $progress
      }
    } -On_OutputChanged {
      # The actual event is on the DataContext object
      $output.Text = $args[0].DataContext.Output -join "`n" | Out-String
    } -On_ProgressChanged {
      $ProgressBar.Value = $args[0].DataContext.LastProgress.PercentComplete
    }
  }
} -Show
 

The first key, of course, is knowing that Invoke-Background sets a DataContext on the object (either the object specified to the -Control parameter, or the parent who’s event handler calls it). That DataContext is a ShowUI.PowerShellDataSource (it’s code is in the C# folder in the ShowUI module), and it has events and properties for each of the streams: Output, Error, Warning, Verbose, Debug, and Progress. It also has a property for the “Last” item from each of those streams, and a TimeStampedOutput property which collects all of the output, in order, with a NoteProperty for the Stream and the TimeStamp. More importantly, it has events which fire on every output.

The second key is knowing that the properties like “Output” contain all the output, and properties like “LastOutput” contain only the very last thing output. Since in the case of the progress we only care about the very last value, we’re able to use the “LastProgress” property. Since we want to show all of the output, rather than try to collect the “last” one each time, we can just overwrite the textbox’s text with the output array.

It’s also very important to remember that the properties are arrays, and in particular to remember that the Output is an array of PSObject, and the others are arrays of ProgressRecords, DebugRecords, ErrorRecords, etc… so we use Out-String to make sure that we convert them to a string before we set the Text of our output pane.

Hopefully this function will help you out — I’ll try to improve it’s help and examples in the next release of ShowUI.

Did you know PowerShell can use Selenium?

This is sort-of a place-holder for a full-length post that I really ought to write about driving web testing from PowerShell using Selenium. I actually have a little module around for doing that with WaTiN, but honestly the Selenium project seems to be a lot more active, and has quite a bit of muscle behind it since they’ve merged with WebDriver…


Add-Type -path ~\Downloads\selenium-dotnet-2.16.0\net40\WebDriver.dll

# Navigate to google in IE (or Firefox, Chrome, Opera, etc)
$driver = New-Object OpenQA.Selenium.IE.InternetExplorerDriver
$driver.Url = "http://google.com"

# Type PowerShell into the query box, the page will update via AJAX
# Note we won't hit enter or anything
$q = $driver.FindElementByname("q")
$q.SendKeys("PowerShell")

# Use a CSS selector to find the first result link and click it
$driver.FindElementByCssSelector("li.g h3.r a").Click()
 

One Catch

The Security tab of the Internet Options dialogIf you try this with IE and you get the error Unexpected error launching Internet Explorer. Protected Mode must be set to the same value (enabled or disabled) for all zones ... it means exactly what it says. You need to open “Internet Options” from your start menu (or from IE), and go through each “zone” and set the “Enabled Protected Mode” check box to the same value for each zone (either all checked, obviously the most secure, or all unchecked). I’m not going to debate whether setting them all unprotected is a good idea … I set mine to all protected, but I don’t generally use IE anyway.

If you want more help, Selenium’s documentation is great, and there’s a section on Getting Started with Selenium WebDriver which I found quite helpful (make sure your examples are in “csharp” and you can almost just copy and paste — someone should offer to do them in PowerShell).

If you want more information about the Internet Explorer driver and this problem in particular, the short answer is that “Protected Mode” is a security boundry, so if you cross over it the COM automation object doesn’t work — thus, you need to make sure you always stay on the same side. There’s a good discussion on the mailing list archive about how it works and why, as well a weird alternative documented on the Selenium JavaDocs

PowerBoots: The tutorial walkthrough

[new] Updated to PowerBoots 0.1

An introduction to PowerBoots

Please excuse me if I start by just copying the basic ideas of the Shoes Tutorial, but I figured that since PowerBoots is inspired by Shoes, that was as good a place as any to start. PowerBoots (or just “Boots”) is a PowerShell 2.0 module with functions for writing Windows Presentation Framework (WPF) applications in the PowerShell scripting language. You should get the latest version of PowerBoots before continuing, and install it by putting the “PowerBoots” folder in one of your “Modules” folders (list them by typing $Env:PSMODULEPATH in PowerShell v2).

Don’t forget to start PowerShell.exe with the STA parameter (This is no longer required in PowerBoots 0.1).

Did I hear someone ask what is WPF? It was introduced as part of .Net 3.0 (and vastly improved in .Net 3.5), so you can expect to find it preinstalled on computers from Vista on, and of course you can download and install it on XP if it’s not already installed. The only thing you really need to know about WPF for the purposes of this tutorial is that it is the new GUI toolkit for .Net, and that it is container based — you put elements into other elements to control the layout, rather like HTML and Java Swing… you can pick up the rest as we go along.

A simple Boots program


New-BootsWindow -SizeToContent WidthAndHeight -Content {
   Button -Content "Push Me"
}
 

I’ve recently changed this first example to pass a script block to the content instead of using parentheses, because although PowerBoots supports running in an MTA PowerShell host, the only UI-creation command that is MTA-safe is the New-BootsWindow command. All of the “new” functions must then be inside of a scriptblock which is passed to the New-BootsWindow cmdlet and executed on that STA thread. You can use parenthesis ( and ) as a container instead, but that requires the host to be in STA threading mode (run: PowerShell -STA) so the controls can be created:


New-BootsWindow -SizeToContent WidthAndHeight -Content (
   Button -Content "Push Me"
)
 

This first example is a bit uglier than the Shoes syntax, so lets see if we can’t clean it up some. The -Content parameter is positional, so the first non-named argument you pass will be used for that. The same is true for the -Children parameter of panels, and in fact, each of the other similar parameters: Items, Blocks, and Inlines.

We have used a function New-BootsWindow which has an alias Boots. Boots takes all the same parameters as the Window function mentioned previously, but it uses slightly more useful defaults, and has a few other major benefits as well, the first of which is that it automatically “shows” the window, and the second is that it supports an -Async parameter which allows the window to come out in a new thread so that you can continue using PowerShell while the window remains alive and responsive. There is one catch: New-BootsWindow cannot take it’s content on the pipeline (the old function, now renamed “Out-BootsWindow” can take pipeline content, but is a script function, and requires -STA mode) — you have to specify it as a ScriptBlock. So now that we know this, we can rewrite our first example like this:


Boots { Button "Push Me" }
 

Just for the record, the simplest Boots program would just be a simple popup dialog to put some text in a Window, like: Boots { $msg }

We can put controls in a stack


Boots {
   StackPanel {
      Button "A bed of clams"
      Button "A coalition of cheetas"
      Button "A gulp of swallows"
   }
}
 

StackPanels are awesome. So are WrapPanels. Try that code with a WrapPanel instead of a StackPanel and see what the difference is. This brings up another point: those positional parameters we mentioned earlier: Content, Children, Items, Blocks, and Inlines, are also set to accept the value from the pipeline. Not only that, but they are intelligent about whether or not the content model accepts multiple items! So we can actually rewrite that script like this, and get the same results:


Boots { "A bed of clams", "A coalition of cheetas", "A gulp of swallows" | Button | StackPanel }
 

Now we’re really onto something! Continue reading

PowerBoots – Shoes for PowerShell

If you haven’t seen the Ruby Shoes graphical framework, you should check it out. In fact, go read the tutorial and come back, because the rest of this will make a lot more sense then.

It’s a very slick toolkit, right? Not only that, but it works on Windows, Linux, and Mac OS X … unlike what I’m about to show you, which works only where PowerShell works …

So, I’m curious if anyone would like something like that for PowerShell … and more to the point, how many people would be interested in it, and whether anyone would be willing to help write it (because exposing all of the properties of the various controls is going to require a lot of repetitive coding).

What would it look like in PowerShell?

The simplest PowerBoots app

The simplest PowerBoots app


# These lines are the same (#2 uses aliases)
New-Button "Push Me" | Out-WPF
button "Push Me" | Wpf
A few more buttons, in a stack

A few more buttons, in a stack


# Again, these lines are the same (#2 uses aliases)
"A bed of clams", "A coalition of cheetahs", "A gulp of swallows" | New-Button | New-Stack | Out-Wpf
"A bed of clams", "A coalition of cheetahs", "A gulp of swallows" | Button | Stack | Wpf

As a disclaimer, I copied the examples here from the Shoes tutorial I mentioned earlier, which is why they’re slightly kooky (Why The Lucky Stiff is a strange guy), and why I suggested you go read it before you read this. Of course, although these demos do work —and it’s all skinable and themeable— this is practically all that works in my demo, so don’t go thinking I’ve got a whole Shoes implementation for PowerShell.

A few options

A few options


"A bed of clams", "A coalition of cheetahs", "A gulp of swallows" | Button -margin 2 | Stack -margin 8 -background red | Wpf

I’m just trying to gauge the interest level — so if you’re interested, please comment below and let me know that you want it, what sorts of things you want it for (if you can think of any off the top of your head), and/or how involved you’d like to be. I’d love for someone to say: “Wow, that’s a great idea, I’m going to go finish it”, but anything short of that, right down to “I’d give you $5 to write it and give it away” is acceptable ;)

One final note: the Out-Wpf cmdlet that you see here does work in v1 and v2 and can even do this (click for the full picture):

Out-WPF without PoshConsole

Out-WPF without PoshConsole

I’ll release that later this week…

[new] PowerBoots Release

I’ve released a full script-based version of this. While it does everything you see above and more, it does not work in PowerShell 1. You can get an idea of how to use it by following the PowerBoots tutorial, and you can download PowerBoots, but for now it requires v2 CTP3. Let me hear from you if v1 support is important to ya.

WPF Window “Native” Behavior: Snap-To Screen Edges

There are many desirable behaviors for Windows applications that are just much harder to do than they should be with the tools that Microsoft has provided in the .Net Framework. In WPF, many of these behaviors are even harder to create than in Windows Forms because the necessary hooks take a bit more work to write (thanks to the fact that there’s no window handles, so dropping down to “Native” code is harder. Luckily, WPF Attached Properties give us a whole new way to reuse these behaviors once they’re written.

I’ve started working on a few classes I’m calling NativeBehaviors, because they rely on intercepting the native Window Message processing, and I’ve put together a simple framework to let me write them, which I thought I would share. The first one I wrote is a SnapToBehavior, which implements a feature that people seem to be constantly re-implementing in apps. Basically, it makes a window snap to the screen edge when it gets close (and prevents them from being moved off-screen). I’ve also written a Global HotkeysBehavior which lets you register Hotkeys that work whenever your app is running (even if another app is active) so you can create a Hotkey to hide your app and show it, or whatever.

In the rest of this article I’ll show you how to achieve this in WPF using my base NativeBehavior class, and how to use it on a Window. Since some of you won’t really care how it works, let’s start with:

How to make your WPF Windows snap to screen edges in 3 easy steps:

Step 1. Add a reference to the Huddled.Wpf.Interop library.
Step 2. Add my Xml namespace to your root Window element
Step 3. Paste three lines from below….


<Window x:Class="GlobalHotkeys.DemoWindow" x:Name="DemoWindow"
   Title="GlobalHotkeys" Height="300" Width="300"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:huddled="http://schemas.huddledmasses.org/wpf"
   >
<!-- You just add a reference to the library, add the "huddled" namespace, and paste: -->
    <huddled:Native.Behaviors>
        <huddled:SnapToBehavior SnapDistance="20" />
    </huddled:Native.Behaviors>
<!-- The rest of your window can be whatever you like. -->
    <Grid>
        <Label Content="Drag this window near the screen edges"/>
    </Grid>
</Window>
 

I should point out the “SnapDistance” property of the SnapToBehavior is actually a WPF “Thickness” which lets you specify the distance from the screen edge as a single number to use on all sides, or as a separate number for each side: Left, Top, Right, Bottom. And that’s pretty much all there is to know.

How to implement a NativeBehavior.

The implementation of the SnapToBehavior is actually ridiculously simple, given the NativeBehavior framework. I simply created a SnapToBehavior class which derives from NativeBehavior, and implemented the single mandatory method:


/// <summary>
/// Gets the MessageMappings for this behavior:
/// A single mapping of a handler for WM_WINDOWPOSCHANGING.
/// </summary>
/// <returns>An enumerable collection of MessageMapping objects.</returns>
public override IEnumerable<MessageMapping> GetHandlers()
{
   yield return new MessageMapping(
      NativeMethods.WindowMessage.WindowPositionChanging, // the message
      OnPreviewPositionChange); // the delegate which will handle that message
}
 

When my new behavior is added to the Behaviors collection, my handler will be registered, and whenever the WM_WINDOWPOSCHANGING message arrives, it will be called. Now I defined a DependencyProperty for the SnapDistance, so that you could set that in XAML. It’s extremely simple, and VisualStudio has a built-in snippet for dependency properties, but here’s the code:


public static readonly DependencyProperty SnapDistanceProperty =
   DependencyProperty.Register(
      "SnapDistance",           // The name of the property (must match)
      typeof(Thickness),        // The type of the values
      typeof(SnapToBehavior),   // The type this property shows up on
      new UIPropertyMetadata(new Thickness(20)) // The default value
   );

public Thickness SnapDistance
{
   get { return (Thickness)GetValue(SnapDistanceProperty); }
   set { SetValue(SnapDistanceProperty, value); }
}
 

Once I have that, the last piece of the puzzle is to actually handle the window position changing message (think of it as an event, if you’re not used to Win32 message-based programming).

The basics of handling WM_WINDOWPOSCHANGING is that you get a structure passed in which has the proposed position of the Window, (including it’s z-index related to other apps) and you can basically tweak that however you like. Obviously there are lots of possibilities for this single message: always-on-bottom windows, undraggable windows, etc., but in our case we’re just concerned about how close we are to the edge.

We use the SystemParameters class to get the VirtualScreenLeft, VirtualScreenTop, and VirtualScreenWidth and VirtualScreenHeight which define the rectangle we’ll use for snapping. In the case of non-rectangular arrangements of multiple monitors this isn’t quite sufficient, but for our example anything more would be a distraction. Then we just check to see if the proposed position is within the “SnapDistance” of any of the edges, and if so, we change the position to be against the edge. That’s really all there is to it.

If you look at the code example below you’ll see I have to “Marshal” the WindowPosition structure in and out of an IntPtr which is passed in the WindowMessage … that’s the downside of intercepting window messages that the framework doesn’t already translate for us, but in this particular case, it’s actually fairly trivial.


/// <summary>lParam for WindowPositionChanging
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct WindowPosition
{
   public IntPtr Handle;
   public IntPtr HandleInsertAfter;
   public int Left;
   public int Top;
   public int Width;
   public int Height;
   public WindowPositionFlags Flags;

   public int Right { get { return Left + Width; } }
   public int Bottom { get { return Top + Height; } }
}  

      private IntPtr OnPreviewPositionChange(IntPtr wParam, IntPtr lParam, ref bool handled)
      {
         bool updated = false;
         var windowPosition = (NativeMethods.WindowPosition)Marshal.PtrToStructure(lParam, typeof(NativeMethods.WindowPosition));

         if ((windowPosition.Flags & NativeMethods.WindowPositionFlags.NoMove) == 0)
         {
            // If we use the WPF SystemParameters, these should be "Logical" pixels
            Rect validArea = new Rect(SystemParameters.VirtualScreenLeft,
                                      SystemParameters.VirtualScreenTop,
                                      SystemParameters.VirtualScreenWidth,
                                      SystemParameters.VirtualScreenHeight);

            Rect snapToBorder = new Rect(SystemParameters.VirtualScreenLeft + SnapDistance.Left,
                                     SystemParameters.VirtualScreenTop + SnapDistance.Top,
                                     SystemParameters.VirtualScreenWidth - (SnapDistance.Left + SnapDistance.Right),
                                     SystemParameters.VirtualScreenHeight - (SnapDistance.Top + SnapDistance.Bottom));

            // Enforce left boundary
            if (windowPosition.Left < snapToBorder.Left)
            {
               windowPosition.Left = (int)validArea.Left;
               updated = true;
            }

            // Enforce top boundary
            if (windowPosition.Top < snapToBorder.Y)
            {
               windowPosition.Top = (int)validArea.Top;
               updated = true;
            }

            // Enforce right boundary
            if (windowPosition.Right > snapToBorder.Right)
            {
               windowPosition.Left = (int)(validArea.Right - windowPosition.Width);
               updated = true;
            }

            // Enforce bottom boundary
            if (windowPosition.Bottom > snapToBorder.Bottom)
            {
               windowPosition.Top = (int)(validArea.Bottom - windowPosition.Height);
               updated = true;
            }

         }
         if (updated)
         {
            Marshal.StructureToPtr(windowPosition, lParam, true);
         }

         return IntPtr.Zero;
      }
 

Download it, or get the source code

If you’d like, you can download the current Huddled Interop for WPF library right now, or you can check out the source from CodePlex SVN or just download the most recent commit (You are only interested in the “Huddled” project which is in the “trunk”, not the “trunk-3.5”). The source is licensed freely under the BSD or GPL v2 (and a few other licenses, see the top of the source code files).

Either way you’ll get not just the SnapToBehavior but also the global HotkeysBehavior, and the Native Behaviors framework which I’ll write more about later, but for now, in case you want to try to use it, here’s an example using both the SnapTo and HotkeysBehavior (you can find this in the GlobalHotkeys demo project, which includes some sample code for handling hotkey conflicts). Enjoy.


<Window x:Class="GlobalHotkeys.DemoWindow" x:Name="window"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:huddled="http://schemas.huddledmasses.org/wpf"
   Title="Demo Window!" Height="300" Width="200"
   >
    <huddled:Native.Behaviors>
        <huddled:SnapToBehavior SnapDistance="80,20,80,10" />
        <huddled:HotkeysBehavior>
            <KeyBinding Command="huddled:GlobalCommands.ActivateWindow" Key="K"  Modifiers="Win" />
            <KeyBinding Command="huddled:GlobalCommands.CloseWindow"    Key="F4" Modifiers="Win" />
            <KeyBinding Command="huddled:GlobalCommands.ToggleWindow"   Key="S"  Modifiers="Win" />
        </huddled:HotkeysBehavior>
    </huddled:Native.Behaviors>
    <Grid>
        <Label Content="Drag this window near the screen edges"/>
    </Grid>
</Window>
 

WPF From PowerShell – Select-Grid

After looking over the scripts I’ve pasted in the last few days it struck me that all of them load the UI from XAML — and for the most part, you can do pretty much whatever you need to do in WPF in pure PowerShell if you want to.

Select-Grid ScreenshotTo demonstrate this, I wrote a simple Out-Grid script. But then I got carried away, and wrote the script I’ve shown in this screenshot. :-D The resulting script not only illustrates how to code WPF in PowerShell without XAML, it also illustrates one of the few areas where you’re much better off loading from XAML than writing the plain code — and that’s a DataTemplate. It is possible to write them in code, but believe it or not, some of their features are accessible only from XAML.

[new] I’ve updated both the script and the screenshot to correct a bug I noticed last night after I posted this … so if you tried this and got a lot more columns than you had bargained for … here is the Select-Grid script again. [new] I updated it again just now to switch my Set-PsDebug statement for a Set-StrictMode statement, after reading Jeffrey Snover’s post about strict mode best practices.

I’m not going to paste the whole script in-line, but I thought I’d paste some of it here so that I could give a little explanation of what’s happening, in case you need a little help figuring it out…

Using modules …

Some of you may know that normally in a script like this we would put the “utility” functions inside the BEGIN block so-as to encapsulate them from your main runspace, and may be wondering why I didn’t in this case. It’s because the new CTP2 of PowerShell has this concept called a “module” ... which is somewhat like a script snapin — basically it allows you to have functions in the script which don’t end up in the main runspace, but which are still available to the other functions (or cmdlets, in this case) in the script.

I will write a separate post about how PowerShell Modules work, and what you can do with them … it’s too complicated to get into here. Suffice it to say that all I had to do to the script is add a line at the bottom: Export-ModuleMember Select-Grid and rename it to [new] Select-Grid.psm1 and put it in a specific location: Documents\WindowsPowerShell\Packages\Select-Grid\Select-Grid.psm1 — but of course, I couldn’t resist cleaning it up a bit as I was writing about it (if you grabbed it before v3.4, you should grab it again — look in the comment at the top).

Having done that, all you have to do is run Add-Module Select-Grid instead of dot-sourcing it, and then run it as before (see the screenshot).

Let’s talk about code bay-bee …

There’s a few things I wanted to point out in the module’s code, so lets get to that. Continue reading

WPF From PowerShell – Something Useful

After posting my last post, I started thinking that perhaps I shouldn’t really have started with something so splashy [rolleyes] . So I started thinking about what I could use as a proper example — not of what WPF can do, but of what you might want to use WPF for in PowerShell.

I came up with two really obvious ideas which I think are both good demonstrations of useful things to do from PowerShell, and are good examples of something that really just doesn’t work with WinForms.

User Input prompts

I’ll write more about this in future posts, but for now, take as an ultimate example the latest post from mow, The PowerShell Guy in which he rewrites his PowerShell WMI Explorer to be WPF based — it seems to not only run faster, but be based on less code (of course, that might just be because he’s gained experience since the first version).

Data-bound Graphs

A WPF databound bar graph dialog from PowerShellThere are dozens of ways you can do data-bound graphs in PowerShell — including 3d — but the simplest to demonstrate (and coincidentally the easiest for me to come up with a use-case for) is a plain bar graph. I’ve written a simple graph window in XAML, and created a script Out-BarGraph which lets you send data to it … but there are, as the Genie says, some caveats, provisos, addendums, and quid pro quos. ;) Continue reading

WPF From PowerShell – Updating Windows

In my last post I wrote about how you could make a WPF Splash screen window in PowerShell, but I stated that: “if the images are remote, the WPF window has to download them, and therefore won’t work” correctly. I had played with downloading images directly by setting the Source attribute of the image to the image URL, and hadn’t been able to find a way to get the threading to work well enough to actually download the image.

Well, I figured that out, so I thought I’d go ahead and share … basically, all you have to do is call Invoke() on the window’s dispatcher. The reason that works is that WPF handles events and “work” in general in the order it needs to be done, so since the most important thing is drawing the UI it will do that first, and since your UI is based on downloading the image, it will take care of that first.

This is PowerShell v2 CTP2 code…

All of this code is written to target the CTP2 release of PowerShell v2 — it will not work in PowerShell v1 or even in v2 CTP1 … and it may not work in later releases, although I expect it will. Also, as with any code which uses WPF from PowerShell, these code examples require you to launch PowerShell with the -STA option.

Having said that, lets just straight to a WPF example Continue reading