mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
added a new host based on Sample06 from msdn, added docker testing support
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
# image_ps
|
||||
#
|
||||
# VERSION 0.0.2
|
||||
|
||||
FROM ubuntu:14.04
|
||||
MAINTAINER Peter Honeder <peterhon@microsoft.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y openssh-server wget libstdc++6 libunwind8
|
||||
RUN mkdir /var/run/sshd
|
||||
#RUN echo 'root:asldkfj23l4kj2lkajsdf' | chpasswd
|
||||
RUN echo 'root:pass' | chpasswd
|
||||
RUN adduser --shell /opt/app_base/runps.sh --disabled-password --gecos "" test1
|
||||
RUN echo 'test1:pass' | chpasswd
|
||||
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config
|
||||
|
||||
RUN cd /root && wget https://github.com/anilgulecha/shellinabox/releases/download/2.14.2/shellinabox_2.14-1_amd64.deb
|
||||
RUN dpkg -i /root/shellinabox_2.14-1_amd64.deb
|
||||
|
||||
# SSH login fix. Otherwise user is kicked off after login
|
||||
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
|
||||
|
||||
ENV NOTVISIBLE "in users profile"
|
||||
RUN echo "export VISIBLE=now" >> /etc/profile
|
||||
|
||||
COPY exec_env/app_base/ /opt/app_base/
|
||||
RUN chmod -R ugo+rX /opt/app_base
|
||||
|
||||
EXPOSE 22
|
||||
EXPOSE 4201
|
||||
#CMD /usr/sbin/sshd && /usr/bin/shellinaboxd -s /:AUTH:HOME:/home/test1/app_base/runps.sh -p 4201 -t -v
|
||||
CMD /usr/sbin/sshd && /usr/bin/shellinaboxd -s /:LOGIN -p 4201 -t -v
|
||||
|
||||
+27
-7
@@ -21,6 +21,9 @@ include platform.mk
|
||||
# builds unit tests
|
||||
include tests.mk
|
||||
|
||||
# powershell-run is the main powershell executable
|
||||
include powershell-run.mk
|
||||
|
||||
# These are the main PS dlls:
|
||||
# - System.Management.Automation.dll (the main PS dll)
|
||||
# - commands/modules (they contain cmdlets): management and utility
|
||||
@@ -54,7 +57,7 @@ SRCS_ALL=${STRING_RESOURCES} ${SRCS}
|
||||
CSC=mono Microsoft.Net.ToolsetCompilers.*/tools/csc.exe
|
||||
MCS=mcs
|
||||
|
||||
all: dotnetlibs/System.Management.Automation.dll dotnetlibs/powershell-run.exe dotnetlibs/Microsoft.PowerShell.Commands.Management.dll dotnetlibs/Microsoft.PowerShell.Commands.Utility.dll dotnetlibs/$(ASSEMBLY_LOAD_CONTEXT_TARGET)
|
||||
all: dotnetlibs/System.Management.Automation.dll $(POWERSHELL_RUN_TARGETS) dotnetlibs/Microsoft.PowerShell.Commands.Management.dll dotnetlibs/Microsoft.PowerShell.Commands.Utility.dll dotnetlibs/$(ASSEMBLY_LOAD_CONTEXT_TARGET)
|
||||
|
||||
# this is the build rule for SMA.dll
|
||||
dotnetlibs/System.Management.Automation.dll: ${SYS_AUTO_SRCS} dotnetlibs/Microsoft.Management.Infrastructure.dll ../src/assembly-info/System.Management.Automation.assembly-info.cs dotnetlibs/$(ASSEMBLY_LOAD_CONTEXT_TARGET) $(PLATFORM_SRCS) ${SYS_AUTO_RES_SRCS} ${SYS_AUTO_RES_CS_SRCS}
|
||||
@@ -98,9 +101,6 @@ TypeCatalogGen.exe: ../src/monad/monad/nttargets/assemblies/core/PSAssemblyLoadC
|
||||
CorePsTypeCatalog.cs: powershell-linux.inc TypeCatalogGen.exe System.Reflection.Metadata.dll System.Collections.Immutable.dll
|
||||
LD_LIBRARY_PATH=. mono TypeCatalogGen.exe powershell-linux.inc $@ $(MONAD_EXT)/coreclr/TargetingPack
|
||||
|
||||
dotnetlibs/powershell-run.exe: ../src/powershell-run/powershell-run.cs dotnetlibs/System.Management.Automation.dll dotnetlibs/Microsoft.PowerShell.Commands.Management.dll dotnetlibs/$(ASSEMBLY_LOAD_CONTEXT_TARGET)
|
||||
$(CSC) -out:$@ -noconfig -nostdlib -target:exe -r:dotnetlibs/System.Management.Automation.dll -r:dotnetlibs/$(ASSEMBLY_LOAD_CONTEXT_TARGET) ${COREREF} ../src/powershell-run/powershell-run.cs
|
||||
|
||||
# the pinvoke library libps.so
|
||||
|
||||
libps-build/Makefile: ../src/monad-native/src/CMakeLists.txt
|
||||
@@ -137,7 +137,7 @@ prepare:
|
||||
nuget install Microsoft.Net.ToolsetCompilers -pre
|
||||
|
||||
# this is an internal target, it's not intended to be called manually
|
||||
internal-prepare-exec_env:
|
||||
internal-prepare-exec_env: runps.sh
|
||||
rm -rf exec_env
|
||||
mkdir exec_env
|
||||
cp -r ../src/monad_app_base/app_base exec_env
|
||||
@@ -145,17 +145,23 @@ internal-prepare-exec_env:
|
||||
cp -r dotnetlibs/*.exe exec_env/app_base
|
||||
cp -r dotnetlibs/lib* exec_env/app_base
|
||||
cp -r dotnetlibs/corerun exec_env/app_base
|
||||
cp runps.sh exec_env/app_base
|
||||
|
||||
run: dotnetlibs/powershell-run.exe dotnetlibs/corerun dotnetlibs/Microsoft.PowerShell.Commands.Management.dll dotnetlibs/Microsoft.PowerShell.Commands.Utility.dll dotnetlibs/api-ms-win-core-registry-l1-1-0.dll internal-prepare-exec_env
|
||||
run: $(POWERSHELL_RUN_TARGETS) dotnetlibs/corerun dotnetlibs/Microsoft.PowerShell.Commands.Management.dll dotnetlibs/Microsoft.PowerShell.Commands.Utility.dll dotnetlibs/api-ms-win-core-registry-l1-1-0.dll internal-prepare-exec_env
|
||||
# check if corerun is the right one (could be the debug version)
|
||||
if ! diff dotnetlibs/corerun $(MONAD_EXT)/coreclr/Release/corerun; then cp -r $(MONAD_EXT)/coreclr/Release/* dotnetlibs; fi
|
||||
#cd exec_env/app_base && PSMODULEPATH=. LD_LIBRARY_PATH=. ./corerun powershell-run.exe "\"test blah\""
|
||||
#cd exec_env/app_base && PSMODULEPATH=. LD_LIBRARY_PATH=. ./corerun powershell-run.exe "get-module -listavailable"
|
||||
#cd exec_env/app_base && PSMODULEPATH=. LD_LIBRARY_PATH=. ./corerun powershell-run.exe "get-module -listavailable -all"
|
||||
#cd exec_env/app_base && PSMODULEPATH=$(shell pwd)/exec_env/app_base/Modules LD_LIBRARY_PATH=. ./corerun powershell-run.exe "import-module -name Microsoft.PowerShell.Utility"
|
||||
cd exec_env/app_base && PSMODULEPATH=$(shell pwd)/exec_env/app_base/Modules LD_LIBRARY_PATH=. ./corerun powershell-run.exe "import-module -name Microsoft.PowerShell.Utility" '"a","b","c","a","a" | Select-Object -Unique'
|
||||
cd exec_env/app_base && PSMODULEPATH=$(shell pwd)/exec_env/app_base/Modules LD_LIBRARY_PATH=. ./corerun powershell-simple.exe "import-module -name Microsoft.PowerShell.Utility" '"a","b","c","a","a" | Select-Object -Unique'
|
||||
#LD_LIBRARY_PATH=exec_env/app_base exec_env/app_base/corerun exec_env/app_base/powershell-run.exe "\"Hello World!\" |out-default"
|
||||
|
||||
run-interactive: $(POWERSHELL_RUN_TARGETS) dotnetlibs/corerun dotnetlibs/Microsoft.PowerShell.Commands.Management.dll dotnetlibs/Microsoft.PowerShell.Commands.Utility.dll dotnetlibs/api-ms-win-core-registry-l1-1-0.dll internal-prepare-exec_env
|
||||
# check if corerun is the right one (could be the debug version)
|
||||
if ! diff dotnetlibs/corerun $(MONAD_EXT)/coreclr/Release/corerun; then cp -r $(MONAD_EXT)/coreclr/Release/* dotnetlibs; fi
|
||||
cd exec_env/app_base && ./runps.sh
|
||||
|
||||
test: dotnetlibs/ps_test_runner.exe dotnetlibs/corerun dotnetlibs/api-ms-win-core-registry-l1-1-0.dll
|
||||
cd dotnetlibs && LD_LIBRARY_PATH=. ./corerun ps_test_runner.exe
|
||||
|
||||
@@ -184,3 +190,17 @@ clean:
|
||||
cleanall: clean
|
||||
rm -rf System.Reflection.Metadata.* System.Collections.Immutable.*
|
||||
|
||||
docker-build:
|
||||
sudo docker build --no-cache=false -t image_ps .
|
||||
$(eval INSTANCE_ID := $(shell sudo docker inspect -f '{{.Id}}' image_ps))
|
||||
rm -rf
|
||||
|
||||
docker-run: docker-build
|
||||
sudo docker run -d -P --name test_ps image_ps
|
||||
sudo docker port test_ps 22
|
||||
sudo docker port test_ps 4201
|
||||
|
||||
docker-stop:
|
||||
sudo docker stop test_ps
|
||||
sudo docker rm test_ps
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# This is the makefile for all kinds of powershell hosts
|
||||
#
|
||||
# Currently there is powershell-run.exe, which is a very generic interactive and
|
||||
# non-interactive host
|
||||
#
|
||||
|
||||
POWERSHELL_RUN_FOLDER=../src/powershell-run
|
||||
POWERSHELL_RUN_SRCS=$(addprefix $(POWERSHELL_RUN_FOLDER)/, main.cs host.cs ui.cs rawui.cs readline.cs)
|
||||
|
||||
# direct dependencies to be linked in
|
||||
POWERSHELL_RUN_DEPS=dotnetlibs/System.Management.Automation.dll dotnetlibs/Microsoft.PowerShell.Commands.Management.dll dotnetlibs/$(ASSEMBLY_LOAD_CONTEXT_TARGET)
|
||||
POWERSHELL_RUN_REFS=$(addprefix -r:,$(POWERSHELL_RUN_DEPS))
|
||||
|
||||
POWERSHELL_RUN_TARGETS=dotnetlibs/powershell-run.exe dotnetlibs/powershell-simple.exe
|
||||
|
||||
dotnetlibs/powershell-run.exe: $(POWERSHELL_RUN_SRCS) $(POWERSHELL_RUN_DEPS)
|
||||
$(CSC) -out:$@ -noconfig -nostdlib -target:exe $(POWERSHELL_RUN_REFS) $(COREREF) $(POWERSHELL_RUN_SRCS)
|
||||
|
||||
dotnetlibs/powershell-simple.exe: $(POWERSHELL_RUN_FOLDER)/powershell-run.cs $(POWERSHELL_RUN_DEPS)
|
||||
$(CSC) -out:$@ -noconfig -nostdlib -target:exe $(POWERSHELL_RUN_REFS) $(COREREF) $(POWERSHELL_RUN_FOLDER)/powershell-run.cs
|
||||
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPTDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
|
||||
cd $SCRIPTDIR
|
||||
echo "launching PS now"
|
||||
PSMODULEPATH=$SCRIPTDIR/Modules LD_LIBRARY_PATH=. ./corerun powershell-run.exe
|
||||
|
||||
+1
-1
Submodule src/monad-ext updated: 9fb89ce1df...4bb973e987
@@ -0,0 +1,217 @@
|
||||
namespace Microsoft.Samples.PowerShell.Host
|
||||
{
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Management.Automation.Host;
|
||||
using System.Management.Automation.Runspaces;
|
||||
|
||||
/// <summary>
|
||||
/// This is 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 or
|
||||
/// return nothing.
|
||||
/// </summary>
|
||||
internal class MyHost : PSHost, IHostSupportsInteractiveSession
|
||||
{
|
||||
public MyHost(PSListenerConsoleSample program)
|
||||
{
|
||||
this.program = program;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the PSHost implementation.
|
||||
/// </summary>
|
||||
private PSListenerConsoleSample program;
|
||||
|
||||
/// <summary>
|
||||
/// The culture information of the thread that created
|
||||
/// this object.
|
||||
/// </summary>
|
||||
private CultureInfo originalCultureInfo = CultureInfo.CurrentCulture;
|
||||
|
||||
/// <summary>
|
||||
/// The UI culture information of the thread that created
|
||||
/// this object.
|
||||
/// </summary>
|
||||
private CultureInfo originalUICultureInfo = CultureInfo.CurrentCulture;
|
||||
|
||||
/// <summary>
|
||||
/// The identifier of this PSHost implementation.
|
||||
/// </summary>
|
||||
private static Guid instanceId = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the implementation of the PSHostUserInterface
|
||||
/// class for this application.
|
||||
/// </summary>
|
||||
private MyHostUserInterface myHostUserInterface = new MyHostUserInterface();
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the runspace used to start an interactive session.
|
||||
/// </summary>
|
||||
public Runspace pushedRunspace = null;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the culture information to use. This implementation
|
||||
/// returns a snapshot of the culture information of the thread
|
||||
/// that created this object.
|
||||
/// </summary>
|
||||
public override CultureInfo CurrentCulture
|
||||
{
|
||||
get { return this.originalCultureInfo; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the UI culture information to use. This implementation
|
||||
/// returns a snapshot of the UI culture information of the thread
|
||||
/// that created this object.
|
||||
/// </summary>
|
||||
public override CultureInfo CurrentUICulture
|
||||
{
|
||||
get { return this.originalUICultureInfo; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an identifier for this host. This implementation always
|
||||
/// returns the GUID allocated at instantiation time.
|
||||
/// </summary>
|
||||
public override Guid InstanceId
|
||||
{
|
||||
get { return instanceId; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string that contains the name of this 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>
|
||||
/// Gets 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 this.myHostUserInterface; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets 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); }
|
||||
}
|
||||
|
||||
#region IHostSupportsInteractiveSession Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a request
|
||||
/// to open a PSSession has been made.
|
||||
/// </summary>
|
||||
public bool IsRunspacePushed
|
||||
{
|
||||
get { return this.pushedRunspace != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the runspace used by the PSSession.
|
||||
/// </summary>
|
||||
public Runspace Runspace
|
||||
{
|
||||
get { return this.program.myRunSpace; }
|
||||
internal set { this.program.myRunSpace = value; }
|
||||
}
|
||||
#endregion IHostSupportsInteractiveSession Properties
|
||||
|
||||
/// <summary>
|
||||
/// This API Instructs the host to interrupt the currently running
|
||||
/// pipeline and start a new nested input loop. In this example this
|
||||
/// functionality is not needed so the method throws a
|
||||
/// NotImplementedException exception.
|
||||
/// </summary>
|
||||
public override void EnterNestedPrompt()
|
||||
{
|
||||
throw new NotImplementedException(
|
||||
"The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This API instructs the host to exit the currently running input loop.
|
||||
/// In this example this functionality is not needed so the method
|
||||
/// throws a NotImplementedException exception.
|
||||
/// </summary>
|
||||
public override void ExitNestedPrompt()
|
||||
{
|
||||
throw new NotImplementedException(
|
||||
"The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This API is called before an external application process is
|
||||
/// started. Typically it is used to save state so that the parent
|
||||
/// can restore state that has been modified by a child process (after
|
||||
/// the child exits). In this example this functionality is not
|
||||
/// needed so the method returns nothing.
|
||||
/// </summary>
|
||||
public override void NotifyBeginApplication()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This API is called after an external application process finishes.
|
||||
/// Typically it is used to restore state that a child process has
|
||||
/// altered. In this example, this functionality is not needed so
|
||||
/// the method returns nothing.
|
||||
/// </summary>
|
||||
public override void NotifyEndApplication()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/// <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">The exit code that the
|
||||
/// host application should use.</param>
|
||||
public override void SetShouldExit(int exitCode)
|
||||
{
|
||||
this.program.ShouldExit = true;
|
||||
this.program.ExitCode = exitCode;
|
||||
}
|
||||
|
||||
#region IHostSupportsInteractiveSession Methods
|
||||
|
||||
/// <summary>
|
||||
/// Requests to close a PSSession.
|
||||
/// </summary>
|
||||
public void PopRunspace()
|
||||
{
|
||||
Runspace = this.pushedRunspace;
|
||||
this.pushedRunspace = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests to open a PSSession.
|
||||
/// </summary>
|
||||
/// <param name="runspace">Runspace to use.</param>
|
||||
public void PushRunspace(Runspace runspace)
|
||||
{
|
||||
this.pushedRunspace = Runspace;
|
||||
Runspace = runspace;
|
||||
}
|
||||
|
||||
#endregion IHostSupportsInteractiveSession Methods
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
namespace Microsoft.Samples.PowerShell.Host
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Host;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Text;
|
||||
using PowerShell = System.Management.Automation.PowerShell;
|
||||
|
||||
/// <summary>
|
||||
/// This sample shows how to implement a basic read-evaluate-print
|
||||
/// loop (or 'listener') that allowing you to interactively work
|
||||
/// with the Windows PowerShell engine.
|
||||
/// </summary>
|
||||
internal class PSListenerConsoleSample
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to read user input.
|
||||
/// </summary>
|
||||
internal ConsoleReadLine consoleReadLine = new ConsoleReadLine();
|
||||
|
||||
/// <summary>
|
||||
/// Holds a reference to the runspace for this interpeter.
|
||||
/// </summary>
|
||||
internal Runspace myRunSpace;
|
||||
|
||||
/// <summary>
|
||||
/// Indicator to tell the host application that it should exit.
|
||||
/// </summary>
|
||||
private bool shouldExit;
|
||||
|
||||
/// <summary>
|
||||
/// The exit code that the host application will use to exit.
|
||||
/// </summary>
|
||||
private int exitCode;
|
||||
|
||||
/// <summary>
|
||||
/// Holds a reference to the PSHost implementation for this interpreter.
|
||||
/// </summary>
|
||||
private MyHost myHost;
|
||||
|
||||
/// <summary>
|
||||
/// Holds a reference to the currently executing pipeline so that it can be
|
||||
/// stopped by the control-C handler.
|
||||
/// </summary>
|
||||
private PowerShell currentPowerShell;
|
||||
|
||||
/// <summary>
|
||||
/// Used to serialize access to instance data.
|
||||
/// </summary>
|
||||
private object instanceLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the host application
|
||||
/// should exit.
|
||||
/// </summary>
|
||||
public bool ShouldExit
|
||||
{
|
||||
get { return this.shouldExit; }
|
||||
set { this.shouldExit = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the host application
|
||||
/// should exit.
|
||||
/// </summary>
|
||||
public int ExitCode
|
||||
{
|
||||
get { return this.exitCode; }
|
||||
set { this.exitCode = value; }
|
||||
}
|
||||
|
||||
public static void init()
|
||||
{
|
||||
string psBasePath = System.IO.Directory.GetCurrentDirectory();
|
||||
PowerShellAssemblyLoadContextInitializer.SetPowerShellAssemblyLoadContext(psBasePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and initiates the listener instance.
|
||||
/// </summary>
|
||||
/// <param name="args">This parameter is not used.</param>
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
init();
|
||||
|
||||
// Display the welcome message.
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("PowerShell for Linux interactive console");
|
||||
Console.WriteLine("========================================");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Current status:");
|
||||
Console.WriteLine("- Type 'exit' to exit");
|
||||
Console.WriteLine("- Utility and Management cmdlet modules are loadable");
|
||||
Console.WriteLine();
|
||||
//Console.ForegroundColor = oldFg;
|
||||
|
||||
// Create the listener and run it. This method never returns.
|
||||
PSListenerConsoleSample listener = new PSListenerConsoleSample();
|
||||
listener.Run();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the PSListenerConsoleSample class.
|
||||
/// </summary>
|
||||
public PSListenerConsoleSample()
|
||||
{
|
||||
// Create the host and runspace instances for this interpreter.
|
||||
// Note that this application does not support console files so
|
||||
// only the default snap-ins will be available.
|
||||
this.myHost = new MyHost(this);
|
||||
InitialSessionState iss = InitialSessionState.CreateDefault2();
|
||||
this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost,iss);
|
||||
this.myRunSpace.Open();
|
||||
|
||||
// Create a PowerShell object to run the commands used to create
|
||||
// $profile and load the profiles.
|
||||
lock (this.instanceLock)
|
||||
{
|
||||
this.currentPowerShell = PowerShell.Create();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.currentPowerShell.Runspace = this.myRunSpace;
|
||||
|
||||
/* PSCommand[] profileCommands = Microsoft.Samples.PowerShell.Host.HostUtilities.GetProfileCommands("SampleHost06");
|
||||
foreach (PSCommand command in profileCommands)
|
||||
{
|
||||
this.currentPowerShell.Commands = command;
|
||||
this.currentPowerShell.Invoke();
|
||||
}*/
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Dispose the PowerShell object and set currentPowerShell
|
||||
// to null. It is locked because currentPowerShell may be
|
||||
// accessed by the ctrl-C handler.
|
||||
lock (this.instanceLock)
|
||||
{
|
||||
this.currentPowerShell.Dispose();
|
||||
this.currentPowerShell = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 does not 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>
|
||||
private 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 currentPowerShell instance
|
||||
// variable.
|
||||
lock (this.instanceLock)
|
||||
{
|
||||
this.currentPowerShell = PowerShell.Create();
|
||||
}
|
||||
|
||||
// Add a script and command to the pipeline and then run the pipeline. Place
|
||||
// the results in the currentPowerShell variable so that the pipeline can be
|
||||
// stopped.
|
||||
try
|
||||
{
|
||||
this.currentPowerShell.Runspace = this.myRunSpace;
|
||||
|
||||
this.currentPowerShell.AddScript(cmd);
|
||||
|
||||
// Add the default outputter to the end of the pipe and then call the
|
||||
// MergeMyResults method to merge the output and error streams from the
|
||||
// pipeline. This will result in the output being written using the PSHost
|
||||
// and PSHostUserInterface classes instead of returning objects to the host
|
||||
// application.
|
||||
this.currentPowerShell.AddCommand("out-default");
|
||||
this.currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
|
||||
|
||||
// If there is any input pass it in, otherwise just invoke the
|
||||
// the pipeline.
|
||||
if (input != null)
|
||||
{
|
||||
this.currentPowerShell.Invoke(new object[] { input });
|
||||
}
|
||||
else
|
||||
{
|
||||
this.currentPowerShell.Invoke();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Dispose the PowerShell object and set currentPowerShell to null.
|
||||
// It is locked because currentPowerShell may be accessed by the
|
||||
// ctrl-C handler.
|
||||
lock (this.instanceLock)
|
||||
{
|
||||
this.currentPowerShell.Dispose();
|
||||
this.currentPowerShell = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To display an exception using the display formatter,
|
||||
/// 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 the Out-String
|
||||
/// cmdlet. The WriteErrorLine method is called to make sure
|
||||
/// the error gets displayed in the correct error color.
|
||||
/// </summary>
|
||||
/// <param name="e">The exception to display.</param>
|
||||
private void ReportException(Exception e)
|
||||
{
|
||||
if (e != null)
|
||||
{
|
||||
object error;
|
||||
IContainsErrorRecord icer = e as IContainsErrorRecord;
|
||||
if (icer != null)
|
||||
{
|
||||
error = icer.ErrorRecord;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = (object)new ErrorRecord(e, "Host.ReportException", ErrorCategory.NotSpecified, null);
|
||||
}
|
||||
|
||||
lock (this.instanceLock)
|
||||
{
|
||||
this.currentPowerShell = PowerShell.Create();
|
||||
}
|
||||
|
||||
this.currentPowerShell.Runspace = this.myRunSpace;
|
||||
|
||||
try
|
||||
{
|
||||
this.currentPowerShell.AddScript("$input").AddCommand("out-string");
|
||||
|
||||
// Do not merge errors, this function will swallow errors.
|
||||
Collection<PSObject> result;
|
||||
PSDataCollection<object> inputCollection = new PSDataCollection<object>();
|
||||
inputCollection.Add(error);
|
||||
inputCollection.Complete();
|
||||
result = this.currentPowerShell.Invoke(inputCollection);
|
||||
|
||||
if (result.Count > 0)
|
||||
{
|
||||
string str = result[0].BaseObject as string;
|
||||
if (!string.IsNullOrEmpty(str))
|
||||
{
|
||||
// Remove \r\n, which is added by the Out-String cmdlet.
|
||||
this.myHost.UI.WriteErrorLine(str.Substring(0, str.Length - 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Dispose of the pipeline and set it to null, locking it because
|
||||
// currentPowerShell may be accessed by the ctrl-C handler.
|
||||
lock (this.instanceLock)
|
||||
{
|
||||
this.currentPowerShell.Dispose();
|
||||
this.currentPowerShell = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Basic script execution routine. Any runtime exceptions are
|
||||
/// caught and passed back to the Windows PowerShell engine to
|
||||
/// display.
|
||||
/// </summary>
|
||||
/// <param name="cmd">Script to run.</param>
|
||||
private void Execute(string cmd)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Run the command with no input.
|
||||
this.executeHelper(cmd, null);
|
||||
}
|
||||
catch (RuntimeException rte)
|
||||
{
|
||||
this.ReportException(rte);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 but otherwise ignored.
|
||||
/// </summary>
|
||||
/// <param name="sender">See sender property documentation of
|
||||
/// ConsoleCancelEventHandler.</param>
|
||||
/// <param name="e">See e property documentation of
|
||||
/// ConsoleCancelEventHandler.</param>
|
||||
private void HandleControlC(object sender, ConsoleCancelEventArgs e)
|
||||
{
|
||||
Console.WriteLine("HandleControlC");
|
||||
try
|
||||
{
|
||||
lock (this.instanceLock)
|
||||
{
|
||||
if (this.currentPowerShell != null && this.currentPowerShell.InvocationStateInfo.State == PSInvocationState.Running)
|
||||
{
|
||||
this.currentPowerShell.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(this.HandleControlC);
|
||||
//Console.TreatControlCAsInput = false;
|
||||
|
||||
// Read commands and run them until the ShouldExit flag is set by
|
||||
// the user calling "exit".
|
||||
while (!this.ShouldExit)
|
||||
{
|
||||
string prompt;
|
||||
if (this.myHost.IsRunspacePushed)
|
||||
{
|
||||
prompt = string.Format("\n[{0}] PSConsoleSample: ", this.myRunSpace.ConnectionInfo.ComputerName);
|
||||
}
|
||||
else
|
||||
{
|
||||
prompt = "\nPSConsoleSample: ";
|
||||
}
|
||||
|
||||
this.myHost.UI.Write(ConsoleColor.White, ConsoleColor.Black, prompt);
|
||||
// string cmd = this.consoleReadLine.Read();
|
||||
string cmd = Console.ReadLine();
|
||||
this.Execute(cmd);
|
||||
}
|
||||
|
||||
// Exit with the desired exit code that was set by the exit command.
|
||||
// The exit code is set in the host by the MyHost.SetShouldExit() method.
|
||||
//Environment.Exit(this.ExitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Management.Automation.Host;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.Samples.PowerShell.Host
|
||||
{
|
||||
// this is all from https://msdn.microsoft.com/en-us/library/ee706570%28v=vs.85%29.aspx
|
||||
|
||||
internal class MyRawUserInterface : PSHostRawUserInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the background color of the displayed text.
|
||||
/// This maps to the corresponding Console.Background property.
|
||||
/// </summary>
|
||||
public override ConsoleColor BackgroundColor
|
||||
{
|
||||
get { return Console.BackgroundColor; }
|
||||
set { Console.BackgroundColor = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size of the host buffer. In this example the
|
||||
/// buffer size is adapted from the Console buffer size members.
|
||||
/// </summary>
|
||||
public override Size BufferSize
|
||||
{
|
||||
get { return new Size(200,500); }
|
||||
set { }
|
||||
//get { return new Size(Console.BufferWidth, Console.BufferHeight); }
|
||||
//set { Console.SetBufferSize(value.Width, value.Height); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the cursor position. In this example this
|
||||
/// functionality is not needed so the property throws a
|
||||
/// NotImplementException exception.
|
||||
/// </summary>
|
||||
public override Coordinates CursorPosition
|
||||
{
|
||||
get { throw new NotImplementedException(
|
||||
"The method or operation is not implemented."); }
|
||||
set { throw new NotImplementedException(
|
||||
"The method or operation is not implemented."); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size of the displayed cursor. In this example
|
||||
/// the cursor size is taken directly from the Console.CursorSize
|
||||
/// property.
|
||||
/// </summary>
|
||||
public override int CursorSize
|
||||
{
|
||||
get { return 12; }
|
||||
set { }
|
||||
//get { return Console.CursorSize; }
|
||||
//set { Console.CursorSize = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the foreground color of the displayed text.
|
||||
/// This maps to the corresponding Console.ForgroundColor property.
|
||||
/// </summary>
|
||||
public override ConsoleColor ForegroundColor
|
||||
{
|
||||
get { return Console.ForegroundColor; }
|
||||
set { Console.ForegroundColor = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the user has pressed a key. This maps
|
||||
/// to the corresponding Console.KeyAvailable property.
|
||||
/// </summary>
|
||||
public override bool KeyAvailable
|
||||
{
|
||||
get { return false; }
|
||||
// get { return Console.KeyAvailable; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dimensions of the largest window that could be
|
||||
/// rendered in the current display, if the buffer was at the least
|
||||
/// that large. This example uses the Console.LargestWindowWidth and
|
||||
/// Console.LargestWindowHeight properties to determine the returned
|
||||
/// value of this property.
|
||||
/// </summary>
|
||||
public override Size MaxPhysicalWindowSize
|
||||
{
|
||||
// get { return new Size(Console.LargestWindowWidth, Console.LargestWindowHeight); }
|
||||
get { return new Size(1024,768); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dimentions of the largest window size that can be
|
||||
/// displayed. This example uses the Console.LargestWindowWidth and
|
||||
/// console.LargestWindowHeight properties to determine the returned
|
||||
/// value of this property.
|
||||
/// </summary>
|
||||
public override Size MaxWindowSize
|
||||
{
|
||||
// get { return new Size(Console.LargestWindowWidth, Console.LargestWindowHeight); }
|
||||
get { return new Size(1024,768); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the position of the displayed window. This example
|
||||
/// uses the Console window position APIs to determine the returned
|
||||
/// value of this property.
|
||||
/// </summary>
|
||||
public override Coordinates WindowPosition
|
||||
{
|
||||
// get { return new Coordinates(Console.WindowLeft, Console.WindowTop); }
|
||||
// set { Console.SetWindowPosition(value.X, value.Y); }
|
||||
get { return new Coordinates(0,0); }
|
||||
set { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size of the displayed window. This example
|
||||
/// uses the corresponding Console window size APIs to determine the
|
||||
/// returned value of this property.
|
||||
/// </summary>
|
||||
public override Size WindowSize
|
||||
{
|
||||
// get { return new Size(Console.WindowWidth, Console.WindowHeight); }
|
||||
// set { Console.SetWindowSize(value.Width, value.Height); }
|
||||
get { return new Size(1024,768); }
|
||||
set { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title of the displayed window. The example
|
||||
/// maps the Console.Title property to the value of this property.
|
||||
/// </summary>
|
||||
public override string WindowTitle
|
||||
{
|
||||
// get { return Console.Title; }
|
||||
// set { Console.Title = value; }
|
||||
get { return "window title"; }
|
||||
set { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This API resets the input buffer. In this example this
|
||||
/// functionality is not needed so the method returns nothing.
|
||||
/// </summary>
|
||||
public override void FlushInputBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This API returns a rectangular region of the screen buffer. In
|
||||
/// this example this functionality is not needed so the method throws
|
||||
/// a NotImplementException exception.
|
||||
/// </summary>
|
||||
/// <param name="rectangle">Defines the size of the rectangle.</param>
|
||||
/// <returns>Throws a NotImplementedException exception.</returns>
|
||||
public override BufferCell[,] GetBufferContents(Rectangle rectangle)
|
||||
{
|
||||
throw new NotImplementedException(
|
||||
"The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This API reads a pressed, released, or pressed and released keystroke
|
||||
/// from the keyboard device, blocking processing until a keystroke is
|
||||
/// typed that matches the specified keystroke options. In this example
|
||||
/// this functionality is not needed so the method throws a
|
||||
/// NotImplementException exception.
|
||||
/// </summary>
|
||||
/// <param name="options">Options, such as IncludeKeyDown, used when
|
||||
/// reading the keyboard.</param>
|
||||
/// <returns>Throws a NotImplementedException exception.</returns>
|
||||
public override KeyInfo ReadKey(ReadKeyOptions options)
|
||||
{
|
||||
throw new NotImplementedException(
|
||||
"The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This API crops a region of the screen buffer. In this example
|
||||
/// this functionality is not needed so the method throws a
|
||||
/// NotImplementException exception.
|
||||
/// </summary>
|
||||
/// <param name="source">The region of the screen to be scrolled.</param>
|
||||
/// <param name="destination">The region of the screen to receive the
|
||||
/// source region contents.</param>
|
||||
/// <param name="clip">The region of the screen to include in the operation.</param>
|
||||
/// <param name="fill">The character and attributes to be used to fill all cell.</param>
|
||||
public override void ScrollBufferContents(Rectangle source, Coordinates destination, Rectangle clip, BufferCell fill)
|
||||
{
|
||||
throw new NotImplementedException(
|
||||
"The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method copies an array of buffer cells into the screen buffer
|
||||
/// at a specified location. In this example this functionality is
|
||||
/// not needed so the method throws a NotImplementedException exception.
|
||||
/// </summary>
|
||||
/// <param name="origin">The parameter is not used.</param>
|
||||
/// <param name="contents">The parameter is not used.</param>
|
||||
public override void SetBufferContents(Coordinates origin,
|
||||
BufferCell[,] contents)
|
||||
{
|
||||
throw new NotImplementedException(
|
||||
"The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method copies a given character, foreground color, and background
|
||||
/// color to a region of the screen buffer. In this example this
|
||||
/// functionality is not needed so the method throws a
|
||||
/// NotImplementException exception./// </summary>
|
||||
/// <param name="rectangle">Defines the area to be filled. </param>
|
||||
/// <param name="fill">Defines the fill character.</param>
|
||||
public override void SetBufferContents(Rectangle rectangle, BufferCell fill)
|
||||
{
|
||||
throw new NotImplementedException(
|
||||
"The method or operation is not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,485 @@
|
||||
namespace Microsoft.Samples.PowerShell.Host
|
||||
{
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Management.Automation;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// This class is used to read the command line and color the text as
|
||||
/// it is entered. Tokens are determined using the PSParser.Tokenize
|
||||
/// method.
|
||||
/// </summary>
|
||||
internal class ConsoleReadLine
|
||||
{
|
||||
/// <summary>
|
||||
/// The buffer used to edit.
|
||||
/// </summary>
|
||||
private StringBuilder buffer = new StringBuilder();
|
||||
|
||||
/// <summary>
|
||||
/// The position of the cursor within the buffer.
|
||||
/// </summary>
|
||||
private int current;
|
||||
|
||||
/// <summary>
|
||||
/// The count of characters in buffer rendered.
|
||||
/// </summary>
|
||||
private int rendered;
|
||||
|
||||
/// <summary>
|
||||
/// Store the anchor and handle cursor movement
|
||||
/// </summary>
|
||||
//private Cursor cursor;
|
||||
|
||||
/// <summary>
|
||||
/// The array of colors for tokens, indexed by PSTokenType
|
||||
/// </summary>
|
||||
private ConsoleColor[] tokenColors;
|
||||
|
||||
/// <summary>
|
||||
/// We do not pick different colors for every token, those tokens
|
||||
/// use this default.
|
||||
/// </summary>
|
||||
private ConsoleColor defaultColor = ConsoleColor.White;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the ConsoleReadLine class.
|
||||
/// </summary>
|
||||
public ConsoleReadLine()
|
||||
{
|
||||
this.tokenColors = new ConsoleColor[]
|
||||
{
|
||||
this.defaultColor, // Unknown
|
||||
ConsoleColor.Yellow, // Command
|
||||
ConsoleColor.Green, // CommandParameter
|
||||
ConsoleColor.Cyan, // CommandArgument
|
||||
ConsoleColor.Cyan, // Number
|
||||
ConsoleColor.Cyan, // String
|
||||
ConsoleColor.Green, // Variable
|
||||
this.defaultColor, // Member
|
||||
this.defaultColor, // LoopLabel
|
||||
ConsoleColor.DarkYellow, // Attribute
|
||||
ConsoleColor.DarkYellow, // Type
|
||||
ConsoleColor.DarkCyan, // Operator
|
||||
this.defaultColor, // GroupStart
|
||||
this.defaultColor, // GroupEnd
|
||||
ConsoleColor.Magenta, // Keyword
|
||||
ConsoleColor.Red, // Comment
|
||||
ConsoleColor.DarkCyan, // StatementSeparator
|
||||
this.defaultColor, // NewLine
|
||||
this.defaultColor, // LineContinuation
|
||||
this.defaultColor, // Position
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a line of text, colorizing while typing.
|
||||
/// </summary>
|
||||
/// <returns>The command line read</returns>
|
||||
public string Read()
|
||||
{
|
||||
this.Initialize();
|
||||
|
||||
while (true)
|
||||
{
|
||||
// no support for Console.ReadKey in CoreCLR yet
|
||||
int key = Console.Read();
|
||||
char keyChar = Convert.ToChar(key);
|
||||
this.Insert(keyChar);
|
||||
/*
|
||||
ConsoleKeyInfo key = Console.ReadKey(true);
|
||||
|
||||
switch (key.Key)
|
||||
{
|
||||
case ConsoleKey.Backspace:
|
||||
this.OnBackspace();
|
||||
break;
|
||||
case ConsoleKey.Delete:
|
||||
this.OnDelete();
|
||||
break;
|
||||
case ConsoleKey.Enter:
|
||||
return this.OnEnter();
|
||||
case ConsoleKey.RightArrow:
|
||||
this.OnRight(key.Modifiers);
|
||||
break;
|
||||
case ConsoleKey.LeftArrow:
|
||||
this.OnLeft(key.Modifiers);
|
||||
break;
|
||||
case ConsoleKey.Escape:
|
||||
this.OnEscape();
|
||||
break;
|
||||
case ConsoleKey.Home:
|
||||
this.OnHome();
|
||||
break;
|
||||
case ConsoleKey.End:
|
||||
this.OnEnd();
|
||||
break;
|
||||
case ConsoleKey.UpArrow:
|
||||
case ConsoleKey.DownArrow:
|
||||
case ConsoleKey.LeftWindows:
|
||||
case ConsoleKey.RightWindows:
|
||||
// ignore these
|
||||
continue;
|
||||
|
||||
default:
|
||||
if (key.KeyChar == '\x0D')
|
||||
{
|
||||
goto case ConsoleKey.Enter; // Ctrl-M
|
||||
}
|
||||
|
||||
if (key.KeyChar == '\x08')
|
||||
{
|
||||
goto case ConsoleKey.Backspace; // Ctrl-H
|
||||
}
|
||||
|
||||
this.Insert(key);
|
||||
break;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the buffer.
|
||||
/// </summary>
|
||||
private void Initialize()
|
||||
{
|
||||
this.buffer.Length = 0;
|
||||
this.current = 0;
|
||||
this.rendered = 0;
|
||||
//this.cursor = new Cursor();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key to insert.</param>
|
||||
private void Insert(char key)
|
||||
{
|
||||
this.buffer.Insert(this.current, key);
|
||||
this.current++;
|
||||
if (key == '\n')
|
||||
this.Render();
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// The End key was enetered..
|
||||
/// </summary>
|
||||
private void OnEnd()
|
||||
{
|
||||
this.current = this.buffer.Length;
|
||||
this.cursor.Place(this.rendered);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Home key was eneterd.
|
||||
/// </summary>
|
||||
private void OnHome()
|
||||
{
|
||||
this.current = 0;
|
||||
this.cursor.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Escape key was enetered.
|
||||
/// </summary>
|
||||
private void OnEscape()
|
||||
{
|
||||
this.buffer.Length = 0;
|
||||
this.current = 0;
|
||||
this.Render();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves to the left of the cursor position.
|
||||
/// </summary>
|
||||
/// <param name="consoleModifiers">Enumeration for Alt, Control,
|
||||
/// and Shift keys.</param>
|
||||
private void OnLeft(ConsoleModifiers consoleModifiers)
|
||||
{
|
||||
if ((consoleModifiers & ConsoleModifiers.Control) != 0)
|
||||
{
|
||||
// Move back to the start of the previous word.
|
||||
if (this.buffer.Length > 0 && this.current != 0)
|
||||
{
|
||||
bool nonLetter = IsSeperator(this.buffer[this.current - 1]);
|
||||
while (this.current > 0 && (this.current - 1 < this.buffer.Length))
|
||||
{
|
||||
this.MoveLeft();
|
||||
|
||||
if (IsSeperator(this.buffer[this.current]) != nonLetter)
|
||||
{
|
||||
if (!nonLetter)
|
||||
{
|
||||
this.MoveRight();
|
||||
break;
|
||||
}
|
||||
|
||||
nonLetter = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.MoveLeft();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a character is a seperator.
|
||||
/// </summary>
|
||||
/// <param name="ch">Character to investigate.</param>
|
||||
/// <returns>A value that indicates whether the character
|
||||
/// is a seperator.</returns>
|
||||
private static bool IsSeperator(char ch)
|
||||
{
|
||||
return !Char.IsLetter(ch);
|
||||
}
|
||||
/*
|
||||
/// <summary>
|
||||
/// Moves to what is to the right of the cursor position.
|
||||
/// </summary>
|
||||
/// <param name="consoleModifiers">Enumeration for Alt, Control,
|
||||
/// and Shift keys.</param>
|
||||
private void OnRight(ConsoleModifiers consoleModifiers)
|
||||
{
|
||||
if ((consoleModifiers & ConsoleModifiers.Control) != 0)
|
||||
{
|
||||
// Move to the next word.
|
||||
if (this.buffer.Length != 0 && this.current < this.buffer.Length)
|
||||
{
|
||||
bool nonLetter = IsSeperator(this.buffer[this.current]);
|
||||
while (this.current < this.buffer.Length)
|
||||
{
|
||||
this.MoveRight();
|
||||
|
||||
if (this.current == this.buffer.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsSeperator(this.buffer[this.current]) != nonLetter)
|
||||
{
|
||||
if (nonLetter)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
nonLetter = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.MoveRight();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor one character to the right.
|
||||
/// </summary>
|
||||
private void MoveRight()
|
||||
{
|
||||
if (this.current < this.buffer.Length)
|
||||
{
|
||||
char c = this.buffer[this.current];
|
||||
this.current++;
|
||||
Cursor.Move(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor one character to the left.
|
||||
/// </summary>
|
||||
private void MoveLeft()
|
||||
{
|
||||
if (this.current > 0 && (this.current - 1 < this.buffer.Length))
|
||||
{
|
||||
this.current--;
|
||||
char c = this.buffer[this.current];
|
||||
Cursor.Move(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Enter key was entered.
|
||||
/// </summary>
|
||||
/// <returns>A newline character.</returns>
|
||||
private string OnEnter()
|
||||
{
|
||||
Console.Out.Write("\n");
|
||||
return this.buffer.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The delete key was entered.
|
||||
/// </summary>
|
||||
private void OnDelete()
|
||||
{
|
||||
if (this.buffer.Length > 0 && this.current < this.buffer.Length)
|
||||
{
|
||||
this.buffer.Remove(this.current, 1);
|
||||
this.Render();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Backspace key was entered.
|
||||
/// </summary>
|
||||
private void OnBackspace()
|
||||
{
|
||||
if (this.buffer.Length > 0 && this.current > 0)
|
||||
{
|
||||
this.buffer.Remove(this.current - 1, 1);
|
||||
this.current--;
|
||||
this.Render();
|
||||
}
|
||||
}
|
||||
*/
|
||||
/// <summary>
|
||||
/// Displays the line.
|
||||
/// </summary>
|
||||
private void Render()
|
||||
{
|
||||
string text = this.buffer.ToString();
|
||||
|
||||
// The PowerShell tokenizer is used to decide how to colorize
|
||||
// the input. Any errors in the input are returned in 'errors',
|
||||
// but we won't be looking at those here.
|
||||
Collection<PSParseError> errors = null;
|
||||
Collection<PSToken> tokens = PSParser.Tokenize(text, out errors);
|
||||
|
||||
if (tokens.Count > 0)
|
||||
{
|
||||
// We can skip rendering tokens that end before the cursor.
|
||||
int i;
|
||||
for (i = 0; i < tokens.Count; ++i)
|
||||
{
|
||||
if (this.current >= tokens[i].Start)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Place the cursor at the start of the first token to render. The
|
||||
// last edit may require changes to the colorization of characters
|
||||
// preceding the cursor.
|
||||
//this.cursor.Place(tokens[i].Start);
|
||||
|
||||
for (; i < tokens.Count; ++i)
|
||||
{
|
||||
// Write out the token. We don't use tokens[i].Content, instead we
|
||||
// use the actual text from our input because the content sometimes
|
||||
// excludes part of the token, e.g. the quote characters of a string.
|
||||
Console.ForegroundColor = this.tokenColors[(int)tokens[i].Type];
|
||||
Console.Out.Write(text.Substring(tokens[i].Start, tokens[i].Length));
|
||||
|
||||
// Whitespace doesn't show up in the array of tokens. Write it out here.
|
||||
if (i != (tokens.Count - 1))
|
||||
{
|
||||
Console.ForegroundColor = this.defaultColor;
|
||||
for (int j = (tokens[i].Start + tokens[i].Length); j < tokens[i + 1].Start; ++j)
|
||||
{
|
||||
Console.Out.Write(text[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It's possible there is text left over to output. This happens when there is
|
||||
// some error during tokenization, e.g. a string literal is missing a closing quote.
|
||||
Console.ForegroundColor = this.defaultColor;
|
||||
for (int j = tokens[i - 1].Start + tokens[i - 1].Length; j < text.Length; ++j)
|
||||
{
|
||||
Console.Out.Write(text[j]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If tokenization completely failed, just redraw the whole line. This
|
||||
// happens most frequently when the first token is incomplete, like a string
|
||||
// literal missing a closing quote.
|
||||
//this.cursor.Reset();
|
||||
Console.Out.Write(text);
|
||||
}
|
||||
|
||||
// If characters were deleted, we must write over previously written characters
|
||||
if (text.Length < this.rendered)
|
||||
{
|
||||
Console.Out.Write(new string(' ', this.rendered - text.Length));
|
||||
}
|
||||
|
||||
this.rendered = text.Length;
|
||||
//this.cursor.Place(this.current);
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// A helper class for maintaining the cursor while editing the command line.
|
||||
/// </summary>
|
||||
internal class Cursor
|
||||
{
|
||||
/// <summary>
|
||||
/// The top anchor for reposition the cursor.
|
||||
/// </summary>
|
||||
private int anchorTop;
|
||||
|
||||
/// <summary>
|
||||
/// The left anchor for repositioning the cursor.
|
||||
/// </summary>
|
||||
private int anchorLeft;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Cursor class.
|
||||
/// </summary>
|
||||
public Cursor()
|
||||
{
|
||||
this.anchorTop = Console.CursorTop;
|
||||
this.anchorLeft = Console.CursorLeft;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor.
|
||||
/// </summary>
|
||||
/// <param name="delta">The number of characters to move.</param>
|
||||
internal static void Move(int delta)
|
||||
{
|
||||
int position = Console.CursorTop * Console.BufferWidth + Console.CursorLeft + delta;
|
||||
|
||||
Console.CursorLeft = position % Console.BufferWidth;
|
||||
Console.CursorTop = position / Console.BufferWidth;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the cursor position.
|
||||
/// </summary>
|
||||
internal void Reset()
|
||||
{
|
||||
Console.CursorTop = this.anchorTop;
|
||||
Console.CursorLeft = this.anchorLeft;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor to a specific position.
|
||||
/// </summary>
|
||||
/// <param name="position">The new position.</param>
|
||||
internal void Place(int position)
|
||||
{
|
||||
Console.CursorLeft = (this.anchorLeft + position) % Console.BufferWidth;
|
||||
int cursorTop = this.anchorTop + (this.anchorLeft + position) / Console.BufferWidth;
|
||||
if (cursorTop >= Console.BufferHeight)
|
||||
{
|
||||
this.anchorTop -= cursorTop - Console.BufferHeight + 1;
|
||||
cursorTop = Console.BufferHeight - 1;
|
||||
}
|
||||
|
||||
Console.CursorTop = cursorTop;
|
||||
}
|
||||
} // End Cursor
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,509 @@
|
||||
namespace Microsoft.Samples.PowerShell.Host
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Host;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// A sample implementation of the PSHostUserInterface abstract class for
|
||||
/// console applications. Not all members are implemented. Those that are
|
||||
/// not implemented throw a NotImplementedException exception or return
|
||||
/// nothing. Members that are implemented include those that map easily to
|
||||
/// Console APIs and a basic implementation of the prompt API provided.
|
||||
/// </summary>
|
||||
internal class MyHostUserInterface : PSHostUserInterface, IHostUISupportsMultipleChoiceSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// A reference to the PSRawUserInterface implementation.
|
||||
/// </summary>
|
||||
private MyRawUserInterface myRawUi = new MyRawUserInterface();
|
||||
|
||||
/// <summary>
|
||||
/// Gets an instance of the PSRawUserInterface class for this host
|
||||
/// application.
|
||||
/// </summary>
|
||||
public override PSHostRawUserInterface RawUI
|
||||
{
|
||||
get { return this.myRawUi; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prompts the user for input.
|
||||
/// <param name="caption">The caption or title of the prompt.</param>
|
||||
/// <param name="message">The text of the prompt.</param>
|
||||
/// <param name="descriptions">A collection of FieldDescription objects
|
||||
/// that describe each field of the prompt.</param>
|
||||
/// <returns>A dictionary object that contains the results of the user
|
||||
/// prompts.</returns>
|
||||
public override Dictionary<string, PSObject> Prompt(
|
||||
string caption,
|
||||
string message,
|
||||
Collection<FieldDescription> descriptions)
|
||||
{
|
||||
this.Write(
|
||||
ConsoleColor.White,
|
||||
ConsoleColor.Black,
|
||||
caption + "\n" + message + " ");
|
||||
Dictionary<string, PSObject> results =
|
||||
new Dictionary<string, PSObject>();
|
||||
foreach (FieldDescription fd in descriptions)
|
||||
{
|
||||
string[] label = GetHotkeyAndLabel(fd.Label);
|
||||
this.WriteLine(label[1]);
|
||||
string userData = Console.ReadLine();
|
||||
if (userData == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
results[fd.Name] = PSObject.AsPSObject(userData);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
/// Provides a set of choices that enable the user to choose a
|
||||
/// single option from a set of options.
|
||||
/// </summary>
|
||||
/// <param name="caption">Text that proceeds (a title) the choices.</param>
|
||||
/// <param name="message">A message that describes the choice.</param>
|
||||
/// <param name="choices">A collection of ChoiceDescription objects that
|
||||
/// describ each choice.</param>
|
||||
/// <param name="defaultChoice">The index of the label in the Choices
|
||||
/// parameter collection. To indicate no default choice, set to -1.</param>
|
||||
/// <returns>The index of the Choices parameter collection element that
|
||||
/// corresponds to the option that is selected by the user.</returns>
|
||||
public override int PromptForChoice(
|
||||
string caption,
|
||||
string message,
|
||||
Collection<ChoiceDescription> choices,
|
||||
int defaultChoice)
|
||||
{
|
||||
// Write the caption and message strings in Blue.
|
||||
this.WriteLine(
|
||||
ConsoleColor.Blue,
|
||||
ConsoleColor.Black,
|
||||
caption + "\n" + message + "\n");
|
||||
|
||||
// Convert the choice collection into something that is
|
||||
// easier to work with. See the BuildHotkeysAndPlainLabels
|
||||
// method for details.
|
||||
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(
|
||||
CultureInfo.CurrentCulture,
|
||||
"|{0}> {1} ",
|
||||
promptData[0, element],
|
||||
promptData[1, element]));
|
||||
}
|
||||
|
||||
sb.Append(String.Format(
|
||||
CultureInfo.CurrentCulture,
|
||||
"[Default is ({0}]",
|
||||
promptData[0, defaultChoice]));
|
||||
|
||||
// Read prompts until a match is made, the default is
|
||||
// chosen, or the loop is interrupted with ctrl-C.
|
||||
while (true)
|
||||
{
|
||||
this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black, sb.ToString());
|
||||
string data = Console.ReadLine().Trim().ToUpper();
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
this.WriteErrorLine("Invalid choice: " + data);
|
||||
}
|
||||
}
|
||||
|
||||
#region IHostUISupportsMultipleChoiceSelection Members
|
||||
|
||||
/// <summary>
|
||||
/// Provides a set of choices that enable the user to choose a one or
|
||||
/// more options from a set of options.
|
||||
/// </summary>
|
||||
/// <param name="caption">Text that proceeds (a title) the choices.</param>
|
||||
/// <param name="message">A message that describes the choice.</param>
|
||||
/// <param name="choices">A collection of ChoiceDescription objects that
|
||||
/// describ each choice.</param>
|
||||
/// <param name="defaultChoices">The index of the label in the Choices
|
||||
/// parameter collection. To indicate no default choice, set to -1.</param>
|
||||
/// <returns>The index of the Choices parameter collection element that
|
||||
/// corresponds to the option that is selected by the user.</returns>
|
||||
public Collection<int> PromptForChoice(
|
||||
string caption,
|
||||
string message,
|
||||
Collection<ChoiceDescription> choices,
|
||||
IEnumerable<int> defaultChoices)
|
||||
{
|
||||
// Write the caption and message strings in Blue.
|
||||
this.WriteLine(
|
||||
ConsoleColor.Blue,
|
||||
ConsoleColor.Black,
|
||||
caption + "\n" + message + "\n");
|
||||
|
||||
// Convert the choice collection into something that is
|
||||
// easier to work with. See the BuildHotkeysAndPlainLabels
|
||||
// method for details.
|
||||
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(
|
||||
CultureInfo.CurrentCulture,
|
||||
"|{0}> {1} ",
|
||||
promptData[0, element],
|
||||
promptData[1, element]));
|
||||
}
|
||||
|
||||
Collection<int> defaultResults = new Collection<int>();
|
||||
if (defaultChoices != null)
|
||||
{
|
||||
int countDefaults = 0;
|
||||
foreach (int defaultChoice in defaultChoices)
|
||||
{
|
||||
++countDefaults;
|
||||
defaultResults.Add(defaultChoice);
|
||||
}
|
||||
|
||||
if (countDefaults != 0)
|
||||
{
|
||||
sb.Append(countDefaults == 1 ? "[Default choice is " : "[Default choices are ");
|
||||
foreach (int defaultChoice in defaultChoices)
|
||||
{
|
||||
sb.AppendFormat(
|
||||
CultureInfo.CurrentCulture,
|
||||
"\"{0}\",",
|
||||
promptData[0, defaultChoice]);
|
||||
}
|
||||
|
||||
sb.Remove(sb.Length - 1, 1);
|
||||
sb.Append("]");
|
||||
}
|
||||
}
|
||||
|
||||
this.WriteLine(
|
||||
ConsoleColor.Cyan,
|
||||
ConsoleColor.Black,
|
||||
sb.ToString());
|
||||
// Read prompts until a match is made, the default is
|
||||
// chosen, or the loop is interrupted with ctrl-C.
|
||||
Collection<int> results = new Collection<int>();
|
||||
while (true)
|
||||
{
|
||||
ReadNext:
|
||||
string prompt = string.Format(CultureInfo.CurrentCulture, "Choice[{0}]:", results.Count);
|
||||
this.Write(ConsoleColor.Cyan, ConsoleColor.Black, prompt);
|
||||
string data = Console.ReadLine().Trim().ToUpper();
|
||||
|
||||
// If the choice string was empty, no more choices have been made.
|
||||
// If there were no choices made, return the defaults
|
||||
if (data.Length == 0)
|
||||
{
|
||||
return (results.Count == 0) ? defaultResults : results;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
results.Add(i);
|
||||
goto ReadNext;
|
||||
}
|
||||
}
|
||||
|
||||
this.WriteErrorLine("Invalid choice: " + data);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Prompts the user for credentials with a specified prompt window
|
||||
/// caption, prompt message, user name, and target name. In this
|
||||
/// example this functionality is not needed so the method throws a
|
||||
/// NotImplementException exception.
|
||||
/// </summary>
|
||||
/// <param name="caption">The caption for the message window.</param>
|
||||
/// <param name="message">The text of the message.</param>
|
||||
/// <param name="userName">The user name whose credential is to be
|
||||
/// prompted for.</param>
|
||||
/// <param name="targetName">The name of the target for which the
|
||||
/// credential is collected.</param>
|
||||
/// <returns>Throws a NotImplementedException exception.</returns>
|
||||
public override PSCredential PromptForCredential(
|
||||
string caption,
|
||||
string message,
|
||||
string userName,
|
||||
string targetName)
|
||||
{
|
||||
throw new NotImplementedException(
|
||||
"The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prompts the user for credentials by using a specified prompt window
|
||||
/// caption, prompt message, user name and target name, credential
|
||||
/// types allowed to be returned, and UI behavior options. In this
|
||||
/// example this functionality is not needed so the method throws a
|
||||
/// NotImplementException exception.
|
||||
/// </summary>
|
||||
/// <param name="caption">The caption for the message window.</param>
|
||||
/// <param name="message">The text of the message.</param>
|
||||
/// <param name="userName">The user name whose credential is to be
|
||||
/// prompted for.</param>
|
||||
/// <param name="targetName">The name of the target for which the
|
||||
/// credential is collected.</param>
|
||||
/// <param name="allowedCredentialTypes">A PSCredentialTypes constant
|
||||
/// that identifies the type of credentials that can be returned.</param>
|
||||
/// <param name="options">A PSCredentialUIOptions constant that
|
||||
/// identifies the UI behavior when it gathers the credentials.</param>
|
||||
/// <returns>Throws a NotImplementedException exception.</returns>
|
||||
public override PSCredential PromptForCredential(
|
||||
string caption,
|
||||
string message,
|
||||
string userName,
|
||||
string targetName,
|
||||
PSCredentialTypes allowedCredentialTypes,
|
||||
PSCredentialUIOptions options)
|
||||
{
|
||||
throw new NotImplementedException(
|
||||
"The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads characters that are entered by the user until a newline
|
||||
/// (carriage return) is encountered.
|
||||
/// </summary>
|
||||
/// <returns>The characters that are entered by the user.</returns>
|
||||
public override string ReadLine()
|
||||
{
|
||||
return Console.ReadLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads characters entered by the user until a newline (carriage return)
|
||||
/// is encountered and returns the characters as a secure string. In this
|
||||
/// example this functionality is not needed so the method throws a
|
||||
/// NotImplementException exception.
|
||||
/// </summary>
|
||||
/// <returns>Throws a NotImplemented exception.</returns>
|
||||
public override System.Security.SecureString ReadLineAsSecureString()
|
||||
{
|
||||
throw new NotImplementedException("The method or operation is not implemented.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes characters to the output display of the host.
|
||||
/// </summary>
|
||||
/// <param name="value">The characters to be written.</param>
|
||||
public override void Write(string value)
|
||||
{
|
||||
Console.Write(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes characters to the output display of the host with possible
|
||||
/// foreground and background colors.
|
||||
/// </summary>
|
||||
/// <param name="foregroundColor">The color of the characters.</param>
|
||||
/// <param name="backgroundColor">The backgound color to use.</param>
|
||||
/// <param name="value">The characters to be written.</param>
|
||||
public override void Write(
|
||||
ConsoleColor foregroundColor,
|
||||
ConsoleColor backgroundColor,
|
||||
string value)
|
||||
{
|
||||
Console.ForegroundColor = foregroundColor;
|
||||
Console.BackgroundColor = backgroundColor;
|
||||
Console.Write(value);
|
||||
//Console.Write(value);
|
||||
Console.ResetColor();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Writes a line of characters to the output display of the host
|
||||
/// with foreground and background colors and appends a newline (carriage return).
|
||||
/// </summary>
|
||||
/// <param name="foregroundColor">The forground color of the display. </param>
|
||||
/// <param name="backgroundColor">The background color of the display. </param>
|
||||
/// <param name="value">The line to be written.</param>
|
||||
public override void WriteLine(
|
||||
ConsoleColor foregroundColor,
|
||||
ConsoleColor backgroundColor,
|
||||
string value)
|
||||
{
|
||||
Console.ForegroundColor = foregroundColor;
|
||||
Console.BackgroundColor = backgroundColor;
|
||||
Console.WriteLine(value);
|
||||
Console.ResetColor();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a debug message to the output display of the host.
|
||||
/// </summary>
|
||||
/// <param name="message">The debug message that is displayed.</param>
|
||||
public override void WriteDebugLine(string message)
|
||||
{
|
||||
this.WriteLine(
|
||||
ConsoleColor.DarkYellow,
|
||||
ConsoleColor.Black,
|
||||
String.Format(CultureInfo.CurrentCulture, "DEBUG: {0}", message));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Writes an error message to the output display of the host.
|
||||
/// </summary>
|
||||
/// <param name="value">The error message that is displayed.</param>
|
||||
public override void WriteErrorLine(string value)
|
||||
{
|
||||
this.WriteLine(
|
||||
ConsoleColor.Red,
|
||||
ConsoleColor.Black,
|
||||
value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a newline character (carriage return)
|
||||
/// to the output display of the host.
|
||||
/// </summary>
|
||||
public override void WriteLine()
|
||||
{
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a line of characters to the output display of the host
|
||||
/// and appends a newline character(carriage return).
|
||||
/// </summary>
|
||||
/// <param name="value">The line to be written.</param>
|
||||
public override void WriteLine(string value)
|
||||
{
|
||||
Console.WriteLine(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a progress report to the output display of the host.
|
||||
/// </summary>
|
||||
/// <param name="sourceId">Unique identifier of the source of the record. </param>
|
||||
/// <param name="record">A ProgressReport object.</param>
|
||||
public override void WriteProgress(long sourceId, ProgressRecord record)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a verbose message to the output display of the host.
|
||||
/// </summary>
|
||||
/// <param name="message">The verbose message that is displayed.</param>
|
||||
public override void WriteVerboseLine(string message)
|
||||
{
|
||||
this.WriteLine(
|
||||
ConsoleColor.Green,
|
||||
ConsoleColor.Black,
|
||||
String.Format(CultureInfo.CurrentCulture, "VERBOSE: {0}", message));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a warning message to the output display of the host.
|
||||
/// </summary>
|
||||
/// <param name="message">The warning message that is displayed.</param>
|
||||
public override void WriteWarningLine(string message)
|
||||
{
|
||||
this.WriteLine(
|
||||
ConsoleColor.Yellow,
|
||||
ConsoleColor.Black,
|
||||
String.Format(CultureInfo.CurrentCulture, "WARNING: {0}", message));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Parse a string containing a hotkey character.
|
||||
/// Take a string of the form
|
||||
/// Yes to &all
|
||||
/// and returns 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();
|
||||
}
|
||||
|
||||
result[1] = (fragments[0] + fragments[1]).Trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
result[1] = input;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is a private worker function 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 the & 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user