Ministry of Innovation / Business of Technology

A guided tour of the Microsoft Command Shell


How to leverage the .NET API in MSH

Integration of the .NET API imbues MSH with a tremendous amount of power. The integration and availability of code libraries for virtually every common task is part of what initially fueled the popularity of the Python programming language. Python developers use the phrase "batteries included" to describe the usability implied by excellent library accessibility. Support for .NET libraries and components ensures that MSH also comes with batteries included.

MSH has a number of unique features that make it easy for users to leverage .NET technology at the command line. Type casting is an easy way to transform a simple core type into a .NET instance or another core type. To cast an instance into another type, simply place the name of the desired type in brackets right in front of the instance. You can change a string into a number with an int cast:

msh> [int]"5" + 5

Let's try a more sophisticated example. Let's say we want to parse a string that contains XML. If we turn that string into an XML document instance, we can use the object-oriented features of MSH to transform and manipulate individual XML elements. We can use the type casting mechanism to transform our string into an XML document instance:

msh>   $x = [xml]"<zoo><animal kind='monkey'><name>Albert</name></animal></zoo>"
msh> $x.zoo.animal
kind                                    name
----                                    ----
monkey                                  Albert

We can also create new instances with the new-object Cmdlet. The System.Net.WebClient class has a DownloadString method that will download data from a remote web site. We can use the new-object Cmdlet to create a new instance of Net.WebClient and then we can use that instance to download the Ars Technica RSS feed and display the contents at the console:

msh> (new-object Net.WebClient).DownloadString("")

The XML in text form is obviously not particularly useful. We can use the XML type casting mechanism to parse the RSS feed data into an XML document instance that we can manipulate with standard MSH commands:

msh> [xml](new-object Net.WebClient).DownloadString("")
xml                        xml-stylesheet             rss
                           {, }                       rss

Now let's try to extract the title and author elements from every item in the tag:

msh> ([xml](new-object Net.WebClient).DownloadString("")
) | select title, author
title                                   author
-----                                   ------
Sneak preview of Windows XP SP3 surf... (Jeremy Reimer)
Microsoft's FAT patents rejected (Hannibal)
AOL buys Weblogs Inc.          (Ken "Caesar"...
Modding PlayStation 2 ok Down Under (Eric Bangeman)
Microsoft stepping up corporate secu... (Ken "Caesar"...

You can instantiate classes from literally any .NET library. Not all libraries are accessible within MSH by default, but you can import .NET assemblies from external DLL files. You can even import third-party assemblies compiled from any CIL compatible language, so it possible to instantiate IronPython classes inside the MSH shell, for instance.

With further experimentation, I figured out how to import the System.Windows.Forms library from the global assembly cache (GAC). With Winforms at my disposal, I can construct native graphical user interfaces from the command line or in MSH scripts!

The trick here is to use the LoadFile function from the Reflection.Assembly module to load the System.Windows.Forms library. Since Reflection.Assembly can't be instantiated, the new-object Cmdlet won't work in this situation. In MSH, it is possible to call a function directly from a module:

msh> [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

Now that we have our Winforms DLL loaded into memory, let's try to instantiate a window and a button:

msh> $window = new-object Windows.Forms.Form
$window.text = "This is a Windows form!"
$button = new-object Windows.Forms.Button
$button.text = "Click me!"

Windows GUI objects created via MSH

Linux users often use the Tk library to produce simple graphical utilities. With MSH and the .NET Winforms API, Windows users can also produce graphical interfaces within scripts or from the command line. Unfortunately, it is not yet possible to bind MSH commands to GUI events, so users can't produce complete graphical utilities. In a Microsft TechNet chat transcript, Microsoft developer Jeffrey Snover says that they have constructed an experimental set of Cmdlets that provide user interface construction capabilities inspired by Tk, but they don't plan to include those Cmdlets in the first major release.

Expand full story

You must to comment.