2004-11-28

get-withit

A long time ago, Microsoft made a bad decision. "Our users are never going to need to get accurate information about the internals of our operating system," they said. "Anyone who wants to get that kind of dirty will probably be a programmer and thus have no problem buying our compiler and learning our APIs."

And for a time, so it was.

It was during this period of time, roughly twenty-five years long, that UNIX perfected the shell. sh, bash, ksh, zsh, and tcsh all made it possible for the conscientious sysadmin to institute any changes on any system in the world that was running telnet. Right off the bat, DOS is running behind. Where is the networked power of a hundred systems at your fingertips? Nonexistent. Adding files? DOS eventually learned to redirect input with the '>' key. Removing files? Yes, it's easy for both DOS and UNIX. But what are you to do, for example, if you're in need of a simple loop? DOS cannot understand the concept of "for i = 0 to 10, print i". Moreover, the power of UNIX software to read from stdin and write to stdout made chaining strings of programs together easy. DOS had no such thing.

Eventually, Microsoft executives realized that a shiny, candy-like UI wouldn't mean much for a server that sits in a closet and gets the odd update from time to time courtesy of a disaffected admin in another state. Windows was losing ground in the server arena to UNIX and then Linux, both operating systems that didn't exactly look like the belle of the ball, but that could run for months on end and take direction by nothing more than ASCII over port 22. The best the company could do was tout their archaic CLI software as "backwards compatible."

To solve this problem, the panacea that will be Longhorn includes a thorough measure by Microsoft to revamp the command line and make it usable after all these decades. The Microsoft Shell, or MSH, is codenamed "Monad" and it combines a limited number of verbs with almost endless possibilities. Just as text-based adventure games could frustrate you endlessly with little more than options to "get" "put" "read" "throw" and "walk", so too does MSH provide the options to "get" "start" "stop" "new" and "output".

Show the list of processes on a system? get-process

Show the list of services on a system? get-service

Stop a service called "winvnc"? stop-service winvnc

Anything more complicated requires a little mojo, but that's OK. We're not compiling anything yet. Sysadmins hate compiling. Sysadmins hate having to write their own damn tools. (Writing new software means, by default, it doesn't come with documentation.)

Monad isn't 100 percent yet. Instead of writing text like in UNIX, Monad writes objects. As such, you get much more potential, but there are caveats. "get-service" returns an object with three parts: a service name, a display name, and a status. For example, you may have the service that displays as "Apache2 Web Server", but as services go it's just "Apache2", and can be "Running|Stopped|Starting|Stopping". You can "get-service -ServiceName Apache2". You can "get-service -DisplayName *Web*Server*". But darned if you can't "get-service -Status Running" or "get-service -Status Stopped".

In current beta releases of Monad, getting this info is tricky. The easy thing to do is bitch until the developers rewrite the "get-service" program (Monad programs are called "cmdlets") to include the -Status flag. If you learn enough MSH to be dangerous, you can figure it out like so:

MSH>get-service | where {$_.Status -eq "Running"}

What? Yes, that's Perl-esque syntax coming out of Redmond. 'bout fuckin' time.

Adam Barr works for Microsoft on the Monad team and he has begun reporting some neat tricks that demonstrate the flexibility of the software. Let's say you want to query Windows for a list of all managed code (i.e., .NET software) running on the system. Why, you'd have to write a program to do it for you! Not so fast.

In C#, the meat of the program looks like this:

PerformanceCounterCategory clr = new PerformanceCounterCategory(".NET
CLR Memory");

foreach(string process in clr.GetInstanceNames())
  if(process != "_Global_")
    Console.WriteLine(process);

Barr shows that with Monad, no compiler is necessary!

MSH>$pcc = new-object System.Diagnostics.PerformanceCounterCategory ".NET CLR Memory"
MSH>foreach ($p in $pcc.GetInstanceNames()) {if ($p -ne "_Global_") {$p}} 

If you haven't soaked your shorts by now, you're an inhuman monster. Get this little thing I cooked up over an episode of Venture Bros.

MSH>$sha1 = new-object System.Securty.Cryptography.SHA1Managed
MSH>$ascii = new-object System.Text.ASCIIEncoding
MSH>$sha1.ComputeHash($ascii.GetBytes("abc"))
169
153
62
54
71
6
129
106
186
62
37
113
120
80
194
108
156
208
216
157

Hashing in three lines of text. Not code, mind you. Text. We didn't compile anything here. Granted, most of that thirty minutes was spent surfing MSDN trying to remember the exact names of appropriate System.* classes and their associated properties. I have very little experience with Monad. What I know I've learned only from seeing brief examples written by others. And yet in half an hour, I'm well on my way to putting pieces of the .NET Framework together for my own nefarious purposes, starting with some basic pieces and combining them.

Is Monad perfect? Far from it. For starters, the "new-object" cmdlet isn't in the default location. To use new-object as easily as you'd use "get-process", you have to modify your "PATH" environment variable to contain both your Monad install directory, let's call it $MSHDIR, and $MSHDIR\Demo. After that, it's practically smooth sailing. Is Monad a step in the right direction? You bet.

No comments: