Windows PowerShell DSC Resource Kit Wave 5–xWindowsOptionalFeature

When PowerShell 4.0 shipped, the major new feature was DSC or Desired State Configuration – a very convenient and declarative way to manage the configuration of your Windows servers.  However as a developer whose IT department doesn’t really allow me anywhere near their servers, I’m interested in DSC from a purely Windows client SKU perspective.  I stand up new test machines and VMs all the time with various Windows client SKUs.  I was disappointed to find that the initial set of DSC resources for Windows clients was missing the equivalent of the WindowsFeature resource that is supported for Windows Server SKU configuration.  Without this resource, you can’t use DSC to configure your machine with features such as IIS, IIS-ASPNET45, etc. 

Well that all changes with the DSC Resource Kit Wave 5.  This version has an updated xPSDesiredStateConfiguration resource that includes xWindowsOptionalFeature.  Add to that the xOneGet resource for installing utilities like dotPeek, SysInternals, and Fiddler and now DSC is going further towards getting my test machines and VMs setup quickly for doing development work.

Here’s basically what I’m doing to configure, well at least start configure, my test machines and VMs.  I’m sure over time I will continue to add to this DSC configuration to automate more of the steps I’m currently doing manually.

First step is to go and grab the DSC Resource Kit Wave 5.  Second, you will need the July “experimental” version of PowerShell (WMF 5) to use these new resources.  You don’t want to install this on a production machine.  This would be a great excuse to spin up a Hyper-V image with Windows 8.1 on it to experiment with this.   To install the July version, go to the Requirements section of the website above and click on either the x64 MSU or x86 MSU links – depending on the bit-width of your OS installation.  Third, download the the resource kit ZIP file via the link at the top of the web page.  After you have downloaded it, be sure to “unblock” the zip before extracting any files from it.  Now fire up PowerShell “as administrator” and execute the following PowerShell commands. Note: the installation of xOneGet will prompt you to install nuget.exe.  Answer “y” to this to allow nuget to be installed. The new Install-Module cmdlets require nuget.

C:\> Set-ExecutionPolicy RemoteSigned –Force
C:\> Enable-PSRemoting –Force
C:\> Install-Module xOneGet
 

Now open the DSC Resource Kit Wave 5 zip you downloaded and unblocked.  Copy the directory xPSDesiredStateConfiguration to your C:\Program Files\WindowsPowerShell\Modules directory.  There should be two directories in there now: xOneGet and xPSDesiredStateConfiguration.

Now open up the 5.0 PowerShell_ISE and copy this script and save it as $home\DevPCConfig.ps1. The first section installs all the Windows optional features required to do ASP.NET development on .NET 4.5.  There is a section in there to modify settings of the console host for both x64 and x86 PowerShell.  Remove that or tweak to your satisfaction.  The last section installs some tools that I use all the time: dotPeek, Fiddler4 and PerfView.  To see what packages are available run:

C:\> Find-Package
 

Now, back to preparing to apply this configuration.  From the admin PowerShell console, cd to the same directory where you saved DevPCConfig.ps1 and execute the script.  Note: this doesn’t actually apply the configuration.  We will do that in the next step.

C:\Users\Keith> .\DevPCConfig.ps1
 

This will create the MOF file that drives the DSC engine.  You can see the file in .\DevPCConfig\localhost.mof.  Now let’s tell the DSC engine to apply this configuration to the machine by executing this command:

C:\Users\Keith> Start-DscConfiguration .\DevPCConfig –Wait –Verbose 
 

This will generate a lot of output but is informative the first time or two.  After that you can drop the –Verbose parameter. 

In an ideal world, I could use the community resource cPSGet to allow me to install my two favorite PowerShell modules but alas, bugs are preventing that from happening.  So as a manual step, I execute the following two commands to install these modules:

C:\> Install-Module Pscx –Scope CurrentUser 
C:\> Install-Module PSReadline –Scope CurrentUser
 

There is still plenty more I find myself tweaking on every new machine I set up.  Over time I’ll be able to “declare” more of that configuration in DevPCConfig.ps1 especially as more Microsoft and community resources become available.

Posted in PowerShell, PowerShell 5.0 | 2 Comments

How to Determine if a Process is 32 or 64 Bit

Your first instinct might be to check [IntPtr]::Size but that only works for the current PowerShell process.  In this scenario you want to check any arbitrary process running on the machine.  There doesn’t seem to be a .NET API for this but fortunately we can easily PInvoke to a Win32 API to get the functionality we need.  Here’s the script that does this:

Add-Type -MemberDefinition @' [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool IsWow64Process( [In] System.IntPtr hProcess, [Out, MarshalAs(UnmanagedType.Bool)] out bool wow64Process); '@ -Name NativeMethods -Namespace Kernel32 Get-Process -Id $id | Foreach { $is32Bit=[int]0 if ([Kernel32.NativeMethods]::IsWow64Process($_.Handle, [ref]$is32Bit)) { "$($_.Name) $($_.Id) is $(if ($is32Bit) {'32-bit'} else {'64-bit'})" } else {"IsWow64Process call failed"} }

Posted in PowerShell | Leave a comment

PowerShell 4.0 Now Available

You can get PowerShell 4.0 for down level operating systems now via the WMF 4.0 download.  NOTE: Be sure you have .NET 4.5 installed *before* you install WMF 4.0.  For various reasons, the WMF 4.0 installer doesn’t alert you to this pre-requisite which can cause PowerShell to indicate it is still version 3.0 after installation i.e. you didn’t get a good install.

Posted in PowerShell, PowerShell 4.0 | 5 Comments

PowerShell Tidbit: Capturing a ScreenShot with PowerShell

This is a crude approach but works for capturing the main window of an application who’s process object you can find –typically via Get-Process.  If you run this script from PowerShell.exe or PowerShell_ISE.exe you will capture a screen shot of the host application’s main window which will get saved to your $home folder as screenshot.bmp.


$src = @'
using System;
using System.Runtime.InteropServices;

namespace PInvoke
{
public static class NativeMethods
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
}

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
}
'
@


Add-Type -TypeDefinition $src
Add-Type -AssemblyName System.Drawing

# Get a process object from which we will get the main window bounds
$iseProc = Get-Process -id $pid

$bmpScreenCap = $g = $null
try {
$rect = new-object PInvoke.RECT
if ([PInvoke.NativeMethods]::GetWindowRect($iseProc.MainWindowHandle, [ref]$rect))
{
$width = $rect.Right - $rect.Left + 1
$height = $rect.Bottom - $rect.Top + 1
$bmpScreenCap = new-object System.Drawing.Bitmap $width,$height
$g = [System.Drawing.Graphics]::FromImage($bmpScreenCap)
$g.CopyFromScreen($rect.Left, $rect.Top, 0, 0, $bmpScreenCap.Size,
[System.Drawing.CopyPixelOperation]::SourceCopy)
$bmpScreenCap.Save("$home\screenshot.bmp")
}
}
finally {
if ($bmpScreenCap) { $bmpScreenCap.Dispose() }
if ($g) { $g.Dispose() }
}

Have fun.

Posted in PowerShell, PowerShell 3.0, PowerShell 4.0 | 3 Comments

PSReadLine: A Better Line Editing Experience for the PowerShell Console

When Windows PowerShell 3.0 shipped, the team created an extensibility mechanism to allow a third party to “take over” the line editing experience.  That hook is a function called PSConsoleHostReadline that PowerShell will call – if it exists – to read a line of text from the user.  The simplicity of this interface belies the potential complexity of what it needs to do.  Users expect to be able to do more than just type a command, mistake free and press enter.  No, they want editing features like cursor left/right, backspace, delete, kill to end of line, multiline editing, etc. 

Fortunately for the community, one of the PowerShell team members – Jason Shirk – has implemented a very nice replacement line editor that uses this hook. It is called PSReadLine and you can get it here on GitHub.  There are no releases on GitHub at this point in time but you can just download the PSReadline.zip file from the master branch, be sure to unblock the ZIP file and then extract the module your Modules folder. Alternatively, if you have PsGet you can install PSReadLine using its Install-Module command e.g:

C:\PS> Install-Module PSReadLine

After installation, import the PSReadLine module to have it take over your command line editing experience. 

C:\PS> Import-Module PSReadLine

Note: the PSReadLine module only works for the PowerShell.exe console. It does not work for the PowerShell ISE console pane. 

You have now imported PSReadLine, so what does it get you?  If you use the default Windows (cmd) mode you get the standard CMD line editing  features:

  • Home/End navigation
  • Up/DownArrow history navigation
  • Right/Left Arrow single char navigation
  • Ctrl+Right/LeftArrow word navigation
  • Ctrl+Home to delete from cursor to beginning of line
  • Ctrl+End to delete from cursor to end of line
  • Esc to revert line
  • Delete to delete a char
  • Backspace to delete char before the cursor

You also get tab & shift+tab completion that you expect from the PowerShell console.  So what else does it buy you? Well syntax color for one thing:

image

And how about indicating when you have a syntax error:

image

Notice the red “>” in my prompt?  That is telling me I have a syntax error in this command.  If you look at the end, I’m missing a closing “}”.  Type  in that closing “}” and the red goes away.

How about being able to paste into the console using Ctrl+V like you can in ISE. PSReadLine has got that covered.  Ever deleted something accidentally in the line and wanted to get it back?  Try the handy Ctrl+Z/Ctrl+Y shortcuts for Undo and Redo.  Yes!!  This line editor has a full blown undo/redo stack. 

Ever had a command go over a single line?  You know multiline commands are a pain in the PowerShell console because:

  1. You can’t go to a previous line to edit it. You have to completely start over. Pressing the UpArrow just cycles through history on the current line which means your current line edits get blown away.
  2. You can’t use Up/DownArrow history recall to recall the *whole* multiline command. You can only recall one line at a time which makes multiline commands a major PITA to recall & edit in the console.

Check this out with PSReadLine.  It doesn’t “look” much different than standard PowerShell e.g.:

image

But you can use the Right/LeftArrow keys to move the cursor between different lines and then edit those lines.  You still don’t want to use the Up/DownArrow keys for line navigation as these keys are still bound to history recall.  However, when you do need to recall this multiline command using the UpArrow, what you get is exactly what you see above.  All three lines included in that one history entry *AND* you can press LeftArrow to move up to the previous lines to edit them.

Last up is my favorite feature called PossibleCompletions.  If I type “Get-Process –<Ctrl+Space>” this is what PSReadLine gives me:

image

Seriously!  Is that cool or what!?  PSReadLine shows you all the parameters in this case.  If you had typed part of the parameter name, it would have shown all parameters that would have matched what you typed.  By the way, this also works for parameter argument values e.g.:

image

It also works for static and instance type members e.g.:

image

There are more capabilities in PSReadLine but most of those come with Emacs mode.  However you can create your own keybindings to do whatever command PSReadLine offers.  If you want to use the Emacs mode, execute this command:

image 

If you like this new command line editing experience as much as I do you will want this in your profile script.  This is my section of profile script for PSReadLine:

if ($host.Name -eq 'ConsoleHost') {
Import-Module PSReadline

Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadlineKeyHandler –Key DownArrow -Function HistorySearchForward
}

Note that I’ve defined a few more keybindings that allow me to use the UpArrow and DownArrow keys to not only navigate backward and forward in history on an empty line but navigate based on a match as well.   That is, when I type the beginning of some command line, the UpArrow and DownArrow keys search history backward or forward respectively for command lines that match what’s been typed.

If you spend a lot of time at the PowerShell console you owe it yourself to give this module a try.  And if you run into issues, remember these are still somewhat early bits, the project developer has been responsive to fixing bugs.  You can post/view issues here on GitHub.  For more info on PSReadLine, check out the about_PSReadline topic after you have installed the module.

Update 12-29-2013:

Jason has delivered some new PSReadLine presents for the holidays.  Version 1.0.0.6 supports some notable new features.  My favorite of which is that you can select text using just the keyboard.  As if you were in Notepad or VS, press Shift+Right/LeftArrow to select one character at a time or use Ctrl+Shift+Right/LeftArrow to select whole words at a time. 

Once you have the desired text selected you can press Ctrl+x to cut or Ctrl+Shift+c to copy.  Before careful with the copy keyboard shortcut because if you forgot to press Shift, the resulting Ctrl+c will abort the current command line and you can’t get it back – not even with Ctrl+z (undo).  I wonder if perhaps the default copy shortcut should be something like Shift+Insert – old school – to avoid any potential mishaps with Ctrl+c?

You might find the following custom keyhandler handy for selecting the whole command line with Ctrl+A:

Set-PSReadlineKeyHandler -Chord Ctrl+A `
-BriefDescription SelectEntireCommandLine `
-Description "Selects the entire command line" `
-ScriptBlock {
param($key, $arg)

[PSConsoleUtilities.PSConsoleReadLine]::BeginningOfLine($key, $arg)

$line = $null
$cursor = $null
[PSConsoleUtilities.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)

while ($cursor -lt $line.Length) {
[PSConsoleUtilities.PSConsoleReadLine]::SelectForwardChar($key, $arg)
[PSConsoleUtilities.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
}
}

Another feature that has been added is CharacterSearch and CharacterSearchBackward. By default these are mapped to F3 and Shift+F3.  Say you are at the beginning of the command line with multiple pipeline stages.  Press F3, then press Shift+\ to specify the “|” character.  PSReadLine will advance the cursor to the next “|” character.  This is cool.  But the next two custom keyhandlers pretty nifty:

Set-PSReadlineKeyHandler -Chord Ctrl+\ `
-BriefDescription SearchForwardPipeChar `
-Description "Searches forward for the next pipeline character" `
-ScriptBlock {
param($key, $arg)
[PSConsoleUtilities.PSConsoleReadLine]::CharacterSearch($key, '|')
}
Set-PSReadlineKeyHandler -Chord Ctrl+Shift+\ `
-BriefDescription SearchBackwardPipeChar `
-Description "Searches backward for the next pipeline character" `
-ScriptBlock {
param($key, $arg)
[PSConsoleUtilities.PSConsoleReadLine]::CharacterSearchBackward($key, '|')
}

These two keyhandlers will allow you to navigate around your command line by jumping forward and backward between pipeline stages.  They use CharacterSearch and CharacterSearchBackward to move around the command line by searching for “|” characters.  So Ctrl+\ moves forward to the next “|” character and Ctrl+Shift+\ moves backwards to the previous “|” character.

And finally, some help for quickly finding out what keyhandlers are mapped to which keyboard shortcuts, just press Ctrl+Alt+? which on a US keyboard is really Ctrl+Alt+Shift+/ and you get this information:

Key                  Function                 Description
---                  --------                 -----------
Enter                AcceptLine               Accept the input or move to the...
Shift+Enter          AddLine                  Move the cursor to the next lin...
Escape               RevertLine               Equivalent to undo all edits (c...
LeftArrow            BackwardChar             Move the cursor back one charac...
RightArrow           ForwardChar              Move the cursor forward one cha...
Ctrl+LeftArrow       BackwardWord             Move the cursor to the beginnin...
Ctrl+RightArrow      NextWord                 Move the cursor forward to the ...
Shift+LeftArrow      SelectBackwardChar       Adjust the current selection to...
Shift+RightArrow     SelectForwardChar        Adjust the current selection to...
Ctrl+Shift+LeftArrow SelectBackwardWord       Adjust the current selection to...
Ctrl+Shift+RightArrow SelectNextWord          Adjust the current selection to...
UpArrow              PreviousHistory          Replace the input with the prev...
DownArrow            NextHistory              Replace the input with the next...
Home                 BeginningOfLine          Move the cursor to the beginnin...
End                  EndOfLine                Move the cursor to the end of t...
Delete               DeleteChar               Delete the character under the ...
Backspace            BackwardDeleteChar       Delete the charcter before the ...
Ctrl+Spacebar        PossibleCompletions      Display the possible completion...
Tab                  TabCompleteNext          Complete the input using the ne...
Shift+Tab            TabCompletePrevious      Complete the input using the pr...
Ctrl+v               Paste                    Paste text from the system clip...
Ctrl+c               CancelLine               Abort editing the current line ...
Ctrl+C               Copy                     Copy selected region to the sys...
Ctrl+l               ClearScreen              Clear the screen and redraw the...
Ctrl+x               Cut                      Delete selected region placing ...
Ctrl+y               Redo                     Redo an undo
Ctrl+z               Undo                     Undo a previous edit
Ctrl+Backspace       BackwardKillWord         Move the text from the start of...
Ctrl+Delete          KillWord                 Move the text from the cursor t...
Ctrl+End             ForwardDeleteLine        Delete text from the cursor to ...
Ctrl+Home            BackwardDeleteLine       Delete text from the cursor to ...
Ctrl+]               GotoBrace                Go to matching brace
Ctrl+Alt+?           ShowKeyBindings          Show all key bindings
Alt+?                WhatIsKey                Show the key binding for the ne...
F3                   CharacterSearch          Read a character and move the c...
Shift+F3             CharacterSearchBackward  Read a character and move the c...

 

And to find out what a specify keyboard shortcut is mapped to, pres Alt+? (or on a US keyboard Alt+Shift+/) and then the keyboard shortcut.  For example, if I press Alt+Shift+/ and then Ctrl+Shift+LeftArrow I get this information:

Ctrl+Shift+LeftArrow: SelectBackwardWord - Adjust the current selection to inclu
de the previous word

Major kudos to Jason and this awesome module.  It is funny how quickly you just get used to it and then when you’re on someone else’s PC without this module – well – you convince them pretty quickly that they need PSReadLine.  Smile 

In closing, I’ll leave you with two more custom keyhandlers I have in my profile. The first creates a pair of single or double quotes and puts the cursor in the middle:

Set-PSReadlineKeyHandler -Chord "Ctrl+'","Ctrl+Shift+'" `
-BriefDescription SmartInsertQuote `
-Description "Insert paired quotes if not already on a quote" `
-ScriptBlock {
param($key, $arg)

$line = $null
$cursor = $null
[PSConsoleUtilities.PSConsoleReadline]::GetBufferState([ref]$line, [ref]$cursor)

$keyChar = $key.KeyChar
if ($key.Key -eq 'Oem7') {
if ($key.Modifiers -eq 'Control') {
$keyChar = "`'"
}
elseif ($key.Modifiers -eq 'Shift','Control') {
$keyChar = '"'
}
}

if ($line[$cursor] -eq $keyChar) {
# Just move the cursor
[PSConsoleUtilities.PSConsoleReadLine]::SetCursorPosition($cursor + 1)
}
else {
# Insert matching quotes, move cursor to be in between the quotes
[PSConsoleUtilities.PSConsoleReadLine]::Insert("$keyChar" * 2)
[PSConsoleUtilities.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
[PSConsoleUtilities.PSConsoleReadLine]::SetCursorPosition($cursor - 1)
}
}

The second handler was inspired by mjolinor’s Clip-ToArray ISE add-on.  It is a more basic version of his function which I call – PasteAsHereString.  It is indeed handy and could be easily modified to do all that the original Clip-ToArray function does.

Set-PSReadlineKeyHandler -Chord Ctrl+Shift+v `
   -BriefDescription PasteAsHereString `
   -Description "Pastes the clipboard text as a here string" `
   -ScriptBlock {
param($key, $arg)

Add-Type -AssemblyName System.Windows.Forms
$str = [windows.forms.clipboard]::GetText() -replace '(?m)[`n\s*]+$',''
[PSConsoleUtilities.PSConsoleReadline]::Insert("@'`n${str}`n'@")
}

Posted in PowerShell, PowerShell 3.0, PowerShell 4.0 | 7 Comments

PowerShell Community Extensions 3.1.0 Released

We released a minor update to PSCX that adds support for Windows PowerShell 4.0 in addition to its support for PowerShell 3.0.  You can grab the updated bits for your shiny new Windows 8.1 or WMF 4.0 install here.

Posted in PowerShell, PowerShell 3.0, PowerShell 4.0 | 3 Comments

Calling WinRT Async Methods from Windows PowerShell

Windows 8 introduced a new API for modern applications called the Windows Runtime API or WinRT API for short.  One of the hallmarks of this API is that it eschews synchronous methods for any method that could take longer than 50 milliseconds to complete.  The reason is that many developers still do most of their logic on the UI thread.  Microsoft wants to make sure that end users have a good experience using modern apps.  These apps should not appear to hang – even momentarily.  The experience should be, as Microsoft has said on many occasions, “fast and fluid”.  By ensuring that long running calls can’t be called synchronously, the chances improve that end users will have a better experience with modern apps.

In order to make this work well for developers, C# and VB have been modified to handle these async methods in a “simple to program” way via new async and await keywords.  Unfortunately, for us PowerShell scripters, we haven’t gotten such keywords added to PowerShell.  And considering PowerShell’s main focus, Windows administration, we may never see language features to make it easier to call these async WinRT APIs. 

Fortunately, where there is a will there is a way.  We can create a C# wrapper class to make it possible for PowerShell script to call these async methods in a synchronous manner.  If you think about it, PowerShell doesn’t usually present GUI that needs to remain responsive.  In many cases, our scripts run unattended where 50 millisecond or longer calls is really no big deal. 

Here is an example of a WinRT API you might like to use from PowerShell:

C:\PS> [Windows.Storage.StorageFile,Windows.Storage,ContentType=WindowsRuntime] > $null
C:\PS> $path = "$home\Pictures\foo.png" C:\PS> $asyncOp = [Windows.Storage.StorageFile]::GetFileFromPathAsync($path)
C:\PS> $asyncOp System.__ComObject

 

First up, loading WinRT types in PowerShell takes a bit of a funky syntax as shown in the first line above.  You first specify the WinRT type – Windows.Storage.StorageFile that you want to load, next I believe you specify the name of the winmd file – Windows.Storage (located in $env:WinDir\System32\WinMetadata).  The third component – ContentType – specifies that the winmetadata refers to a WindowsRuntime type.  Documentation on this format is somewhere between sparse and non-existent as far as I can tell.

Once we have the WinRT type loaded, we try to call one of its static type members – “GetFileFromPathAsync()”.  This method returns an object that implements IAsyncOperation<StorageFile>.  To PowerShell it looks like a System.__ComObject which means you don’t get any type info on the object and as far as I can tell, it isn’t usable.  The interface should implement a Completed property and a GetResults() method, neither of which are recognized as a member of the PowerShell object $asyncOp. 

Whenever we run into these sort of problems with PowerShell, the solution is typically to create a “PowerShell friendly” C# wrapper around the functionality.  In this case, I have created a C# wrapper around objects that implement IAsyncOperation.  The code is pretty simple.  You can view it here on GitHub.

With this compiled into a .NET assembly called PoshWinRT.dll, I can then use the API like so:

C:\PS> [Windows.Storage.StorageFile,Windows.Storage,ContentType=WindowsRuntime] > $null
C:\PS> $path = "$home\Pictures\foo.png"
C:\PS> $asyncOp = [Windows.Storage.StorageFile]::GetFileFromPathAsync($path)
C:\PS> Add-Type -Path ~\PoshWinRT.dll
C:\PS> $typeName = 'PoshWinRT.AsyncOperationWrapper[Windows.Storage.StorageFile]'
C:\PS> $wrapper = new-object $typeName -Arg $asyncOp
C:\PS> $file = $wrapper.AwaitResult()
C:\PS> $file


ContentType      : image/png
FileType         : .png
Attributes       : Archive
DateCreated      : 8/9/2013 10:34:22 AM -06:00
Name             : foo.png
Path             : C:\Users\Keith\Pictures\foo.png
DisplayName      : foo
DisplayType      : PNG File
FolderRelativeId : 6AE4A0202B76C225\foo.png
Properties       : Windows.Storage.FileProperties.StorageItemContentProperties
Provider         : Windows.Storage.StorageProvider
IsAvailable      : True

 

Note that we have to Add-Type our helper DLL PoshWinRT.dll.  Then after we get back the $asyncOp object from the GetFileFromPathAsync() call, we create an instance of the PoshWinRT.AsyncOperationWrapper class.  This class is a generic class so we need to pass in the type parameter – Windows.Storage.StorageFile in this case.  This, by the way, means that you can use this wrapper class with other WinRT async APIs that return types other than StorageFile.  Just pass the appropriate type in as the type parameter when constructing the AsyncOperationWrapper class.  The last thing we do when creating the wrapper is to pass in the object that we got back from the async API call.  The one that is of type IAsyncOperation<T>.  The wrapper will wrap that object.

Once we have the wrapper class created, we simply call its AwaitResult() method.  That will return whatever type you specified when creating the wrapper class.  In this case, it will return a Windows.Storage.StorageFile object as you can see when we dump the result in $file to screen.

There are a number of challenges using WinRT from PowerShell.  Fortunately we can overcome async APIs that return IAsyncOperation with a C# wrapper class like the one introduced in this post.  One of the next challenges to overcome is how to subscribe to WinRT events which is not supported by PowerShell V3 out-of-the-box.

Posted in PowerShell, PowerShell 3.0, WinRT | 4 Comments