This section describes how to write a hosting application for Windows PowerShell that supports a custom host with high-level and low-level user interfaces. This type of application implements the PSHost class to define the custom host, a PSHostUserInterface class for the high-level user interface, and a PSHostRawUserInterface class for the low-level interface. The low-level interface allows the hosting application to support cmdlets that do character-mode interaction with the user, such as reading from the screen, writing to the screen, and setting the foreground and background colors on the screen.
The hosting application described here is a simple Windows PowerShell interactive console host listener that implements a basic read-evaluate-print loop (listener), allowing the user to work interactively with the runspace.
Topics in this section include:
Defining Properties to Support the Custom Host
Hosting applications should identify properties that reflect the parameters for the custom host that it is using. This hosting application does this by defining a ShouldExit property that the custom host will use to tell the application when it should exit, and an ExitCode property that the custom host uses to identify the exit code for the application to issue when exiting.
Defining a Custom Host
The custom host class used by this hosting application derives from the PSHost base class. For the complete implementation, see Code Sample for Custom Host. Within this class, the UI property indicates that the custom host supports an implementation of PSHostUserInterface. An instance of this interface is allocated once at startup and returned every time thereafter.
Here is the implementation of the UI property for this hosting application.
public override PSHostUserInterface UI
{
get { return myHostUserInterface; }
}
private MyHostUserInterface myHostUserInterface = new MyHostUserInterface();
Implement the PSHostUserInterface
To support a high-level user interface, the hosting application needs to implement the PSHostUserInterface class. For more information about implementing this interface, see Creating a Console Application That Implements PSHostUserInterface.
The complete implementation of this class is shown in Code Sample for PSHostUserInterface Implementation. Within this class, the RawUI property indicates that the custom host also supports a low level user interface.
Here is the implementation of the RawUI property.
private MyRawUserInterface myRawUi = new MyRawUserInterface();
public override PSHostRawUserInterface RawUI
{
get { return myRawUi; }
}
Implementing the PSHostRawUserInterface
To support low-level operations, such as cursor movements, the hosting application implements the PSHostRawUserInterface base class. This low-level user interface (also referred to as a "raw" interface) is used to support cmdlets and other commands that require character-mode interactions with the user. (The complete implementation of this interface is provided in Code Sample for PSHostRawUserInterface Implementation.)
Declaring the Raw User Interface Class
Here is a typical class declaration for a raw user interface class.
class MyRawUserInterface : PSHostRawUserInterface
Defining a Window Title
This raw user interface implements a read/write WindowTitle property to define the text in the title bar of the current application window. The title bar is located outside the borders of the text area for the window.
Here is the implementation of the WindowTitle property. In this case, the implementation just uses the corresponding Title property of .NET Console.
public override string WindowTitle
{
get { return Console.Title; }
set { Console.Title = value; }
}
Defining Window Position
This raw user interface implements a read/write WindowPosition property to define the position of the application window. The position is rendered in coordinates identifying the area in the screen buffer allocated for window contents.
The following code shows how the sample raw user interface implements this property.
Here is the implementation of the WindowPosition property. In this case, the implementation just uses the .NET Console window position information.
public override Coordinates WindowPosition
{
get { return new Coordinates(Console.WindowLeft, Console.WindowTop); }
set { Console.SetWindowPosition(value.X, value.Y); }
}
Defining Window Size
The PSHostRawUserInterface class supports several application window size properties that a hosting application can implement. This raw user interface implements three of these properties.
- The WindowSize property indicates the size, in character cells, of the visible contents of the current window.
- The MaxWindowSize property indicates the maximum size of the window. This is the largest size that is possible for the current buffer, font, and display hardware.
- The MaxPhysicalWindowSize property indicates the maximum size of the window if it completely covers the desktop.
Here is the implementation of the WindowSize property. In this case, the implementation just adapts the window size to the corresponding .NET Console information.
public override Size WindowSize
{
get { return new Size(Console.WindowWidth, Console.WindowHeight); }
set { Console.SetWindowSize(value.Width, value.Height); }
}
Here is the implementation of the MaxWindowSize property. In this case, the implementation adapts the maximum window size from the largest window width and height for the .NET Console object.
public override Size MaxWindowSize
{
get { return new Size(Console.LargestWindowWidth, Console.LargestWindowHeight); }
}
Here is the implementation of the MaxPhysicalWindowSize property. In this case, the implementation adapts the maximum physical window size from the largest window width and height for the .NET Console object.
public override Size MaxPhysicalWindowSize
{
get { return new Size(Console.LargestWindowWidth, Console.LargestWindowHeight); }
}
Defining Console Colors
The raw user interface can implement the following properties to support console colors for the current application window.
- The ForegroundColor property defines the color that is used to render characters on the screen.
- The BackgroundColor property defines the color that is used to render the background behind characters on the screen.
Here is the implementation of the ForegroundColor property.
public override ConsoleColor ForegroundColor
{
get { return Console.ForegroundColor; }
set { Console.ForegroundColor = value; }
}
Here is the implementation of the BackgroundColor property.
public override ConsoleColor BackgroundColor
{
get { return Console.BackgroundColor; }
set { Console.BackgroundColor = value; }
}
Defining Cursor Position
The raw user interface can implement the CursorPosition property to define the cursor position. The position is rendered in coordinates indicating the location in the application window, including any lines in the scroll buffer.
Our sample user interface does not implement this property, but just throws informational exceptions.
Here is the implementation of the CursorPosition property.
public override Coordinates CursorPosition
{
get { throw new NotImplementedException("The CursorPosition property is not implemented by MyRawUserInterface."); }
set { throw new NotImplementedException("The CursorPosition property is not implemented by MyRawUserInterface."); }
}
Defining Cursor Size
The raw user interface can implement the CursorSize property to define the size of the cursor. Size is rendered as a value from 0 to 100 percent.
Here is the implementation of the CursorSize property.
public override int CursorSize
{
get { return Console.CursorSize; }
set { Console.CursorSize = value; }
}
Defining Key Availability
The raw user interface can implement the read-only KeyAvailable property to indicate whether a keystroke is waiting in the input buffer. A call to retrieve this information is non-blocking.
Here is the implementation of the KeyAvailable property. In this case, the implementation just uses the associated .NET Console property.
public override bool KeyAvailable
{
get { return Console.KeyAvailable; }
}
Define Buffer Size
The raw user interface can implement the BufferSize property to indicate the current size, in character cells, of the screen buffer for the host.
The sample raw user interface implements this property to render the host buffer size adapted from the .NET Console buffer size.
Here is the implementation of the BufferSize property. In this case, the implementation adapts from the .NET Console buffer size.
public override Size BufferSize
{
get { return new Size(Console.BufferWidth, Console.BufferHeight); }
set { Console.SetBufferSize(value.Width, value.Height); }
}
Read User Keystrokes
The raw user interface can implement the ReadKey method to read the next keystroke entered by the user. This method blocks until the user presses a key.
Here is the implementation of the ReadKey method. In this case, the implementation throws an informational exception.
public override KeyInfo ReadKey(ReadKeyOptions options)
{
throw new NotImplementedException("The ReadKey() method is not implemented by MyRawUserInterface.");
}
Flush the Input Buffer
The raw user interface can implement the FlushInputBuffer method to reset the input buffer by discarding all input records currently in the buffer. The sample raw user interface implements this method to do nothing but return silently.
Here is the implementation of the FlushInputBuffer method. In this case, the implementation throws an informational exception.
public override void FlushInputBuffer()
{
; //Do nothing...
}
Handling Buffer Contents
The PSHostRawUserInterface class supports a number of methods to handle buffer contents. See the complete code in Code Sample for PSHostRawUserInterface Implementation for their implementations in this raw host user interface.
-
SetBufferContents. The variants of this method can be used to fill the buffer with an array of buffer cells and fill a specific region with a single character.
-
GetBufferContents. This method extracts the contents of the specified region of the screen buffer and returns the contents in a BufferCell array.
-
ScrollBufferContents. This method moves the specified portion of the contents of the screen buffer from the source location to the destination location.
-
LengthInBufferCells. This method returns the length, in buffer cells, of the specified character or string.
-
NewBufferCellArray. This method creates a two-dimensional array of BufferCell objects indicating cells in the screen buffer.
Provide a Callback Function for I/O Notifications
To receive I/O notifications from the runspace, your hosting application can define a callback function. The sample application does not define one of these.
Code Sample for Hosting Application
Here is the complete code for this hosting application.
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
namespace Microsoft.Samples.PowerShell.Host
{
/// <summary>
/// Simple PowerShell interactive console host listener implementation. This class
/// implements a basic read-evaluate-print loop or 'listener' allowing you to
/// interactively work with the PowerShell runtimw.
/// </summary>
class PSListenerConsoleSample
{
/// <summary>
/// Define the property that the PSHost implementation will use to tell the host
/// application that it should exit.
/// </summary>
public bool ShouldExit
{
get { return shouldExit; }
set { shouldExit = value; }
}
private bool shouldExit;
/// <summary>
/// Define the property that the PSHost implementation will use to tell the host
/// application what code to use when exiting.
/// </summary>
public int ExitCode
{
get { return exitCode; }
set { exitCode = value; }
}
private int exitCode;
/// <summary>
/// Holds the instance of the PSHost implementation for this interpreter.
/// </summary>
private MyHost myHost;
/// <summary>
/// Holds the runspace for this interpeter.
/// </summary>
private Runspace myRunSpace;
/// <summary>
/// Holds a reference to the currently executing pipeline so it can be
/// stopped by the control-C handler.
/// </summary>
private Pipeline currentPipeline;
/// <summary>
/// Used to serialize access to instance data...
/// </summary>
private object instanceLock = new object();
/// <summary>
/// Create this instance of the console listener.
/// </summary>
PSListenerConsoleSample()
{
// Create the host and runspace instances for this interpreter. Note that
// this application doesn't support console files so only the default snapins
// will be available.
myHost = new MyHost(this);
myRunSpace = RunspaceFactory.CreateRunspace(myHost);
myRunSpace.Open();
}
/// <summary>
/// A helper class that builds and executes a pipeline that writes to the
/// default output path. Any exceptions that are thrown are just passed to
/// the caller. Since all output goes to the default outter, this method()
/// won't return anything.
/// </summary>
/// <param name="cmd">The script to run</param>
/// <param name="input">Any input arguments to pass to the script. If null
/// then nothing is passed in.</param>
void executeHelper(string cmd, object input)
{
// Ignore empty command lines.
if (String.IsNullOrEmpty(cmd))
return;
// Create the pipeline object and make it available
// to the ctrl-C handle through the currentPipeline instance
// variable.
lock (instanceLock)
{
currentPipeline = myRunSpace.CreatePipeline();
}
// Create a pipeline for this execution. Place the result in the currentPipeline
// instance variable so that it is available to be stopped.
try
{
currentPipeline.Commands.AddScript(cmd);
// Now add the default outputter to the end of the pipe and indicate
// that it should handle both output and errors from the previous
// commands. This will result in the output being written using the PSHost
// and PSHostUserInterface classes instead of returning objects to the hosting
// application.
currentPipeline.Commands.Add("out-default");
currentPipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
// If there was any input specified, pass it in, otherwise just
// execute the pipeline.
if (input != null)
{
currentPipeline.Invoke(new object[] { input });
}
else
{
currentPipeline.Invoke();
}
}
finally
{
// Dispose of the pipeline line and set it to null, locked because currentPipeline
// may be accessed by the ctrl-C handler.
lock (instanceLock)
{
currentPipeline.Dispose();
currentPipeline = null;
}
}
}
/// <summary>
/// Basic script execution routine - any runtime exceptions are
/// caught and passed back into the runtime to display.
/// </summary>
/// <param name="cmd"></param>
void Execute(string cmd)
{
try
{
// execute the command with no input...
executeHelper(cmd, null);
}
catch (RuntimeException rte)
{
// An exception occurred that we want to display
// using the display formatter. To do this we run
// a second pipeline passing in the error record.
// The runtime will bind this to the $input variable
// which is why $input is being piped to out-default
executeHelper("$input | out-default", rte.ErrorRecord);
}
}
/// <summary>
/// Method used to handle control-C's from the user. It calls the
/// pipeline Stop() method to stop execution. If any exceptions occur,
/// they are printed to the console; otherwise they are ignored.
/// </summary>
/// <param name="sender">See ConsoleCancelEventHandler documentation</param>
/// <param name="e">See ConsoleCancelEventHandler documentation</param>
void HandleControlC(object sender, ConsoleCancelEventArgs e)
{
try
{
lock (instanceLock)
{
if (currentPipeline != null && currentPipeline.PipelineStateInfo.State == PipelineState.Running)
currentPipeline.Stop();
}
e.Cancel = true;
}
catch (Exception exception)
{
this.myHost.UI.WriteErrorLine(exception.ToString());
}
}
/// <summary>
/// Implements the basic listener loop. It sets up the ctrl-C handler, then
/// reads a command from the user, executes it and repeats until the ShouldExit
/// flag is set.
/// </summary>
private void Run()
{
// Set up the control-C handler.
Console.CancelKeyPress += new ConsoleCancelEventHandler(HandleControlC);
Console.TreatControlCAsInput = false;
// Loop reading commands to execute until ShouldExit is set by
// the user calling "exit".
while (!ShouldExit)
{
myHost.UI.Write(ConsoleColor.Cyan, ConsoleColor.Black, "\nPSConsoleSample: ");
string cmd = Console.ReadLine();
Execute(cmd);
}
// Exit with the desired exit code that was set by exit command.
// This is set in the host by the MyHost.SetShouldExit() implementation.
Environment.Exit(ExitCode);
}
/// <summary>
/// Creates and initiates the listener instance.
/// </summary>
/// <param name="args">Ignored for now.</param>
static void Main(string[] args)
{
// Display the welcome message.
Console.Title = "PowerShell Console Host Sample Application";
ConsoleColor oldFg = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine(" PowerShell Console Host Interactive Sample");
Console.WriteLine(" =====================================");
Console.WriteLine("");
Console.WriteLine("This is an example of a simple interactive console host using the PowerShell");
Console.WriteLine("engine to interpret commands. Type 'exit' to exit.");
Console.WriteLine("");
Console.ForegroundColor = oldFg;
// Create the listener and run it - this never returns.
PSListenerConsoleSample listener = new PSListenerConsoleSample();
listener.Run();
}
}
}
Code Sample for Custom Host
Here is the complete code for the custom host MyHost for this hosting application.
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Host
{
/// <summary>
/// A sample implementation of the PSHost abstract class for console
/// applications. Not all members are implemented. Those that are
/// not implemented throw a NotImplementedException exception.
/// </summary>
class MyHost : PSHost
{
public MyHost(PSListenerConsoleSample program)
{
this.program = program;
}
private PSListenerConsoleSample program;
/// <summary>
/// Return the culture info to use - this implementation just snapshots the
/// culture info of the thread that created this object.
/// </summary>
public override CultureInfo CurrentCulture
{
get { return originalCultureInfo; }
}
private CultureInfo originalCultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture;
/// <summary>
/// Return the UI culture info to use - this implementation just snapshots the
/// UI culture info of the thread that created this object.
/// </summary>
public override CultureInfo CurrentUICulture
{
get { return originalUICultureInfo; }
}
private CultureInfo originalUICultureInfo = System.Threading.Thread.CurrentThread.CurrentUICulture;
/// <summary>
/// Not implemented by this example class. The call fails with an exception.
/// </summary>
public override void EnterNestedPrompt()
{
throw new NotImplementedException("Cannot suspend the shell, EnterNestedPrompt() method is not implemented by MyHost.");
}
/// <summary>
/// Not implemented by this example class. The call fails with an exception.
/// </summary>
public override void ExitNestedPrompt()
{
throw new NotImplementedException("The ExitNestedPrompt() method is not implemented by MyHost.");
}
private static Guid instanceId = Guid.NewGuid();
/// <summary>
/// This implementation always returns the GUID allocated at instantiation time.
/// </summary>
public override Guid InstanceId
{
get { return instanceId; }
}
/// <summary>
/// Return an appropriate string to identify your host implementation.
/// Keep in mind that this string may be used by script writers to identify
/// when your host is being used.
/// </summary>
public override string Name
{
get { return "MySampleConsoleHostImplementation"; }
}
/// <summary>
/// This API is called before an external application process is started. Typically
/// it's used to save state that the child process may alter so the parent can
/// restore that state when the child exits. In this sample, we don't need this so
/// the method simple returns.
/// </summary>
public override void NotifyBeginApplication()
{
return; // Do nothing...
}
/// <summary>
/// This API is called after an external application process finishes. Typically
/// it's used to restore state that the child process may have altered. In this
/// sample, we don't need this so the method simple returns.
/// </summary>
public override void NotifyEndApplication()
{
return; // Do nothing...
}
/// <summary>
/// Indicate to the host application that exit has
/// been requested. Pass the exit code that the host
/// application should use when exiting the process.
/// </summary>
/// <param name="exitCode"></param>
public override void SetShouldExit(int exitCode)
{
program.ShouldExit = true;
program.ExitCode = exitCode;
}
/// <summary>
/// Return an instance of the implementation of the PSHostUserInterface
/// class for this application. This instance is allocated once at startup time
/// and returned every time thereafter.
/// </summary>
public override PSHostUserInterface UI
{
get { return myHostUserInterface; }
}
private MyHostUserInterface myHostUserInterface = new MyHostUserInterface();
/// <summary>
/// Return the version object for this application. Typically this should match the version
/// resource in the application.
/// </summary>
public override Version Version
{
get {return new Version(1,0,0,0); }
}
}
}
Code Sample for PSHostUserInterface Implementation
Here is the complete code for the PSHostUserInterface implementation (MyHostUserInterface) for this hosting application.
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
namespace Microsoft.Samples.PowerShell.Host
{
/// <summary>
/// Sample implementation of the PSHostUserInterface class.
/// Note that not all members of this class are implemented.
/// Members that are not implemented usually throw a
/// NotImplementedException exception although some just do
/// nothing and silently return. Members that map onto the
/// existing .NET console APIs are supported. The credential and
/// secure string methods are not supported.
/// </summary>
class MyHostUserInterface : PSHostUserInterface
{
public override Dictionary<string, PSObject> Prompt(
string caption, string message,
Collection<FieldDescription> descriptions)
{
Write(ConsoleColor.Blue, ConsoleColor.Black,
caption + "\n" + message + " ");
Dictionary<string, PSObject> results =
new Dictionary<string, PSObject>();
foreach (FieldDescription fd in descriptions)
{
string[] label = GetHotkeyAndLabel(fd.Label);
WriteLine(label[1]);
string userData = Console.ReadLine();
if (userData == null)
return null;
results[fd.Name] = PSObject.AsPSObject(userData);
}
return results;
}
public override int PromptForChoice(
string caption, string message,
Collection<ChoiceDescription> choices, int defaultChoice)
{
// Write the caption and message strings in Blue.
WriteLine(ConsoleColor.Blue, ConsoleColor.Black,
caption + "\n" + message + "\n");
// Convert the choice collection into something that's a
// little easier to work with
// See the BuildHotkeysAndPlainLabels method for details.
Dictionary<string, PSObject> results =
new Dictionary<string, PSObject>();
string[,] promptData = BuildHotkeysAndPlainLabels(choices);
// Format the overall choice prompt string to display...
StringBuilder sb = new StringBuilder();
for (int element=0; element < choices.Count; element++)
{
sb.Append(String.Format("|{0}> {1} ",
promptData[0,element], promptData[1, element]));
}
sb.Append(String.Format("[Default is ({0}]",
promptData[0,defaultChoice]));
// Loop reading prompts until a match is made, the default is
// chosen or the loop is interrupted with ctrl-C.
while (true)
{
WriteLine(ConsoleColor.Cyan, ConsoleColor.Black, sb.ToString());
string data = Console.ReadLine().Trim()
.ToUpper(CultureInfo.CurrentCulture);
// If the choice string was empty, use the default selection.
if (data.Length == 0)
return defaultChoice;
// See if the selection matched and return the
// corresponding index if it did...
for (int i = 0; i < choices.Count; i++)
{
if (promptData[0, i] == data)
return i;
}
WriteErrorLine("Invalid choice: " + data);
}
}
/// <summary>
/// Parse a string containing a hotkey character.
///
/// Take a string of the form:
/// "Yes to &all"
/// And return a two-dimensional array split out as
/// "A", "Yes to all".
/// </summary>
/// <param name="input">The string to process</param>
/// <returns>
/// A two dimensional array containing the parsed components.
/// </returns>
private static string[] GetHotkeyAndLabel(string input)
{
string[] result = new string[] {String.Empty, String.Empty };
string[] fragments = input.Split('&');
if (fragments.Length == 2)
{
if (fragments[1].Length > 0)
result[0] = fragments[1][0].ToString().
ToUpper(CultureInfo.CurrentCulture);
result[1] = (fragments[0] + fragments[1]).Trim();
}
else
{
result[1] = input;
}
return result;
}
/// <summary>
/// This is a private worker function that splits out the
/// accelerator keys from the menu and builds a two dimentional
/// array with the first access containing the
/// accelerator and the second containing the label string
/// with & removed.
/// </summary>
/// <param name="choices">The choice collection to process</param>
/// <returns>
/// A two dimensional array containing the accelerator characters
/// and the cleaned-up labels</returns>
private static string[,] BuildHotkeysAndPlainLabels(
Collection<ChoiceDescription> choices)
{
// Allocate the result array
string[,] hotkeysAndPlainLabels = new string[2, choices.Count];
for (int i = 0; i < choices.Count; ++i)
{
string[] hotkeyAndLabel = GetHotkeyAndLabel(choices[i].Label);
hotkeysAndPlainLabels[0,i] = hotkeyAndLabel[0];
hotkeysAndPlainLabels[1,i] = hotkeyAndLabel[1];
}
return hotkeysAndPlainLabels;
}
public override PSCredential PromptForCredential(
string caption, string message, string userName, string targetName)
{
throw new NotImplementedException(
"The method PromptForCredential() is not implemented by MyHost.");
}
public override PSCredential PromptForCredential(
string caption, string message, string userName,
string targetName, PSCredentialTypes allowedCredentialTypes,
PSCredentialUIOptions options)
{
throw new NotImplementedException(
"The method PromptForCredential() is not implemented by MyHost.");
}
private MyRawUserInterface myRawUi = new MyRawUserInterface();
public override PSHostRawUserInterface RawUI
{
get { return myRawUi; }
}
public override string ReadLine()
{
return Console.ReadLine();
}
public override System.Security.SecureString ReadLineAsSecureString()
{
throw new NotImplementedException(
"The method ReadLineAsSecureString() is not implemented by MyHost.");
}
public override void Write(string value)
{
Console.Write(value); ;
}
public override void Write(ConsoleColor foregroundColor,
ConsoleColor backgroundColor, string value)
{
ConsoleColor oldFg = Console.ForegroundColor;
ConsoleColor oldBg = Console.BackgroundColor;
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.Write(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
}
public override void WriteLine(ConsoleColor foregroundColor,
ConsoleColor backgroundColor, string value)
{
ConsoleColor oldFg = Console.ForegroundColor;
ConsoleColor oldBg = Console.BackgroundColor;
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.WriteLine(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
}
public override void WriteDebugLine(string message)
{
this.WriteLine(ConsoleColor.DarkYellow, ConsoleColor.Black,
String.Format("DEBUG: {0}", message));
}
public override void WriteErrorLine(string value)
{
this.WriteLine(ConsoleColor.Red, ConsoleColor.Black, value);
}
public override void WriteLine()
{
Console.WriteLine();
}
public override void WriteLine(string value)
{
Console.WriteLine(value);
}
public override void WriteVerboseLine(string message)
{
this.WriteLine(ConsoleColor.Green, ConsoleColor.Black,
String.Format("VERBOSE: {0}", message));
}
public override void WriteWarningLine(string message)
{
this.WriteLine(ConsoleColor.Yellow, ConsoleColor.Black,
String.Format("WARNING: {0}", message));
}
/// <summary>
/// Progress is not implemented by this class. Since it's not
/// required for the cmdlet to work, it is better to do nothing
/// instead of throwing an exception.
/// </summary>
/// <param name="sourceId">See base class</param>
/// <param name="record">See base class</param>
public override void WriteProgress(long sourceId, ProgressRecord record)
{
; // Do nothing...
}
}
}
Code Sample for PSHostRawUserInterface Implementation
Here is the complete code for the PSHostRawUserInterface implementation (MyRawUserInterface) for this hosting application.
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
namespace Microsoft.Samples.PowerShell.Host
{
/// <summary>
/// A sample implementation of the PSHostRawUserInterface for a console
/// application. Members of this class that map trivially to the .NET console
/// class are implemented. More complex methods are not implemented and will
/// throw a NotImplementedException.
/// </summary>
class MyRawUserInterface : PSHostRawUserInterface
{
/// <summary>
/// Get and set the background color of text to be written.
/// This maps pretty directly onto the corresponding .NET Console
/// property.
/// </summary>
public override ConsoleColor BackgroundColor
{
get { return Console.BackgroundColor; }
set { Console.BackgroundColor = value; }
}
/// <summary>
/// Return the host buffer size adapted from the .NET Console buffer size.
/// </summary>
public override Size BufferSize
{
get { return new Size(Console.BufferWidth, Console.BufferHeight); }
set { Console.SetBufferSize(value.Width, value.Height); }
}
/// <summary>
/// This functionality is not currently implemented. The call fails with an exception.
/// </summary>
public override Coordinates CursorPosition
{
get { throw new NotImplementedException("The CursorPosition property is not implemented by MyRawUserInterface."); }
set { throw new NotImplementedException("The CursorPosition property is not implemented by MyRawUserInterface."); }
}
/// <summary>
/// Return the cursor size taken directly from the .NET Console cursor size.
/// </summary>
public override int CursorSize
{
get { return Console.CursorSize; }
set { Console.CursorSize = value; }
}
/// <summary>
/// This functionality is not currently implemented. The call simple returns silently.
/// </summary>
public override void FlushInputBuffer()
{
; //Do nothing...
}
/// <summary>
/// Get and set the foreground color of text to be written.
/// This maps closely onto the corresponding .NET Console property.
/// </summary>
public override ConsoleColor ForegroundColor
{
get { return Console.ForegroundColor; }
set { Console.ForegroundColor = value; }
}
/// <summary>
/// This functionality is not currently implemented. The call fails with an exception.
/// </summary>
/// <param name="rectangle">Unused</param>
/// <returns>Returns nothing - call fails.</returns>
public override BufferCell[,] GetBufferContents(Rectangle rectangle)
{
throw new NotImplementedException("The GetBufferContents method is not implemented by MyRawUserInterface.");
}
/// <summary>
/// Map directly to the corresponding .NET Console property.
/// </summary>
public override bool KeyAvailable
{
get { return Console.KeyAvailable; }
}
/// <summary>
/// Return the MaxPhysicalWindowSize size adapted from the .NET Console
/// LargestWindowWidth and LargestWindowHeight.
/// </summary>
public override Size MaxPhysicalWindowSize
{
get { return new Size(Console.LargestWindowWidth, Console.LargestWindowHeight); }
}
/// <summary>
/// Return the MaxWindowSize size adapted from the .NET Console
/// LargestWindowWidth and LargestWindowHeight.
/// </summary>
public override Size MaxWindowSize
{
get { return new Size(Console.LargestWindowWidth, Console.LargestWindowHeight); }
}
/// <summary>
/// This functionality is not currently implemented. The call fails with an exception.
/// </summary>
/// <param name="options">Unused</param>
/// <returns>Nothing</returns>
public override KeyInfo ReadKey(ReadKeyOptions options)
{
throw new NotImplementedException("The ReadKey() method is not implemented by MyRawUserInterface.");
}
/// <summary>
/// This functionality is not currently implemented. The call fails with an exception.
/// </summary>
/// <param name="source">Unused</param>
/// <param name="destination">Unused</param>
/// <param name="clip">Unused</param>
/// <param name="fill">Unused</param>
public override void ScrollBufferContents(Rectangle source, Coordinates destination, Rectangle clip, BufferCell fill)
{
throw new NotImplementedException("The ScrollBufferContents() method is not implemented by MyRawUserInterface.");
}
/// <summary>
/// This functionality is not currently implemented. The call fails with an exception.
/// </summary>
/// <param name="origin">Unused</param>
/// <param name="contents">Unused</param>
public override void SetBufferContents(Coordinates origin, BufferCell[,] contents)
{
throw new NotImplementedException("The SetBufferContents() method is not implemented by MyRawUserInterface.");
}
/// <summary>
/// This functionality is not currently implemented. The call fails with an exception.
/// </summary>
/// <param name="rectangle">Unused</param>
/// <param name="fill">Unused</param>
public override void SetBufferContents(Rectangle rectangle, BufferCell fill)
{
throw new NotImplementedException("The SetBufferContents() method is not implemented by MyRawUserInterface.");
}
/// <summary>
/// Return the window position adapted from the Console window position information.
/// </summary>
public override Coordinates WindowPosition
{
get { return new Coordinates(Console.WindowLeft, Console.WindowTop); }
set { Console.SetWindowPosition(value.X, value.Y); }
}
/// <summary>
/// Return the window size adapted from the corresponding .NET Console calls.
/// </summary>
public override Size WindowSize
{
get { return new Size(Console.WindowWidth, Console.WindowHeight); }
set { Console.SetWindowSize(value.Width, value.Height); }
}
/// <summary>
/// Mapped to the Console.Title property.
/// </summary>
public override string WindowTitle
{
get { return Console.Title; }
set { Console.Title = value; }
}
}
}
See Also