Merge pull request #939 from PowerShell/andschwa/consolehost
Converge the console hosts
This commit is contained in:
commit
85f45399c3
@ -7,7 +7,6 @@ matrix:
|
||||
- os: osx
|
||||
osx_image: xcode7.3
|
||||
language: generic
|
||||
env: PATH+=/usr/local/share/dotnet
|
||||
git:
|
||||
submodules: false
|
||||
before_install:
|
||||
|
@ -221,10 +221,10 @@ function New-PSOptions {
|
||||
[switch]$FullCLR
|
||||
)
|
||||
|
||||
$Top = if ($FullCLR) {
|
||||
"$PSScriptRoot\src\Microsoft.PowerShell.ConsoleHost"
|
||||
if ($FullCLR) {
|
||||
$Top = "$PSScriptRoot/src/Microsoft.PowerShell.ConsoleHost"
|
||||
} else {
|
||||
"$PSScriptRoot/src/Microsoft.PowerShell.CoreConsoleHost"
|
||||
$Top = "$PSScriptRoot/src/powershell"
|
||||
}
|
||||
Write-Verbose "Top project directory is $Top"
|
||||
|
||||
@ -315,7 +315,7 @@ function Start-PSPester {
|
||||
[string]$Directory = "$PSScriptRoot/test/powershell"
|
||||
)
|
||||
|
||||
& (Get-PSOutput) -c "Invoke-Pester $Flags $Directory/$Tests"
|
||||
& (Get-PSOutput) -noprofile -c "Invoke-Pester $Flags $Directory/$Tests"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "$LASTEXITCODE Pester tests failed"
|
||||
}
|
||||
|
@ -33,17 +33,17 @@ test_script:
|
||||
$ErrorActionPreference = 'Stop'
|
||||
#
|
||||
# CoreCLR
|
||||
$env:CoreOutput = "$pwd\src\Microsoft.PowerShell.CoreConsoleHost\bin\Debug\netcoreapp1.0\win81-x64\publish"
|
||||
$env:CoreOutput = Split-Path -Parent (Get-PSOutput -Options (New-PSOptions -Publish))
|
||||
Write-Host -Foreground Green 'Run CoreCLR tests'
|
||||
$testResultsFile = "$pwd\TestsResults.xml"
|
||||
& ("$env:CoreOutput\powershell.exe") -c "Invoke-Pester test/powershell -OutputFormat NUnitXml -OutputFile $testResultsFile"
|
||||
& ("$env:CoreOutput\powershell.exe") -noprofile -noninteractive -c "Invoke-Pester test/powershell -OutputFormat NUnitXml -OutputFile $testResultsFile"
|
||||
(New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultsFile))
|
||||
#
|
||||
# FullCLR
|
||||
$env:FullOutput = "$pwd\src\Microsoft.PowerShell.ConsoleHost\bin\Debug\net451"
|
||||
$env:FullOutput = Split-Path -Parent (Get-PSOutput -Options (New-PSOptions -FullCLR))
|
||||
Write-Host -Foreground Green 'Run FullCLR tests'
|
||||
$testResultsFileFullCLR = "$pwd\TestsResults.FullCLR.xml"
|
||||
Start-DevPSGitHub -binDir $env:FullOutput -NoNewWindow -ArgumentList '-command', "Import-Module .\src\Modules\Pester; Invoke-Pester test/fullCLR -OutputFormat NUnitXml -OutputFile $testResultsFileFullCLR"
|
||||
Start-DevPSGitHub -binDir $env:FullOutput -NoNewWindow -ArgumentList '-noprofile', '-noninteractive', '-command', "Import-Module .\src\Modules\Pester; Invoke-Pester test/fullCLR -OutputFormat NUnitXml -OutputFile $testResultsFileFullCLR"
|
||||
(New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $testResultsFileFullCLR))
|
||||
#
|
||||
# Fail the build, if tests failed
|
||||
|
@ -1187,12 +1187,12 @@
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Archive/ArchiveResources.psd1": "src/Modules/Microsoft.PowerShell.Archive/ArchiveResources.psd1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1": "src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psd1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1": "src/Modules/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Diagnostics/CoreClr/Microsoft.PowerShell.Diagnostics.psd1": "src/Microsoft.PowerShell.CoreConsoleHost/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Diagnostics/CoreClr/Microsoft.PowerShell.Diagnostics.psd1": "src/powershell/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1": "src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Diagnostics/Microsoft.PowerShell.Diagnostics.psd1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1": "src/Modules/Microsoft.PowerShell.Host/Microsoft.PowerShell.Host.psd1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1": "src/Modules/Microsoft.PowerShell.Management/Microsoft.PowerShell.Management.psd1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1": "src/Modules/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Utility/CoreClr/Microsoft.PowerShell.Utility.psd1": "src/Microsoft.PowerShell.CoreConsoleHost/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Utility/CoreClr/Microsoft.PowerShell.Utility.psd1": "src/powershell/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1": "src/Microsoft.PowerShell.ConsoleHost/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1": "src/Modules/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psm1",
|
||||
"src/monad/monad/miscfiles/modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1": "src/Modules/Microsoft.WSMan.Management/Microsoft.WSMan.Management.psd1",
|
||||
|
@ -2,12 +2,16 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
#if !CORECLR
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Security.Permissions;
|
||||
#endif
|
||||
|
||||
#if CORECLR
|
||||
[assembly:AssemblyCulture("")]
|
||||
[assembly:NeutralResourcesLanguage("en-US")]
|
||||
|
||||
[assembly:InternalsVisibleTo("powershell-tests")]
|
||||
#else
|
||||
[assembly:AssemblyConfiguration("")]
|
||||
[assembly:AssemblyInformationalVersionAttribute (@"10.0.10011.16384")]
|
||||
[assembly:ReliabilityContractAttribute(Consistency.MayCorruptAppDomain, Cer.MayFail)]
|
||||
@ -15,14 +19,16 @@ using System.Security.Permissions;
|
||||
[assembly:AssemblyDescription("Microsoft Windows PowerShell Console Host")]
|
||||
|
||||
[assembly:System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5")]
|
||||
[assembly:System.Reflection.AssemblyFileVersion("10.0.10011.16384")]
|
||||
[assembly:AssemblyKeyFileAttribute(@"..\signing\visualstudiopublic.snk")]
|
||||
[assembly:System.Reflection.AssemblyDelaySign(true)]
|
||||
#endif
|
||||
|
||||
[assembly:System.Runtime.InteropServices.ComVisible(false)]
|
||||
[assembly:System.Reflection.AssemblyVersion("3.0.0.0")]
|
||||
[assembly:System.Reflection.AssemblyProduct("Microsoft (R) Windows (R) Operating System")]
|
||||
[assembly:System.Reflection.AssemblyCopyright("Copyright (c) Microsoft Corporation. All rights reserved.")]
|
||||
[assembly:System.Reflection.AssemblyCompany("Microsoft Corporation")]
|
||||
[assembly:System.Reflection.AssemblyFileVersion("10.0.10011.16384")]
|
||||
[assembly:AssemblyKeyFileAttribute(@"..\signing\visualstudiopublic.snk")]
|
||||
[assembly:System.Reflection.AssemblyDelaySign(true)]
|
||||
|
||||
internal static class AssemblyStrings
|
||||
{
|
||||
|
@ -118,13 +118,13 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
}
|
||||
|
||||
internal bool ReadFromStdin
|
||||
internal bool ExplicitReadCommandsFromStdin
|
||||
{
|
||||
get
|
||||
{
|
||||
Dbg.Assert(dirty, "Parse has not been called yet");
|
||||
|
||||
return readFromStdin;
|
||||
return explicitReadCommandsFromStdin;
|
||||
}
|
||||
}
|
||||
|
||||
@ -365,6 +365,12 @@ namespace Microsoft.PowerShell
|
||||
|
||||
switchKey = switchKey.Substring(1);
|
||||
|
||||
// chop off the second dash so we're agnostic wrt specifying - or --
|
||||
if (SpecialCharacters.IsDash(switchKey[0]))
|
||||
{
|
||||
switchKey = switchKey.Substring(1);
|
||||
}
|
||||
|
||||
if (MatchSwitch(switchKey, "help", "h") || MatchSwitch(switchKey, "?", "?"))
|
||||
{
|
||||
showHelp = true;
|
||||
@ -482,7 +488,7 @@ namespace Microsoft.PowerShell
|
||||
{
|
||||
// the arg to -file is -, which is secret code for "read the commands from stdin with prompts"
|
||||
|
||||
readFromStdin = true;
|
||||
explicitReadCommandsFromStdin = true;
|
||||
noPrompt = false;
|
||||
}
|
||||
else
|
||||
@ -844,7 +850,7 @@ namespace Microsoft.PowerShell
|
||||
{
|
||||
// the arg to -command is -, which is secret code for "read the commands from stdin with no prompts"
|
||||
|
||||
readFromStdin = true;
|
||||
explicitReadCommandsFromStdin = true;
|
||||
noPrompt = true;
|
||||
|
||||
++i;
|
||||
@ -859,7 +865,7 @@ namespace Microsoft.PowerShell
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parent.IsStandardInputRedirected)
|
||||
if (!Console.IsInputRedirected)
|
||||
{
|
||||
ui.WriteErrorLine(CommandLineParameterParserStrings.StdinNotRedirected);
|
||||
showHelp = true;
|
||||
@ -968,7 +974,7 @@ namespace Microsoft.PowerShell
|
||||
// default is sta.
|
||||
private bool? staMode = null;
|
||||
private bool noExit = true;
|
||||
private bool readFromStdin;
|
||||
private bool explicitReadCommandsFromStdin;
|
||||
private bool noPrompt;
|
||||
private string commandLineCommand;
|
||||
private bool wasCommandEncoded;
|
||||
|
@ -1,3 +1,4 @@
|
||||
#if !PORTABLE
|
||||
/********************************************************************++
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
--********************************************************************/
|
||||
@ -3685,4 +3686,4 @@ namespace Microsoft.PowerShell
|
||||
private static PSTraceSource tracer = PSTraceSource.GetTracer("ConsoleControl", "Console control methods");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
@ -170,8 +170,15 @@ namespace Microsoft.PowerShell
|
||||
{
|
||||
try
|
||||
{
|
||||
var profileDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) +
|
||||
@"\Microsoft\Windows\PowerShell";
|
||||
string profileDir;
|
||||
if (Platform.IsWindows)
|
||||
{
|
||||
profileDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) +
|
||||
@"\Microsoft\Windows\PowerShell";
|
||||
} else
|
||||
{
|
||||
profileDir = System.IO.Path.Combine(Environment.GetEnvironmentVariable("HOME"), ".powershell");
|
||||
}
|
||||
|
||||
if (!Directory.Exists(profileDir))
|
||||
{
|
||||
@ -190,9 +197,11 @@ namespace Microsoft.PowerShell
|
||||
System.Threading.Thread.CurrentThread.Name = "ConsoleHost main thread";
|
||||
|
||||
theConsoleHost = ConsoleHost.CreateSingletonInstance(configuration);
|
||||
#if !PORTABLE
|
||||
theConsoleHost.BindBreakHandler();
|
||||
#endif
|
||||
|
||||
PSHost.IsStdOutputRedirected = theConsoleHost.IsStandardOutputRedirected;
|
||||
PSHost.IsStdOutputRedirected = Console.IsOutputRedirected;
|
||||
|
||||
if (args == null)
|
||||
{
|
||||
@ -268,6 +277,7 @@ namespace Microsoft.PowerShell
|
||||
|
||||
|
||||
|
||||
#if !PORTABLE
|
||||
/// <summary>
|
||||
///
|
||||
/// The break handler for the program. Dispatches a break event to the current Executor.
|
||||
@ -307,6 +317,7 @@ namespace Microsoft.PowerShell
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private static bool BreakIntoDebugger()
|
||||
{
|
||||
@ -425,8 +436,10 @@ namespace Microsoft.PowerShell
|
||||
// call the console APIs directly, instead of ui.rawui.FlushInputHandle, as ui may be finalized
|
||||
// already if this thread is lagging behind the main thread.
|
||||
|
||||
#if !PORTABLE
|
||||
ConsoleHandle handle = ConsoleControl.GetInputHandle();
|
||||
ConsoleControl.FlushConsoleInputBuffer(handle);
|
||||
#endif
|
||||
|
||||
ConsoleHost.SingletonInstance.breakHandlerThread = null;
|
||||
}
|
||||
@ -1019,11 +1032,13 @@ namespace Microsoft.PowerShell
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !PORTABLE
|
||||
private void BindBreakHandler()
|
||||
{
|
||||
breakHandlerGcHandle = GCHandle.Alloc(new ConsoleControl.BreakHandler(MyBreakHandler));
|
||||
ConsoleControl.AddBreakHandler((ConsoleControl.BreakHandler)breakHandlerGcHandle.Target);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !CORECLR // Not used on NanoServer: CurrentDomain.UnhandledException not supported on CoreCLR
|
||||
private void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)
|
||||
@ -1076,9 +1091,11 @@ namespace Microsoft.PowerShell
|
||||
{
|
||||
if (!isDisposed)
|
||||
{
|
||||
#if !PORTABLE
|
||||
Dbg.Assert(breakHandlerGcHandle != null, "break handler should be set");
|
||||
ConsoleControl.RemoveBreakHandler();
|
||||
breakHandlerGcHandle.Free();
|
||||
#endif
|
||||
|
||||
if (isDisposingNotFinalizing)
|
||||
{
|
||||
@ -1193,7 +1210,7 @@ namespace Microsoft.PowerShell
|
||||
|
||||
//If this shell is invoked in minishell interop mode and error is redirected,
|
||||
//always write data in error stream in xml format.
|
||||
if (IsInteractive == false && IsStandardErrorRedirected && wasInitialCommandEncoded)
|
||||
if (IsInteractive == false && Console.IsErrorRedirected && wasInitialCommandEncoded)
|
||||
{
|
||||
format = Serialization.DataFormat.XML;
|
||||
}
|
||||
@ -1205,19 +1222,7 @@ namespace Microsoft.PowerShell
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsInteractive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
(OutputFormat != Serialization.DataFormat.Text)
|
||||
|| (IsStandardInputRedirected && !ui.ReadFromStdin))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return !IsInteractive && ((OutputFormat != Serialization.DataFormat.Text) || Console.IsInputRedirected);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1236,7 +1241,7 @@ namespace Microsoft.PowerShell
|
||||
new WrappedSerializer(
|
||||
outputFormat,
|
||||
"Output",
|
||||
IsStandardOutputRedirected ? StandardOutputWriter : ConsoleTextWriter);
|
||||
Console.IsOutputRedirected ? Console.Out : ConsoleTextWriter);
|
||||
}
|
||||
return outputSerializer;
|
||||
}
|
||||
@ -1252,7 +1257,7 @@ namespace Microsoft.PowerShell
|
||||
new WrappedSerializer(
|
||||
ErrorFormat,
|
||||
"Error",
|
||||
IsStandardErrorRedirected ? StandardErrorWriter : ConsoleTextWriter);
|
||||
Console.IsErrorRedirected ? Console.Error : ConsoleTextWriter);
|
||||
}
|
||||
return errorSerializer;
|
||||
}
|
||||
@ -1328,7 +1333,7 @@ namespace Microsoft.PowerShell
|
||||
inputFormat = cpp.InputFormat;
|
||||
wasInitialCommandEncoded = cpp.WasInitialCommandEncoded;
|
||||
|
||||
ui.ReadFromStdin = cpp.ReadFromStdin;
|
||||
ui.ReadFromStdin = cpp.ExplicitReadCommandsFromStdin || Console.IsInputRedirected;
|
||||
ui.NoPrompt = cpp.NoPrompt;
|
||||
ui.ThrowOnReadAndPrompt = cpp.ThrowOnReadAndPrompt;
|
||||
noExit = cpp.NoExit;
|
||||
@ -1486,8 +1491,15 @@ namespace Microsoft.PowerShell
|
||||
|
||||
private bool LoadPSReadline()
|
||||
{
|
||||
return ((cpp.InitialCommand == null && cpp.File == null) || cpp.NoExit) &&
|
||||
(!IsStandardInputRedirected && !cpp.NonInteractive && !cpp.ReadFromStdin);
|
||||
// Don't load PSReadline if:
|
||||
// * we don't think the process will be interactive, e.g. -command or -file
|
||||
// - exception: when -noexit is specified, we will be interactive after the command/file finishes
|
||||
// * -noniteractive: this should be obvious, they've asked that we don't every prompt
|
||||
//
|
||||
// Note that PSReadline doesn't support redirected stdin/stdout, but we don't check that here because
|
||||
// a future version might, and we should automatically load it at that unknown point in the future.
|
||||
// PSReadline will ideally fall back to Console.ReadLine or whatever when stdin/stdout is redirected.
|
||||
return ((cpp.InitialCommand == null && cpp.File == null) || cpp.NoExit) && !cpp.NonInteractive;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1528,7 +1540,7 @@ namespace Microsoft.PowerShell
|
||||
{
|
||||
// Create and open Runspace with PSReadline.
|
||||
defaultImportModulesList = DefaultInitialSessionState.Modules;
|
||||
DefaultInitialSessionState.ImportPSModule(new[] { "PSReadline" });
|
||||
DefaultInitialSessionState.ImportPSModule(new[] { "PSReadLine" });
|
||||
consoleRunspace = RunspaceFactory.CreateRunspace(this, DefaultInitialSessionState);
|
||||
try
|
||||
{
|
||||
@ -1787,6 +1799,9 @@ namespace Microsoft.PowerShell
|
||||
if (AstSearcher.IsUsingDollarInput(parsedInput))
|
||||
{
|
||||
executionOptions |= Executor.ExecutionOptions.ReadInputObjects;
|
||||
|
||||
// We will consume all of the input to pass to the script, so don't try to read commands from stdin.
|
||||
ui.ReadFromStdin = false;
|
||||
}
|
||||
|
||||
exec.ExecuteCommandAsyncHelper(tempPipeline, out e1, executionOptions);
|
||||
@ -1846,6 +1861,9 @@ namespace Microsoft.PowerShell
|
||||
if (AstSearcher.IsUsingDollarInput(parsedInput))
|
||||
{
|
||||
executionOptions |= Executor.ExecutionOptions.ReadInputObjects;
|
||||
|
||||
// We will consume all of the input to pass to the script, so don't try to read commands from stdin.
|
||||
ui.ReadFromStdin = false;
|
||||
}
|
||||
|
||||
exec.ExecuteCommandAsyncHelper(tempPipeline, out e1, executionOptions);
|
||||
@ -2049,205 +2067,6 @@ namespace Microsoft.PowerShell
|
||||
|
||||
#endregion non-overrides
|
||||
|
||||
#region stdio redirection
|
||||
|
||||
|
||||
|
||||
private delegate void InitializeStandardHandleDelegate(NakedWin32Handle handle);
|
||||
|
||||
|
||||
[ArchitectureSensitive]
|
||||
private bool IsStandardHandleRedirected(
|
||||
ConsoleControl.StandardHandleId handleId,
|
||||
ref bool isHandleRedirectionDetermined,
|
||||
ref bool isHandleRedirected,
|
||||
InitializeStandardHandleDelegate handleInit)
|
||||
{
|
||||
// lock because we update a bunch of instance vars here...
|
||||
|
||||
lock (hostGlobalLock)
|
||||
{
|
||||
if (!isHandleRedirectionDetermined)
|
||||
{
|
||||
isHandleRedirected = false;
|
||||
|
||||
NakedWin32Handle stdHandle = ConsoleControl.GetStdHandle(handleId);
|
||||
SafeFileHandle sfh = new SafeFileHandle(stdHandle, false);
|
||||
if (!sfh.IsInvalid)
|
||||
{
|
||||
var fileType = ConsoleControl.NativeMethods.GetFileType(stdHandle);
|
||||
if (fileType != ConsoleControl.NativeMethods.FileType.Char)
|
||||
{
|
||||
// stdHandle is not a console handle; so it has been redirected.
|
||||
|
||||
isHandleRedirected = true;
|
||||
handleInit(stdHandle);
|
||||
}
|
||||
}
|
||||
|
||||
isHandleRedirectionDetermined = true;
|
||||
}
|
||||
}
|
||||
|
||||
return isHandleRedirected;
|
||||
}
|
||||
|
||||
internal bool IsStandardOutputRedirected
|
||||
{
|
||||
get
|
||||
{
|
||||
if (initStandardOutDelegate == null)
|
||||
{
|
||||
initStandardOutDelegate = new InitializeStandardHandleDelegate(InitializeStandardOutputWriter);
|
||||
}
|
||||
|
||||
return
|
||||
IsStandardHandleRedirected(
|
||||
ConsoleControl.StandardHandleId.Output,
|
||||
ref isStandardOutputRedirectionDetermined,
|
||||
ref isStandardOutputRedirected,
|
||||
initStandardOutDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsStandardInputRedirected
|
||||
{
|
||||
get
|
||||
{
|
||||
if (initStandardInDelegate == null)
|
||||
{
|
||||
initStandardInDelegate = new InitializeStandardHandleDelegate(InitializeStandardInputReader);
|
||||
}
|
||||
|
||||
return
|
||||
IsStandardHandleRedirected(
|
||||
ConsoleControl.StandardHandleId.Input,
|
||||
ref isStandardInputRedirectionDetermined,
|
||||
ref isStandardInputRedirected,
|
||||
initStandardInDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
internal bool IsStandardErrorRedirected
|
||||
{
|
||||
get
|
||||
{
|
||||
if (initStandardErrorDelegate == null)
|
||||
{
|
||||
initStandardErrorDelegate = new InitializeStandardHandleDelegate(InitializeStandardErrorWriter);
|
||||
}
|
||||
|
||||
return
|
||||
IsStandardHandleRedirected(
|
||||
ConsoleControl.StandardHandleId.Error,
|
||||
ref isStandardErrorRedirectionDetermined,
|
||||
ref isStandardErrorRedirected,
|
||||
initStandardErrorDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
[ArchitectureSensitive]
|
||||
private void InitializeStandardInputReader(NakedWin32Handle stdHandle)
|
||||
{
|
||||
Dbg.Assert(standardInputReader == null, "standardInputReader should not exist at this point");
|
||||
|
||||
// stdin has been redirected. Use ReadFile instead of ReadConsole.
|
||||
|
||||
uint codePage = (uint) ConsoleControl.NativeMethods.GetConsoleCP();
|
||||
Encoding encoding = Encoding.GetEncoding((int) codePage);
|
||||
|
||||
try
|
||||
{
|
||||
Stream s =
|
||||
new FileStream(
|
||||
|
||||
// since stdHandle was retreived not with an open, flag its safe wrapper as not needing to be closed.
|
||||
|
||||
new SafeFileHandle(stdHandle, false),
|
||||
FileAccess.Read);
|
||||
|
||||
// The "false" flag here means "don't detect the byte order mark in the input stream." I hope that's the right
|
||||
// thing.
|
||||
|
||||
#if CORECLR // There is no TextReader.Synchronized on CoreCLR
|
||||
standardInputReader = new StreamReader(s, encoding, false);
|
||||
#else
|
||||
standardInputReader = TextReader.Synchronized(new StreamReader(s, encoding, false));
|
||||
#endif
|
||||
}
|
||||
catch (System.IO.IOException)
|
||||
{
|
||||
#if CORECLR // There is no TextReader.Synchronized on CoreCLR
|
||||
standardInputReader = new StringReader("");
|
||||
#else
|
||||
standardInputReader = TextReader.Synchronized(new StringReader(""));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
[ArchitectureSensitive]
|
||||
private void InitializeStandardOutputWriter(NakedWin32Handle stdHandle)
|
||||
{
|
||||
Dbg.Assert(standardOutputWriter == null, "standardOutputWriter should not exist at this point");
|
||||
standardOutputWriter = Console.Out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[ArchitectureSensitive]
|
||||
private void InitializeStandardErrorWriter(NakedWin32Handle stdHandle)
|
||||
{
|
||||
Dbg.Assert(standardErrorWriter == null, "standardErrorWriter should not exist at this point");
|
||||
standardErrorWriter = Console.Error;
|
||||
}
|
||||
|
||||
internal TextWriter StandardOutputWriter
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsStandardOutputRedirected)
|
||||
{
|
||||
Dbg.Assert(standardOutputWriter != null, "standardOutputWriter should be initialized");
|
||||
|
||||
return standardOutputWriter;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal TextWriter StandardErrorWriter
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsStandardErrorRedirected)
|
||||
{
|
||||
Dbg.Assert(standardErrorWriter != null, "standardErrorWriter should be initialized");
|
||||
|
||||
return standardErrorWriter;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal TextReader StandardInReader
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsStandardInputRedirected)
|
||||
{
|
||||
Dbg.Assert(standardInputReader != null, "standardInputReader should be initialized");
|
||||
|
||||
return standardInputReader;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion stdio redirection
|
||||
|
||||
#region debugger
|
||||
|
||||
/// <summary>
|
||||
@ -2544,12 +2363,6 @@ namespace Microsoft.PowerShell
|
||||
bool inBlockMode = false;
|
||||
bool previousResponseWasEmpty = false;
|
||||
StringBuilder inputBlock = new StringBuilder();
|
||||
bool displayPrompt = false;
|
||||
// If the prompt has not been displayed in the native code or if the input loop is nested, we need to display the prompt here
|
||||
if (!parent.promptDisplayedInNativeCode || inputLoopIsNested)
|
||||
{
|
||||
displayPrompt = true;
|
||||
}
|
||||
|
||||
while (!parent.ShouldEndSession && !shouldExit)
|
||||
{
|
||||
@ -2559,53 +2372,42 @@ namespace Microsoft.PowerShell
|
||||
|
||||
string prompt = null;
|
||||
string line = null;
|
||||
if (displayPrompt)
|
||||
if (!ui.NoPrompt)
|
||||
{
|
||||
if (!ui.NoPrompt)
|
||||
if (inBlockMode)
|
||||
{
|
||||
if (inBlockMode)
|
||||
{
|
||||
// use a special prompt that denotes block mode
|
||||
// use a special prompt that denotes block mode
|
||||
|
||||
prompt = ">> ";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure the cursor is at the start of the line - some external programs don't
|
||||
// write a newline, so we do that for them.
|
||||
if (ui.RawUI.CursorPosition.X != 0)
|
||||
ui.WriteLine();
|
||||
|
||||
// Evaluate any suggestions
|
||||
if(! previousResponseWasEmpty)
|
||||
{
|
||||
EvaluateSuggestions(ui);
|
||||
}
|
||||
|
||||
// Then output the prompt
|
||||
if (this.parent.InDebugMode)
|
||||
{
|
||||
prompt = EvaluateDebugPrompt();
|
||||
}
|
||||
if (prompt == null)
|
||||
{
|
||||
prompt = EvaluatePrompt();
|
||||
}
|
||||
}
|
||||
ui.Write(prompt);
|
||||
prompt = ">> ";
|
||||
}
|
||||
previousResponseWasEmpty = false;
|
||||
// There could be a profile. So there could be a user defined custom readline command
|
||||
line = ui.ReadLineWithTabCompletion(exec, useUserDefinedCustomReadLine: true);
|
||||
else
|
||||
{
|
||||
// Make sure the cursor is at the start of the line - some external programs don't
|
||||
// write a newline, so we do that for them.
|
||||
if (ui.RawUI.CursorPosition.X != 0)
|
||||
ui.WriteLine();
|
||||
|
||||
// Evaluate any suggestions
|
||||
if(! previousResponseWasEmpty)
|
||||
{
|
||||
EvaluateSuggestions(ui);
|
||||
}
|
||||
|
||||
// Then output the prompt
|
||||
if (this.parent.InDebugMode)
|
||||
{
|
||||
prompt = EvaluateDebugPrompt();
|
||||
}
|
||||
if (prompt == null)
|
||||
{
|
||||
prompt = EvaluatePrompt();
|
||||
}
|
||||
}
|
||||
ui.Write(prompt);
|
||||
}
|
||||
else
|
||||
{
|
||||
previousResponseWasEmpty = false;
|
||||
// There are no profiles. So there is no user defined custom readline command
|
||||
line = ui.ReadLineWithTabCompletion(exec, useUserDefinedCustomReadLine: false);
|
||||
displayPrompt = true;
|
||||
}
|
||||
previousResponseWasEmpty = false;
|
||||
// There could be a profile. So there could be a user defined custom readline command
|
||||
line = ui.ReadLineWithTabCompletion(exec);
|
||||
|
||||
// line will be null in the case that Ctrl-C terminated the input
|
||||
|
||||
@ -2623,7 +2425,7 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
inBlockMode = false;
|
||||
|
||||
if (parent.IsStandardInputRedirected)
|
||||
if (Console.IsInputRedirected)
|
||||
{
|
||||
// null is also the result of reading stdin to EOF.
|
||||
|
||||
@ -2711,7 +2513,7 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parent.IsRunningAsync)
|
||||
if (parent.IsRunningAsync && !parent.IsNested)
|
||||
{
|
||||
exec.ExecuteCommandAsync(line, out e, Executor.ExecutionOptions.AddOutputter | Executor.ExecutionOptions.AddToHistory);
|
||||
}
|
||||
@ -3047,7 +2849,9 @@ namespace Microsoft.PowerShell
|
||||
/// </summary>
|
||||
private RunspaceRef runspaceRef;
|
||||
|
||||
#if !PORTABLE
|
||||
private GCHandle breakHandlerGcHandle;
|
||||
#endif
|
||||
private System.Threading.Thread breakHandlerThread;
|
||||
private bool isDisposed;
|
||||
internal ConsoleHostUserInterface ui;
|
||||
@ -3076,18 +2880,6 @@ namespace Microsoft.PowerShell
|
||||
private bool shouldEndSession;
|
||||
private int beginApplicationNotifyCount;
|
||||
|
||||
private bool isStandardOutputRedirectionDetermined;
|
||||
private bool isStandardOutputRedirected;
|
||||
private TextWriter standardOutputWriter;
|
||||
private bool isStandardErrorRedirectionDetermined;
|
||||
private bool isStandardErrorRedirected;
|
||||
private TextWriter standardErrorWriter;
|
||||
private bool isStandardInputRedirectionDetermined;
|
||||
private bool isStandardInputRedirected;
|
||||
private TextReader standardInputReader;
|
||||
private InitializeStandardHandleDelegate initStandardOutDelegate;
|
||||
private InitializeStandardHandleDelegate initStandardInDelegate;
|
||||
private InitializeStandardHandleDelegate initStandardErrorDelegate;
|
||||
private ConsoleTextWriter consoleWriter;
|
||||
private WrappedSerializer outputSerializer;
|
||||
private WrappedSerializer errorSerializer;
|
||||
|
@ -1,3 +1,4 @@
|
||||
#if !PORTABLE
|
||||
/********************************************************************++
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
--********************************************************************/
|
||||
@ -1499,3 +1500,280 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#else
|
||||
|
||||
// Managed code only implementation for portability
|
||||
|
||||
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;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.PowerShell
|
||||
{
|
||||
// this is all originally from https://msdn.microsoft.com/en-us/library/ee706570%28v=vs.85%29.aspx
|
||||
|
||||
internal sealed class ConsoleHostRawUserInterface : PSHostRawUserInterface
|
||||
{
|
||||
private ConsoleColor defaultForeground = ConsoleColor.Gray;
|
||||
|
||||
private ConsoleColor defaultBackground = ConsoleColor.Black;
|
||||
|
||||
private ConsoleHostUserInterface parent = null;
|
||||
|
||||
internal ConsoleHostRawUserInterface(ConsoleHostUserInterface mshConsole) : base()
|
||||
{
|
||||
defaultForeground = ForegroundColor;
|
||||
defaultBackground = BackgroundColor;
|
||||
parent = mshConsole;
|
||||
}
|
||||
|
||||
/// <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; }
|
||||
}
|
||||
|
||||
// TODO: Make wrap width user-customizable.
|
||||
private static Size WrapSize = new Size(80, 40);
|
||||
|
||||
/// <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
|
||||
{
|
||||
// When stdout is redirected, the buffer size is (0, 0);
|
||||
// however, this is still queried for use in formatting, so we
|
||||
// provide the WrapSize.
|
||||
if (Console.IsOutputRedirected)
|
||||
{
|
||||
return WrapSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
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 { return new Coordinates(Console.CursorLeft, Console.CursorTop); }
|
||||
set { Console.SetCursorPosition(value.X, value.Y); }
|
||||
}
|
||||
|
||||
/// <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 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 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); }
|
||||
}
|
||||
|
||||
/// <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); }
|
||||
}
|
||||
|
||||
/// <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); }
|
||||
}
|
||||
|
||||
/// <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
|
||||
{
|
||||
if (Console.IsOutputRedirected)
|
||||
{
|
||||
return WrapSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Size(Console.WindowWidth, Console.WindowHeight);
|
||||
}
|
||||
}
|
||||
set { Console.SetWindowSize(value.Width, value.Height); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cached Window Title, for systems that needs it
|
||||
/// </summary>
|
||||
private string title = String.Empty;
|
||||
|
||||
/// <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
|
||||
{
|
||||
// In Unix/Linux systems, Console.Title current results in a not-implemented
|
||||
// exception. In that case, we return a cached copy of title that was set earlier.
|
||||
// Obviously, this will not work if: 1) Title was never set in PowerShell, or 2)
|
||||
// one sets the windows's title outside of PowerShell.
|
||||
string result;
|
||||
try
|
||||
{
|
||||
result = Console.Title;
|
||||
}
|
||||
catch (PlatformNotSupportedException)
|
||||
{
|
||||
return title;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
Console.Title = value;
|
||||
title = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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.
|
||||
/// </summary>
|
||||
/// <param name="options">Unused</param>
|
||||
public override KeyInfo ReadKey(ReadKeyOptions options)
|
||||
{
|
||||
ConsoleKeyInfo key = Console.ReadKey();
|
||||
return new KeyInfo((int)key.Key, key.KeyChar, new ControlKeyStates(), true);
|
||||
}
|
||||
|
||||
/// <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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -14,7 +14,9 @@ using System.Management.Automation.Internal;
|
||||
using System.Management.Automation.Host;
|
||||
using System.Security;
|
||||
using Dbg = System.Management.Automation.Diagnostics;
|
||||
#if !PORTABLE
|
||||
using ConsoleHandle = Microsoft.Win32.SafeHandles.SafeFileHandle;
|
||||
#endif
|
||||
|
||||
namespace Microsoft.PowerShell
|
||||
{
|
||||
@ -58,7 +60,11 @@ namespace Microsoft.PowerShell
|
||||
|
||||
this.parent = parent;
|
||||
this.rawui = new ConsoleHostRawUserInterface(this);
|
||||
isInteractiveTestToolListening = false;
|
||||
|
||||
#if PORTABLE
|
||||
this._supportsVirtualTerminal = true;
|
||||
#else
|
||||
// Turn on virtual terminal if possible.
|
||||
var handle = ConsoleControl.GetActiveScreenBufferHandle();
|
||||
var m = ConsoleControl.GetMode(handle);
|
||||
@ -71,9 +77,7 @@ namespace Microsoft.PowerShell
|
||||
// systems ignore the setting.
|
||||
m = ConsoleControl.GetMode(handle);
|
||||
this._supportsVirtualTerminal = (m & ConsoleControl.ConsoleModes.VirtualTerminal) != 0;
|
||||
|
||||
isInteractiveTestToolListening = false;
|
||||
isTestingShiftTab = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -140,17 +144,7 @@ namespace Microsoft.PowerShell
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
internal bool ReadFromStdin
|
||||
{
|
||||
get
|
||||
{
|
||||
return readFromStdin;
|
||||
}
|
||||
set
|
||||
{
|
||||
readFromStdin = value;
|
||||
}
|
||||
}
|
||||
internal bool ReadFromStdin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@ -284,6 +278,9 @@ namespace Microsoft.PowerShell
|
||||
|
||||
private object ReadLineSafe(bool isSecureString, char? printToken)
|
||||
{
|
||||
#if PORTABLE
|
||||
throw new PlatformNotSupportedException("Cannot read secure strings!");
|
||||
#else
|
||||
// Don't lock (instanceLock) in here -- the caller needs to do that...
|
||||
|
||||
PreRead();
|
||||
@ -404,8 +401,11 @@ namespace Microsoft.PowerShell
|
||||
{
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !PORTABLE
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Handle writing print token with proper cursor adjustment for ReadLineSafe
|
||||
@ -535,7 +535,6 @@ namespace Microsoft.PowerShell
|
||||
/// false otherwise
|
||||
///
|
||||
/// </returns>
|
||||
|
||||
private static bool shouldUnsetMode(
|
||||
ConsoleControl.ConsoleModes flagToUnset,
|
||||
ref ConsoleControl.ConsoleModes m)
|
||||
@ -547,11 +546,14 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#region WriteToConsole
|
||||
|
||||
internal void WriteToConsole(string value, bool transcribeResult)
|
||||
{
|
||||
|
||||
#if !PORTABLE
|
||||
ConsoleHandle handle = ConsoleControl.GetActiveScreenBufferHandle();
|
||||
|
||||
// Ensure that we're in the proper line-output mode. We don't lock here as it does not matter if we
|
||||
@ -568,17 +570,21 @@ namespace Microsoft.PowerShell
|
||||
m |= desiredMode;
|
||||
ConsoleControl.SetMode(handle, m);
|
||||
}
|
||||
#endif
|
||||
|
||||
PreWrite();
|
||||
|
||||
// This is atomic, so we don't lock here...
|
||||
|
||||
#if !PORTABLE
|
||||
ConsoleControl.WriteConsole(handle, value);
|
||||
#else
|
||||
Console.Out.Write(value);
|
||||
#endif
|
||||
|
||||
if (isInteractiveTestToolListening && parent.IsStandardOutputRedirected)
|
||||
if (isInteractiveTestToolListening && Console.IsOutputRedirected)
|
||||
{
|
||||
Dbg.Assert(parent.StandardOutputWriter != null, "stdout writer should be initialized");
|
||||
parent.StandardOutputWriter.Write(value);
|
||||
Console.Out.Write(value);
|
||||
}
|
||||
|
||||
if (transcribeResult)
|
||||
@ -659,10 +665,7 @@ namespace Microsoft.PowerShell
|
||||
// If the test hook is set, write to it and continue.
|
||||
if (_h != null) _h.Write(value);
|
||||
|
||||
TextWriter writer =
|
||||
(!parent.IsStandardOutputRedirected || parent.IsInteractive)
|
||||
? parent.ConsoleTextWriter
|
||||
: parent.StandardOutputWriter;
|
||||
TextWriter writer = Console.IsOutputRedirected ? Console.Out : parent.ConsoleTextWriter;
|
||||
|
||||
if (parent.IsRunningAsync)
|
||||
{
|
||||
@ -1362,9 +1365,9 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
|
||||
TextWriter writer =
|
||||
(!parent.IsStandardErrorRedirected || parent.IsInteractive)
|
||||
(!Console.IsErrorRedirected || parent.IsInteractive)
|
||||
? parent.ConsoleTextWriter
|
||||
: parent.StandardErrorWriter;
|
||||
: Console.Error;
|
||||
|
||||
if (parent.ErrorFormat == Serialization.DataFormat.XML)
|
||||
{
|
||||
@ -1378,7 +1381,7 @@ namespace Microsoft.PowerShell
|
||||
WriteLine(errorForegroundColor, errorBackgroundColor, value);
|
||||
else
|
||||
|
||||
parent.StandardErrorWriter.Write(value + Crlf);
|
||||
Console.Error.Write(value + Crlf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1480,9 +1483,9 @@ namespace Microsoft.PowerShell
|
||||
|
||||
|
||||
|
||||
// We don't use System.Environment.NewLine because we are very platform specific with our use of the win32 console APIs
|
||||
// We use System.Environment.NewLine because we are platform-agnostic
|
||||
|
||||
internal const string Crlf = "\x000D\x000A";
|
||||
internal static string Crlf = System.Environment.NewLine;
|
||||
private const string Tab = "\x0009";
|
||||
|
||||
internal enum ReadLineResult
|
||||
@ -1555,21 +1558,75 @@ namespace Microsoft.PowerShell
|
||||
// If the test hook is set, read from it.
|
||||
if (_h != null) return _h.ReadLine();
|
||||
|
||||
string s = "";
|
||||
if (parent.IsStandardInputRedirected && readFromStdin)
|
||||
string restOfLine = null;
|
||||
|
||||
string s = ReadFromStdin
|
||||
? ReadLineFromFile(initialContent)
|
||||
: ReadLineFromConsole(endOnTab, initialContent, calledFromPipeline, ref restOfLine, ref result);
|
||||
|
||||
if (transcribeResult)
|
||||
{
|
||||
// When reading from a file handle instead of a console, endOnTab and initial content are ignored.
|
||||
|
||||
// StreamReader.ReadLine simply returns null when EOF is reached.
|
||||
|
||||
s = parent.StandardInReader.ReadLine();
|
||||
if (endOnTab && !string.IsNullOrEmpty(s) && s.IndexOf(Tab, StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
result = isTestingShiftTab ? ReadLineResult.endedOnShiftTab : ReadLineResult.endedOnTab;
|
||||
return s;
|
||||
}
|
||||
return s;
|
||||
PostRead(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
PostRead();
|
||||
}
|
||||
|
||||
if (restOfLine != null)
|
||||
s += restOfLine;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private string ReadLineFromFile(string initialContent)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
if (initialContent != null)
|
||||
{
|
||||
sb.Append(initialContent);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
var inC = Console.In.Read();
|
||||
if (inC == -1)
|
||||
{
|
||||
// EOF - we return null which tells our caller to exit
|
||||
return null;
|
||||
}
|
||||
|
||||
var c = unchecked((char)inC);
|
||||
if (!NoPrompt) Console.Out.Write(c);
|
||||
|
||||
if (c == '\r')
|
||||
{
|
||||
// Treat as newline, but consume \n if there is one.
|
||||
if (Console.In.Peek() == '\n')
|
||||
{
|
||||
if (!NoPrompt) Console.Out.Write('\n');
|
||||
Console.In.Read();
|
||||
}
|
||||
sb.Append('\n');
|
||||
break;
|
||||
}
|
||||
|
||||
sb.Append(c);
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private string ReadLineFromConsole(bool endOnTab, string initialContent, bool calledFromPipeline, ref string restOfLine, ref ReadLineResult result)
|
||||
{
|
||||
#if PORTABLE
|
||||
return ReadLineFromFile(initialContent);
|
||||
#else
|
||||
|
||||
ConsoleHandle handle = ConsoleControl.GetInputHandle();
|
||||
PreRead();
|
||||
@ -1588,6 +1645,7 @@ namespace Microsoft.PowerShell
|
||||
m |= desiredMode;
|
||||
ConsoleControl.SetMode(handle, m);
|
||||
}
|
||||
|
||||
// If more characters are typed than you asked, then the next call to ReadConsole will return the
|
||||
// additional characters beyond those you requested.
|
||||
//
|
||||
@ -1604,10 +1662,10 @@ namespace Microsoft.PowerShell
|
||||
// the empty string.
|
||||
|
||||
uint keyState = 0;
|
||||
string restOfLine = null;
|
||||
|
||||
rawui.ClearKeyCache();
|
||||
|
||||
string s = "";
|
||||
do
|
||||
{
|
||||
s += ConsoleControl.ReadConsole(handle, initialContent, maxInputLineLength, endOnTab, out keyState);
|
||||
@ -1688,23 +1746,12 @@ namespace Microsoft.PowerShell
|
||||
while (true);
|
||||
|
||||
Dbg.Assert(
|
||||
(s == null && result == ReadLineResult.endedOnBreak)
|
||||
|| (s != null && result != ReadLineResult.endedOnBreak),
|
||||
"s should only be null if input ended with a break");
|
||||
|
||||
if (transcribeResult)
|
||||
{
|
||||
PostRead(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
PostRead();
|
||||
}
|
||||
|
||||
if (restOfLine != null)
|
||||
s += restOfLine;
|
||||
(s == null && result == ReadLineResult.endedOnBreak)
|
||||
|| (s != null && result != ReadLineResult.endedOnBreak),
|
||||
"s should only be null if input ended with a break");
|
||||
|
||||
return s;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1712,6 +1759,7 @@ namespace Microsoft.PowerShell
|
||||
/// </summary>
|
||||
/// <param name="cursorPosition">the cursor position where 'tab' is hit</param>
|
||||
/// <returns></returns>
|
||||
#if !PORTABLE
|
||||
private char GetCharacterUnderCursor(Coordinates cursorPosition)
|
||||
{
|
||||
Rectangle region = new Rectangle(0, cursorPosition.Y, RawUI.BufferSize.Width - 1, cursorPosition.Y);
|
||||
@ -1734,6 +1782,7 @@ namespace Microsoft.PowerShell
|
||||
Dbg.Assert(false, "the character at the cursor should be retrieved, never gets to here");
|
||||
return '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/// <summary>
|
||||
@ -1764,29 +1813,23 @@ namespace Microsoft.PowerShell
|
||||
///
|
||||
/// The Executor instance on which to run any pipelines that are needed to find matches
|
||||
///
|
||||
/// </param>
|
||||
///
|
||||
/// <param name="useUserDefinedCustomReadLine">
|
||||
///
|
||||
/// Flag which decides if we should look for a user defined ReadLine function
|
||||
///
|
||||
/// </param>
|
||||
///
|
||||
/// <returns>
|
||||
///
|
||||
/// null on a break event
|
||||
/// the completed line otherwise
|
||||
///
|
||||
/// </returns>
|
||||
internal string ReadLineWithTabCompletion(Executor exec, bool useUserDefinedCustomReadLine)
|
||||
internal string ReadLineWithTabCompletion(Executor exec)
|
||||
{
|
||||
ConsoleHandle handle = ConsoleControl.GetActiveScreenBufferHandle();
|
||||
|
||||
string input = null;
|
||||
string lastInput = "";
|
||||
string lastCompletion = "";
|
||||
|
||||
ReadLineResult rlResult = ReadLineResult.endedOnEnter;
|
||||
|
||||
#if !PORTABLE
|
||||
ConsoleHandle handle = ConsoleControl.GetActiveScreenBufferHandle();
|
||||
|
||||
string lastCompletion = "";
|
||||
Size screenBufferSize = RawUI.BufferSize;
|
||||
|
||||
// Save the cursor position at the end of the prompt string so that we can restore it later to write the
|
||||
@ -1796,19 +1839,17 @@ namespace Microsoft.PowerShell
|
||||
|
||||
CommandCompletion commandCompletion = null;
|
||||
string completionInput = null;
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
if (TryInvokeUserDefinedReadLine(out input, useUserDefinedCustomReadLine))
|
||||
if (!ReadFromStdin && TryInvokeUserDefinedReadLine(out input))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
input = ReadLine(true, lastInput, out rlResult, false, false);
|
||||
|
||||
Coordinates endOfInputCursorPos = RawUI.CursorPosition;
|
||||
string completedInput = null;
|
||||
|
||||
if (input == null)
|
||||
{
|
||||
break;
|
||||
@ -1819,6 +1860,13 @@ namespace Microsoft.PowerShell
|
||||
break;
|
||||
}
|
||||
|
||||
#if PORTABLE // Portable code only ends on enter (or no input), so tab is not processed
|
||||
throw new PlatformNotSupportedException("This readline state is unsupported in portable code!");
|
||||
#else
|
||||
|
||||
Coordinates endOfInputCursorPos = RawUI.CursorPosition;
|
||||
string completedInput = null;
|
||||
|
||||
if (rlResult == ReadLineResult.endedOnTab || rlResult == ReadLineResult.endedOnShiftTab)
|
||||
{
|
||||
int tabIndex = input.IndexOf(Tab, StringComparison.CurrentCulture);
|
||||
@ -1828,16 +1876,11 @@ namespace Microsoft.PowerShell
|
||||
int leftover = input.Length - tabIndex - 1;
|
||||
if (leftover > 0)
|
||||
{
|
||||
// Check if the std input is redirected, e.g. reading from a file
|
||||
bool isStdInputRedirected = parent.IsStandardInputRedirected && readFromStdin;
|
||||
if (!isStdInputRedirected)
|
||||
{
|
||||
// We are reading from the console
|
||||
// If the cursor is at the end of a line, there is actually a space character at the cursor's position and when we type tab
|
||||
// at the end of a line, that space character is replaced by the tab. But when we type tab at the middle of a line, the space
|
||||
// character at the end is preserved, we should remove that space character because it's not provided by the user.
|
||||
input = input.Remove(input.Length - 1);
|
||||
}
|
||||
// We are reading from the console (not redirected, b/c we don't end on tab when redirected)
|
||||
// If the cursor is at the end of a line, there is actually a space character at the cursor's position and when we type tab
|
||||
// at the end of a line, that space character is replaced by the tab. But when we type tab at the middle of a line, the space
|
||||
// character at the end is preserved, we should remove that space character because it's not provided by the user.
|
||||
input = input.Remove(input.Length - 1);
|
||||
restOfLine = input.Substring(tabIndex + 1);
|
||||
}
|
||||
input = input.Remove(tabIndex);
|
||||
@ -1927,6 +1970,7 @@ namespace Microsoft.PowerShell
|
||||
|
||||
lastInput = completedInput;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
while (true);
|
||||
|
||||
@ -1942,6 +1986,7 @@ namespace Microsoft.PowerShell
|
||||
return input;
|
||||
}
|
||||
|
||||
#if !PORTABLE
|
||||
private void SendLeftArrows(int length)
|
||||
{
|
||||
var inputs = new ConsoleControl.INPUT[length * 2];
|
||||
@ -1971,6 +2016,7 @@ namespace Microsoft.PowerShell
|
||||
|
||||
ConsoleControl.MimicKeyPress(inputs);
|
||||
}
|
||||
#endif
|
||||
|
||||
private CommandCompletion GetNewCompletionResults(string input)
|
||||
{
|
||||
@ -2011,44 +2057,43 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
|
||||
const string CustomReadlineCommand = "PSConsoleHostReadLine";
|
||||
private bool TryInvokeUserDefinedReadLine(out string input, bool useUserDefinedCustomReadLine)
|
||||
private bool TryInvokeUserDefinedReadLine(out string input)
|
||||
{
|
||||
// We're using GetCommands instead of GetCommand so we don't auto-load a module should the command exist, but isn't loaded.
|
||||
// The idea is that if someone hasn't defined the command (say because they started -noprofile), we shouldn't auto-load
|
||||
// this function.
|
||||
|
||||
// If we need to look for user defined custom readline command, then we need to wait for Runspace to be created.
|
||||
if (useUserDefinedCustomReadLine)
|
||||
var runspace = this.parent.LocalRunspace;
|
||||
if (runspace != null &&
|
||||
runspace.Engine.Context.EngineIntrinsics.InvokeCommand.
|
||||
GetCommands(CustomReadlineCommand,
|
||||
CommandTypes.Function | CommandTypes.Cmdlet, nameIsPattern: false).Any())
|
||||
{
|
||||
var runspace = this.parent.LocalRunspace;
|
||||
if (runspace != null
|
||||
&& runspace.Engine.Context.EngineIntrinsics.InvokeCommand.GetCommands(CustomReadlineCommand, CommandTypes.Function | CommandTypes.Cmdlet, nameIsPattern: false).Any())
|
||||
try
|
||||
{
|
||||
try
|
||||
PowerShell ps;
|
||||
if ((runspace.ExecutionContext.EngineHostInterface.NestedPromptCount > 0) &&
|
||||
(Runspace.DefaultRunspace != null))
|
||||
{
|
||||
PowerShell ps;
|
||||
if ((runspace.ExecutionContext.EngineHostInterface.NestedPromptCount > 0) && (Runspace.DefaultRunspace != null))
|
||||
{
|
||||
ps = PowerShell.Create(RunspaceMode.CurrentRunspace);
|
||||
}
|
||||
else
|
||||
{
|
||||
ps = PowerShell.Create();
|
||||
ps.Runspace = runspace;
|
||||
}
|
||||
ps = PowerShell.Create(RunspaceMode.CurrentRunspace);
|
||||
}
|
||||
else
|
||||
{
|
||||
ps = PowerShell.Create();
|
||||
ps.Runspace = runspace;
|
||||
}
|
||||
|
||||
var result = ps.AddCommand(CustomReadlineCommand).Invoke();
|
||||
if (result.Count == 1)
|
||||
{
|
||||
input = PSObject.Base(result[0]) as string;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
var result = ps.AddCommand(CustomReadlineCommand).Invoke();
|
||||
if (result.Count == 1)
|
||||
{
|
||||
CommandProcessorBase.CheckForSevereException(e);
|
||||
input = PSObject.Base(result[0]) as string;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CommandProcessorBase.CheckForSevereException(e);
|
||||
}
|
||||
}
|
||||
|
||||
input = null;
|
||||
@ -2061,7 +2106,6 @@ namespace Microsoft.PowerShell
|
||||
|
||||
private object instanceLock = new object();
|
||||
|
||||
private bool readFromStdin;
|
||||
private bool noPrompt;
|
||||
|
||||
//If this is true, class throws on read or prompt method which require
|
||||
@ -2086,7 +2130,6 @@ namespace Microsoft.PowerShell
|
||||
// this is a test hook for the ConsoleInteractiveTestTool, which sets this field to true.
|
||||
|
||||
private bool isInteractiveTestToolListening;
|
||||
private bool isTestingShiftTab;
|
||||
|
||||
// This instance data is "read-only" and need not have access serialized.
|
||||
|
||||
|
@ -215,11 +215,11 @@ namespace Microsoft.PowerShell
|
||||
PipelineFinishedWaitHandle waiterThereIsAFlyInMySoup = new PipelineFinishedWaitHandle(tempPipeline);
|
||||
|
||||
tempPipeline.InvokeAsync();
|
||||
if ((options & ExecutionOptions.ReadInputObjects) > 0 && parent.IsStandardInputRedirected)
|
||||
if ((options & ExecutionOptions.ReadInputObjects) > 0 && Console.IsInputRedirected)
|
||||
{
|
||||
// read input objects from stdin
|
||||
|
||||
WrappedDeserializer des = new WrappedDeserializer(parent.InputFormat, "Input", parent.StandardInReader);
|
||||
WrappedDeserializer des = new WrappedDeserializer(parent.InputFormat, "Input", Console.In);
|
||||
while (!des.AtEnd)
|
||||
{
|
||||
object o = des.Deserialize();
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Microsoft.PowerShell.ConsoleHost",
|
||||
"version": "1.0.0-*",
|
||||
"description": "Full Windows PowerShell Host (requires native host)",
|
||||
"description": "PowerShell Host",
|
||||
"authors": [ "sevoroby", "andschwa" ],
|
||||
|
||||
"compilationOptions": {
|
||||
@ -10,6 +10,7 @@
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"Microsoft.PowerShell.PSReadLine": "1.0.0-*",
|
||||
"Microsoft.PowerShell.Commands.Management": "1.0.0-*",
|
||||
"Microsoft.PowerShell.Commands.Utility": "1.0.0-*"
|
||||
},
|
||||
@ -21,6 +22,17 @@
|
||||
],
|
||||
|
||||
"frameworks": {
|
||||
"netstandard1.5": {
|
||||
"imports": [ "dnxcore50", "portable-net45+win8" ],
|
||||
"compilationOptions": {
|
||||
"define": [ "CORECLR", "PORTABLE" ]
|
||||
},
|
||||
"dependencies": {
|
||||
"Newtonsoft.Json": "8.0.2",
|
||||
"System.Xml.XDocument": "4.0.11-rc2-24103",
|
||||
"System.IO.MemoryMappedFiles": "4.0.0-rc2-24103"
|
||||
}
|
||||
},
|
||||
"net451": {
|
||||
}
|
||||
},
|
||||
|
@ -1,3 +1,4 @@
|
||||
#if !PORTABLE
|
||||
/********************************************************************++
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
--********************************************************************/
|
||||
@ -86,3 +87,4 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1,3 +1,4 @@
|
||||
#if !PORTABLE
|
||||
/********************************************************************++
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
--********************************************************************/
|
||||
@ -92,3 +93,4 @@ namespace Microsoft.PowerShell
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1,8 +0,0 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
[assembly:InternalsVisibleTo("powershell-tests")]
|
||||
|
||||
[assembly:AssemblyCulture("")]
|
||||
[assembly:NeutralResourcesLanguage("en-US")]
|
@ -1,25 +0,0 @@
|
||||
# Core PowerShell Host
|
||||
|
||||
This host is based off the infamous `host06` example. It relies only on managed
|
||||
code, and is cross-platform. It needs a fair bit of work, but it loads
|
||||
profiles, has tab-completion, and can be used to debug PowerShell scripts.
|
||||
|
||||
## Executable
|
||||
|
||||
The `bin/powershell[.exe]` executable for Core PowerShell is built by this
|
||||
project, as it is the top dependency of the graph, and has `emitEntryPoint:
|
||||
true`, meaning a native executable is produced automatically by CLI (no need to
|
||||
own a separate native host). It is also the project that deploys the `ps1xml`
|
||||
types and formatting files, as well as the default profile and the included
|
||||
PowerShell modules.
|
||||
|
||||
Note that many of these should probably live with System.Management.Automation,
|
||||
but we're waiting on a bug fix from CLI to move them.
|
||||
|
||||
## update-content.sh
|
||||
|
||||
This script is used to update our current tree's files with those that live in
|
||||
`src/monad`. We only need to update them when new changes are merged from
|
||||
Source Depot, and the build scripts are much simpler without this logic. With
|
||||
the files living here, the `content` key in the `project.json` handles the
|
||||
deployment for us in a cross-platform manner.
|
@ -1,218 +0,0 @@
|
||||
namespace Microsoft.PowerShell.CoreConsoleHost
|
||||
{
|
||||
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(Listener Listener)
|
||||
{
|
||||
this.Listener = Listener;
|
||||
this.myHostUserInterface = new MyHostUserInterface(Listener.HasUI, Listener.Interactive);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the PSHost implementation.
|
||||
/// </summary>
|
||||
private Listener Listener;
|
||||
|
||||
/// <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;
|
||||
|
||||
/// <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 "CoreConsoleHost"; }
|
||||
}
|
||||
|
||||
/// <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.Listener.myRunSpace; }
|
||||
internal set { this.Listener.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.Listener.ShouldExit = true;
|
||||
this.Listener.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
|
||||
}
|
||||
}
|
||||
|
@ -1,857 +0,0 @@
|
||||
namespace Microsoft.PowerShell.CoreConsoleHost
|
||||
{
|
||||
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 System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Linq;
|
||||
using PowerShell = System.Management.Automation.PowerShell;
|
||||
|
||||
public static class Program
|
||||
{
|
||||
private enum Options {Help, File, Command, NoProfile, NonInteractive, EncodedCommand, Invalid};
|
||||
private class CommandOptions
|
||||
{
|
||||
public Options opt;
|
||||
public string optString;
|
||||
|
||||
public CommandOptions(Options o, string s)
|
||||
{
|
||||
opt = o;
|
||||
optString = s;
|
||||
}
|
||||
}
|
||||
|
||||
private static CommandOptions[] commandOptions = new CommandOptions[]
|
||||
{
|
||||
new CommandOptions(Options.Help, "help"),
|
||||
new CommandOptions(Options.Help, "?"),
|
||||
new CommandOptions(Options.File, "file"),
|
||||
new CommandOptions(Options.Command, "command"),
|
||||
new CommandOptions(Options.NoProfile, "noprofile"),
|
||||
new CommandOptions(Options.NonInteractive, "noninteractive"),
|
||||
new CommandOptions(Options.EncodedCommand, "encodedcommand")
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Creates and initiates the listener instance.
|
||||
/// </summary>
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Setup the Assembly Load Context, which Core PowerShell uses to
|
||||
// analyze the libraries for types, functions, cmdlets, etc. and
|
||||
// provide the ability to load assemblies by file path. Doing this
|
||||
// here eliminates the need for a custom native host.
|
||||
PowerShellAssemblyLoadContextInitializer.SetPowerShellAssemblyLoadContext(string.Empty);
|
||||
|
||||
|
||||
// Argument parsing
|
||||
string initialScript = null;
|
||||
bool loadProfiles = true;
|
||||
bool interactive = true;
|
||||
|
||||
if (args.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
{
|
||||
string arg = args[i];
|
||||
bool hasNext = (i+1) < args.Length;
|
||||
string nextArg = hasNext ? args[i+1] : string.Empty;
|
||||
|
||||
// options start with "-" or "--"
|
||||
|
||||
string option;
|
||||
if (arg.StartsWith("-"))
|
||||
{
|
||||
if (arg.StartsWith("--"))
|
||||
{
|
||||
option = arg.Remove(0, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
option = arg.Remove(0, 1);
|
||||
}
|
||||
|
||||
Options bestOption = FindOption(option);
|
||||
|
||||
switch (bestOption)
|
||||
{
|
||||
case Options.Help:
|
||||
Console.WriteLine(@"
|
||||
usage: powershell[.exe] [ (--help | -h | -?) ]
|
||||
[ (--file | -f) <filePath> ]
|
||||
[ <script>.ps1 ]
|
||||
[ (--command | -c) <string> ]
|
||||
[ --noprofile | -nop ]
|
||||
[ --noninteractive | -non ]
|
||||
[ (--encodedcommand | -e) <base64Command> ]
|
||||
|
||||
SYNOPSIS
|
||||
|
||||
Open PowerShell console can take none or one of several arguments.
|
||||
|
||||
OPTIONS
|
||||
|
||||
No arguments
|
||||
Will launch PowerShell interactively.
|
||||
|
||||
(--file | -f) <filePath>
|
||||
Given a file path, will execute as a PowerShell script.
|
||||
|
||||
<script>.ps1
|
||||
Given a .ps1 script, will execute without needing --flag.
|
||||
|
||||
(--command | -c) <string>
|
||||
Will execute given string as a PowerShell script.
|
||||
|
||||
(--noprofile | -nop)
|
||||
Disables parsing of PowerShell profiles.
|
||||
|
||||
(--help | -h | -?)
|
||||
Prints this text.
|
||||
|
||||
(--noninteractive | -non)
|
||||
Does not present an interactive prompt to the user.
|
||||
|
||||
(--encodedcommand | -e) <base64Command>
|
||||
Accepts a base-64-encoded string version of a command.
|
||||
");
|
||||
return;
|
||||
|
||||
case Options.NoProfile:
|
||||
loadProfiles = false;
|
||||
break;
|
||||
case Options.File:
|
||||
initialScript = Path.GetFullPath(nextArg);
|
||||
++i;
|
||||
break;
|
||||
case Options.Command:
|
||||
if (nextArg == "-")
|
||||
{
|
||||
initialScript = "\"TODO: read stdin using Console.OpenStandardInput\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
initialScript = nextArg;
|
||||
}
|
||||
++i;
|
||||
break;
|
||||
case Options.NonInteractive:
|
||||
interactive = false;
|
||||
break;
|
||||
case Options.EncodedCommand:
|
||||
byte[] data = Convert.FromBase64String(nextArg);
|
||||
initialScript = Encoding.Unicode.GetString(data);
|
||||
++i;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("Invalid command-line option: {0}. Use '-help' option to get a list of valid options.", arg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else // not an option parameter
|
||||
{
|
||||
// lone argument is a script
|
||||
if (!hasNext && arg.EndsWith(".ps1"))
|
||||
{
|
||||
initialScript = Path.GetFullPath(arg);
|
||||
}
|
||||
// lone argument is an inline script
|
||||
else if (!hasNext)
|
||||
{
|
||||
initialScript = arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: check for input on stdin
|
||||
|
||||
ConsoleColor InitialForegroundColor = Console.ForegroundColor;
|
||||
ConsoleColor InitialBackgroundColor = Console.BackgroundColor;
|
||||
|
||||
// Create the listener and run it
|
||||
Listener listener = new Listener(initialScript, loadProfiles, interactive);
|
||||
|
||||
// only run if there was no script file passed in
|
||||
if (initialScript == null)
|
||||
{
|
||||
listener.Run();
|
||||
}
|
||||
|
||||
Console.ForegroundColor = InitialForegroundColor;
|
||||
Console.BackgroundColor = InitialBackgroundColor;
|
||||
|
||||
// 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.
|
||||
System.Environment.Exit(listener.ExitCode);
|
||||
}
|
||||
|
||||
private static Options FindOption(string option)
|
||||
{
|
||||
int matches = 0;
|
||||
int index = -1;
|
||||
|
||||
for (int i=0; i<commandOptions.Length; ++i)
|
||||
{
|
||||
if (commandOptions[i].optString.StartsWith(option, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
matches++;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return (matches == 1) ? commandOptions[index].opt : Options.Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Listener
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to read user input.
|
||||
/// </summary>
|
||||
internal ConsoleReadLine 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>
|
||||
/// To keep track whether we've displayed the debugger help message
|
||||
/// </summary>
|
||||
private bool _showHelpMessage;
|
||||
|
||||
/// <summary>
|
||||
/// To keep track whether last entered command was complete
|
||||
/// </summary>
|
||||
private bool incompleteLine = false;
|
||||
|
||||
/// <summary>
|
||||
/// To store incomplete lines
|
||||
/// </summary>
|
||||
private string partialLine = string.Empty;
|
||||
|
||||
/// <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; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether UI exists (display prompt)
|
||||
/// </summary>
|
||||
public bool HasUI;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether session is interactive (allow popup)
|
||||
/// </summary>
|
||||
public bool Interactive;
|
||||
|
||||
public Listener(string initialScript, bool loadProfiles, bool interactive)
|
||||
{
|
||||
this.HasUI = (initialScript == null) ? true : false;
|
||||
this.Interactive = interactive;
|
||||
|
||||
// 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();
|
||||
this.consoleReadLine = new ConsoleReadLine(this.myHost.Runspace, this.myHost.UI);
|
||||
|
||||
if (this.myRunSpace.Debugger != null)
|
||||
{
|
||||
this.myRunSpace.Debugger.DebuggerStop += HandleDebuggerStopEvent;
|
||||
|
||||
// Workflow debugging is new for PowerShell version 4 and is an opt-in
|
||||
// feature. In order to debug Workflow script functions the debugger
|
||||
// DebugMode must include the DebugModes.LocalScript flag.
|
||||
this.myRunSpace.Debugger.SetDebugMode(DebugModes.LocalScript);
|
||||
}
|
||||
|
||||
if (loadProfiles)
|
||||
{
|
||||
LoadProfiles();
|
||||
}
|
||||
|
||||
// run the initial script
|
||||
if (initialScript != null)
|
||||
{
|
||||
Execute(initialScript);
|
||||
}
|
||||
}
|
||||
|
||||
internal void LoadProfiles()
|
||||
{
|
||||
// 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 = HostUtilities.GetProfileCommands("Microsoft.PowerShellCore");
|
||||
foreach (PSCommand command in profileCommands)
|
||||
{
|
||||
RunCommand(command);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
// The PowerShell instance will be null if it failed to
|
||||
// start due to, say, a parse exception in a profile.
|
||||
if (this.currentPowerShell != null) {
|
||||
this.currentPowerShell.Dispose();
|
||||
this.currentPowerShell = null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the prompt equal to the output of the prompt function
|
||||
public string Prompt(Runspace rs)
|
||||
{
|
||||
string returnVal = string.Empty;
|
||||
|
||||
if (this.myHost.IsRunspacePushed)
|
||||
{
|
||||
returnVal = string.Format($"{System.Environment.NewLine}[{this.myRunSpace.ConnectionInfo.ComputerName}] PSL> ");
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
if (incompleteLine)
|
||||
{
|
||||
return ">> ";
|
||||
}
|
||||
|
||||
Collection<PSObject> output;
|
||||
Command promptCommand = new Command("prompt");
|
||||
|
||||
using (Pipeline pipeline = rs.CreatePipeline())
|
||||
{
|
||||
pipeline.Commands.Add(promptCommand);
|
||||
output = pipeline.Invoke();
|
||||
}
|
||||
|
||||
foreach (PSObject item in output)
|
||||
{
|
||||
returnVal = item.BaseObject.ToString();
|
||||
}
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs individual commands
|
||||
/// </summary>
|
||||
/// <param name="command">command to run</param>
|
||||
internal void RunCommand(PSCommand command)
|
||||
{
|
||||
if (command == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
command.AddCommand("out-default");
|
||||
command.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
|
||||
|
||||
this.currentPowerShell.Commands = command;
|
||||
|
||||
try
|
||||
{
|
||||
this.currentPowerShell.Invoke();
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
this.ReportException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
string fullCommand = incompleteLine ? (partialLine + cmd) : cmd;
|
||||
this.currentPowerShell.AddScript(fullCommand);
|
||||
incompleteLine = false;
|
||||
|
||||
// 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.
|
||||
PSInvocationSettings settings = new PSInvocationSettings();
|
||||
settings.AddToHistory = true;
|
||||
if (input != null)
|
||||
{
|
||||
this.currentPowerShell.Invoke(new object[] { input }, settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.currentPowerShell.Invoke(null, settings);
|
||||
}
|
||||
}
|
||||
catch (IncompleteParseException)
|
||||
{
|
||||
incompleteLine = true;
|
||||
partialLine = $"{partialLine}{cmd}{System.Environment.NewLine}";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!incompleteLine)
|
||||
{
|
||||
partialLine = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
// Return non-zero exit code if an exception is thrown
|
||||
this.ExitCode = 1;
|
||||
|
||||
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)
|
||||
{
|
||||
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>
|
||||
internal void Run()
|
||||
{
|
||||
// Set up the control-C handler.
|
||||
Console.CancelKeyPress += new ConsoleCancelEventHandler(this.HandleControlC);
|
||||
|
||||
string initialCommand = String.Empty;
|
||||
|
||||
// Read commands and run them until the ShouldExit flag is set by
|
||||
// the user calling "exit".
|
||||
while (!this.ShouldExit && this.myHost.Runspace != null)
|
||||
{
|
||||
// Reset exit code for each command
|
||||
this.ExitCode = 0;
|
||||
|
||||
// If the prompt function failed for any reason, use a sane default
|
||||
string prompt;
|
||||
try
|
||||
{
|
||||
prompt = Prompt(this.myHost.Runspace);
|
||||
}
|
||||
catch
|
||||
{
|
||||
prompt = "PS> ";
|
||||
}
|
||||
|
||||
this.myHost.UI.Write(prompt);
|
||||
|
||||
string input;
|
||||
if (TryInvokeUserDefinedReadLine(out input, true))
|
||||
{
|
||||
this.Execute(input);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConsoleReadLine.ReadResult result = consoleReadLine.Read(false, initialCommand);
|
||||
|
||||
switch(result.state)
|
||||
{
|
||||
case ConsoleReadLine.ReadResult.State.Abort:
|
||||
incompleteLine = false;
|
||||
partialLine = string.Empty;
|
||||
initialCommand = String.Empty;
|
||||
break;
|
||||
case ConsoleReadLine.ReadResult.State.Redraw:
|
||||
initialCommand = result.command;
|
||||
break;
|
||||
case ConsoleReadLine.ReadResult.State.Complete:
|
||||
default:
|
||||
this.Execute(result.command);
|
||||
initialCommand = String.Empty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function to test if PSReadLine or another alternate ReadLine has been loaded
|
||||
/// </summary>
|
||||
const string CustomReadlineCommand = "PSConsoleHostReadLine";
|
||||
private bool TryInvokeUserDefinedReadLine(out string input, bool useUserDefinedCustomReadLine)
|
||||
{
|
||||
if (useUserDefinedCustomReadLine)
|
||||
{
|
||||
var runspace = this.myHost.Runspace;
|
||||
if (runspace != null
|
||||
&& runspace.ExecutionContext.EngineIntrinsics.InvokeCommand.GetCommands(CustomReadlineCommand, CommandTypes.Function | CommandTypes.Cmdlet, nameIsPattern: false).Any())
|
||||
{
|
||||
try
|
||||
{
|
||||
PowerShell ps;
|
||||
if ((runspace.ExecutionContext.EngineHostInterface.NestedPromptCount > 0) && (Runspace.DefaultRunspace != null))
|
||||
{
|
||||
ps = PowerShell.Create(RunspaceMode.CurrentRunspace);
|
||||
}
|
||||
else
|
||||
{
|
||||
ps = PowerShell.Create();
|
||||
ps.Runspace = runspace;
|
||||
}
|
||||
|
||||
var result = ps.AddCommand(CustomReadlineCommand).Invoke();
|
||||
if (result.Count == 1)
|
||||
{
|
||||
input = PSObject.Base(result[0]) as string;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CommandProcessorBase.CheckForSevereException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to handle the Debugger DebuggerStop event.
|
||||
/// </summary>
|
||||
/// <param name="sender"> Debugger instance
|
||||
/// <param name="args"> DebuggerStop event args
|
||||
private void HandleDebuggerStopEvent(object sender, DebuggerStopEventArgs args)
|
||||
{
|
||||
Debugger debugger = sender as Debugger;
|
||||
DebuggerResumeAction? resumeAction = null;
|
||||
|
||||
WriteDebuggerStopMessages(args);
|
||||
|
||||
string initialCommand = String.Empty;
|
||||
|
||||
// loop to process Debugger commands.
|
||||
while (resumeAction == null)
|
||||
{
|
||||
string prompt = incompleteLine ? ">> " : "[DBG] PS >> ";
|
||||
this.myHost.UI.Write(prompt);
|
||||
|
||||
ConsoleReadLine.ReadResult result = consoleReadLine.Read(true, initialCommand);
|
||||
|
||||
switch(result.state)
|
||||
{
|
||||
case ConsoleReadLine.ReadResult.State.Abort:
|
||||
incompleteLine = false;
|
||||
partialLine = string.Empty;
|
||||
initialCommand = String.Empty;
|
||||
continue;
|
||||
case ConsoleReadLine.ReadResult.State.Redraw:
|
||||
initialCommand = result.command;
|
||||
continue;
|
||||
case ConsoleReadLine.ReadResult.State.Complete:
|
||||
default:
|
||||
initialCommand = String.Empty;
|
||||
break;
|
||||
}
|
||||
|
||||
// Stream output from command processing to console.
|
||||
var output = new PSDataCollection<PSObject>();
|
||||
output.DataAdded += (dSender, dArgs) =>
|
||||
{
|
||||
foreach (var item in output.ReadAll())
|
||||
{
|
||||
this.myHost.UI.WriteLine(item.ToString());
|
||||
}
|
||||
};
|
||||
|
||||
// Process command.
|
||||
// The Debugger.ProcesCommand method will parse and handle debugger specific
|
||||
// commands such as 'h' (help), 'list', 'stepover', etc. If the command is
|
||||
// not specific to the debugger then it will be evaluated as a PowerShell
|
||||
// command or script. The returned DebuggerCommandResults object will indicate
|
||||
// whether the command was evaluated by the debugger and if the debugger should
|
||||
// be released with a specific resume action.
|
||||
|
||||
PSCommand psCommand = new PSCommand();
|
||||
|
||||
string fullCommand = incompleteLine ? (partialLine + result.command) : result.command;
|
||||
psCommand.AddScript(fullCommand).AddCommand("Out-String").AddParameter("Stream", true);
|
||||
incompleteLine = false;
|
||||
|
||||
DebuggerCommandResults results = null;
|
||||
try
|
||||
{
|
||||
results = debugger.ProcessCommand(psCommand, output);
|
||||
}
|
||||
catch (IncompleteParseException)
|
||||
{
|
||||
incompleteLine = true;
|
||||
partialLine = $"{partialLine}{result.command}{System.Environment.NewLine}";
|
||||
}
|
||||
|
||||
if (!incompleteLine)
|
||||
{
|
||||
partialLine = string.Empty;
|
||||
}
|
||||
|
||||
if (!incompleteLine && results.ResumeAction != null)
|
||||
{
|
||||
resumeAction = results.ResumeAction;
|
||||
}
|
||||
}
|
||||
|
||||
// Return from event handler with user resume action.
|
||||
args.ResumeAction = resumeAction.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to write debugger stop messages.
|
||||
/// </summary>
|
||||
/// <param name="args">DebuggerStopEventArgs for current debugger stop</param>
|
||||
private void WriteDebuggerStopMessages(DebuggerStopEventArgs args)
|
||||
{
|
||||
// Write debugger stop information in yellow.
|
||||
ConsoleColor saveFGColor = Console.ForegroundColor;
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
|
||||
// Show help message only once.
|
||||
if (!_showHelpMessage)
|
||||
{
|
||||
this.myHost.UI.WriteLine("Entering debug mode. Type 'h' to get help.");
|
||||
this.myHost.UI.WriteLine();
|
||||
_showHelpMessage = true;
|
||||
}
|
||||
|
||||
// Breakpoint stop information. Writes all breakpoints that
|
||||
// pertain to this debugger execution stop point.
|
||||
if (args.Breakpoints.Count > 0)
|
||||
{
|
||||
this.myHost.UI.WriteLine("Debugger hit breakpoint on:");
|
||||
foreach (var breakPoint in args.Breakpoints)
|
||||
{
|
||||
this.myHost.UI.WriteLine(breakPoint.ToString());
|
||||
}
|
||||
this.myHost.UI.WriteLine();
|
||||
}
|
||||
|
||||
// Script position stop information.
|
||||
// This writes the InvocationInfo position message if
|
||||
// there is one.
|
||||
if (args.InvocationInfo != null)
|
||||
{
|
||||
this.myHost.UI.WriteLine(args.InvocationInfo.PositionMessage);
|
||||
this.myHost.UI.WriteLine();
|
||||
}
|
||||
|
||||
Console.ForegroundColor = saveFGColor;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,237 +0,0 @@
|
||||
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;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.PowerShell.CoreConsoleHost
|
||||
{
|
||||
// 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(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 { return new Coordinates(Console.CursorLeft, Console.CursorTop); }
|
||||
set { Console.SetCursorPosition(value.X, value.Y); }
|
||||
}
|
||||
|
||||
/// <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 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 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); }
|
||||
}
|
||||
|
||||
/// <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); }
|
||||
}
|
||||
|
||||
/// <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); }
|
||||
}
|
||||
|
||||
/// <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); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cached Window Title, for systems that needs it
|
||||
/// </summary>
|
||||
private string title = String.Empty;
|
||||
|
||||
/// <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
|
||||
{
|
||||
// In Unix/Linux systems, Console.Title current results in a not-implemented
|
||||
// exception. In that case, we return a cached copy of title that was set earlier.
|
||||
// Obviously, this will not work if: 1) Title was never set in PowerShell, or 2)
|
||||
// one sets the windows's title outside of PowerShell.
|
||||
string result;
|
||||
try
|
||||
{
|
||||
result = Console.Title;
|
||||
}
|
||||
catch (PlatformNotSupportedException)
|
||||
{
|
||||
return title;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
Console.Title = value;
|
||||
title = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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.
|
||||
/// </summary>
|
||||
/// <param name="options">Unused</param>
|
||||
public override KeyInfo ReadKey(ReadKeyOptions options)
|
||||
{
|
||||
ConsoleKeyInfo key = Console.ReadKey();
|
||||
return new KeyInfo((int)key.Key, key.KeyChar, new ControlKeyStates(), true);
|
||||
}
|
||||
|
||||
/// <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.");
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,566 +0,0 @@
|
||||
namespace Microsoft.PowerShell.CoreConsoleHost
|
||||
{
|
||||
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>
|
||||
/// Public constructor
|
||||
/// </summary>
|
||||
public MyHostUserInterface(bool hasUI, bool interactive)
|
||||
{
|
||||
myRawUi = (hasUI) ? new MyRawUserInterface() : null;
|
||||
Interactive = interactive;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the PSRawUserInterface implementation.
|
||||
/// </summary>
|
||||
private MyRawUserInterface myRawUi;
|
||||
|
||||
/// <summary>
|
||||
/// Gets an instance of the PSRawUserInterface class for this host
|
||||
/// application.
|
||||
/// </summary>
|
||||
public override PSHostRawUserInterface RawUI
|
||||
{
|
||||
get { return this.myRawUi; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether user pop-ups are allowed
|
||||
/// </summary>
|
||||
public bool Interactive;
|
||||
|
||||
/// <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)
|
||||
{
|
||||
if (Interactive)
|
||||
{
|
||||
this.Write(
|
||||
ConsoleColor.White,
|
||||
Console.BackgroundColor,
|
||||
caption + System.Environment.NewLine + 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;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PSInvalidOperationException("Cannot prompt user when invoked with --noninteractive option.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
if (Interactive)
|
||||
{
|
||||
// Write the caption and message strings in Blue.
|
||||
this.WriteLine(
|
||||
ConsoleColor.Blue,
|
||||
Console.BackgroundColor,
|
||||
caption + System.Environment.NewLine + message + System.Environment.NewLine);
|
||||
|
||||
// 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, Console.BackgroundColor, 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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PSInvalidOperationException("Cannot prompt user when invoked with --noninteractive option.");
|
||||
}
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
if (Interactive)
|
||||
{
|
||||
// Write the caption and message strings in Blue.
|
||||
this.WriteLine(
|
||||
ConsoleColor.Blue,
|
||||
Console.BackgroundColor,
|
||||
caption + System.Environment.NewLine + message + System.Environment.NewLine);
|
||||
|
||||
// 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,
|
||||
Console.BackgroundColor,
|
||||
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, Console.BackgroundColor, 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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PSInvalidOperationException("Cannot prompt user when invoked with --noninteractive option.");
|
||||
}
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
ConsoleColor oldFg = Console.ForegroundColor;
|
||||
ConsoleColor oldBg = Console.BackgroundColor;
|
||||
Console.ForegroundColor = foregroundColor;
|
||||
Console.BackgroundColor = backgroundColor;
|
||||
Console.Write(value);
|
||||
Console.ForegroundColor = oldFg;
|
||||
Console.BackgroundColor = oldBg;
|
||||
}
|
||||
|
||||
|
||||
/// <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 foreground 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)
|
||||
{
|
||||
ConsoleColor oldFg = Console.ForegroundColor;
|
||||
ConsoleColor oldBg = Console.BackgroundColor;
|
||||
Console.ForegroundColor = foregroundColor;
|
||||
Console.BackgroundColor = backgroundColor;
|
||||
Console.WriteLine(value);
|
||||
Console.ForegroundColor = oldFg;
|
||||
Console.BackgroundColor = oldBg;
|
||||
}
|
||||
|
||||
/// <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.Yellow,
|
||||
Console.BackgroundColor,
|
||||
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,
|
||||
Console.BackgroundColor,
|
||||
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)
|
||||
{
|
||||
|
||||
if (record == null)
|
||||
{
|
||||
throw PSTraceSource.NewArgumentNullException("record");
|
||||
}
|
||||
|
||||
string percentComplete = " [";
|
||||
|
||||
for (int i =0; i < record.PercentComplete; i++){
|
||||
percentComplete = percentComplete + "0";
|
||||
}
|
||||
|
||||
percentComplete = percentComplete + "]";
|
||||
Console.Write ("\r{0} {1} {2} ", record.Activity, record.StatusDescription, percentComplete, "\r");
|
||||
|
||||
if (record.PercentComplete == 100){
|
||||
Console.WriteLine(); //create a new line for the prompt
|
||||
}
|
||||
}
|
||||
|
||||
/// <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,
|
||||
Console.BackgroundColor,
|
||||
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,
|
||||
Console.BackgroundColor,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,13 @@
|
||||
"define": [ "CORECLR" ]
|
||||
},
|
||||
"imports": [ "dnxcore50", "portable-net45+win8" ]
|
||||
},
|
||||
"net451": {
|
||||
"frameworkAssemblies": {
|
||||
"System.Windows.Forms": {
|
||||
"type": "build"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ using System.Resources;
|
||||
[assembly:InternalsVisibleTo("Microsoft.PowerShell.Commands.Utility")]
|
||||
[assembly:InternalsVisibleTo("Microsoft.PowerShell.Security")]
|
||||
[assembly:InternalsVisibleTo("Microsoft.PowerShell.CoreCLR.AssemblyLoadContext")]
|
||||
[assembly:InternalsVisibleTo("powershell")]
|
||||
[assembly:InternalsVisibleTo("Microsoft.PowerShell.ConsoleHost")]
|
||||
[assembly:InternalsVisibleTo("powershell-tests")]
|
||||
|
||||
#else
|
||||
|
@ -60,7 +60,10 @@ namespace System.Management.Automation.Runspaces
|
||||
var unused0 = RunspaceInit.OutputEncodingDescription;
|
||||
|
||||
// Amsi initialize can also be a little slow
|
||||
AmsiUtils.Init();
|
||||
if (Platform.IsWindows)
|
||||
{
|
||||
AmsiUtils.Init();
|
||||
}
|
||||
|
||||
// This will init some tables and could load some assemblies.
|
||||
var unused1 = TypeAccelerators.builtinTypeAccelerators;
|
||||
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8.4)
|
||||
project(PSL-NATIVE)
|
||||
|
||||
add_compile_options(-std=c++11 -Wall -Werror)
|
||||
set(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/../Microsoft.PowerShell.CoreConsoleHost")
|
||||
set(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/../powershell")
|
||||
|
||||
# test in BUILD_DIR
|
||||
enable_testing()
|
||||
|
@ -1,3 +1,3 @@
|
||||
*.a
|
||||
*.so
|
||||
*.dylib
|
||||
*.dylib
|
29
src/powershell/Program.cs
Normal file
29
src/powershell/Program.cs
Normal file
@ -0,0 +1,29 @@
|
||||
/********************************************************************++
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
--********************************************************************/
|
||||
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace Microsoft.PowerShell
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an entry point for the .NET CLI "powershell" app
|
||||
/// </summary>
|
||||
public sealed class ManagedPSEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts the managed MSH
|
||||
/// </summary>
|
||||
/// <param name="args">
|
||||
/// Command line arguments to the managed MSH
|
||||
/// </param>
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
#if CORECLR
|
||||
// Open PowerShell has to set the ALC here, since we don't own the native host
|
||||
PowerShellAssemblyLoadContextInitializer.SetPowerShellAssemblyLoadContext(string.Empty);
|
||||
#endif
|
||||
return UnmanagedPSEntry.Start(string.Empty, args, args.Length);
|
||||
}
|
||||
}
|
||||
}
|
20
src/powershell/README.md
Normal file
20
src/powershell/README.md
Normal file
@ -0,0 +1,20 @@
|
||||
PowerShell
|
||||
==========
|
||||
|
||||
The `powershell[.exe]` executable for Open PowerShell is built by this project,
|
||||
as it is the top dependency of the graph, and has `emitEntryPoint: true`,
|
||||
meaning a native executable is produced automatically by CLI (no need to own a
|
||||
separate native host).
|
||||
|
||||
This project is a very simple shim that provides a `Main` function for .NET CLI
|
||||
to produce an app. It initializes PowerShell's custom `AssemblyLoadContext` and
|
||||
then delegates to the same `Start` function in
|
||||
`Microsoft.PowerShell.ConsoleHost` that the original native PowerShell host
|
||||
executes; thus we share the same entry point and the same PowerShell host, but
|
||||
use a different native host. This lets us take full advantage of .NET CLI's
|
||||
native host.
|
||||
|
||||
We use this shim so that the `ConsoleHost` project and the original native host
|
||||
do not have to be changed. Additionally, until .NET CLI bugs surrounding content
|
||||
file deployment are solved, this shim allows us to continue with our split
|
||||
`Modules` folders work-around to deploy the correct versions.
|
@ -1,21 +1,17 @@
|
||||
{
|
||||
"name": "powershell",
|
||||
"version": "1.0.0-*",
|
||||
"description": "PowerShell Managed Console for .NET Core",
|
||||
"description": ".NET CLI PowerShell app",
|
||||
"authors": [ "andschwa" ],
|
||||
|
||||
"compilationOptions": {
|
||||
"warningsAsErrors": true,
|
||||
"allowUnsafe": true,
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"Newtonsoft.Json": "8.0.2",
|
||||
"System.Xml.XDocument": "4.0.11-rc2-24103",
|
||||
"System.IO.MemoryMappedFiles": "4.0.0-rc2-24103",
|
||||
"Microsoft.PowerShell.Commands.Management": "1.0.0-*",
|
||||
"Microsoft.PowerShell.Commands.Utility": "1.0.0-*",
|
||||
"Microsoft.PowerShell.PSReadLine": "1.0.0-*"
|
||||
"Microsoft.PowerShell.ConsoleHost": "1.0.0-*"
|
||||
},
|
||||
|
||||
"content": [
|
||||
@ -29,8 +25,11 @@
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"imports": [ "dnxcore50", "portable-net45+win8" ],
|
||||
"compilationOptions": {
|
||||
"define": [ "CORECLR" ]
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": "1.0.0-rc2-3002485"
|
||||
"Microsoft.NETCore.App": "1.0.0-rc2-3002668"
|
||||
}
|
||||
}
|
||||
},
|
@ -1,7 +1,6 @@
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using Microsoft.PowerShell.CoreConsoleHost;
|
||||
|
||||
// This collection fixture initializes Core PowerShell's AssemblyLoadContext once and only
|
||||
// once. Attempting to initialize in a class level fixture will cause multiple
|
||||
|
@ -5,7 +5,7 @@
|
||||
"authors": [ "andschwa" ],
|
||||
|
||||
"dependencies": {
|
||||
"Microsoft.PowerShell.CoreConsoleHost": "1.0.0-*"
|
||||
"Microsoft.PowerShell.ConsoleHost": "1.0.0-*"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
|
@ -9,18 +9,6 @@ namespace PSTests
|
||||
[Collection("AssemblyLoadContext")]
|
||||
public static class PlatformTests
|
||||
{
|
||||
[Fact]
|
||||
public static void TestIsLinux()
|
||||
{
|
||||
Assert.True(Platform.IsLinux);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TestIsWindows()
|
||||
{
|
||||
Assert.False(Platform.IsWindows);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TestIsCore()
|
||||
{
|
||||
@ -80,7 +68,7 @@ namespace PSTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Skip="Bad arguments for OS X")]
|
||||
public static void TestGetMachineName()
|
||||
{
|
||||
var startInfo = new ProcessStartInfo
|
||||
@ -103,7 +91,7 @@ namespace PSTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Skip="Bad arguments for OS X")]
|
||||
public static void TestGetFQDN()
|
||||
{
|
||||
var startInfo = new ProcessStartInfo
|
||||
@ -126,7 +114,7 @@ namespace PSTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Skip="Bad arguments for OS X")]
|
||||
public static void TestGetDomainName()
|
||||
{
|
||||
var startInfo = new ProcessStartInfo
|
||||
|
@ -13,7 +13,6 @@ using System.Management.Automation.Provider;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using Microsoft.PowerShell;
|
||||
using Microsoft.PowerShell.Commands;
|
||||
using Microsoft.PowerShell.CoreConsoleHost;
|
||||
|
||||
namespace PSTests
|
||||
{
|
||||
|
@ -2,7 +2,6 @@ using Xunit;
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using Microsoft.PowerShell.CoreConsoleHost;
|
||||
|
||||
namespace PSTests
|
||||
{
|
||||
@ -63,55 +62,6 @@ namespace PSTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestRunspaceWithPowerShellAndHost()
|
||||
{
|
||||
Listener listener = new Listener("", false, false);
|
||||
MyHost myHost = new MyHost(listener);
|
||||
using (var runspace = RunspaceFactory.CreateRunspace(myHost))
|
||||
{
|
||||
runspace.Open();
|
||||
|
||||
using (PowerShell powerShell = PowerShell.Create())
|
||||
{
|
||||
powerShell.Runspace = runspace;
|
||||
|
||||
powerShell.AddScript(script);
|
||||
|
||||
int objCount = 0;
|
||||
foreach (var result in powerShell.Invoke())
|
||||
{
|
||||
++objCount;
|
||||
Assert.NotNull(result);
|
||||
}
|
||||
Assert.Equal(count, objCount);
|
||||
}
|
||||
|
||||
runspace.Close();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestRunspaceWithFunction()
|
||||
{
|
||||
Listener listener = new Listener("", false, false);
|
||||
MyHost myHost = new MyHost(listener);
|
||||
using (var runspace = RunspaceFactory.CreateRunspace(myHost))
|
||||
{
|
||||
runspace.Open();
|
||||
|
||||
using (PowerShell powerShell = PowerShell.Create())
|
||||
{
|
||||
powerShell.Runspace = runspace;
|
||||
|
||||
powerShell.AddScript("{1}.Invoke()");
|
||||
powerShell.Invoke();
|
||||
}
|
||||
|
||||
runspace.Close();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestRunspaceWithPowerShellAndInitialSessionState()
|
||||
{
|
||||
|
@ -9,7 +9,6 @@ using System.Management.Automation.Internal;
|
||||
using System.Management.Automation.Internal.Host;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using Microsoft.PowerShell;
|
||||
using Microsoft.PowerShell.CoreConsoleHost;
|
||||
|
||||
namespace PSTests
|
||||
{
|
||||
|
145
test/powershell/ConsoleHost.Tests.ps1
Normal file
145
test/powershell/ConsoleHost.Tests.ps1
Normal file
@ -0,0 +1,145 @@
|
||||
using namespace System.Diagnostics
|
||||
|
||||
Describe "ConsoleHost unit tests" {
|
||||
$powershell = Join-Path -Path $PsHome -ChildPath "powershell"
|
||||
|
||||
Context "CommandLine" {
|
||||
It "simple -args" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
& $powershell -noprofile { $args[0] } -args "hello world" | Should Be "hello world"
|
||||
}
|
||||
|
||||
It "array -args" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
& $powershell -noprofile { $args[0] } -args 1,(2,3) | Should Be 1
|
||||
(& $powershell -noprofile { $args[1] } -args 1,(2,3))[1] | Should Be 3
|
||||
}
|
||||
foreach ($x in "--help", "-help", "-h", "-?", "--he", "-hel", "--HELP", "-hEl") {
|
||||
It "Accepts '$x' as a parameter for help" {
|
||||
& $powershell -noprofile $x | ?{ $_ -match "PowerShell[.exe] -Help | -? | /?" } | Should Not BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
|
||||
It "Should accept a Base64 encoded command" {
|
||||
$commandString = "Get-Location"
|
||||
$encodedCommand = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($commandString))
|
||||
# We don't compare to `Get-Location` directly because object and formatted output comparisons are difficult
|
||||
$expected = & $powershell -noprofile -command $commandString
|
||||
$actual = & $powershell -noprofile -EncodedCommand $encodedCommand
|
||||
$actual | Should Be $expected
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Context "Pipe to/from powershell" {
|
||||
$p = [PSCustomObject]@{X=10;Y=20}
|
||||
|
||||
It "xml input" {
|
||||
$p | & $powershell -noprofile { $input | Foreach-Object {$a = 0} { $a += $_.X + $_.Y } { $a } } | Should Be 30
|
||||
$p | & $powershell -noprofile -inputFormat xml { $input | Foreach-Object {$a = 0} { $a += $_.X + $_.Y } { $a } } | Should Be 30
|
||||
}
|
||||
|
||||
It "text input" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
# Join (multiple lines) and remove whitespace (we don't care about spacing) to verify we converted to string (by generating a table)
|
||||
$p | & $powershell -noprofile -inputFormat text { -join ($input -replace "\s","") } | Should Be "XY--1020"
|
||||
}
|
||||
|
||||
It "xml output" {
|
||||
& $powershell -noprofile { [PSCustomObject]@{X=10;Y=20} } | Foreach-Object {$a = 0} { $a += $_.X + $_.Y } { $a } | Should Be 30
|
||||
& $powershell -noprofile -outputFormat xml { [PSCustomObject]@{X=10;Y=20} } | Foreach-Object {$a = 0} { $a += $_.X + $_.Y } { $a } | Should Be 30
|
||||
}
|
||||
|
||||
It "text output" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
# Join (multiple lines) and remove whitespace (we don't care about spacing) to verify we converted to string (by generating a table)
|
||||
-join (& $powershell -noprofile -outputFormat text { [PSCustomObject]@{X=10;Y=20} }) -replace "\s","" | Should Be "XY--1020"
|
||||
}
|
||||
}
|
||||
|
||||
Context "Redirected standard handles" {
|
||||
function NewProcessStartInfo([string]$CommandLine, [switch]$RedirectStdIn)
|
||||
{
|
||||
return [ProcessStartInfo]@{
|
||||
FileName = $powershell
|
||||
Arguments = $CommandLine
|
||||
RedirectStandardInput = $RedirectStdIn
|
||||
RedirectStandardOutput = $true
|
||||
RedirectStandardError = $true
|
||||
UseShellExecute = $false
|
||||
}
|
||||
}
|
||||
|
||||
function RunPowerShell([ProcessStartInfo]$si)
|
||||
{
|
||||
$process = [Process]::Start($si)
|
||||
|
||||
return $process
|
||||
}
|
||||
|
||||
function EnsureChildHasExited([Process]$process, [int]$WaitTimeInMS = 15000)
|
||||
{
|
||||
$process.WaitForExit($WaitTimeInMS)
|
||||
|
||||
if (!$process.HasExited)
|
||||
{
|
||||
$process.HasExited | Should Be $true
|
||||
$process.Kill()
|
||||
}
|
||||
}
|
||||
|
||||
It "Simple redirected output" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$si = NewProcessStartInfo "-noprofile 1+1"
|
||||
$process = RunPowerShell $si
|
||||
$process.StandardOutput.ReadToEnd() | Should Be 2
|
||||
EnsureChildHasExited $process
|
||||
}
|
||||
|
||||
$nl = [Environment]::Newline
|
||||
|
||||
# Redirected input is broken on Windows in .NET Core
|
||||
It "Redirected input" -Pending:$IsWindows {
|
||||
$si = NewProcessStartInfo "-noprofile ""`$function:prompt = { 'PS> ' }""" -RedirectStdIn
|
||||
$process = RunPowerShell $si
|
||||
$process.StandardInput.Write("1+1`n")
|
||||
$process.StandardOutput.ReadLine() | Should Be "PS> 1+1"
|
||||
$process.StandardOutput.ReadLine() | Should Be "2"
|
||||
$process.StandardInput.Write("1+2`n")
|
||||
$process.StandardOutput.ReadLine() | Should Be "PS> 1+2"
|
||||
$process.StandardOutput.ReadLine() | Should Be "3"
|
||||
$process.StandardInput.Close()
|
||||
$process.StandardOutput.ReadToEnd() | Should Be "PS> "
|
||||
EnsureChildHasExited $process
|
||||
}
|
||||
|
||||
It "Redirected input explicit prompting" -Pending:$IsCore {
|
||||
$si = NewProcessStartInfo "-noprofile -File -" -RedirectStdIn
|
||||
$process = RunPowerShell $si
|
||||
$process.StandardInput.Write("`$function:prompt = { 'PS> ' }`n")
|
||||
$null = $process.StandardOutput.ReadLine()
|
||||
$process.StandardInput.Write("1+1`n")
|
||||
$process.StandardOutput.ReadLine() | Should Be "PS> 1+1"
|
||||
$process.StandardOutput.ReadLine() | Should Be "2"
|
||||
$process.StandardInput.Close()
|
||||
$process.StandardOutput.ReadToEnd() | Should Be "PS> "
|
||||
EnsureChildHasExited $process
|
||||
}
|
||||
|
||||
It "Redirected input no prompting" -Pending:$IsCore {
|
||||
$si = NewProcessStartInfo "-noprofile -" -RedirectStdIn
|
||||
$process = RunPowerShell $si
|
||||
$process.StandardInput.Write("1+1`n")
|
||||
$process.StandardInput.Close()
|
||||
$process.StandardOutput.ReadToEnd() | Should Be "2${nl}"
|
||||
EnsureChildHasExited $process
|
||||
}
|
||||
|
||||
It "Redirected input w/ nested prompt" -Pending:$IsCore {
|
||||
$si = NewProcessStartInfo "-noprofile ""`$function:prompt = { 'PS' + ('>'*(`$nestedPromptLevel+1)) + ' ' }""" -RedirectStdIn
|
||||
$process = RunPowerShell $si
|
||||
$process.StandardInput.Write("`$host.EnterNestedPrompt()`n")
|
||||
$process.StandardOutput.ReadLine() | Should Be "PS> `$host.EnterNestedPrompt()"
|
||||
$process.StandardInput.Write("exit`n")
|
||||
$process.StandardOutput.ReadLine() | Should Be "PS>> exit"
|
||||
$process.StandardInput.Close()
|
||||
$process.StandardOutput.ReadToEnd() | Should Be "PS> "
|
||||
EnsureChildHasExited $process
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
Describe "CoreConsoleHost unit tests" {
|
||||
$powershell = Join-Path -Path $PsHome -ChildPath "powershell"
|
||||
|
||||
Context "Command-line parsing" {
|
||||
|
||||
foreach ($x in "--help", "-help", "-h", "-?", "--he", "-hel", "--HELP", "-hEl") {
|
||||
It "Accepts '$x' as a parameter for help" {
|
||||
& $powershell -noprofile $x | ?{ $_ -match "usage: powershell" } | Should Not BeNullOrEmpty
|
||||
}
|
||||
}
|
||||
|
||||
It "Should accept a Base64 encoded command" {
|
||||
$commandString = "Get-Location"
|
||||
$encodedCommand = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($commandString))
|
||||
# We don't compare to `Get-Location` directly because object and formatted output comparisons are difficult
|
||||
$expected = & $powershell -noprofile -command $commandString
|
||||
$actual = & $powershell -noprofile -EncodedCommand $encodedCommand
|
||||
$actual | Should Be $expected
|
||||
}
|
||||
}
|
||||
}
|
@ -26,19 +26,19 @@ Describe "Format-Custom" {
|
||||
|
||||
|
||||
Describe "Format-Custom DRT basic functionality" -Tags DRT{
|
||||
It "Format-Custom with subobject should work"{
|
||||
$expectResult1 = "this is the name"
|
||||
$expectResult2 = "this is the name of the sub object"
|
||||
$testObject = @{}
|
||||
$testObject.name = $expectResult1
|
||||
$testObject.subObjectValue = @{}
|
||||
$testObject.subObjectValue.name = $expectResult2
|
||||
$testObject.subObjectValue.array = (0..63)
|
||||
$testObject.subObjectValue.stringarray = @("one","two")
|
||||
$result = $testObject | Format-Custom | Out-String
|
||||
$result | Should Match $expectResult1
|
||||
$result | Should Match $expectResult2
|
||||
$result | Should Match "one"
|
||||
$result | Should Match "two"
|
||||
}
|
||||
}
|
||||
It "Format-Custom with subobject should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$expectResult1 = "this is the name"
|
||||
$expectResult2 = "this is the name of the sub object"
|
||||
$testObject = @{}
|
||||
$testObject.name = $expectResult1
|
||||
$testObject.subObjectValue = @{}
|
||||
$testObject.subObjectValue.name = $expectResult2
|
||||
$testObject.subObjectValue.array = (0..63)
|
||||
$testObject.subObjectValue.stringarray = @("one","two")
|
||||
$result = $testObject | Format-Custom | Out-String
|
||||
$result | Should Match $expectResult1
|
||||
$result | Should Match $expectResult2
|
||||
$result | Should Match "one"
|
||||
$result | Should Match "two"
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ Describe "Format-List" {
|
||||
$actual | Should Be $expected
|
||||
}
|
||||
|
||||
It "Should produce the expected output" {
|
||||
It "Should produce the expected output" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$expected = "${nl}${nl}testName : testValue${nl}${nl}${nl}${nl}"
|
||||
$in = New-Object PSObject
|
||||
Add-Member -InputObject $in -MemberType NoteProperty -Name testName -Value testValue
|
||||
@ -68,14 +68,14 @@ Describe "Format-List" {
|
||||
}
|
||||
|
||||
Describe "Format-List DRT basic functionality" -Tags DRT{
|
||||
It "Format-List with array should work"{
|
||||
$al = (0..255)
|
||||
$info = @{}
|
||||
$info.array = $al
|
||||
$result = $info | Format-List | Out-String
|
||||
$result | Should Match "Name : array\s+Value : {0, 1, 2, 3...}"
|
||||
}
|
||||
|
||||
It "Format-List with array should work"-Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$al = (0..255)
|
||||
$info = @{}
|
||||
$info.array = $al
|
||||
$result = $info | Format-List | Out-String
|
||||
$result | Should Match "Name : array\s+Value : {0, 1, 2, 3...}"
|
||||
}
|
||||
|
||||
It "Format-List with No Objects for End-To-End should work"{
|
||||
$p = @{}
|
||||
$result = $p | Format-List -Force -Property "foo","bar" | Out-String
|
||||
@ -106,22 +106,22 @@ Describe "Format-List DRT basic functionality" -Tags DRT{
|
||||
$result.Trim() | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
It "Format-List with complex object for End-To-End should work"{
|
||||
Add-Type -TypeDefinition "public enum MyDayOfWeek{Sun,Mon,Tue,Wed,Thr,Fri,Sat}"
|
||||
$eto = New-Object MyDayOfWeek
|
||||
$info = @{}
|
||||
$info.intArray = 1,2,3,4
|
||||
$info.arrayList = "string1","string2"
|
||||
$info.enumerable = [MyDayOfWeek]$eto
|
||||
$info.enumerableTestObject = $eto
|
||||
$result = $info|Format-List|Out-String
|
||||
$result | Should Match "Name : enumerableTestObject"
|
||||
$result | Should Match "Value : Sun"
|
||||
$result | Should Match "Name : arrayList"
|
||||
$result | Should Match "Value : {string1, string2}"
|
||||
$result | Should Match "Name : enumerable"
|
||||
$result | Should Match "Value : Sun"
|
||||
$result | Should Match "Name : intArray"
|
||||
$result | Should Match "Value : {1, 2, 3, 4}"
|
||||
}
|
||||
It "Format-List with complex object for End-To-End should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
Add-Type -TypeDefinition "public enum MyDayOfWeek{Sun,Mon,Tue,Wed,Thr,Fri,Sat}"
|
||||
$eto = New-Object MyDayOfWeek
|
||||
$info = @{}
|
||||
$info.intArray = 1,2,3,4
|
||||
$info.arrayList = "string1","string2"
|
||||
$info.enumerable = [MyDayOfWeek]$eto
|
||||
$info.enumerableTestObject = $eto
|
||||
$result = $info|Format-List|Out-String
|
||||
$result | Should Match "Name : enumerableTestObject"
|
||||
$result | Should Match "Value : Sun"
|
||||
$result | Should Match "Name : arrayList"
|
||||
$result | Should Match "Value : {string1, string2}"
|
||||
$result | Should Match "Name : enumerable"
|
||||
$result | Should Match "Value : Sun"
|
||||
$result | Should Match "Name : intArray"
|
||||
$result | Should Match "Value : {1, 2, 3, 4}"
|
||||
}
|
||||
}
|
||||
|
@ -1,213 +1,213 @@
|
||||
Describe "Format-Table" {
|
||||
It "Should call format table on piped input without error" {
|
||||
{ Get-Date | Format-Table } | Should Not Throw
|
||||
It "Should call format table on piped input without error" {
|
||||
{ Get-Date | Format-Table } | Should Not Throw
|
||||
|
||||
{ Get-Date | ft } | Should Not Throw
|
||||
}
|
||||
{ Get-Date | ft } | Should Not Throw
|
||||
}
|
||||
|
||||
It "Should return a format object data type" {
|
||||
$val = (Get-Date | Format-Table | gm )
|
||||
It "Should return a format object data type" {
|
||||
$val = (Get-Date | Format-Table | gm )
|
||||
|
||||
$val2 = (Get-Date | Format-Table | gm )
|
||||
$val2 = (Get-Date | Format-Table | gm )
|
||||
|
||||
$val.TypeName | Should Match "Microsoft.Powershell.Commands.Internal.Format"
|
||||
$val.TypeName | Should Match "Microsoft.Powershell.Commands.Internal.Format"
|
||||
|
||||
$val2.TypeName | Should Match "Microsoft.Powershell.Commands.Internal.Format"
|
||||
}
|
||||
$val2.TypeName | Should Match "Microsoft.Powershell.Commands.Internal.Format"
|
||||
}
|
||||
|
||||
It "Should be able to be called with optional parameters" {
|
||||
$v1 = (Get-Date | Format-Table *)
|
||||
$v2 = (Get-Date | Format-Table -Property Hour)
|
||||
$v3 = (Get-Date | Format-Table -GroupBy Hour)
|
||||
It "Should be able to be called with optional parameters" {
|
||||
$v1 = (Get-Date | Format-Table *)
|
||||
$v2 = (Get-Date | Format-Table -Property Hour)
|
||||
$v3 = (Get-Date | Format-Table -GroupBy Hour)
|
||||
|
||||
$v12 = (Get-Date | ft *)
|
||||
$v22 = (Get-Date | ft -Property Hour)
|
||||
$v32 = (Get-Date | ft -GroupBy Hour)
|
||||
$v12 = (Get-Date | ft *)
|
||||
$v22 = (Get-Date | ft -Property Hour)
|
||||
$v32 = (Get-Date | ft -GroupBy Hour)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Describe "Format-Table DRT Unit Tests" -Tags DRT{
|
||||
It "Format-Table with not existing table with force should throw PipelineStoppedException"{
|
||||
$obj = New-Object -typename PSObject
|
||||
try
|
||||
{
|
||||
$obj | Format-Table -view bar -force -EA Stop
|
||||
Throw "Execution OK"
|
||||
It "Format-Table with not existing table with force should throw PipelineStoppedException"{
|
||||
$obj = New-Object -typename PSObject
|
||||
try
|
||||
{
|
||||
$obj | Format-Table -view bar -force -EA Stop
|
||||
Throw "Execution OK"
|
||||
}
|
||||
catch
|
||||
{
|
||||
$_.CategoryInfo | Should Match "PipelineStoppedException"
|
||||
$_.FullyQualifiedErrorId | Should be "FormatViewNotFound,Microsoft.PowerShell.Commands.FormatTableCommand"
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
$_.CategoryInfo | Should Match "PipelineStoppedException"
|
||||
$_.FullyQualifiedErrorId | Should be "FormatViewNotFound,Microsoft.PowerShell.Commands.FormatTableCommand"
|
||||
|
||||
It "Format-Table with array should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$al = (0..255)
|
||||
$info = @{}
|
||||
$info.array = $al
|
||||
$result = $info|Format-Table|Out-String
|
||||
$result | Should Match "array\s+{0, 1, 2, 3...}"
|
||||
}
|
||||
}
|
||||
|
||||
It "Format-Table with array should work"{
|
||||
$al = (0..255)
|
||||
$info = @{}
|
||||
$info.array = $al
|
||||
$result = $info|Format-Table|Out-String
|
||||
$result | Should Match "array\s+{0, 1, 2, 3...}"
|
||||
}
|
||||
|
||||
It "Format-Table with Negative Count should work"{
|
||||
$FormatEnumerationLimit = -1
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{1, 2}"
|
||||
}
|
||||
|
||||
#pending on issue#888
|
||||
It "Format-Table with Zero Count should work" -pending{
|
||||
$FormatEnumerationLimit = 0
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{...}"
|
||||
}
|
||||
|
||||
It "Format-Table with Less Count should work"{
|
||||
$FormatEnumerationLimit = 1
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{1...}"
|
||||
}
|
||||
|
||||
It "Format-Table with More Count should work"{
|
||||
$FormatEnumerationLimit = 10
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{1, 2}"
|
||||
}
|
||||
|
||||
It "Format-Table with Equal Count should work"{
|
||||
$FormatEnumerationLimit = 2
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{1, 2}"
|
||||
}
|
||||
|
||||
#pending on issue#888
|
||||
It "Format-Table with Bogus Count should throw Exception" -pending{
|
||||
$FormatEnumerationLimit = "abc"
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{1, 2}"
|
||||
}
|
||||
|
||||
#pending on issue#888
|
||||
It "Format-Table with Var Deleted should throw Exception" -pending{
|
||||
$FormatEnumerationLimit = 2
|
||||
Remove-Variable FormatEnumerationLimit
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{1, 2}"
|
||||
}
|
||||
|
||||
It "Format-Table with new line should work"{
|
||||
$info = @{}
|
||||
$info.name = "1\n2"
|
||||
$result = $info|Format-Table|Out-String
|
||||
$result | Should Match "name\s+1.+2"
|
||||
}
|
||||
|
||||
It "Format-Table with ExposeBug920454 should work"{
|
||||
$IP1 = [System.Net.IPAddress]::Parse("1.1.1.1")
|
||||
$IP2 = [System.Net.IPAddress]::Parse("4fde:0000:0000:0002:0022:f376:255.59.171.63")
|
||||
$IPs = New-Object System.Collections.ArrayList
|
||||
$IPs.Add($IP1)
|
||||
$IPs.Add($IP2)
|
||||
$info = @{}
|
||||
$info.test = $IPs
|
||||
$result = $info|Format-Table|Out-String
|
||||
$result | Should Match "test\s+{1.1.1.1, 4fde::2:22:f376:ff3b:ab3f}"
|
||||
}
|
||||
|
||||
It "Format-Table with Autosize should work"{
|
||||
$IP1 = [PSCustomObject]@{'name'='Bob';'size'=1234;'booleanValue'=$true;}
|
||||
$IP2 = [PSCustomObject]@{'name'='Jim';'size'=5678;'booleanValue'=$false;}
|
||||
$IPs = New-Object System.Collections.ArrayList
|
||||
$IPs.Add($IP1)
|
||||
$IPs.Add($IP2)
|
||||
$result = $IPs|Format-Table -Autosize|Out-String
|
||||
$result | Should Match "name size booleanValue"
|
||||
$result | Should Match "---- ---- ------------"
|
||||
$result | Should Match "Bob\s+1234\s+True"
|
||||
$result | Should Match "Jim\s+5678\s+False"
|
||||
}
|
||||
|
||||
It "Format-Table with No Objects for End-To-End should work"{
|
||||
$p = @{}
|
||||
$result = $p|Format-Table -Property "foo","bar"|Out-String
|
||||
$result | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
It "Format-Table with Null Objects for End-To-End should work"{
|
||||
$p = $null
|
||||
$result = $p|Format-Table -Property "foo","bar"|Out-String
|
||||
$result | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
#pending on issue#900
|
||||
It "Format-Table with single line string for End-To-End should work" -pending{
|
||||
$p = "single line string"
|
||||
$result = $p|Format-Table -Property "foo","bar"|Out-String
|
||||
$result | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
#pending on issue#900
|
||||
It "Format-Table with multiple line string for End-To-End should work" -pending{
|
||||
$p = "Line1\nLine2"
|
||||
$result = $p|Format-Table -Property "foo","bar"|Out-String
|
||||
$result | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
#pending on issue#900
|
||||
It "Format-Table with string sequence for End-To-End should work" -pending{
|
||||
$p = "Line1","Line2"
|
||||
$result = $p|Format-Table -Property "foo","bar"|Out-String
|
||||
$result | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
#pending on issue#900
|
||||
It "Format-Table with string sequence for End-To-End should work" -pending{
|
||||
$p = "Line1","Line2"
|
||||
$result = $p|Format-Table -Property "foo","bar"|Out-String
|
||||
$result | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
It "Format-Table with complex object for End-To-End should work"{
|
||||
Add-Type -TypeDefinition "public enum MyDayOfWeek{Sun,Mon,Tue,Wed,Thr,Fri,Sat}"
|
||||
$eto = New-Object MyDayOfWeek
|
||||
$info = @{}
|
||||
$info.intArray = 1,2,3,4
|
||||
$info.arrayList = "string1","string2"
|
||||
$info.enumerable = [MyDayOfWeek]$eto
|
||||
$info.enumerableTestObject = $eto
|
||||
$result = $info|Format-Table|Out-String
|
||||
$result | Should Match "intArray\s+{1, 2, 3, 4}"
|
||||
$result | Should Match "arrayList\s+{string1, string2}"
|
||||
$result | Should Match "enumerable\s+Sun"
|
||||
$result | Should Match "enumerableTestObject\s+Sun"
|
||||
}
|
||||
|
||||
It "Format-Table with Expand Enumerable should work"{
|
||||
$obj1 = "x 0","y 0"
|
||||
$obj2 = "x 1","y 1"
|
||||
$objs = New-Object System.Collections.ArrayList
|
||||
$objs.Add($obj1)
|
||||
$objs.Add($obj2)
|
||||
$mo = [PSCustomObject]@{name = "this is name";sub = $objs}
|
||||
$result1 = $mo|Format-Table -Expand CoreOnly|Out-String
|
||||
$result1 | Should Match "name\s+sub"
|
||||
$result1 | Should Match "this is name"
|
||||
|
||||
$result2 = $mo|Format-Table -Expand EnumOnly|Out-String
|
||||
$result2 | Should Match "name\s+sub"
|
||||
$result2 | Should Match "this is name\s+{x 0 y 0, x 1 y 1}"
|
||||
|
||||
$result3 = $mo|Format-Table -Expand Both|Out-String
|
||||
$result3 | Should Match "name\s+sub"
|
||||
$result3 | Should Match "this is name\s+{x 0 y 0, x 1 y 1}"
|
||||
}
|
||||
}
|
||||
|
||||
It "Format-Table with Negative Count should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$FormatEnumerationLimit = -1
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{1, 2}"
|
||||
}
|
||||
|
||||
# Pending on issue#888
|
||||
It "Format-Table with Zero Count should work" -Pending {
|
||||
$FormatEnumerationLimit = 0
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{...}"
|
||||
}
|
||||
|
||||
It "Format-Table with Less Count should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$FormatEnumerationLimit = 1
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{1...}"
|
||||
}
|
||||
|
||||
It "Format-Table with More Count should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$FormatEnumerationLimit = 10
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{1, 2}"
|
||||
}
|
||||
|
||||
It "Format-Table with Equal Count should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$FormatEnumerationLimit = 2
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{1, 2}"
|
||||
}
|
||||
|
||||
# Pending on issue#888
|
||||
It "Format-Table with Bogus Count should throw Exception" -Pending {
|
||||
$FormatEnumerationLimit = "abc"
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{1, 2}"
|
||||
}
|
||||
|
||||
# Pending on issue#888
|
||||
It "Format-Table with Var Deleted should throw Exception" -Pending {
|
||||
$FormatEnumerationLimit = 2
|
||||
Remove-Variable FormatEnumerationLimit
|
||||
$result = Format-Table -inputobject @{'test'= 1, 2}
|
||||
$resultStr = $result|Out-String
|
||||
$resultStr | Should Match "test\s+{1, 2}"
|
||||
}
|
||||
|
||||
It "Format-Table with new line should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$info = @{}
|
||||
$info.name = "1\n2"
|
||||
$result = $info|Format-Table|Out-String
|
||||
$result | Should Match "name\s+1.+2"
|
||||
}
|
||||
|
||||
It "Format-Table with ExposeBug920454 should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$IP1 = [System.Net.IPAddress]::Parse("1.1.1.1")
|
||||
$IP2 = [System.Net.IPAddress]::Parse("4fde:0000:0000:0002:0022:f376:255.59.171.63")
|
||||
$IPs = New-Object System.Collections.ArrayList
|
||||
$IPs.Add($IP1)
|
||||
$IPs.Add($IP2)
|
||||
$info = @{}
|
||||
$info.test = $IPs
|
||||
$result = $info|Format-Table|Out-String
|
||||
$result | Should Match "test\s+{1.1.1.1, 4fde::2:22:f376:ff3b:ab3f}"
|
||||
}
|
||||
|
||||
It "Format-Table with Autosize should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$IP1 = [PSCustomObject]@{'name'='Bob';'size'=1234;'booleanValue'=$true;}
|
||||
$IP2 = [PSCustomObject]@{'name'='Jim';'size'=5678;'booleanValue'=$false;}
|
||||
$IPs = New-Object System.Collections.ArrayList
|
||||
$IPs.Add($IP1)
|
||||
$IPs.Add($IP2)
|
||||
$result = $IPs|Format-Table -Autosize|Out-String
|
||||
$result | Should Match "name size booleanValue"
|
||||
$result | Should Match "---- ---- ------------"
|
||||
$result | Should Match "Bob\s+1234\s+True"
|
||||
$result | Should Match "Jim\s+5678\s+False"
|
||||
}
|
||||
|
||||
It "Format-Table with No Objects for End-To-End should work"{
|
||||
$p = @{}
|
||||
$result = $p|Format-Table -Property "foo","bar"|Out-String
|
||||
$result | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
It "Format-Table with Null Objects for End-To-End should work"{
|
||||
$p = $null
|
||||
$result = $p|Format-Table -Property "foo","bar"|Out-String
|
||||
$result | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
#pending on issue#900
|
||||
It "Format-Table with single line string for End-To-End should work" -pending{
|
||||
$p = "single line string"
|
||||
$result = $p|Format-Table -Property "foo","bar"|Out-String
|
||||
$result | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
#pending on issue#900
|
||||
It "Format-Table with multiple line string for End-To-End should work" -pending{
|
||||
$p = "Line1\nLine2"
|
||||
$result = $p|Format-Table -Property "foo","bar"|Out-String
|
||||
$result | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
#pending on issue#900
|
||||
It "Format-Table with string sequence for End-To-End should work" -pending{
|
||||
$p = "Line1","Line2"
|
||||
$result = $p|Format-Table -Property "foo","bar"|Out-String
|
||||
$result | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
#pending on issue#900
|
||||
It "Format-Table with string sequence for End-To-End should work" -pending{
|
||||
$p = "Line1","Line2"
|
||||
$result = $p|Format-Table -Property "foo","bar"|Out-String
|
||||
$result | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
It "Format-Table with complex object for End-To-End should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
Add-Type -TypeDefinition "public enum MyDayOfWeek{Sun,Mon,Tue,Wed,Thr,Fri,Sat}"
|
||||
$eto = New-Object MyDayOfWeek
|
||||
$info = @{}
|
||||
$info.intArray = 1,2,3,4
|
||||
$info.arrayList = "string1","string2"
|
||||
$info.enumerable = [MyDayOfWeek]$eto
|
||||
$info.enumerableTestObject = $eto
|
||||
$result = $info|Format-Table|Out-String
|
||||
$result | Should Match "intArray\s+{1, 2, 3, 4}"
|
||||
$result | Should Match "arrayList\s+{string1, string2}"
|
||||
$result | Should Match "enumerable\s+Sun"
|
||||
$result | Should Match "enumerableTestObject\s+Sun"
|
||||
}
|
||||
|
||||
It "Format-Table with Expand Enumerable should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$obj1 = "x 0","y 0"
|
||||
$obj2 = "x 1","y 1"
|
||||
$objs = New-Object System.Collections.ArrayList
|
||||
$objs.Add($obj1)
|
||||
$objs.Add($obj2)
|
||||
$mo = [PSCustomObject]@{name = "this is name";sub = $objs}
|
||||
$result1 = $mo|Format-Table -Expand CoreOnly|Out-String
|
||||
$result1 | Should Match "name\s+sub"
|
||||
$result1 | Should Match "this is name"
|
||||
|
||||
$result2 = $mo|Format-Table -Expand EnumOnly|Out-String
|
||||
$result2 | Should Match "name\s+sub"
|
||||
$result2 | Should Match "this is name\s+{x 0 y 0, x 1 y 1}"
|
||||
|
||||
$result3 = $mo|Format-Table -Expand Both|Out-String
|
||||
$result3 | Should Match "name\s+sub"
|
||||
$result3 | Should Match "this is name\s+{x 0 y 0, x 1 y 1}"
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ Describe "Format-Wide" {
|
||||
}
|
||||
|
||||
Describe "Format-Wide DRT basic functionality" -Tags DRT{
|
||||
It "Format-Wide with array should work"{
|
||||
It "Format-Wide with array should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$al = (0..255)
|
||||
$info = @{}
|
||||
$info.array = $al
|
||||
@ -80,7 +80,7 @@ Describe "Format-Wide DRT basic functionality" -Tags DRT{
|
||||
$result | Should Match "Line2"
|
||||
}
|
||||
|
||||
It "Format-Wide with complex object for End-To-End should work"{
|
||||
It "Format-Wide with complex object for End-To-End should work" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
Add-Type -TypeDefinition "public enum MyDayOfWeek{Sun,Mon,Tue,Wed,Thr,Fri,Sat}"
|
||||
$eto = New-Object MyDayOfWeek
|
||||
$info = @{}
|
||||
@ -94,4 +94,4 @@ Describe "Format-Wide DRT basic functionality" -Tags DRT{
|
||||
$result | Should Match "enumerable"
|
||||
$result | Should Match "enumerableTestObject"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ Describe "Get-Date DRT Unit Tests" -Tags DRT {
|
||||
$result.Millisecond | Should be 200
|
||||
}
|
||||
|
||||
It "using -displayhint produces the correct output" {
|
||||
It "using -displayhint produces the correct output" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$d = Get-date -Date:"Jan 1, 2020" -DisplayHint Date | Out-String
|
||||
$d.Trim() | Should be "Wednesday, January 1, 2020"
|
||||
}
|
||||
|
@ -21,7 +21,8 @@ Describe "Import-Alias DRT Unit Tests" -Tags DRT{
|
||||
Remove-Item -Path $testAliasDirectory -Recurse -Force
|
||||
}
|
||||
|
||||
It "Import-Alias Resolve To Multiple will throw PSInvalidOperationException" {
|
||||
It "Import-Alias Resolve To Multiple will throw PSInvalidOperationException" {
|
||||
$ErrorActionPreference = "Stop"
|
||||
try {
|
||||
Import-Alias *
|
||||
Throw "Execution OK"
|
||||
@ -31,7 +32,8 @@ Describe "Import-Alias DRT Unit Tests" -Tags DRT{
|
||||
}
|
||||
}
|
||||
|
||||
It "Import-Alias From Exported Alias File Aliases Already Exist should throw SessionStateException skip now as bug#777" -Skip:$true{
|
||||
It "Import-Alias From Exported Alias File Aliases Already Exist should throw SessionStateException" {
|
||||
$ErrorActionPreference = "Stop"
|
||||
{Export-Alias $fulltestpath abcd*}| Should Not Throw
|
||||
try {
|
||||
Import-Alias $fulltestpath
|
||||
|
@ -52,7 +52,7 @@ Describe "Out-File" {
|
||||
{ Out-File -FilePath $testfile -InputObject $inObject } | Should Not Throw
|
||||
}
|
||||
|
||||
It "Should not overwrite when the noclobber switch is used" {
|
||||
It "Should not overwrite when the noclobber switch is used" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
|
||||
Out-File -FilePath $testfile -InputObject $inObject
|
||||
|
||||
@ -67,7 +67,7 @@ Describe "Out-File" {
|
||||
$actual[3] | Should Match "some test text"
|
||||
}
|
||||
|
||||
It "Should Append a new line when the append switch is used" {
|
||||
It "Should Append a new line when the append switch is used" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
{ Out-File -FilePath $testfile -InputObject $inObject } | Should Not Throw
|
||||
{ Out-File -FilePath $testfile -InputObject $inObject -Append } | Should Not Throw
|
||||
|
||||
@ -101,7 +101,7 @@ Describe "Out-File" {
|
||||
|
||||
}
|
||||
|
||||
It "Should allow the cmdlet to overwrite an existing read-only file" {
|
||||
It "Should allow the cmdlet to overwrite an existing read-only file" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
# create a read-only text file
|
||||
{ Out-File -FilePath $testfile -InputObject $inObject } | Should Not Throw
|
||||
Set-ItemProperty -Path $testfile -Name IsReadOnly -Value $true
|
||||
|
@ -1,6 +1,6 @@
|
||||
Describe "Out-String DRT Unit Tests" -Tags DRT{
|
||||
|
||||
It "check display of properties with names containing wildcard characters" {
|
||||
It "check display of properties with names containing wildcard characters" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$results = new-object psobject | add-member -passthru noteproperty 'name with square brackets: [0]' 'myvalue' | out-string
|
||||
$results.Length | Should BeGreaterThan 1
|
||||
$results.GetType() | Should Be string
|
||||
|
@ -86,12 +86,12 @@ set-psbreakpoint -command foo
|
||||
Remove-PSBreakPoint -Id $brk.Id
|
||||
}
|
||||
|
||||
It "Should throw Exception when missing mandatory parameter -line"{
|
||||
It "Should throw Exception when missing mandatory parameter -line" -Pending {
|
||||
$output = & $ps -noninteractive -command "sbp -column 1 -script $scriptFileName"
|
||||
[system.string]::Join(" ", $output) | Should Match "MissingMandatoryParameter,Microsoft.PowerShell.Commands.SetPSBreakpointCommand"
|
||||
}
|
||||
|
||||
It "Should throw Exception when missing mandatory parameter" {
|
||||
It "Should throw Exception when missing mandatory parameter" -Pending {
|
||||
$output = & $ps -noprofile -noninteractive -command "sbp -line 1"
|
||||
[system.string]::Join(" ", $output) | Should Match "MissingMandatoryParameter,Microsoft.PowerShell.Commands.SetPSBreakpointCommand"
|
||||
}
|
||||
|
@ -1,31 +1,17 @@
|
||||
Describe "Set-PSDebug" {
|
||||
# Because it is running through pester, no functions need to be called. Pester should provide plenty
|
||||
# of output.
|
||||
It "Should be able to be called without error" {
|
||||
{ Set-PSDebug -Trace 0 } | Should Not Throw
|
||||
Context "Tracing can be used" {
|
||||
AfterEach {
|
||||
Set-PSDebug -Off
|
||||
}
|
||||
|
||||
It "Should be able to go through the tracing options" -Skip:($env:APPVEYOR -eq "TRUE") {
|
||||
{ Set-PSDebug -Trace 0 } | Should Not Throw
|
||||
{ Set-PSDebug -Trace 1 } | Should Not Throw
|
||||
{ Set-PSDebug -Trace 2 } | Should Not Throw
|
||||
}
|
||||
|
||||
It "Should be able to set strict" -Skip:($env:APPVEYOR -eq "TRUE") {
|
||||
{ Set-PSDebug -Strict } | Should Not Throw
|
||||
}
|
||||
}
|
||||
|
||||
It "Should be able to be turned off without error" {
|
||||
{ Set-PSDebug -Off } | Should Not Throw
|
||||
}
|
||||
|
||||
Context "Validate functionality" {
|
||||
BeforeEach {
|
||||
Set-PSDebug -Off
|
||||
}
|
||||
|
||||
It "Should be able to go through the tracing options" {
|
||||
{ Set-PSDebug -Trace 0 } | Should Not Throw
|
||||
{ Set-PSDebug -Trace 1 } | Should Not Throw
|
||||
{ Set-PSDebug -Trace 2 } | Should Not Throw
|
||||
}
|
||||
|
||||
It "Should be able to set strict" {
|
||||
{ Set-PSDebug -Strict } | Should Not Throw
|
||||
}
|
||||
}
|
||||
|
||||
# final cleanup
|
||||
|
||||
Set-PSDebug -Off
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ Describe "Set-Variable" {
|
||||
$testVar | Should Be $testValue
|
||||
}
|
||||
|
||||
It "Should be able to pipe object properties to output using the PassThru switch" {
|
||||
It "Should be able to pipe object properties to output using the PassThru switch" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
$in = Set-Variable -Name testVar -Value "test" -Description "test description" -PassThru
|
||||
|
||||
$output = $in | Format-List -Property Description | Out-String
|
||||
|
@ -30,8 +30,8 @@ Describe "Write-Error DRT Unit Tests" -Tags DRT{
|
||||
$Error[0].InvocationInfo.MyCommand.Name | Should BeNullOrEmpty
|
||||
}
|
||||
|
||||
#Skip with issue #846
|
||||
It "Should be works with all parameters" -Skip:$true {
|
||||
# Skip with issue #846
|
||||
It "Should be works with all parameters" -Pending {
|
||||
$exception = New-Object -TypeName System.ArgumentNullException -ArgumentList paramname
|
||||
Write-Error -Message myerrortext -Exception $exception -ErrorId myerrorid -Category syntaxerror -TargetObject TargetObject -CategoryActivity myactivity -CategoryReason myreason -CategoryTargetName mytargetname -CategoryTargetType mytargettype -RecommendedAction myrecommendedaction -ErrorAction SilentlyContinue
|
||||
$Error[0] | Should Not BeNullOrEmpty
|
||||
@ -104,4 +104,4 @@ Describe "Write-Error" {
|
||||
|
||||
$error[0]| Should Be $theError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,11 +35,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
It "all mandatory params works" {
|
||||
It "all mandatory params works" -Pending {
|
||||
{ write-progress -activity 'myactivity' -status 'mystatus' } | Should Not Throw
|
||||
}
|
||||
|
||||
It "all params works" {
|
||||
It "all params works" -Pending {
|
||||
{ write-progress -activity 'myactivity' -status 'mystatus' -id 1 -parentId 2 -completed:$false -current 'current' -sec 1 -percent 1 } | Should Not Throw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,67 +5,67 @@ Describe "Stream writer tests" {
|
||||
# that would normally
|
||||
function Write-Messages
|
||||
{
|
||||
[CmdletBinding()]
|
||||
[CmdletBinding()]
|
||||
|
||||
param()
|
||||
If ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' }
|
||||
Write-Verbose "Verbose message"
|
||||
param()
|
||||
If ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' }
|
||||
Write-Verbose "Verbose message"
|
||||
|
||||
Write-Debug "Debug message"
|
||||
Write-Debug "Debug message"
|
||||
|
||||
}
|
||||
|
||||
function Get-OutputResults
|
||||
{
|
||||
# Get the contents of the targetfile.
|
||||
# Make the array a string for less brittle testing
|
||||
$output = $(Get-Content $args[0])
|
||||
[String]::Join([Environment]::NewLine, $output )
|
||||
# Get the contents of the targetfile.
|
||||
# Make the array a string for less brittle testing
|
||||
$output = $(Get-Content $args[0])
|
||||
[String]::Join([Environment]::NewLine, $output )
|
||||
|
||||
return $output
|
||||
return $output
|
||||
}
|
||||
Context "Redirect Stream Tests" {
|
||||
# These tests validate that a stream is actually being written to by redirecting the output of that stream
|
||||
# These tests validate that a stream is actually being written to by redirecting the output of that stream
|
||||
|
||||
AfterEach { Remove-Item $targetfile }
|
||||
It "Should write warnings to the warning stream" {
|
||||
Write-Warning "Test Warning" 3>&1 > $targetfile
|
||||
AfterEach { Remove-Item $targetfile }
|
||||
It "Should write warnings to the warning stream" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
Write-Warning "Test Warning" 3>&1 > $targetfile
|
||||
|
||||
Get-Content $targetfile | Should Be "Test Warning"
|
||||
}
|
||||
Get-Content $targetfile | Should Be "Test Warning"
|
||||
}
|
||||
|
||||
It "Should write error messages to the error stream" {
|
||||
Write-Error "Testing Error" 2>&1 > $targetfile
|
||||
It "Should write error messages to the error stream" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
Write-Error "Testing Error" 2>&1 > $targetfile
|
||||
|
||||
$result = Get-OutputResults $targetfile
|
||||
# The contents of the error stream should contain the expected text
|
||||
$result -match ": Testing Error" | Should Be $true
|
||||
}
|
||||
$result = Get-OutputResults $targetfile
|
||||
# The contents of the error stream should contain the expected text
|
||||
$result -match ": Testing Error" | Should Be $true
|
||||
}
|
||||
|
||||
It "Should write debug messages to the debug stream" {
|
||||
Write-Messages -Debug -EA SilentlyContinue 5>&1 > $targetfile
|
||||
It "Should write debug messages to the debug stream" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
Write-Messages -Debug -EA SilentlyContinue 5>&1 > $targetfile
|
||||
|
||||
$result = Get-OutputResults $targetfile
|
||||
$result = Get-OutputResults $targetfile
|
||||
|
||||
# The contents of the debug stream should contain the expected text
|
||||
$result -match "Debug Message" | Should Be $true
|
||||
}
|
||||
# The contents of the debug stream should contain the expected text
|
||||
$result -match "Debug Message" | Should Be $true
|
||||
}
|
||||
|
||||
It "Should write messages to the verbose stream" {
|
||||
Write-Messages -Verbose 4>&1 > $targetfile
|
||||
It "Should write messages to the verbose stream" -Pending:($env:TRAVIS_OS_NAME -eq "osx") {
|
||||
Write-Messages -Verbose 4>&1 > $targetfile
|
||||
|
||||
$result = Get-OutputResults $targetfile
|
||||
$result = Get-OutputResults $targetfile
|
||||
|
||||
# The contents of the debug stream should contain the expected text
|
||||
$result -match "Verbose Message" | Should Be $true
|
||||
}
|
||||
# The contents of the debug stream should contain the expected text
|
||||
$result -match "Verbose Message" | Should Be $true
|
||||
}
|
||||
}
|
||||
|
||||
Context "Error automatic variable" {
|
||||
It "Should write error messages to the `$Error automatic variable" {
|
||||
Write-Error "Test Error Message" -ErrorAction SilentlyContinue
|
||||
It "Should write error messages to the `$Error automatic variable" {
|
||||
Write-Error "Test Error Message" -ErrorAction SilentlyContinue
|
||||
|
||||
$Error[0] | Should Match "Test Error Message"
|
||||
}
|
||||
$Error[0] | Should Match "Test Error Message"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user