PowerShell Remoting Project Home

Monday, April 24, 2006

Build Your Own Client for Monad Remoting

New version of Monad Remoting with a client class library suitable for building you own client. Available at MSH For Fun Workspace at gotdotnet.

Uninstall your old Server before upgrade!

My DELL laptop was down again. This time, it was hard drive. I lost two weeks' work. (Ouch! If anyone want to donate a hard drive to me for backup, please contact me. Hehe. ) But I am not giving up. After one month's hard work, I was able to present you the new version of Monad Remoting.

We have a better server: more compatible with ConsoleHost and many bug fixed. But most dramatic changes were made at client side. Now you can build your own cleint application using client class library :

1. To build your own client, you need to initialize an instance of ClientMshHost (Add reference MonadRemoting.ClientMshHost.dll, namespace MonadRemoting), which served as proxy between Monad Remoting server user interface (remote UI) and Local userinterface (Local UI). Although with similar public properties, this "Host" is not derived from MshHost thus can not be used to open a runspace.

2. ClientMshHost has only two public method Start() (to connect server and run) and SetShouldExit(int) (to force client to quit) . Let ClientMshHost do all the hard work: connect to server, authenticate & encrypt, open runspace and run script. Whenever a user interface API was invoked at Server, parameters were sent to ClientMshHost. ClientMshHost will invoke same user interface API at Local UI: display information or get user input, return data back to server. ClientMshHost tries not to throw any exceptions, instead it use Local UI to display all server error and local error.

3. The constructor of ClientMshHost requires a IPEndPoint (to connect Remote UI) and a MshHostUserinterface (to connect LocalUI).
public ClientMshHost(IPEndPoint host, MshHostUserInterface UI){}
MshHostRawUserinterface within MshHostUserinterface is NOT mandatory but is supported by ClientMshHost. Minimum requirement is to implement a MshHostUserinterface which overridden
public abstract string ReadLine();
public abstract SecureString ReadLineAsSecureString();
public abstract void Write(string value);
public abstract void Write(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value);
public abstract void WriteDebugLine(string message);
public abstract void WriteErrorLine(string value);
public virtual void WriteLine();
public abstract void WriteLine(string value);
public virtual void WriteLine(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value);
public abstract void WriteVerboseLine(string message);
public abstract void WriteWarningLine(string message);
Note: To simplify server and client implementation, following API in local UI were ignored (instead normal Read/Write API will be invoked):
public abstract Dictionary<string, MshObject> Prompt(string caption, string message, Collection<FieldDescription> descriptions);
public abstract int PromptForChoice(string caption, string message, Collection<ChoiceDescription> choices, int defaultChoice);
public abstract MshCredential PromptForCredential(string caption, string message, string userName, string targetName);
public abstract MshCredential PromptForCredential(string caption, string message, string userName, string targetName, MshCredentialTypes allowedCredentialTypes, MshCredentialUIOptions options);
There are great advantages of this design:
1. There is no need to implement my own console client. Don't invent wheels! Msh.exe already exposed a great MshHostUserinterface (ConsoleHostUserInterface) as $host.UI variable. So just run a simple script, we are able to "steal" ConsoleHostUserInterface for remoting (Or I should say,unleash the power of $host.UI). I already add following script into my profile.msh.
function start-remotehost {
Param ([string] $IPAddress = "", [int] $Port = 8080)

# Make sure you change path to where you saved MonadRemoting.ClientMshHost.dll

 $RemoteIP = [System.Net.IPAddress]::Parse($IPAddress)
 $RemoteEP = new-object  System.Net.IPEndPoint ($RemoteIP, $Port)
 $RemotingClient = new-object
 $RemotingClient = $null
2. We enjoy all the benefits of ConsoleHostUserInterface and whenever Monad was upgraded, our Monad Remoting local UI was automatically upgraded. Actually, because it use 100% naive msh.exe UI, it is difficult to find out you are in local shell or remote shell. You can always invoke
If you saw ConsoleHost, you were in local shell
Name             : ConsoleHost
Version          : 1.0.7487.0
InstanceId       : ae801745-7671-4a46-9501-6f120bae8a81
UI               : System.Management.Automation.Internal.Host.InternalHostUserI
If you saw ServerMshHost, you were in remote shell.
Name             : ServerMshHost
Version          :
InstanceId       : 84574e63-2b39-4438-b8cc-bb13bd7af932
UI               : System.Management.Automation.Internal.Host.InternalHostUserI

3. You will never leave you msh.exe console window and start another program for remote access. You can call start-remoteHost to gain remote access within msh.exe. When you are done, type
and return to your local shell. You want connect to Remote host again? Just call start-remoteHost again. Actually, I am now using this client as a in-process su command. I was thinking of building this client as a MshSnapin someday.

4. The ClientMshHost dose not care what kind of outter application it is in. It works for console application like msh.exe, also works for Winform base GUI application like Karl Prosser's Msh Analyzer. Hopefully, soon I can use Msh analyzer as my Monad remoting client (Its Rich UI is really cool)

Have Fun

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]


This rocks...keep it up! I'm thrilled!
thanks, man!

Post a Comment

Links to this post:

Create a Link

<< Home