Friday, June 25, 2004

I took a session on Monad at the Bangalore .NET User Group meeting yesterday. Here is a brief write-up about the session for those of you who missed the session. People starting off on Monad may be interested in reading this.

 

Introduction

Unlike conventional shells that work on text streams and expect the end user to be an expert in text parsing, MSH introduces the idea of using structured object pipelines where objects instead of text flow between commands.

 

At the msh prompt, if we type

MSH C:/ > dir

we see a list of files [the same way the dos dir worked]. We see the same output for ls.

 

In Monad commands are called cmdlet [Commandlets]. Each cmdlet is a combination of a verb-noun pair. For example the cmdlet get-children or get/children gets all the children [files and directories when invoked in a FS]. dir and ls are aliases of get-children. By default the verb ‘get’ is assumed for a command given without a verb. So typing children gives the result of get-children and command gives the result of get-command. Alias is an exception. Typing alias gives the result of set-alias and typing aliases give the result of get-alias.

 

To see all the commands type command. To see all the aliases type aliases.

 

Some example Commands

 

MSH C:/> get-process

 

By using reflection, any object can list the methods and properties that it supports. To get a list of methods supported by a get-process object [which is a System.Diagnostics.Process object] try the command below.

 

MSH C:/> get-process | get-member -methods

 

MSH C:/> $a = get-process

 

MSH C:/> $a[0]

 

MSH C:/> $a[0].ToString()

 

Here $a is an array of Process Objects. We can invoke any function or property from the process class on object $a[0] and see the results like the ToString() example above.

 

MSH C:/> get-process | get-member -property

 

MSH C:/> $a[0].handlecount

 

MSH C:/> gps

 

MSH C:/> gps | tail

 

MSH C:/> gps | sort id | tail

 

MSH C:/> gps | where “processname –like cmd*”

 

MSH C:/> gps | reduce-expression {$_.handlecount -ge 500}

 

get-process or gps returns an array of objects. Reduce-expression works like a lambda in functional programming languages [similar to anonymous method]

For example in scheme (lambda((a b)(+ a b))) acts as a block of code.

In Monad the block of code after reduce-expression in braces is the script that will be carried for each pipeline object. $_ is set to the current pipeline object. So for each object in the object array returned by gps, $_ is filled with an object (the current pipeline object) for which the block of code is executed.

 

MSH C:/> gps | sort handlecount | tail | out-excel

 

MSH C:/> get-process | out-chart processname,handlecount -Title "Processes" -Filename Processes.html

 

MSH C:/> gps | sort handlecount | tail | out-grid processname,handlecount

 

MSH C:/> get-command out-*

 

MSH C:/> foreach ($p in $a | where "handlecount -ge 500"  | sort handlecount) { "{0,-15} has {1,6} handles" % $p.processname,$p.handlecount }

 

Notice the .NET style for formatting strings above.

 

MSH C:/> function n{notepad}

 

MSH C:/> n

 

MSH C:/> n;n;n

 

MSH C:/> gps [a-c]*,[t-z]* -exclude *[p-t] | stop-process –whatif

 

MSH C:/> gps | where “processname –like notepad*” | stop-ps1 –confirm

 

For invalid process ids, an error message is displaying when trying to stop them.

 

MSH C:/> stop-process 123,345,100000,200000,300000

 

MSH C:/> stop-process 123,345,100000,200000,300000 -errorpolicy notifystop

 

MSH C:/> stop-process 100000,200000,300000 -errorpolicy inquire

[Error stop-process]: (No process found for given ID :  : 100000) 100000"

 

[Error stop-process]: (No process found for given ID :  : 100000) 100000"

Continue :[y/yes/ n/no t/yestoall l/notoall s/suspend] s

MSH C:/> exit

 

[Error stop-process]: (No process found for given ID :  : 100000) 100000"

Continue :

[y/yes/ n/no t/yestoall l/notoall s/suspend] l

Stopped (Cmdlet:stop-process): User requested stop

 

MSH C:/>

 

Cmdlet

Each cmdlet is a managed class and not a separate executable. A simple cmdlet code is given below.

 

using System;

using System.Diagnostics;

using System.Management.Automation;

 

namespace SampleCmdlet

{

#region GetPs1

       [CmdletDeclaration("get", "ps1")]

       public class GetPs1: Cmdlet

       {

              public override void ProcessRecord()

              {

                     WriteObjects(Process.GetProcesses());

              }

       }

#endregion

}

 

The class that is to be exposed as a cmdlet is annotated with a CmdletDeclaration property specifying the verb and noun that is to be used to access this cmdlet. Also your class must inherit from the Cmdlet class and override atleast one of the three functions StartProcessing, ProcessRecord and EndProcessing.

 

A cmdlet that receives some input parameters and does exception-handling is given below

 

using System;

using System.Diagnostics;

using System.Management.Automation;

 

namespace SampleCmdlet

{

#region StopPs1

       [CmdletDeclaration("stop", "ps1")]

       public class StopPs1: Cmdlet

       {

              [ParsingParameterMapping(0)]

              [ParsingAllowPipelineInput]

              [ParsingMandatoryParameter]

              [ParsingPromptString( "Input the id: "  )]

              public int [] Id;

      

              public override void ProcessRecord()

              {

                     Process p = null;

                     foreach ( int i in Id )

                     {      if (ShouldProcess(i.ToString()))

                           {

try

                                  {

p = Process.GetProcessById(i);

                                         p.Kill();

                                  }

                                  catch (System.ComponentModel.Win32Exception e)

                                  { WriteErrorObject("No adequate permissions",e); }

 

                                  catch (System.ArgumentException e)

                                  { WriteErrorObject("No such process exists",e); }

                           }

                     }

              }

       }

#endregion

      

}

 

The code declares the input parameter, annotates it with attributes and assumes that the input values have been filled in. It doesn’t care if the input is coming form the pipeline, file, console or any other means. All the parsing and filling up the value is taken care by the shell. The same goes for output. The code calls WriteObject() function to do any output and the shell takes care of the formatting, displaying and routing of output as per the context.

 

The code above is for Monad, March 2004 build. Sample code for July, 2004 build is available at

http://msdn.microsoft.com/theshow/Episode043/Transcript.html

 

Cmdlet Providers

Cmdlet Providers provide the user with a basic set of cmdlets like pushd, move, copy, cd, dir etc that make the provider as navigable as a file store. Two standard providers come with the msh installation, one for registry browsing and the other for active directory.

 

[ProviderDeclaration("REG", "Microsoft", "Windows", "6.0", "MSH", "Registry", "1.0", ProviderCapabilityFlags.None)]

public class RegistryProvider :  NavigationCmdletBase

{

    protected override void GetItem(string path)

    {

        RegistryKey key = GetRegkeyForPath(path, false);

 

        if (key == null)

        {  WriteErrorObject(path, new ArgumentException("does not exist"));

        }

        WriteObject(key);

    }

    ....

}

 

For installing registry provider use:

MSH C:/> new-provider -Assembly "${MSHHOME}\System.Management.Automation.Core.dll" -Provider REG

 

 

 

 

 

Registry Example

To add a new item to the context menu of directories, some values need to be added to the registry. Here is an example that adds a “Launch MSH” option in the context menu of a directory such that on right clicking a directory and selecting “Launch MSH”, Monad is launched and a changedir [or cd] to the corresponding directory is done.

 

For this we create new items, “Launch msh” and “Command: in the registry using msh commands to give HKLM:/Software/Classes/Directory/Shell/Launch MSH/Command. Note: The escape character in MSH is ` => the back quote character.

 

MSH C:/> $val = format-string "`"{0}`" `"{1}`" `"{2}`" "  "${MSHHOME}\msh.exe" "-command" "cd  '%1' "

 

MSH C:/> $val

 

MSH C:/> new-item -path "HKLM:/SOFTWARE/Classes/Directory/shell" -name "Launch MSH"

 

MSH C:/> new-item -path "HKLM:/SOFTWARE/Classes/Directory/shell/Launch MSH" -name "Command"

 

MSH C:/> set-item -path "HKLM:/SOFTWARE/Classes/Directory/shell/Launch MSH/Command" –value $val

 

Now on right clicking any directory an option “Launch MSH” should appear. On selecting that option, MSH is launched with the current directory as the directory that was right clicked. Neat?

 

MSH C:/> Get-drive

 

MSH C:/> cd HKLM:/

 

MSH HKLM:/> dir

 

MSH HKLM:/> cd Software

 

Yeah, the registry provider lets you move through the registry just the way you move through a file system!

 

Download and Installation

Monad Beta Release 1.0

  1. Go to beta.microsoft.com
  2. Sign in with your passport id
  3. Enter Guest login as mshPDC
  4. Fill up the form with your details and submit
  5. After 24-36 hours you should be able to login to the system. Click the downloads link on left pane
  6. Click the Microsoft Command Shell link.
  7. Download .NET framework 2.0. Install this [22.16MB] [It does not interfere with your earlier .NET versions]
  8. Download msh – Microsoft Command Shell Preview [1.88 MB]

 

System requirements

Windows XP or Windows Server 2003.

[If you are on another windows version read 1 and 2]

 

Reference Material

http://msdn.microsoft.com/theshow/Episode043/default.asp

 

The best way to learn monad is to download the shell and read the documentation that comes with the shell. As of now, there are no technical resources about the shell except for the video by Jeffrey Snover – Architect, Monad and Jim Truher – Program Manager, Monad[link above]

 

Take a look at profile.msh file that is installed along with Monad in the user’s home directory.

There is a lot of code using aliases, environment variables, functions, commandlets etc – a good place to pick up some tips from.

 

Do write to me your feedback about Monad – good and bad.

Friday, June 25, 2004 6:22:04 AM (US Eastern Standard Time, UTC-05:00)  #    Comments [14]Trackback
 Tuesday, June 15, 2004

Monad works on .NET framework V2.0. After a comment on one of my earlier entries, I decided to find out if there were any framework 2.0 dependencies in Monad. If not, then we could get it to run on an earlier version of the framework with a bit of work. Else, it will be good to know what features of the new framework are being used by Monad. [Optimistic, ain’t I? ;)]

 

I modified the version numbers in the IL generated by ildasm [.NET framework V1.0 and V1.1] on msh.exe and tried assembling the modified IL using ilasm. Worked smoothly. Next step was to take the dependent assemblies and generate each of them for .NET framework 1.1. On disassembling System.Management.Automation.Core.dll [one of the assemblies referenced by monad], changing the version info in the IL and assembling it back an error message with failure popped up. Looking through the IL generated I noticed generics being used throughout the code.

 

Okay, so monad is using generics. Well, that ensures that Monad will not work on earlier version of .NET framework. Generics is one of the new additions in the new .NET framework. So I have decided not to get too ambitious as to try and get this working on the earlier version(s) of .NET framework.

 

So much for installing Monad J

 

I noticed that .NET framework 2.0 doesn’t come with ildasm.exe. ilasm.exe is there though.

 

[If you are not able to install monad do read my previous post]

Tuesday, June 15, 2004 2:53:58 AM (US Eastern Standard Time, UTC-05:00)  #    Comments [11]Trackback

Recently, an installation exe refused to run on my OS with an error message saying that the adequate OS was not present. All I wanted to do was extract the files from the package. If I could just get past the OS check within the installation exe, then I could get the files. Changing the OS string and environment variable etc didn’t help in this case.

 

Fortunately, I found an easier way to do this.

 

How do you extract files from an install shield exe?

 

If it is based on install shield wizard you may want to take a look at i6comp tool.

If it is based on msi package, then you first need to get the msi out of the exe.

 

From Brad’s e-mail:

Quote

To Hack the MSI file you have to first get to the .MSI file. Begin the install process by double clicking on the .EXE file. When you get the error message DO NOT click ok. Browse to your /local settings/temp folder in /Documents and Settings/. In the temp  folder look for a new folder with current date and time. Inside the folder you will see  file called, "Microsoft command shell Preview.msi" This file can be edited with a program called ORCA.

Unquote

 

Once you have the msi file, you need to edit the target OS version in the file using orca. [Refer this KB article]. Save the msi file after making the changes. Run the msi and you should be able to install the package.

 

Credits: Thanks to Brad Hite for helping out with install shield exe/msi packages.

Tuesday, June 15, 2004 1:32:45 AM (US Eastern Standard Time, UTC-05:00)  #    Comments [9]Trackback
 Thursday, June 10, 2004

Microsoft Command Shell [codename Monad] is Microsoft’s upcoming shell that is planned to ship with Longhorn. I read up a bit about the shell and decided that I have to try things for myself to believe that it was actually true. There is not much material about Monad on the internet now, except a lot of blogs, most people blogging about it are PDC attendees.

 

I downloaded the monad beta bits, its release notes claim that monad will work on Windows XP and Windows Server 2003 only. Monad requires .NET framework 2.0. I installed the framework on my Win2k Professional machine and tried installing monad. The monad installer started off and displayed a message box with the message “The operating system is not adequate for running Microsoft Command Shell Preview”. I did the same things on another machine with win2k3 server. Monad installed and I could work on the shell. Monad is a .NET application and I can’t think of reasons why this shouldn’t work on my win2k machine. Good time to use the deployment feature of .NET apps that I keep talking about. I copied the extracted files [dll,exe and configs] from the server machine to my machine. Launched cmd.exe, moved to the monad folder in my machine [where I copied the monad files from server] and started msh.exe. Bingo, after a minute the shell prompt appeared. Something was different though. I did not see the regular message “Microsoft Command Shell (msh)” that is displayed when you start msh. I took the profile.msh file from my home directory on the server machine and copied to my home directory in my machine. And presto, I have msh.exe working on my win2k machine now. I haven’t found anything missing until now, the behavior of the shell seems to be the same on my machine as on the server machine.


Monad is cool :), absolutely!

Thursday, June 10, 2004 6:54:34 AM (US Eastern Standard Time, UTC-05:00)  #    Comments [17]Trackback
 Tuesday, May 18, 2004

-James Gosling is talking at Hyderabad, Too bad it’s not at Bangalore.

 

-Canadian Differentrepreneurs: http://www.microsoft.com/canada/mac/default.mspx#

 

-How easy it is today to get pirated stuff? http://www.the-cool-book-shop.com/ [Scroll to the bottom and read].

 

-From “The FountainHead” by Ayn Rand:

"Look," said Roark evenly, and pointed at the window. "Can you see the campus and the town? Do you see how many men are walking and living down there? Well, I don't give a damn what any or all of them think about architecture -- or about anything else, for that matter. Why should I consider what their grandfathers thought of it?"

"That is our sacred tradition."

"Why?"

"For heaven's sake, can't you stop being so naive about it?"

"But I don't understand. Why do you want me to think that this is great architecture?" He pointed to the picture of the Parthenon.

"That," said the Dean, "is the Parthenon."

"So it is."

"I haven't the time to waste on silly questions."

"All right, then." Roark got up, he took a long ruler from the desk, he walked to the picture. "Shall I tell you what's rotten about it?"

"It's the Parthenon!" said the Dean.

"Yes, God damn it, the Parthenon!"

The ruler struck the glass over the picture.

"Look," said Roark. "The famous flutings on the famous columns -- what are they there for? To hide the joints in wood -- when columns were made of wood, only these aren't, they're marble. The triglyphs, what are they? Wood. Wooden beams, the way they had to be laid when people began to build wooden shacks. Your Greeks took marble and they made copies of their wooden structures out of it, because others had done it that way. Then your masters of the Renaissance came along and made copies in plaster of copies in marble of copies in wood. Now here we are, making copies in steel and concrete of copies in plaster of copies in marble of copies in wood. Why?"

The Dean sat watching him curiously. Something puzzled him, not in the words, but in Roark's manner of saying them.

"Rules?" said Roark. "Here are my rules: what can be done with one substance must never be done with another. No two materials are alike. No two sites on earth are alike. No two buildings have the same purpose. The purpose, the site, the material determine the shape. Nothing can be reasonable or beautiful unless it's made by one central idea, and the idea sets every detail. A building is alive, like a man. Its integrity is to follow its own truth, its one single theme, and to serve its own single purpose. A man doesn't borrow pieces of his body. A building doesn't borrow hunks of its soul. Its maker gives it the soul and every wall, window and stairway to express it."

"But all the proper forms of expression have been discovered long ago."

"Expression -- of what? The Parthenon did not serve the same purpose as its wooden ancestor. An airline terminal does not serve the same purpose as the Parthenon. Every form has its own meaning. Every man creates his meaning and form and goal. Why is it so important -- what others have done? Why does it become sacred by the mere fact of not being your own? Why is anyone and everyone right -- so long as it's not yourself? Why does the number of those others take the place of truth? Why is truth made a mere matter of arithmetic -- and only of addition at that? Why is everything twisted out of all sense to fit everything else? There must be some reason. I don't know. I've never known it. I'd like to understand."

"For heaven's sake," said the Dean. "Sit down....That's better....Would you mind very much putting that ruler down?...Thank you....Now listen to me. No one has ever denied the importance of modern technique to an architect. We must learn to adapt the beauty of the past to the needs of the present. The voice of the past is the voice of the people. Nothing has ever been invented by one man in architecture. The proper creative process is a slow, gradual, anonymous, collective one, in which each man collaborates with all the others and subordinates himself to the standards of the majority."

"But you see," said Roark quietly, "I have, let's say, sixty years to live. Most of that time will be spent working. I've chosen the work I want to do. If I find no joy in it, then I'm only condemning myself to sixty years of torture. And I can find the joy only if I do my work in the best way possible to me. But the best is a matter of standards -- and I set my own standards. I inherit nothing. I stand at the end of no tradition. I may, perhaps, stand at the beginning of one."

-And fans of “Friends” may find this interesting:

http://shlomif.il.eu.org/humour/TOWTF/TOW_Fountainhead_1.html

Tuesday, May 18, 2004 2:18:00 AM (US Eastern Standard Time, UTC-05:00)  #    Comments [16]Trackback
 Monday, May 17, 2004

I am enjoying the sleek UI that gmail provides you. For once I seem to be happy emailing without outlook express or Microsoft Outlook.

 

If you have a gmail id then do check out http://www.bladam.com/archives/0404202120.htm, some useful tips in there. I am quite happy about the dot tip [My email id is my Firstname.Lastname@gmail.com]. I wonder what will happen when somebody actually chooses my FirstnameLastname@gmail.com.

 

To check for name availability try

http://www.google.com/accounts/CheckAvailability?service=mail&continue=http://www.google.com&Email=YOURNAMEHERE

 

Too bad I can’t have pooja@gmail.com :(

Nonetheless, gmail did help while I was on vacation.

Monday, May 17, 2004 3:22:46 AM (US Eastern Standard Time, UTC-05:00)  #    Comments [19]Trackback
 Tuesday, May 04, 2004

I am leaving for a vacation trip today. Its after 8+ years  that I am going to be traveling to Rajasthan, am quite excited. I am back on 17th May. I am going to Baroda [Gujarat], from there to Udaipur. On the way back will be visiting Nathdwara and Bombay.

 

Will have lots to say when I am back. I wonder how life is going to be without a computer for 2 weeks at a stretch :)). I wish I had a digital cam, that is one of the things I am going to get soon after I am back.

 

Adios!

 

Tuesday, May 04, 2004 12:10:43 AM (US Eastern Standard Time, UTC-05:00)  #    Comments [0]Trackback
 Friday, April 23, 2004

Today’s the 4th...no the 5th day since I started feeling sick [sick as in ill]. The reasons - not sure, except that I had this really stale milk peda from Woody’s at commercial street, Bangalore. I knew it was stale the moment I bit into it, I still gobbled down the whole piece to make it worth my money [I can be really stupid sometimes]. This was on Sunday evening, April 18, 2004. Monday evening my stomach started giving me trouble. Tuesday, it felt funny but I wasn’t sure if it was the Stress Management workshop or something else.

 

Couldn’t get sleep the whole night, neck hurt like mad. Wednesday felt giddy the whole day, and in the night again no sleep. Thursday morning I knew something was wrong and that I better see the doctor. I had developed these rashes in my whole body and the back of my neck was swollen. I stay with about 15 girls as a paying guest with a family. Now each one came up with her own reasoning as to what the disease could be. One said it could be measles/mumps. Another said it couldn’t be that since I had no itching. So it was more likely an allergy. One said I needn’t see a doc, she advised me to take an anti-allergy tablet and take rest. Apparently she had done that and had recovered. Another said run to the doc, she got an injection when she had the same problem and the rash went instantly. My maid said it was coz of the food poisoning and probably the egg I had had the previous night. My friend said it could be an insect bite. Well, I was feeling quite tired and restless, I decided to see the doc.

 

I went to a general physician on Thursday morning. He seemed quite unsure what the problem was. He said it could be an insect bite, allergy, acute viral fever etc etc. He gave me some medicines and asked me to see him again on Saturday morning. He asked me to see him the next day i.e. today if my condition got worse. I also took a blood test. I feel quite uncomfortable seeing a syringe go into my skin and even worse when it stays there and they draw your blood. As a kid I was a lot braver, there was a time when I could watch a nurse take a syringe, inject it into my vein and pull it out. Very normal. But that was long long ago.

 

The medicines gave me temporary relief. But today morning I got up feeling worse. I also think the illness is beginning to affect my head. And I don’t like it when I can’t think straight. I have been asked to take 4 days complete bed rest, Today’s the second day. I do not have a comp at home and so I keep running to my office [People think I love my office]. I thought I could print out some stuff, sit at home and read.

 

I am really sick of being this weakling for 5 days now. Can’t wait to get back to normal and do some work.I think I will visit my doc today evening itself.

Friday, April 23, 2004 1:59:20 AM (US Eastern Standard Time, UTC-05:00)  #    Comments [7]Trackback

Finally, setup Antlr to successfully generate the C# parser and lexer files.

I am on a win2k professional machine with Visual Studio.NET installed.

Things to take care of:

 

  • Have one of the later versions of java installed and ensure that java is working fine [its in the PATH and stuff]
  • Install the antlr binaries.
  • Define a CLASSPATH environment variable to point to your antlr.jar file.
  • The java.g that ships with antlr will not compile as it has an extra character in line 1627. Comment that line and it works as expected. [This file will generate those 4 missing files I spoke about in my previous post]
  • The command line arguments to generate code is
    java antlr.Tool <filename.g> where filename is the path to your rules file. The expected language output is given in the rules file itself, by default it is java.

 

Quite neat.

 

Okay now the reason I was checking out antlr is so that I can start working on the DDL with Rosh. Originally we had used Lemon to generate the parser for us and used the parser tree generated to write further code. Recently we ported the DDL to .NET and are now considering writing a compiler for it. Instead of writing the parser by hand and the code following, I thought I would give antlr a shot and see what its generated files are like. Saves us a lot of time and lets us concentrate on the main problem at hand.

 

I like the exception handling that antlr does on its own and the way it leaves room for the programmer to add custom exception handlers. It wouldn’t have been a big pain to do this on your own all together, but like I said, it saves you time and lets you concentrate on the real issues.

 

I definitely do not believe in re-inventing the wheel J. Removing parts of the wheel and re-writing, adding to the wheel etc are different but simply re-inventing the wheel – NO. Time is too short.

Friday, April 23, 2004 1:29:21 AM (US Eastern Standard Time, UTC-05:00)  #    Comments [5]Trackback