forked from PowerShell/PowerShell
-
Notifications
You must be signed in to change notification settings - Fork 1
/
ConsoleHost.cs
3043 lines (2617 loc) · 112 KB
/
ConsoleHost.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma warning disable 1634, 1691
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Configuration;
using System.Management.Automation.Host;
using System.Management.Automation.Internal;
using System.Management.Automation.Language;
using System.Management.Automation.Remoting;
using System.Management.Automation.Remoting.Server;
using System.Management.Automation.Runspaces;
using System.Management.Automation.Tracing;
using System.Reflection;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Microsoft.PowerShell.Commands;
using Microsoft.PowerShell.Telemetry;
#if LEGACYTELEMETRY
using Microsoft.PowerShell.Telemetry.Internal;
#endif
using ConsoleHandle = Microsoft.Win32.SafeHandles.SafeFileHandle;
using Dbg = System.Management.Automation.Diagnostics;
using Debugger = System.Management.Automation.Debugger;
namespace Microsoft.PowerShell
{
/// <summary>
/// Subclasses S.M.A.Host to implement a console-mode monad host.
/// </summary>
[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
internal sealed partial class ConsoleHost
:
PSHost,
IDisposable,
#if LEGACYTELEMETRY
IHostProvidesTelemetryData,
#endif
IHostSupportsInteractiveSession
{
#region static methods
internal const int ExitCodeSuccess = 0;
internal const int ExitCodeCtrlBreak = 128 + 21; // SIGBREAK
internal const int ExitCodeInitFailure = 70; // Internal Software Error
internal const int ExitCodeBadCommandLineParameter = 64; // Command Line Usage Error
private const uint SPI_GETSCREENREADER = 0x0046;
#if UNIX
internal const string DECCKM_ON = "\x1b[?1h";
internal const string DECCKM_OFF = "\x1b[?1l";
#endif
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SystemParametersInfo(uint uiAction, uint uiParam, ref bool pvParam, uint fWinIni);
/// <summary>
/// Internal Entry point in msh console host implementation.
/// </summary>
/// <param name="bannerText">
/// Banner text to be displayed by ConsoleHost
/// </param>
/// <param name="helpText">
/// Help text for minishell. This is displayed on 'minishell -?'.
/// </param>
/// <returns>
/// The exit code for the shell.
///
/// The behavior here is related to monitor work.
/// The low word of the exit code is available for the user. The high word is reserved for the shell and monitor.
///
/// The shell process needs to return:
///
/// - if the shell.exe fails init, 0xFFFF0000
/// - if the exit keyword is called with no parameter at the point of top-level prompt, 0x80000000 (e.g. 0 with the high
/// bit set)
/// - if the exit keyword is called with any int param less than or equal to 0xFFFF, then that int masked with the high
/// bit set. e.g. "exit 3" results in 0x80000003
/// - if the script ends (in the case of msh -command or msh -commandfile), then 0x80000000.
/// - if ctrl-break is pressed, with 0xFFFE0000
/// - if the shell.exe is passed a bad command-line parameter, with 0xFFFD0000.
/// - if the shell.exe crashes, with 0x00000000
///
/// The monitor process gets the exit code. If the high bit is set, then the shell process exited normally (though
/// possibly due to an error). If not, the shell process crashed. If the shell.exe exit code is x00000000 (crashed)
/// or 0xFFFE0000 (user hit ctrl-break), the monitor should restart the shell.exe. Otherwise, the monitor should exit
/// with the same exit code as the shell.exe.
///
/// Anyone checking the exit code of the shell or monitor can mask off the high word to determine the exit code passed
/// by the script that the shell last executed.
/// </returns>
internal static int Start(string bannerText, string helpText)
{
#if DEBUG
if (Environment.GetEnvironmentVariable("POWERSHELL_DEBUG_STARTUP") != null)
{
while (!System.Diagnostics.Debugger.IsAttached)
{
Thread.Sleep(1000);
}
}
#endif
// put PSHOME in front of PATH so that calling `powershell` within `powershell` always starts the same running version
string path = Environment.GetEnvironmentVariable("PATH");
string pshome = Utils.DefaultPowerShellAppBase + Path.PathSeparator;
// to not impact startup perf, we don't remove duplicates, but we avoid adding a duplicate to the front
// we also don't handle the edge case where PATH only contains $PSHOME
if (string.IsNullOrEmpty(path))
{
Environment.SetEnvironmentVariable("PATH", pshome);
}
else if (!path.StartsWith(pshome, StringComparison.Ordinal))
{
Environment.SetEnvironmentVariable("PATH", pshome + path);
}
try
{
string profileDir = Platform.CacheDirectory;
#if !UNIX
if (!Directory.Exists(profileDir))
{
Directory.CreateDirectory(profileDir);
}
#endif
ProfileOptimization.SetProfileRoot(profileDir);
}
catch
{
// It's safe to ignore errors, the guarded code is just there to try and
// improve startup performance.
}
uint exitCode = ExitCodeSuccess;
Thread.CurrentThread.Name = "ConsoleHost main thread";
try
{
// We might be able to ignore console host creation error if we are running in
// server mode, which does not require a console.
HostException hostException = null;
try
{
s_theConsoleHost = ConsoleHost.CreateSingletonInstance();
}
catch (HostException e)
{
hostException = e;
}
PSHostUserInterface hostUI = s_theConsoleHost?.UI ?? new NullHostUserInterface();
s_cpp.ShowErrorHelpBanner(hostUI, bannerText, helpText);
if (s_cpp.ShowVersion)
{
// Alternatively, we could call s_theConsoleHost.UI.WriteLine(s_theConsoleHost.Version.ToString());
// or start up the engine and retrieve the information via $psversiontable.GitCommitId
// but this returns the semantic version and avoids executing a script
s_theConsoleHost.UI.WriteLine("PowerShell " + PSVersionInfo.GitCommitId);
return 0;
}
// Servermode parameter validation check.
if ((s_cpp.ServerMode && s_cpp.NamedPipeServerMode) || (s_cpp.ServerMode && s_cpp.SocketServerMode) || (s_cpp.NamedPipeServerMode && s_cpp.SocketServerMode))
{
s_tracer.TraceError("Conflicting server mode parameters, parameters must be used exclusively.");
if (s_theConsoleHost != null)
{
s_theConsoleHost.ui.WriteErrorLine(ConsoleHostStrings.ConflictingServerModeParameters);
}
return ExitCodeBadCommandLineParameter;
}
#if !UNIX
TaskbarJumpList.CreateRunAsAdministratorJumpList();
#endif
// First check for and handle PowerShell running in a server mode.
if (s_cpp.ServerMode)
{
ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("ServerMode", s_cpp.ParametersUsedAsDouble);
ProfileOptimization.StartProfile("StartupProfileData-ServerMode");
StdIOProcessMediator.Run(
initialCommand: s_cpp.InitialCommand,
workingDirectory: s_cpp.WorkingDirectory,
configurationName: null);
exitCode = 0;
}
else if (s_cpp.SSHServerMode)
{
ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("SSHServer", s_cpp.ParametersUsedAsDouble);
ProfileOptimization.StartProfile("StartupProfileData-SSHServerMode");
StdIOProcessMediator.Run(
initialCommand: s_cpp.InitialCommand,
workingDirectory: null,
configurationName: null);
exitCode = 0;
}
else if (s_cpp.NamedPipeServerMode)
{
ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("NamedPipe", s_cpp.ParametersUsedAsDouble);
ProfileOptimization.StartProfile("StartupProfileData-NamedPipeServerMode");
RemoteSessionNamedPipeServer.RunServerMode(
configurationName: s_cpp.ConfigurationName);
exitCode = 0;
}
else if (s_cpp.SocketServerMode)
{
ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("SocketServerMode", s_cpp.ParametersUsedAsDouble);
ProfileOptimization.StartProfile("StartupProfileData-SocketServerMode");
HyperVSocketMediator.Run(
initialCommand: s_cpp.InitialCommand,
configurationName: s_cpp.ConfigurationName);
exitCode = 0;
}
else
{
// Run PowerShell in normal console mode.
if (hostException != null)
{
// Unable to create console host.
throw hostException;
}
if (LoadPSReadline())
{
ProfileOptimization.StartProfile("StartupProfileData-Interactive");
if (UpdatesNotification.CanNotifyUpdates)
{
// Start a task in the background to check for the update release.
_ = UpdatesNotification.CheckForUpdates();
}
}
else
{
ProfileOptimization.StartProfile("StartupProfileData-NonInteractive");
}
s_theConsoleHost.BindBreakHandler();
PSHost.IsStdOutputRedirected = Console.IsOutputRedirected;
// Send startup telemetry for ConsoleHost startup
ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("Normal", s_cpp.ParametersUsedAsDouble);
exitCode = s_theConsoleHost.Run(s_cpp, false);
}
}
finally
{
if (s_theConsoleHost != null)
{
#if LEGACYTELEMETRY
TelemetryAPI.ReportExitTelemetry(s_theConsoleHost);
#endif
#if UNIX
if (s_theConsoleHost.IsInteractive && s_theConsoleHost.UI.SupportsVirtualTerminal)
{
// https://github.com/dotnet/runtime/issues/27626 leaves terminal in application mode
// for now, we explicitly emit DECRST 1 sequence
s_theConsoleHost.UI.Write(DECCKM_OFF);
}
#endif
s_theConsoleHost.Dispose();
}
}
unchecked
{
return (int)exitCode;
}
}
internal static void ParseCommandLine(string[] args)
{
s_cpp.Parse(args);
#if !UNIX
if (s_cpp.WindowStyle.HasValue)
{
ConsoleControl.SetConsoleMode(s_cpp.WindowStyle.Value);
}
#endif
if (s_cpp.SettingsFile is not null)
{
PowerShellConfig.Instance.SetSystemConfigFilePath(s_cpp.SettingsFile);
}
// Check registry setting for a Group Policy ConfigurationName entry and
// use it to override anything set by the user.
// It depends on setting file so 'SetSystemConfigFilePath()' should be called before.
s_cpp.ConfigurationName = CommandLineParameterParser.GetConfigurationNameFromGroupPolicy();
}
private static readonly CommandLineParameterParser s_cpp = new CommandLineParameterParser();
#if UNIX
/// <summary>
/// The break handler for the program. Dispatches a break event to the current Executor.
/// </summary>
private static void MyBreakHandler(object sender, ConsoleCancelEventArgs args)
{
// Set the Cancel property to true to prevent the process from terminating.
args.Cancel = true;
switch (args.SpecialKey)
{
case ConsoleSpecialKey.ControlC:
SpinUpBreakHandlerThread(shouldEndSession: false);
return;
case ConsoleSpecialKey.ControlBreak:
if (s_cpp.NonInteractive)
{
// ControlBreak mimics ControlC in Noninteractive shells
SpinUpBreakHandlerThread(shouldEndSession: true);
}
else
{
// Break into script debugger.
BreakIntoDebugger();
}
return;
}
}
#else
/// <summary>
/// The break handler for the program. Dispatches a break event to the current Executor.
/// </summary>
/// <param name="signal"></param>
/// <returns></returns>
private static bool MyBreakHandler(ConsoleControl.ConsoleBreakSignal signal)
{
switch (signal)
{
case ConsoleControl.ConsoleBreakSignal.CtrlBreak:
if (s_cpp.NonInteractive)
{
// ControlBreak mimics ControlC in Noninteractive shells
SpinUpBreakHandlerThread(shouldEndSession: true);
}
else
{
// Break into script debugger.
BreakIntoDebugger();
}
return true;
// Run the break handler...
case ConsoleControl.ConsoleBreakSignal.CtrlC:
SpinUpBreakHandlerThread(shouldEndSession: false);
return true;
case ConsoleControl.ConsoleBreakSignal.Logoff:
// Just ignore the logoff signal. This signal is sent to console
// apps running as service anytime *any* user logs off which means
// that PowerShell couldn't be used in services/tasks if we didn't
// suppress this signal...
return true;
case ConsoleControl.ConsoleBreakSignal.Close:
case ConsoleControl.ConsoleBreakSignal.Shutdown:
SpinUpBreakHandlerThread(shouldEndSession: true);
return false;
default:
// Log as much sqm data as possible before we exit.
SpinUpBreakHandlerThread(shouldEndSession: true);
return false;
}
}
#endif
private static bool BreakIntoDebugger()
{
ConsoleHost host = ConsoleHost.SingletonInstance;
Debugger debugger = null;
lock (host.hostGlobalLock)
{
if (host._runspaceRef.Runspace != null &&
host._runspaceRef.Runspace.GetCurrentlyRunningPipeline() != null)
{
debugger = host._runspaceRef.Runspace.Debugger;
}
}
if (debugger != null)
{
debugger.SetDebuggerStepMode(true);
return true;
}
return false;
}
/// <summary>
/// Spin up a new thread to cancel the current pipeline. This will allow subsequent break interrupts to be received even
/// if the cancellation is blocked (which can be the case when the pipeline blocks and nothing implements Cmdlet.Stop
/// properly). That is because the OS will not inject another thread when a break event occurs if one has already been
/// injected and is running.
/// </summary>
/// <param name="shouldEndSession">
/// if true, then flag the parent ConsoleHost that it should shutdown the session. If false, then only the current
/// executing instance is stopped.
///
///</param>
private static void SpinUpBreakHandlerThread(bool shouldEndSession)
{
ConsoleHost host = ConsoleHost.SingletonInstance;
Thread bht = null;
lock (host.hostGlobalLock)
{
bht = host._breakHandlerThread;
if (!host.ShouldEndSession && shouldEndSession)
{
host.ShouldEndSession = shouldEndSession;
}
// Creation of the thread and starting it should be an atomic operation.
// otherwise the code in Run method can get instance of the breakhandlerThread
// after it is created and before started and call join on it. This will result
// in ThreadStateException.
// NTRAID#Windows OutofBand Bugs-938289-2006/07/27-hiteshr
if (bht == null)
{
// we're not already running HandleBreak on a separate thread, so run it now.
host._breakHandlerThread = new Thread(new ThreadStart(ConsoleHost.HandleBreak));
host._breakHandlerThread.Name = "ConsoleHost.HandleBreak";
host._breakHandlerThread.Start();
}
}
}
private static void HandleBreak()
{
ConsoleHost consoleHost = s_theConsoleHost;
if (consoleHost != null)
{
if (consoleHost.InDebugMode)
{
// Only stop a running user command, ignore prompt evaluation.
if (consoleHost.DebuggerCanStopCommand)
{
// Cancel any executing debugger command if in debug mode.
try
{
consoleHost.Runspace.Debugger.StopProcessCommand();
}
catch (Exception)
{
}
}
}
else
{
// Cancel the reconnected debugged running pipeline command.
if (!StopPipeline(consoleHost.runningCmd))
{
Executor.CancelCurrentExecutor();
}
}
if (consoleHost.ShouldEndSession)
{
var runspaceRef = ConsoleHost.SingletonInstance._runspaceRef;
if (runspaceRef != null)
{
var runspace = runspaceRef.Runspace;
if (runspace != null)
{
runspace.Close();
}
}
}
}
// 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 !UNIX
ConsoleHandle handle = ConsoleControl.GetConioDeviceHandle();
ConsoleControl.FlushConsoleInputBuffer(handle);
#endif
ConsoleHost.SingletonInstance._breakHandlerThread = null;
}
private static bool StopPipeline(Pipeline cmd)
{
if (cmd != null &&
(cmd.PipelineStateInfo.State == PipelineState.Running ||
cmd.PipelineStateInfo.State == PipelineState.Disconnected))
{
try
{
cmd.StopAsync();
return true;
}
catch (Exception)
{
}
}
return false;
}
/// <summary>
/// Create single instance of ConsoleHost.
/// </summary>
internal static ConsoleHost CreateSingletonInstance()
{
Dbg.Assert(s_theConsoleHost == null, "CreateSingletonInstance should not be called multiple times");
s_theConsoleHost = new ConsoleHost();
return s_theConsoleHost;
}
internal static ConsoleHost SingletonInstance
{
get
{
Dbg.Assert(s_theConsoleHost != null, "CreateSingletonInstance should be called before calling this method");
return s_theConsoleHost;
}
}
#endregion static methods
#region overrides
/// <summary>
/// See base class.
/// </summary>
/// <value></value>
/// <exception/>
public override string Name
{
get
{
const string myName = "ConsoleHost";
// const, no lock needed.
return myName;
}
}
/// <summary>
/// See base class.
/// </summary>
/// <value></value>
/// <exception/>
public override System.Version Version
{
get
{
// const, no lock needed.
return _ver;
}
}
/// <summary>
/// See base class.
/// </summary>
/// <value></value>
/// <exception/>
public override System.Guid InstanceId { get; } = Guid.NewGuid();
/// <summary>
/// See base class.
/// </summary>
/// <value></value>
/// <exception/>
public override PSHostUserInterface UI
{
get
{
Dbg.Assert(ui != null, "ui should have been allocated in ctor");
return ui;
}
}
/// <summary>
/// See base class.
/// </summary>
public void PushRunspace(Runspace newRunspace)
{
if (_runspaceRef == null) { return; }
RemoteRunspace remoteRunspace = newRunspace as RemoteRunspace;
Dbg.Assert(remoteRunspace != null, "Expected remoteRunspace != null");
remoteRunspace.StateChanged += HandleRemoteRunspaceStateChanged;
// Unsubscribe the local session debugger.
if (_runspaceRef.Runspace.Debugger != null)
{
_runspaceRef.Runspace.Debugger.DebuggerStop -= OnExecutionSuspended;
}
// Subscribe to debugger stop event.
if (remoteRunspace.Debugger != null)
{
remoteRunspace.Debugger.DebuggerStop += OnExecutionSuspended;
}
// Connect a disconnected command.
this.runningCmd = EnterPSSessionCommand.ConnectRunningPipeline(remoteRunspace);
// Push runspace.
_runspaceRef.Override(remoteRunspace, hostGlobalLock, out _isRunspacePushed);
RunspacePushed.SafeInvoke(this, EventArgs.Empty);
if (this.runningCmd != null)
{
EnterPSSessionCommand.ContinueCommand(
remoteRunspace,
this.runningCmd,
this,
InDebugMode,
_runspaceRef.OldRunspace.ExecutionContext);
}
this.runningCmd = null;
}
/// <summary>
/// Handles state changed event of the remote runspace. If the remote runspace
/// gets into a broken or closed state, writes a message and pops out the
/// runspace.
/// </summary>
/// <param name="sender">Not sure.</param>
/// <param name="eventArgs">Arguments describing this event.</param>
private void HandleRemoteRunspaceStateChanged(object sender, RunspaceStateEventArgs eventArgs)
{
RunspaceState state = eventArgs.RunspaceStateInfo.State;
switch (state)
{
case RunspaceState.Opening:
case RunspaceState.Opened:
{
return;
}
case RunspaceState.Closing:
case RunspaceState.Closed:
case RunspaceState.Broken:
case RunspaceState.Disconnected:
{
PopRunspace();
}
break;
}
}
/// <summary>
/// See base class.
/// </summary>
public void PopRunspace()
{
if (_runspaceRef == null ||
!_runspaceRef.IsRunspaceOverridden)
{
return;
}
if (_inPushedConfiguredSession)
{
// For configured endpoint sessions, end session when configured runspace is popped.
this.ShouldEndSession = true;
}
if (_runspaceRef.Runspace.Debugger != null)
{
// Unsubscribe pushed runspace debugger.
_runspaceRef.Runspace.Debugger.DebuggerStop -= OnExecutionSuspended;
StopPipeline(this.runningCmd);
if (this.InDebugMode)
{
ExitDebugMode(DebuggerResumeAction.Continue);
}
}
this.runningCmd = null;
lock (hostGlobalLock)
{
_runspaceRef.Revert();
_isRunspacePushed = false;
}
// Re-subscribe local runspace debugger.
_runspaceRef.Runspace.Debugger.DebuggerStop += OnExecutionSuspended;
// raise events outside the lock
RunspacePopped.SafeInvoke(this, EventArgs.Empty);
}
/// <summary>
/// True if a runspace is pushed; false otherwise.
/// </summary>
public bool IsRunspacePushed
{
get
{
return _isRunspacePushed;
}
}
private bool _isRunspacePushed = false;
/// <summary>
/// Returns the current runspace associated with this host.
/// </summary>
public Runspace Runspace
{
get
{
if (this.RunspaceRef == null) { return null; }
return this.RunspaceRef.Runspace;
}
}
internal LocalRunspace LocalRunspace
{
get
{
if (_isRunspacePushed)
{
return RunspaceRef.OldRunspace as LocalRunspace;
}
if (RunspaceRef == null) { return null; }
return RunspaceRef.Runspace as LocalRunspace;
}
}
public class ConsoleColorProxy
{
private readonly ConsoleHostUserInterface _ui;
public ConsoleColorProxy(ConsoleHostUserInterface ui)
{
if (ui == null) throw new ArgumentNullException(nameof(ui));
_ui = ui;
}
public ConsoleColor FormatAccentColor
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
get
{
return _ui.FormatAccentColor;
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
set
{
_ui.FormatAccentColor = value;
}
}
public ConsoleColor ErrorAccentColor
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
get
{
return _ui.ErrorAccentColor;
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
set
{
_ui.ErrorAccentColor = value;
}
}
public ConsoleColor ErrorForegroundColor
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
get
{
return _ui.ErrorForegroundColor;
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
set
{
_ui.ErrorForegroundColor = value;
}
}
public ConsoleColor ErrorBackgroundColor
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
get
{
return _ui.ErrorBackgroundColor;
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
set
{
_ui.ErrorBackgroundColor = value;
}
}
public ConsoleColor WarningForegroundColor
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
get
{
return _ui.WarningForegroundColor;
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
set
{
_ui.WarningForegroundColor = value;
}
}
public ConsoleColor WarningBackgroundColor
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
get
{
return _ui.WarningBackgroundColor;
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
set
{
_ui.WarningBackgroundColor = value;
}
}
public ConsoleColor DebugForegroundColor
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
get
{
return _ui.DebugForegroundColor;
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
set
{
_ui.DebugForegroundColor = value;
}
}
public ConsoleColor DebugBackgroundColor
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
get
{
return _ui.DebugBackgroundColor;
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
set
{
_ui.DebugBackgroundColor = value;
}
}
public ConsoleColor VerboseForegroundColor
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
get
{
return _ui.VerboseForegroundColor;
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
set
{
_ui.VerboseForegroundColor = value;
}
}
public ConsoleColor VerboseBackgroundColor
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
get
{
return _ui.VerboseBackgroundColor;
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
set
{
_ui.VerboseBackgroundColor = value;
}
}
public ConsoleColor ProgressForegroundColor
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
get
{
return _ui.ProgressForegroundColor;
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
set
{
_ui.ProgressForegroundColor = value;
}
}
public ConsoleColor ProgressBackgroundColor
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
get
{
return _ui.ProgressBackgroundColor;
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
set
{
_ui.ProgressBackgroundColor = value;
}
}
}
/// <summary>
/// Return the actual console host object so that the user can get at
/// the unproxied methods.
/// </summary>
public override PSObject PrivateData
{
get
{
if (ui == null) return null;
return _consoleColorProxy ??= PSObject.AsPSObject(new ConsoleColorProxy(ui));
}
}
private PSObject _consoleColorProxy;
/// <summary>
/// See base class.
/// </summary>
/// <value></value>
/// <exception/>
public override System.Globalization.CultureInfo CurrentCulture
{
get
{
lock (hostGlobalLock)
{
return CultureInfo.CurrentCulture;
}
}
}
/// <summary>
/// See base class.
/// </summary>
/// <value></value>
/// <exception/>
public override System.Globalization.CultureInfo CurrentUICulture
{
get
{
lock (hostGlobalLock)
{
return CultureInfo.CurrentUICulture;
}
}
}
/// <summary>
/// </summary>
/// <exception/>
public override void SetShouldExit(int exitCode)
{