Get-WindowsFeature Wow64*

While trying to download and install some Windows updates on a machine running Windows 2008 R2 Server Core, I got the following message and the updates failed.

This program can’t start because mscoree.dll is missing from your computer.

The updates in question are listed below.

  1. KB2468871 – Update for Microsoft .NET Framework 4 on Windows XP, Windows Server 2003, Windows Vista, Windows 7, Windows Server 2008, Windows Server 2008 R2 for x64-based Systems

  2. KB2533523 – Update for Microsoft .NET Framework 4 on Windows XP, Windows Server 2003, Windows Vista, Windows 7, Windows Server 2008, Windows Server 2008 R2 for x64-based Systems

  3. KB2539636 – Security Update for Microsoft .NET Framework 4 on Windows XP, Windows Server 2003, Windows Vista, Windows 7, Windows Server 2008, Windows Server 2008 R2 for x64-based Systems

I couldn’t find anything on Google that was relevant so I started poking around in the Windows system directories, .NET Framework directories, and the registry to see what was going on.

The machine itself is running the x64 flavor of Windows, but apparently I did not install the WoW64 support for .NET and PowerShell.

A quick check at a PowerShell prompt confirmed this.

PS> Get-WindowsFeature Wow64*

Display Name                                            Name
------------                                            ----
[X] WoW64 Support                                       WoW64-Support
    [X] WoW64                                           WoW64-ServerCore
    [ ] WoW64 for .NET Framework 2.0 and Windows Pow... WoW64-NetFx2-Support
        [ ] WoW64 for .NET Framework 2.0                WoW64-NetFx2
        [ ] WoW64 for Windows PowerShell                WoW64-PowerShell
    [ ] WOW64 for .NET Framework 3.0 and 3.5            WoW64-NetFx3
    [ ] WoW64 for Print Services                        WoW64-PrintServices
    [ ] WoW64 for Input Method Editor                   WoW64-InputMethodEditor
    [ ] WoW64 for Subsystem for UNIX-based Applications WoW64-SUA

Once I installed those features (and restarted the server for good measure) all was well.

PS> Get-WindowsFeature Wow64-NetFx*,Wow64-PowerShell | Add-WindowsFeature
PS> Restart-Computer

Just putting this out there in the hopes that it helps someone else.

Sometimes it’s fun to do something that any self-respecting developer would cringe if they saw someone else do it. That’s kind of how I feel about abusing the capabilities of C# 4′s dynamic binding capabilities. Even though I stubbornly resisted the idea of adding dynamic binding to C#, I find myself playing around with it every now and then to make really ugly code look nicer.

For example, let’s consider the case where you’re matching a US telephone number (with optional extension) against a regular expression and separating the individual components into separate variables. In the US telecom industry it’s very common to deal with 10 digit numbers without having to worry about international phone formats, but the regular expression is still ugly. Unfortunately there’s nothing I can do about that, but this is about making code pretty, not making regular expressions pretty.

(?<npa>\d{3})-?(?<nxx>\d{3})\-?(?<line>\d{4})( x(?<ext>\d+))?

Let’s look at the implementation of such a task in PowerShell vs. C#.

Here is how the code would look in PowerShell. It’s elegance gets me sexually aroused.

if ('555-123-4567' -match $PhoneRegex) {
    $npa = $matches.npa
    $nxx = $matches.nxx
    $line = $matches.line
    $ext = $matches.ext
}

Here is how the equivalent code would look in C#.

var match = Regex.Match("555-123-4567", PhoneRegex);
if (match.Success) {
    string npa = match.Groups["npa"].Value;
    string nxx = match.Groups["nxx"].Value;
    string line = match.Groups["line"].Value;
    string ext = match.Groups["ext"].Success ?
                     match.Groups["ext"].Value :
                     null;
}

It’s not the end of the world, but it still feels like it could be so much more concise. Well with C# 4 I can create an object that derives from DynamicObject and wraps a System.Text.RegularExpressions.Match object to provide a much more “scripty” feel to the above code.

var match = DynamicRegex.Match("555-123-4567", PhoneRegex);
if (match) {
    string npa = match.npa;
    string nxx = match.nxx;
    string line = match.line;
    string ext = match.ext;
}

Note that a static method called DynamicRegex.Match is returning an object of type dynamic. The actual implementation is my wrapper class called DynamicMatch. It overrides the TryGetMember and TryConvert calls that make the above possible. It simply directs property and indexer calls into the Match.Groups collection and has some special logic for conversion to Boolean.

Anyhow, to get into detail about how C# does dynamic binding at runtime would take a series of posts in itself. I just thought this was a pretty interesting use of the dynamic binding that wasn’t yet another dynamic XML wrapper. Yeah I know it defeats the purpose of using a strongly-typed language like C# but oh well I thought it was interesting. Source is below.

public sealed class DynamicMatch : DynamicObject
{

    private readonly Regex _Regex;
    private readonly Match _Match;

    public DynamicMatch( Regex regex, Match match )
    {

        Contract.Requires( regex != null, "Regex cannot be null." );
        Contract.Requires( match != null, "Match cannot be null." );

        _Regex = regex;
        _Match = match;

    }

    public override IEnumerable GetDynamicMemberNames( )
    {
        // i honestly don't know where the hell this is used
        return _Regex.GetGroupNames( );
    }

    public override bool TryConvert( ConvertBinder binder, out object result )
    {

        // supports casting back to the original Match object
        if ( binder.Type == typeof( Match ) ) {
            result = _Match;
            return true;
        }

        // supports casting the match to its string representation
        // is the complete match result
        if ( binder.Type == typeof( String ) ) {
            if ( _Match.Success ) {
                result = _Match.Value;
                return true;
            }
            else {
                result = null;
                return true;
            }
        }

        // supports casting the match to a boolean indicating success
        if ( binder.Type == typeof( Boolean ) || binder.Type == typeof(Boolean?) ) {
            result = _Match.Success;
            return true;
        }

        return base.TryConvert( binder, out result );

    }

    public override bool TryGetIndex( GetIndexBinder binder, object[] indexes, out object result )
    {

        // supports 'match[x]' where x is a named capture group
        // or 'match[n]' where n is an implicit capture group index

        if ( indexes.Length == 1 ) {
            Group group = _Match.Groups[Convert.ToString( indexes[0] )];
            if ( group != null && group.Success ) {
                result = group.Value;
                return true;
            }
            else {
                result = null;
                return true;
            }
        }

        return base.TryGetIndex( binder, indexes, out result );

    }

    public override bool TryGetMember( GetMemberBinder binder, out object result )
    {

        // supports 'match.x' where x is a named capture group

        Group group = _Match.Groups[binder.Name];
        if ( group != null && group.Success ) {
            result = group.Value;
            return true;
        }
        else {
            result = null;
            return true;
        }

    }

    public override bool TryUnaryOperation( UnaryOperationBinder binder, out object result )
    {

        // supports 'if (match) {...}'
        if ( binder.Operation == ExpressionType.IsTrue ) {
            result = _Match.Success;
            return true;
        }

        // supports 'if (!match) {...}'
        if ( binder.Operation == ExpressionType.IsFalse || binder.Operation == ExpressionType.Not ) {
            result = !_Match.Success;
            return true;
        }

        return base.TryUnaryOperation( binder, out result );

    }

    public static bool operator ==( DynamicMatch x, bool y )
    {
        // supports 'if (match == true) {...}'
        return x._Match.Success == y;
    }

    public static bool operator !=( DynamicMatch x, bool y )
    {
        // supports 'if (match != true) {...}'
        return x._Match.Success != y;
    }

    public static bool operator ==( DynamicMatch x, string y )
    {
        // supports 'if (match == "foo") {...}'
        return x._Match.Value == y;
    }

    public static bool operator !=( DynamicMatch x, string y )
    {
        // supports 'if (match != "foo") {...}'
        return x._Match.Value != y;
    }

}

public static class DynamicRegex
{

    public static dynamic Match( string input, string pattern )
    {
        var regex = new Regex( pattern );
        var match = regex.Match( input );
        return new DynamicMatch( regex, match );
    }

}
[TestClass]
public class DynamicRegexTests
{

    [TestMethod]
    public void DynamicMatchConvertsToMatch( )
    {

        var dynamicMatch = DynamicRegex.Match( "Hello World", @"H[A-Za-z]+" );
        Match regularMatch = dynamicMatch;

        Assert.IsTrue( regularMatch.Success );
        Assert.AreEqual( "Hello", regularMatch.Value );

    }

    [TestMethod]
    public void SuccessfulMatchConvertsToTrue( )
    {

        var match = DynamicRegex.Match( "Hello World", @"H[A-Za-z]+" );

        // Convert To Boolean
        Assert.IsTrue( (bool)match, "Successful match should convert to true." );

        // Compare To Boolean
        if ( !match ) { Assert.Fail( "Successful match should convert to true." ); }
        if ( match == false ) { Assert.Fail( "Successful match should convert to true." ); }
        if ( match != true ) { Assert.Fail( "Successful match should convert to true." ); }

    }

    [TestMethod]
    public void UnsuccessfulMatchConvertsToFalse( )
    {

        var match = DynamicRegex.Match( "Hello World", @"^H[A-Za-z]+$" );

        // Convert To Boolean
        Assert.IsFalse( (bool)match, "Unsuccessful match should convert to false." );

        // Compare To Boolean
        if ( match ) { Assert.Fail( "Unsuccessful match should convert to false." ); }
        if ( match == true ) { Assert.Fail( "Unsuccessful match should convert to false." ); }
        if ( match != false ) { Assert.Fail( "Unsuccessful match should convert to false." ); }

    }

    [TestMethod]
    public void SuccessfulMatchConvertsToString( )
    {

        var match = DynamicRegex.Match( "Hello World", @"H[A-Za-z]+" );

        // Convert To String
        Assert.AreEqual( "Hello", (string)match, "Successful match should convert to Match.Value." );

        // Compare To String
        if ( match != "Hello" ) { Assert.Fail( "Successful match should convert to Match.Value." ); }

    }

    [TestMethod]
    public void UnsuccessfulMatchConvertsToNull( )
    {

        var match = DynamicRegex.Match( "Hello World", @"^H[A-Za-z]+$" );

        // Convert To String
        Assert.IsNull( (string)match, "Unsuccessful match should convert to null." );

        // The following will always fail - C# does the null check without converting
        // if (match != null) { Assert.Fail("..."); }

    }

    [TestMethod]
    public void SuccessfulCapturesAccessedAsProperties( )
    {

        var match = DynamicRegex.Match( "123-456-7890", @"(?\d{3})-?(?\d{3})-?(\d{4})" );

        Assert.AreEqual( "123", match.npa, "Capture group npa could not be accessed by name." );
        Assert.AreEqual( "456", match.nxx, "Capture group nxx could not be accessed by name." );

    }

    [TestMethod]
    public void SuccessfulCapturesAccessedAsIndexer( )
    {

        var match = DynamicRegex.Match( "123-456-7890", @"(?\d{3})-?(?\d{3})-?(\d{4})" );

        Assert.AreEqual( "123", match["npa"], "Capture group npa could not be accessed by name." );
        Assert.AreEqual( "456", match["nxx"], "Capture group nxx could not be accessed by name." );
        Assert.AreEqual( "7890", match[1], "Unnamed capture group could not be accessed by number." );
        Assert.AreEqual( "123-456-7890", match[0], "Capture group 0 should return entire match." );

    }

    [TestMethod]
    public void UnsuccessfulMatchReturnsPropertiesAsNull( )
    {

        // Must match 123-456-7890
        // Last 4 digits will cause unsuccessful match
        var match = DynamicRegex.Match( "123-456-XXXX", @"(?\d{3})-?(?\d{3})-?(\d{4})" );

        Assert.IsNull( match.npa, "Unsuccessful match must return all properties as null." );
        Assert.IsNull( match["npa"], "Unsuccessful match must return all properties as null." );
        Assert.IsNull( match["1"], "Unsuccessful match must return all properties as null." );
        Assert.IsNull( match["0"], "Unsuccessful match must return all properties as null." );

    }

    [TestMethod]
    public void SuccessfulMatchReturnsOptionalGroupAsNull( )
    {

        // Must match at least 123-456-
        // Last 4 digits are optional
        var match = DynamicRegex.Match( "123-456-XXXX", @"(?\d{3})-?(?\d{3})-?(\d{4})?" );

        Assert.AreEqual( "123", match["npa"], "Successful match should return captured groups as string." );
        Assert.AreEqual( "456", match["nxx"], "Successful match should return captured groups as string." );
        Assert.AreEqual( "123-456-", match[0], "Successful match should return entire match as string." );

        Assert.IsNull( match[1], "Successful match should return missing optional groups as null." );

    }

}

This confused me for a minute. But once I realized what was going on I felt like a dolt.

$Query = $UriBuilder.Query

if ($Query.Length > 1) {
    $Query = $Query.Substring(1) + '&'
}

$UriBuilder.Query = $Query + $KeyValuePair
Access to the path 'C:\Windows\system32\1' is denied.
At C:\Blah\Blah.psm1:366 char:32
+             if ($Query.Length > <<<<  1) {
    + CategoryInfo          : OpenError: (:) [], UnauthorizedAccessException
    + FullyQualifiedErrorId : FileOpenFailure

I find it very frustrating sometimes to get something to build in Blend. Like many developers, I have a "Me.dll" that contains a lot of commonly used classes, custom controls, etc. As you might expect, this DLL often takes dependencies on other DLL’s that must also then be referenced.

In Blend, this can be a pain in the butt because the Silverlight assemblies are scattered into 3 main locations:

  • %ProgramFiles%\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0
  • %ProgramFiles%\Microsoft SDKs\Silverlight\v4.0\Libraries\Client
  • %ProgramFiles%\Microsoft SDKs\Silverlight\v4.0\Toolkit\Apr10\Bin

It gets to be pretty frustrating pointing blend to these various paths to find System.ServiceModel.dll or something.

You can make this a lot easier without copying all the DLL’s by using symbolic links in Windows Vista/7/2008.

To create the symbolic links, open a PowerShell prompt as an administrator. (Make sure you have PowerShell Community Extensions installed, but who doesn’t?) Then paste or type the following script.

Set-Location C:\Temp\Refs

$SearchArgs = @{
    ErrorAction = 'SilentlyContinue'
    Include = @("System.*.dll", "Microsoft.*.dll")
    Exclude = @("*.resources.dll", "*.design.dll")
    Path = @(
        "$($Env:ProgramFiles)\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0\*"
        "$($Env:ProgramFiles)\Microsoft SDKs\Silverlight\v4.0\Libraries\Client\*"
        "$($Env:ProgramFiles)\Microsoft SDKs\Silverlight\v4.0\Toolkit\Apr10\Bin\*"
        "$($Env:ProgramFiles) (x86)\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0\*"
        "$($Env:ProgramFiles) (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\Client\*"
        "$($Env:ProgramFiles) (x86)\Microsoft SDKs\Silverlight\v4.0\Toolkit\Apr10\Bin\*"
    )
}

Get-ChildItem @SearchArgs | %{

    $LinkPath = $_.Name
    $TargetPath = $_.FullName
    
    Write-Host "$LinkPath -> $TargetPath"
    New-Symlink -Path:$LinkPath -Target:$TargetPath | Out-Null

}

PowerShell Team has announced FxCop rules for cmdlet authors.

List of rules

  • AcceptForceParameterWhenCallingShouldContinue
  • AllCmdletsShouldAcceptPipelineInput
  • CallShouldProcessOnlyIfDeclaringSupport
  • DefineCmdletInTheCorrectNamespace
  • DoNotAccessPipelineParametersOutsideProcessRecord
  • DoNotCallCertainHostMethods
  • DoNotUseConsoleApi
  • FollowCmdletClassNamingConvention
  • OverrideProcessRecordIfAcceptingPipelineInput
  • ParameterShouldHaveConsistentTypePerNoun
  • UseCredentialAttributeForPSCredentialParameter
  • UseOnlyApprovedCharactersInVerbsAndNouns
  • UseOnlyStandardVerbs
  • UsePascalCasingInVerbsAndNouns
  • UseRecommendedParameterTypes
  • UseSingularNouns
  • UseSingularParameterNames
  • UseSwitchParameterInsteadOfBoolean

I wanted to post this last night but I did not have an internet connection.

The best part about being a developer is that when software drives you nuts, many times you can do something about it that mere mortals cannot. That’s the case with TweetDeck. I love it but I am sick of having to move windows around to keep it in view. I have a wide screen so I wanted to dedicate a band of space to it, much like how the Vista sidebar worked. When I maximize other windows, they should not obscure the taskbar or TweetDeck.

The title of this post is a little misleading for two reasons…

  1. PowerShell really has nothing to do with it. It’s just the method I chose to kick off this little hack. The actual implementation is all Win32 API via C#.
  2. TweetDeck is just the application that happened to drive me to write this. You could just as easily change one line to dock Windows Live Messenger instead.

So the code is shown below. It’s nearly all in C# but PowerShell will dynamically compile it when you run the script. No exe’s needed. Just run the script and…

  • TweetDeck’s caption and window border will be removed
  • It will be docked against the right hand side of your primary screen (hard coded, sorry)
  • Maximized windows will adjust to the new workspace size

A couple caveats though.

  • Resize TweetDeck to the size you want it before doing this
  • Once docked, there’s currently no way to undock. So just close it from the taskbar.
  • TweetDeck is buggy in "single column view" as many UI elements are cut off. It’s best to turn off "use narrow columns" first.

Code is below. Enjoy.

$DockProcessName = 'tweetdeck'

Add-Type -Language CSharpVersion3 @"
using System;
using System.Runtime.InteropServices;

public static class WindowDockUtil
{

    #region Public Methods

    /// <summary>
    /// Docks the window to the right side of the screen.
    /// </summary>
    /// <param name="hWnd">The window handle.</param>
    public static void Dock( IntPtr hWnd )
    {

        if ( hWnd == IntPtr.Zero ) {
            return;
        }   // if

        ulong windowLong = GetWindowLong( hWnd, GWL_STYLE );
        windowLong &= ~WS_BORDER;
        windowLong &= ~WS_CAPTION;
        windowLong &= ~WS_THICKFRAME;

        SetWindowLong( hWnd, GWL_STYLE, windowLong );

        var abd = new APPBARDATA( );
        abd.cbSize = Marshal.SizeOf( abd );
        abd.hWnd = hWnd;
        abd.uCallbackMessage = RegisterWindowMessage( "AppBarMessage" );

        // Create AppBar
        SHAppBarMessage( ABMsg.ABM_NEW, ref abd );

        // Get the Window's size
        RECT wc = new RECT( );
        if ( !GetWindowRect( hWnd, ref wc ) ) {
            return;
        }   // if

        int screenWidth = GetSystemMetrics( SM_CXSCREEN );
        int screenHeight = GetSystemMetrics( SM_CYSCREEN );
        int borderWidth = GetSystemMetrics( SM_CXSIZEFRAME );

        // Set the app bar to dock to the right
        abd.uEdge = ABEdge.ABE_RIGHT;
        abd.rc.top = 0;
        abd.rc.bottom = screenHeight;
        abd.rc.right = screenWidth;
        abd.rc.left = abd.rc.right - ( wc.right - wc.left ) + ( borderWidth * 2 );

        // Set AppBar Size
        SHAppBarMessage( ABMsg.ABM_SETPOS, ref abd );

        // Move Window to New Position
        MoveWindow( abd.hWnd, abd.rc.left, abd.rc.top, abd.rc.right - abd.rc.left, abd.rc.bottom - abd.rc.top, true );

    }

    ///// <summary>
    ///// Removes the window from the side of the screen.
    ///// </summary>
    ///// <param name="hWnd">The handle.</param>
    //public static void UndockWindow( IntPtr hWnd )
    //{

    //    if ( hWnd == IntPtr.Zero ) {
    //        return;
    //    }   // if

    //    var abd = new APPBARDATA( );
    //    abd.cbSize = Marshal.SizeOf( abd );
    //    abd.hWnd = hWnd;

    //    // Remove AppBar
    //    SHAppBarMessage( ABMsg.ABM_REMOVE, ref abd );

    //    // How should I store state between Dock and Undock?
    //    ulong windowLong = GetWindowLong( hWnd, GWL_STYLE );
    //    windowLong |= WS_BORDER;
    //    windowLong |= WS_CAPTION;

    //    SetWindowLong( hWnd, GWL_STYLE, windowLong );

    //}

    #endregion

    #region Interop

    #region AppBar

    [StructLayout( LayoutKind.Sequential )]
    private struct APPBARDATA
    {
        public int cbSize;
        public IntPtr hWnd;
        public int uCallbackMessage;
        public ABEdge uEdge;
        public RECT rc;
        public IntPtr lParam;
    }

    private enum ABMsg : int
    {
        ABM_NEW = 0,
        ABM_REMOVE = 1,
        ABM_QUERYPOS = 2,
        ABM_SETPOS = 3,
        ABM_GETSTATE = 4,
        ABM_GETTASKBARPOS = 5,
        ABM_ACTIVATE = 6,
        ABM_GETAUTOHIDEBAR = 7,
        ABM_SETAUTOHIDEBAR = 8,
        ABM_WINDOWPOSCHANGED = 9,
        ABM_SETSTATE = 10
    }

    private enum ABNotify : int
    {
        ABN_STATECHANGE = 0,
        ABN_POSCHANGED = 1,
        ABN_FULLSCREENAPP = 2,
        ABN_WINDOWARRANGE = 3
    }

    private enum ABEdge : int
    {
        ABE_LEFT = 0,
        ABE_TOP = 1,
        ABE_RIGHT = 2,
        ABE_BOTTOM = 3
    }

    [DllImport( "Shell32", CallingConvention = CallingConvention.StdCall )]
    private static extern uint SHAppBarMessage( ABMsg dwMessage, ref APPBARDATA pData );

    #endregion

    #region Window Management

    [DllImport( "User32" )]
    private static extern int RegisterWindowMessage( string msg );

    [DllImport( "User32" )]
    private static extern IntPtr FindWindow( string lpClassName, string lpWindowName );

    [DllImport( "User32" )]
    private static extern bool MoveWindow( IntPtr hWnd, int x, int y, int cx, int cy, bool repaint );

    [DllImport( "User32" )]
    private static extern bool GetWindowRect( IntPtr hWnd, ref RECT rect );

    [StructLayout( LayoutKind.Sequential )]
    private struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }

    [DllImport( "User32" )]
    private static extern int GetSystemMetrics( int Index );

    private const int SM_CXSCREEN = 0;
    private const int SM_CYSCREEN = 1;
    private const int SM_CXSIZEFRAME = 32;

    #endregion

    #region GetWindowLong/SetWindowLong

    [DllImport( "User32", EntryPoint = "SetWindowLongPtr" )]
    private static extern ulong SetWindowLong64( IntPtr hWnd, int nIndex, ulong dwNewLong );

    [DllImport( "User32", EntryPoint = "GetWindowLongPtr" )]
    private static extern ulong GetWindowLong64( IntPtr hWnd, int nIndex );

    [DllImport( "User32", EntryPoint = "SetWindowLong" )]
    private static extern uint SetWindowLong32( IntPtr hWnd, int nIndex, uint dwNewLong );

    [DllImport( "User32", EntryPoint = "SetWindowLong" )]
    private static extern uint GetWindowLong32( IntPtr hWnd, int nIndex );

    private const int GWL_WNDPROC =    ( -4 );
    private const int GWL_HINSTANCE =  ( -6 );
    private const int GWL_HWNDPARENT = ( -8 );
    private const int GWL_STYLE =      ( -16 );
    private const int GWL_EXSTYLE =    ( -20 );
    private const int GWL_USERDATA =   ( -21 );
    private const int GWL_ID =         ( -12 );

    private static ulong GetWindowLong( IntPtr hWnd, int nIndex )
    {
        if ( IntPtr.Size == 4 ) {
            return GetWindowLong32( hWnd, nIndex );
        }   // if
        else if ( IntPtr.Size == 8 ) {
            return GetWindowLong64( hWnd, nIndex );
        }   // else if
        else {
            throw new NotSupportedException( "Unsupported platform." );
        }   // else
    }

    private static ulong SetWindowLong( IntPtr hWnd, int nIndex, ulong dwNewLong )
    {
        if ( IntPtr.Size == 4 ) {
            return SetWindowLong32( hWnd, nIndex, (uint)dwNewLong );
        }   // if
        else if ( IntPtr.Size == 8 ) {
            return SetWindowLong64( hWnd, nIndex, dwNewLong );
        }   // else if
        else {
            throw new NotSupportedException( "Unsupported platform." );
        }   // else
    }

    #endregion

    #region Window Styles

    private const ulong WS_OVERLAPPED = 0x0000;
    private const ulong WS_POPUP = 0x80000000;
    private const ulong WS_CHILD = 0x40000000;
    private const ulong WS_MINIMIZE = 0x20000000;
    private const ulong WS_VISIBLE = 0x10000000;
    private const ulong WS_DISABLED = 0x8000000;
    private const ulong WS_CLIPSIBLINGS = 0x4000000;
    private const ulong WS_CLIPCHILDREN = 0x2000000;
    private const ulong WS_MAXIMIZE = 0x1000000;
    private const ulong WS_BORDER = 0x800000;
    private const ulong WS_DLGFRAME = 0x400000;
    private const ulong WS_VSCROLL = 0x200000;
    private const ulong WS_HSCROLL = 0x100000;
    private const ulong WS_SYSMENU = 0x80000;
    private const ulong WS_THICKFRAME = 0x40000;
    private const ulong WS_GROUP = 0x20000;
    private const ulong WS_TABSTOP = 0x10000;
    private const ulong WS_MINIMIZEBOX = 0x20000;
    private const ulong WS_MAXIMIZEBOX = 0x10000;
    private const ulong WS_CAPTION = WS_BORDER | WS_DLGFRAME;
    private const ulong WS_TILED = WS_OVERLAPPED;
    private const ulong WS_ICONIC = WS_MINIMIZE;
    private const ulong WS_SIZEBOX = WS_THICKFRAME;
    private const ulong WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW;
    private const ulong WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
    private const ulong WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU;
    private const ulong WS_CHILDWINDOW = WS_CHILD;

    #endregion

    #endregion

}   // class
"@

if ($DockProcess = Get-Process $DockProcessName -ea 0) {
   [WindowDockUtil]::Dock($DockProcess.MainWindowHandle)
}
else {
    Write-Warning "Cannot find the $DockProcessName process."
}

image

If you’re a system administrator (or like many developers), chances are you use PowerShell a lot and have the PowerShell console or PowerShell ISE on your Windows 7 taskbar. On Windows Vista and on Windows Server 2008 prior to R2 I was annoyed by having both ISE and console on the quick launch bar or pinned to the start menu.

In Windows 7 here’s a neat tip. Pin the PowerShell console to the taskbar and not the PowerShell ISE. When you right click on the icon, you get a handy jump list which includes not only "Run As Administrator" but also "Open PowerShell ISE". All in the space of a single tile.

Windows PowerShell Jump List

Feb 272010

Download LINQ.psm1

I’m gonna start off by saying the module I’m posting about does not follow the PowerShell naming guidelines. In fact, not only does it use non-standard verb names, but the "verb" part of all the function names aren’t even verbs. I hate breaking the rules like this but the Verb-Noun naming couldn’t really group these functions together the way I wanted and naming them correctly would have been very difficult. So feel free to rename as needed.

A while back I posted about a ConvertTo-Dictionary PowerShell function. This handy little function would take an input object from the pipeline and populate a Hashtable using a key selector and optional value selector. Very similar to how LINQ’s ToDictionary method works. It uses ScriptBlocks in the same way C# uses lambda expressions. There is one very nice trick in the module. A function called Invoke-ScriptBlock that shows how to inject a $_ (dollar underbar) variable into a ScriptBlock’s scope when invoking it. This is very handy for simulating lambdas in PowerShell functions.

Anyhow, over time I added several more LINQ-like functions and then I just went all out and tried to implement all the most popular LINQ methods. I managed to get a good deal done although there is still some documentation work needed. Some of the functions may seem redundant because they have nearly the same functionality as existing PowerShell cmdlets. In these cases it’s usually because I thought it could be more LINQ-like. For example I have Linq-Min because it’s simpler and more flexible than Measure-Object. But I didn’t duplicate Where-Object because there was no point.

The following code example shows how you might use these functions. Not all of them are shown. Notice the lamba-like syntax for predicates, selectors, etc. They also make use of the convenient $_ (dollar underbar) variable to represent the "current item" which makes them more consistent with Where-Object, Foreach-Object, etc.

Import-Module LINQ

function Assert-AreEqual($Expected, $Actual) {
    if (@(Compare-Object $Expected $Actual -SyncWindow 0).Length) {
        $OFS = ','
        Write-Error "Assert-AreEqual Failed: Expected=($Expected), Actual=($Actual)"
    }
}

# All
Assert-AreEqual -Expected ($true)   -Actual (1..5 | Linq-All { $_ -gt 0 })
Assert-AreEqual -Expected ($false)  -Actual (1..5 | Linq-All { $_ -gt 6 })
Assert-AreEqual -Expected ($true)   -Actual (@()  | Linq-All { $_ -gt 6 })

# Any
Assert-AreEqual -Expected ($true)   -Actual (1..5 | Linq-Any)
Assert-AreEqual -Expected ($false)  -Actual (@()  | Linq-Any)
Assert-AreEqual -Expected ($true)   -Actual (1..5 | Linq-Any { $_ -eq 3 })
Assert-AreEqual -Expected ($false)  -Actual (1..5 | Linq-Any { $_ -eq 6 })

# First
Assert-AreEqual -Expected @(1)      -Actual @(1..5 | Linq-First)
Assert-AreEqual -Expected @(2)      -Actual @(1..5 | Linq-First { $_ -gt 1 })
Assert-AreEqual -Expected @()       -Actual @(1..5 | Linq-First { $_ -gt 5 })

# Last
Assert-AreEqual -Expected @(5)      -Actual @(1..5 | Linq-Last)
Assert-AreEqual -Expected @(4)      -Actual @(1..5 | Linq-Last { $_ -lt 5 })
Assert-AreEqual -Expected @()       -Actual @(1..5 | Linq-Last { $_ -lt 1 })

# Single
Assert-AreEqual -Expected @(2)      -Actual @(1..5 | Linq-Single { $_ -eq 2 })
Assert-AreEqual -Expected @()       -Actual @(1..5 | Linq-Single { $_ -gt 5 })

# Skip
Assert-AreEqual -Expected @(1..5)   -Actual @(1..5 | Linq-Skip 0)
Assert-AreEqual -Expected @(3..5)   -Actual @(1..5 | Linq-Skip 2)
Assert-AreEqual -Expected @()       -Actual @(1..5 | Linq-Skip 5)
Assert-AreEqual -Expected @()       -Actual @(1..5 | Linq-Skip 6)

# SkipWhile
Assert-AreEqual -Expected @(2..5)   -Actual @(1..5 | Linq-SkipWhile { $_ -eq 1})
Assert-AreEqual -Expected @(3..5)   -Actual @(1..5 | Linq-SkipWhile { $_ -lt 3})
Assert-AreEqual -Expected @(1..5)   -Actual @(1..5 | Linq-SkipWhile { $false })
Assert-AreEqual -Expected @()       -Actual @(1..5 | Linq-SkipWhile { $true })

# Take
Assert-AreEqual -Expected @(1..5)   -Actual @(1..5 | Linq-Take 5)
Assert-AreEqual -Expected @(1..5)   -Actual @(1..5 | Linq-Take 6)
Assert-AreEqual -Expected @(1..5)   -Actual @(1..6 | Linq-Take 5)
Assert-AreEqual -Expected @(1..3)   -Actual @(1..5 | Linq-Take 3)
Assert-AreEqual -Expected @()       -Actual @(1..5 | Linq-Take 0)

# TakeWhile
Assert-AreEqual -Expected @(1..2)   -Actual @(1..5 | Linq-TakeWhile { $_ -lt 3})
Assert-AreEqual -Expected @()       -Actual @(1..5 | Linq-TakeWhile { $_ -eq 2})
Assert-AreEqual -Expected @()       -Actual @(1..5 | Linq-TakeWhile { $false })
Assert-AreEqual -Expected @(1..5)   -Actual @(1..5 | Linq-TakeWhile { $true })

# Distinct
Assert-AreEqual -Expected @(1..5)   -Actual @(1..5 | Linq-Distinct)
Assert-AreEqual -Expected @(1..5)   -Actual @(1,2,3,4,5,1,2,3,4,5 | Linq-Distinct)
Assert-AreEqual -Expected @()       -Actual @(Linq-Distinct)

# Repeat
Assert-AreEqual -Expected @(1..5)   -Actual @(1..5 | Linq-Repeat 1)
Assert-AreEqual -Expected @()       -Actual @(1..5 | Linq-Repeat 0)
Assert-AreEqual -Expected @(1,1,2,2,3,3,4,4,5,5) -Actual @(1..5 | Linq-Repeat 2)

# Except
Assert-AreEqual -Expected @(1,3,5)  -Actual @(1..5 | Linq-Except (2,4))
Assert-AreEqual -Expected @(1..5)   -Actual @(1..5 | Linq-Except 6)
Assert-AreEqual -Expected @()       -Actual @(1..5 | Linq-Except (1..5))

# Intersect
Assert-AreEqual -Expected @(2,4)    -Actual @(1..5 | Linq-Intersect (2,4))
Assert-AreEqual -Expected @()       -Actual @(1..5 | Linq-Intersect 6)
Assert-AreEqual -Expected @(1..5)   -Actual @(1..5 | Linq-Intersect (1..5))

# IndexOf
Assert-AreEqual -Expected (0)       -Actual (1..5 | Linq-IndexOf { $_ -eq 1 })
Assert-AreEqual -Expected (3)       -Actual (1..5 | Linq-IndexOf { $_ -eq 4 })
Assert-AreEqual -Expected (-1)      -Actual (1..5 | Linq-IndexOf { $_ -eq 6 })
Assert-AreEqual -Expected (2)       -Actual (1,2,3,3,3 | Linq-IndexOf { $_ -eq 3 })

# Count
Assert-AreEqual -Expected (5)       -Actual (1..5 | Linq-Count)
Assert-AreEqual -Expected (1)       -Actual (1..5 | Linq-Count { $_ -eq 3 })
Assert-AreEqual -Expected (0)       -Actual (1..5 | Linq-Count { $_ -eq 6 })

# Average, Min, Max
Assert-AreEqual -Expected (3)       -Actual (1..5 | Linq-Average)
Assert-AreEqual -Expected (15)      -Actual (1..5 | Linq-Sum)
Assert-AreEqual -Expected (5)       -Actual (1..5 | Linq-Max)
Assert-AreEqual -Expected (1)       -Actual (1..5 | Linq-Min)

The complete function listing is shown below. I’ve been selfishly keeping this module to myself for about a year now and I felt it was time to post it. Let me know what you think!

Name Synopsis
Linq-All Determines whether all elements of a sequence satisfy a condition.
Linq-Any Determines whether any element of a sequence satisfies a condition.
Linq-Average Returns the average of values in a sequence.
Linq-Count Returns a number that represents how many elements in the specified sequence satisfy a condition.
Linq-Distinct Returns unique items from the pipeline input.
Linq-Except Excludes from the pipeline input the items which also appear in a second set.
Linq-Expand Drills into an input object based on one or more property names to simplify access to data inside nested structures.
Linq-First Returns the first element in a sequence that satisfies a specified condition.
Linq-IndexOf Returns the zero-based position of the first element in a sequence that meets the specified criteria.
Linq-Intersect Includes from the pipeline input only the items that exist in a second set.
Linq-Last Returns the last element of a sequence that satisfies a specified condition.
Linq-Max Returns the maximum value in a sequence.
Linq-Min Returns the minimum value in a sequence.
Linq-Repeat Repeats the items from the pipeline a specified number of times.
Linq-Select Selects a property, property set, or ScriptBlock projection of the input.
Linq-SelectMany Similar to Linq-Select but always ensures the output is wrapped in an array.
Linq-Single Returns a single item that satisfies a specified condition, and throws an exception if more than one or zero such element exists.
Linq-Skip Skips the specified number of items from the input and then returns the remaining items.
Linq-SkipWhile Skips items from the input as long as a specified condition is true and then returns the remaining items.
Linq-Sum Returns the sum of values in a sequence.
Linq-Take Returns a specified number of contiguous items from the start of the input pipeline.
Linq-TakeWhile Returns items from the input as long as a specified condition is true.
Linq-ToDictionary Creates a Hashtable from a sequence according to specified key selector and value selector functions.
Linq-ToSet Creates a HashSet containing only unique items from a sequence.
Where-Like Returns items from a sequence whose selected values match one or more wildcard patterns.
Where-Match Returns items from a sequence whose selected values match one or more regular expression patterns.

Download LINQ.psm1

It’s a simple one, but useful. And it can clean up some of your ugly scripts that have a lot of redundant paths embedded in strings.

# Reduced for the sake of the example
# The full advanced function is included at the end.
function Use-Location($Path, $Body) {

    Push-Location $Path

    try { &$Body }
    finally { Pop-Location }

}

Usage of the function couldn’t be simpler and uses a C#-style scope syntax.

Use-Location "C:\Temp" {

    mkdir textfiles
    dir *.txt | move textfiles

    mkdir images
    dir *.jpg,*.png | move images

}

Obviously you could just as well use Push-Location and Pop-Location in a try/catch yourself but why? This way enforces clean scoping and ensures you don’t forget the call to pop.

##############################################################################
#.SYNOPSIS
# Executes a ScriptBlock within the context of the specified working directory.
#
#.DESCRIPTION
# This function sets the current location to the specified Path and executes a
# ScriptBlock. All relative paths in the ScriptBlock will be based on the new
# current directory. When the ScriptBlock exits, the old current directory
# will be restored.
#
#.PARAMETER Path
# The working directory to use for the duration of the ScriptBlock.
#
#.PARAMETER ScriptBlock
# The code to execute within the context of the new current directory.
#
#.PARAMETER Create
# Creates the directory if it does not exist.
#
#.EXAMPLE
# Use-Location "C:\Temp" {
#
#    mkdir textfiles
#    dir *.txt | move textfiles
#
#    mkdir images
#    dir *.jpg,*.png | move images
#
# }
#
#.LINK 
# Push-Location
# Pop-Location
##############################################################################
function Use-Location {

    [CmdletBinding()]
    param(
        
        [Alias('PSPath')]
        [Alias('LiteralPath')]
        [Parameter(Position=1, Mandatory=$true)]
        [String]$Path,
        
        [Parameter(Position=2, Mandatory=$true)]
        [ScriptBlock]$ScriptBlock,
        
        [Parameter()]
        [Switch]$Create
        
    )

    $ErrorActionPreference = 'Stop'

    # Create if necessary
    if ($Create) {
        $Exists = Test-Path -LiteralPath $Path -PathType Container
        if (-not $Exists) {
            New-Item $Path -ItemType Directory | Out-Null
        }
    }

    Push-Location $Path -StackName 'Use-Location'

    try { &$ScriptBlock }
    finally { Pop-Location -StackName 'Use-Location' }

}

I’m pretty excited about this new module. Originally I threw something very crappy together just to get a rough idea of which commands I was calling. But then I started polishing it up and polishing it up and I arrived at something I just had to post.

Dir . -i *.ps1,*.psm1 -r | Get-Dependency -Unresolved | Out-GridView

The above line of code will scan each ps1 and psm1 file in the current directory as well as subdirectories and send the information about any unresolved dependencies to the Out-GridView cmdlet for display. Another nice feature is that if you run the command from within PowerShell ISE and you don’t give it a path, it will check whichever file is currently open in the editor.

NAME
    Get-Dependency

SYNOPSIS
    Calculates the dependencies of a script file, block of PowerShell code, or
    an open PowerShell ISE document.

SYNTAX
    Get-Dependency [-Unresolved] [-Force] [-Verbose] [-Debug] [-ErrorAction []]
                   [-WarningAction []] [-ErrorVariable []]
                   [-WarningVariable []] [-OutVariable []] [-OutBuffer []]
                   []

    Get-Dependency [-Path] [] [-Unresolved] [-Force] [-Verbose] [-Debug]
                   [-ErrorAction []] [-WarningAction []]
                   [-ErrorVariable []] [-WarningVariable []] [-OutVariable []]
                   [-OutBuffer []] []

    Get-Dependency -LiteralPath [] [-Unresolved] [-Force] [-Verbose] [-Debug]
                   [-ErrorAction []] [-WarningAction
                   []] [-ErrorVariable []] [-WarningVariable []]
                   [-OutVariable []] [-OutBuffer []] []

DETAILED DESCRIPTION
    Before deploying a script or module, it is important to ensure that any
    external dependencies are resolved otherwise code that runs fine on your
    machine will bomb on someone else's. This function will scan a single
    level of dependencies from the specified script and by default returns
    any dependency that is 1) not a part of the built-in PowerShell command
    and variable configuration and 2) not defined in the script being analyzed.
    You can override this behavior and include these dependencies with the
    Force parameter.

PARAMETERS
    -Path
        Specifies the path to an item. Wildcards are permitted.

        Required?                    false
        Position?                    named
        Default value
        Accept pipeline input?       false
        Accept wildcard characters?  

    -LiteralPath
        Specifies the path to an item. Unlike Path, the value of LiteralPath is
        used exactly as it is typed. No characters are interpreted as wildcards.
        If the path includes escape characters, enclose it in single quotation marks.
        Single quotation marks tell Windows PowerShell not to interpret any
        characters as escape sequences.

        Required?                    false
        Position?                    named
        Default value
        Accept pipeline input?       false
        Accept wildcard characters?  

    -Unresolved
        When specified, only unresolved dependencies are returned.

        Required?                    false
        Position?                    named
        Default value
        Accept pipeline input?       false
        Accept wildcard characters?  

    -Force
        When specified, all dependencies are included, even if they are known to
        be defined locally or in the default PowerShell configuration.

        Required?                    false
        Position?                    named
        Default value
        Accept pipeline input?       false
        Accept wildcard characters?  

        This cmdlet supports the common parameters: -Verbose, -Debug,
        -ErrorAction, -ErrorVariable, -WarningAction, -WarningVariable,
        -OutBuffer and -OutVariable. For more information, type,
        &amp;quot;get-help about_commonparameters&amp;quot;.

RETURN TYPE
    An array of PSObjects containing information about the external dependencies.

    -------------------------- EXAMPLE 1 --------------------------

    Get-Dependency | Out-GridView

RELATED LINKS
    Get-PSToken

imageI will post back with some more information later, but the basic idea is that this uses the new PSParser class to parse a PowerShell script into tokens. It then analyzes the tokens to figure out some basic facts about the script:

  • Which global variables are being referenced
  • Which modules does the script import that are not currently imported
  • Which commands are being referenced by the script?
    • Which commands are functions defined in the current script?
    • Which command are aliases and which commands do they resolve to?
    • Which commands are built-in functions/cmdlets/aliases/etc?

Once all of the above has been determined, it’s presented in a format that is easy to read.

I added mine to the custom menu of PowerShell ISE. :)

Dependency Module