- A Quick Tour of Monad<p class="MsoNormal" style="margin: 0in 0in 0pt;">You’ve got Monad, and now you’re wondering how the heck it works.<span style=""> </span>You’re wondering this because you haven’t read the first few sections of the GettingStarted.rtf that comes with it.<span style=""> </span>If you have it, go read it now, it answers all the basic questions. </p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">(short pause while you read that)<o:p> </o:p></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">Okay welcome back.<span style=""> </span>So now you know that Monad is a fresh approach to providing a command line interface to an operating system.<span style=""> </span>Cmdlets (a Cmdlet is a small unit of shell functionality, but you knew that) produce and consume objects, and the command-line interface lets you do things like get objects, select properties from objects, and pipe objects around.</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">If you didn’t read it, maybe because you don’t have Monad yet, I’ll try to quickly mention the points that it covers, but not in nearly as much detail.</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">For example:</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;"><span style=""> </span>dir</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">A simple command.<span style=""> </span>But it’s actually an alias for:</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;"><span style=""> </span>get-childitem</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">What get-childitem does is enumerates the children of the current directory, producing an array for each item found.<span style=""> </span>The object it produces is a System.Info.FileInfo object.<o:p> </o:p></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">The FileInfo object part of the.NET framework’s base class library.<span style=""> </span>This is very powerful because it means that instead of some custom object created by the get-childitem command, you’ve got a real object that other functions in the framework understand, and that’s well documented (<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemIOFileInfoClassTopic.asp">here</a>) and understood by developers.</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">I said that get-childitem produces an array.<span style=""> </span>It’s actually a System.Array.<span style=""> </span>Again, using a class library object instead of defining a special kind of shell array.</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">So get-childitem produced an array and gave it back to the shell.<span style=""> </span>The default thing that the shell does with an object, when you haven’t piped it to another command or redirected it, is sends it to the format-table or format-list Cmdlet, which formats and writes objects to the console.<span style=""> </span>Format-list is used if one object is returned; format-table is used if many.</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">When you do a Dir, the first few lines look like this:</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;"><span style="font-size: 10pt; font-family: 'Courier New';">MSH> dir</span><span style="font-size: 10pt; font-family: 'Courier New';"><span style=""><br> </span>Directory: FileSystem::D:\MSH<br></span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;"><span style="font-size: 10pt; font-family: 'Courier New';">Mode<span style=""> </span>LastWriteTime<span style=""> </span>Length Name<br></span><span style="font-size: 10pt; font-family: 'Courier New';">----<span style=""> </span>-------------<span style=""> </span>------ ----<br></span><span style="font-size: 10pt; font-family: 'Courier New';">-a---<span style=""> </span>Jun 06 17:25<span style=""> </span>2086 SomeFile.txt<br></span><span style="font-size: 10pt; font-family: 'Courier New';">-a---<span style=""> </span>Jun 06 17:25<span style=""> </span>3049 OtherFile.txt</span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">There are some differences here from what you’d expect if this was simply a dump of FileInfo objects:</p>
<ul style="margin-top: 0in;" type="disc">
<li class="MsoNormal" style="margin: 0in 0in 0pt;">There’s a header, the “Directory:” line.
</li><li class="MsoNormal" style="margin: 0in 0in 0pt;">Not every property of the FileInfo object is printed, just the Mode, LastWriteTime, Length, and Name.</li></ul>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">How does the shell format the array of FileInfo objects that get-childitem returned?</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">The question gets even more interesting if you try writing out the objects in the array using syntax like this:</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;"><span style="font-size: 10pt; font-family: 'Courier New';">MSH> $f = dir<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;"><span style="font-size: 10pt; font-family: 'Courier New';">MSH> foreach ($fi in $f) { write-object $fi }<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;"><span style="font-size: 10pt; font-family: 'Courier New';"><span style=""> </span>Directory: FileSystem::D:\MSH</span><span style="font-size: 10pt; font-family: 'Courier New';"><o:p> </o:p></span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;"><span style="font-size: 10pt; font-family: 'Courier New';">Mode<span style=""> </span>LastWriteTime<span style=""> </span>Length Name<br></span><span style="font-size: 10pt; font-family: 'Courier New';">----<span style=""> </span>-------------<span style=""> </span>------ ----<br></span><span style="font-size: 10pt; font-family: 'Courier New';">-a---<span style=""> </span>Jun 06 17:25<span style=""> </span>2086 SomeFile.txt<br></span><span style="font-size: 10pt; font-family: 'Courier New';">-a---<span style=""> </span>Jun 06 17:25<span style=""> </span>3049 OtherFile.txt<o:p></o:p></span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;"><o:p> </o:p>In this case, we’re not just passing the results of Dir somewhere; we’re explicitly enumerating through the results of the Dir command and writing each object separately.</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">The answer is that there’s a file called FileSystem.Format.mshxml that describes how to format the FileInfo and DirectoryInfo objects that get-childitem returns.<span style=""> </span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">The format cmdlets looks at these files to determine how to format the object, including which properties to display and what template to use for the table, list and wide “views” of the object. </p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">There really is no built-in functionality in MSH to “get a directory listing”.<span style=""> </span>The functionality of “dir” is provided by a number of pieces of the shell, and the great part is most of those pieces will be the same for other commands.<span style=""> </span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">With most shells, every command has its own syntax.<span style=""> </span>If you want to get a list of files bigger than 10k in size, you have to figure out the syntax for the “dir” or “ls” command to do that.<span style=""> </span>If you wanted a list of processes with more than 10 threads, or a list of Event Log entries generated by a particular service or, well, anything, selected by any property, there’s only one syntax to figure out, and every command will support it.</p>
<h2 style="margin: 12pt 0in 3pt;"><em><font face="Arial">XML</font></em></h2>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">I wish there was more support for XML built into the shell, but you can still do some interesting stuff with what’s provided, and with the System.Xml namespace that the framework provides.</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">For example:</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;"><span style=""> </span>$x = (new-object System.Xml.XmlDocument)<br><span style=""> </span>$x.Load(“c:\iTunes.xml”)<br><span style=""> </span>$keys = $x.SelectNodes(“/plist/dict/key”)<br><span style=""> </span>$keys | foreach-object { $_ }</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">This prints the nodes that match the XPath query “/plist/dict/key” in the XML file loaded, using no built-in shell XML functionality; it all comes form the .NET framework.</p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">Developers familiar with the .NET framework have a huge advantage when it comes to using MSH.<span style=""> </span>The shell isn’t so much a provider of functionality as it is a way to access functionality provided by the framework.<span style=""> </span></p>
<p class="MsoNormal" style="margin: 0in 0in 0pt;">I think this is a good thing.<span style=""> </span>The more ways there are to access the framework, the more familiar everyone becomes with it.<span style=""> </span>It makes it easier to really choose the best tool for the job, be it VB, C#, C++, or a shell script.<span style=""> </span>The knowledge of how the system works and what functionality it provides is portable.</p><br>Thu, 01 Sep 2005 19:17:09 GMT