MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Management.Automation.Internal;6using System.Management.Automation.Remoting;7using System.Management.Automation.Runspaces;8using System.Security.Principal;9using System.Threading;10 11using Dbg = System.Management.Automation.Diagnostics;12 13namespace System.Management.Automation14{15 /// <summary>16 /// This class wraps a PowerShell object. It is used to function17 /// as a server side powershell.18 /// </summary>19 internal class ServerPowerShellDriver20 {21 #region Private Members22 23 private bool _extraPowerShellAlreadyScheduled;24 25 // extra PowerShell at the server to be run after localPowerShell26 private readonly PowerShell _extraPowerShell;27 28 // output buffer for the local PowerShell that is associated with this powershell driver29 // associated with this powershell data structure handler object to handle all communications with the client30 private readonly PSDataCollection<PSObject> _localPowerShellOutput;31 32 // if the remaining data has been sent to the client before sending state information33 private readonly bool[] _datasent = new bool[2];34 35 // sync object for synchronizing sending data to client36 private readonly object _syncObject = new object();37 38 // there is no input when this driver was created39 private readonly bool _noInput;40 private readonly bool _addToHistory;41 42 // the server remote host instance43 // associated with this powershell44 private readonly ServerRemoteHost _remoteHost;45 46 // apartment state for this powershell47 private readonly ApartmentState apartmentState;48 49 // Handles nested invocation of PS drivers.50 private readonly IRSPDriverInvoke _psDriverInvoker;51 52 #endregion Private Members53 54 #region Constructors55 56 /// <summary>57 /// Default constructor for creating ServerPowerShellDrivers.58 /// </summary>59 /// <param name="powershell">Decoded powershell object.</param>60 /// <param name="extraPowerShell">Extra pipeline to be run after <paramref name="powershell"/> completes.</param>61 /// <param name="noInput">Whether there is input for this powershell.</param>62 /// <param name="clientPowerShellId">The client powershell id.</param>63 /// <param name="clientRunspacePoolId">The client runspacepool id.</param>64 /// <param name="runspacePoolDriver">runspace pool driver65 /// which is creating this powershell driver</param>66 /// <param name="apartmentState">Apartment state for this powershell.</param>67 /// <param name="hostInfo">host info using which the host for68 /// this powershell will be constructed</param>69 /// <param name="streamOptions">Serialization options for the streams in this powershell.</param>70 /// <param name="addToHistory">71 /// true if the command is to be added to history list of the runspace. false, otherwise.72 /// </param>73 /// <param name="rsToUse">74 /// If not null, this Runspace will be used to invoke Powershell.75 /// If null, the RunspacePool pointed by <paramref name="runspacePoolDriver"/> will be used.76 /// </param>77 internal ServerPowerShellDriver(PowerShell powershell, PowerShell extraPowerShell, bool noInput, Guid clientPowerShellId,78 Guid clientRunspacePoolId, ServerRunspacePoolDriver runspacePoolDriver,79 ApartmentState apartmentState, HostInfo hostInfo, RemoteStreamOptions streamOptions,80 bool addToHistory, Runspace rsToUse)81 : this(powershell, extraPowerShell, noInput, clientPowerShellId, clientRunspacePoolId, runspacePoolDriver,82 apartmentState, hostInfo, streamOptions, addToHistory, rsToUse, null)83 {84 }85 86 /// <summary>87 /// Default constructor for creating ServerPowerShellDrivers.88 /// </summary>89 /// <param name="powershell">Decoded powershell object.</param>90 /// <param name="extraPowerShell">Extra pipeline to be run after <paramref name="powershell"/> completes.</param>91 /// <param name="noInput">Whether there is input for this powershell.</param>92 /// <param name="clientPowerShellId">The client powershell id.</param>93 /// <param name="clientRunspacePoolId">The client runspacepool id.</param>94 /// <param name="runspacePoolDriver">runspace pool driver95 /// which is creating this powershell driver</param>96 /// <param name="apartmentState">Apartment state for this powershell.</param>97 /// <param name="hostInfo">host info using which the host for98 /// this powershell will be constructed</param>99 /// <param name="streamOptions">Serialization options for the streams in this powershell.</param>100 /// <param name="addToHistory">101 /// true if the command is to be added to history list of the runspace. false, otherwise.102 /// </param>103 /// <param name="rsToUse">104 /// If not null, this Runspace will be used to invoke Powershell.105 /// If null, the RunspacePool pointed by <paramref name="runspacePoolDriver"/> will be used.106 /// </param>107 /// <param name="output">108 /// If not null, this is used as another source of output sent to the client.109 /// </param>110 internal ServerPowerShellDriver(PowerShell powershell, PowerShell extraPowerShell, bool noInput, Guid clientPowerShellId,111 Guid clientRunspacePoolId, ServerRunspacePoolDriver runspacePoolDriver,112 ApartmentState apartmentState, HostInfo hostInfo, RemoteStreamOptions streamOptions,113 bool addToHistory, Runspace rsToUse, PSDataCollection<PSObject> output)114 {115 InstanceId = clientPowerShellId;116 RunspacePoolId = clientRunspacePoolId;117 RemoteStreamOptions = streamOptions;118 this.apartmentState = apartmentState;119 LocalPowerShell = powershell;120 _extraPowerShell = extraPowerShell;121 _localPowerShellOutput = new PSDataCollection<PSObject>();122 _noInput = noInput;123 _addToHistory = addToHistory;124 _psDriverInvoker = runspacePoolDriver;125 126 DataStructureHandler = runspacePoolDriver.DataStructureHandler.CreatePowerShellDataStructureHandler(clientPowerShellId, clientRunspacePoolId, RemoteStreamOptions, LocalPowerShell);127 _remoteHost = DataStructureHandler.GetHostAssociatedWithPowerShell(hostInfo, runspacePoolDriver.ServerRemoteHost);128 129 if (!noInput)130 {131 InputCollection = new PSDataCollection<object>();132 InputCollection.ReleaseOnEnumeration = true;133 InputCollection.IdleEvent += HandleIdleEvent;134 }135 136 RegisterPipelineOutputEventHandlers(_localPowerShellOutput);137 138 if (LocalPowerShell != null)139 {140 RegisterPowerShellEventHandlers(LocalPowerShell);141 _datasent[0] = false;142 }143 144 if (extraPowerShell != null)145 {146 RegisterPowerShellEventHandlers(extraPowerShell);147 _datasent[1] = false;148 }149 150 RegisterDataStructureHandlerEventHandlers(DataStructureHandler);151 152 // set the runspace pool and invoke this powershell153 if (rsToUse != null)154 {155 LocalPowerShell.Runspace = rsToUse;156 if (extraPowerShell != null)157 {158 extraPowerShell.Runspace = rsToUse;159 }160 }161 else162 {163 LocalPowerShell.RunspacePool = runspacePoolDriver.RunspacePool;164 if (extraPowerShell != null)165 {166 extraPowerShell.RunspacePool = runspacePoolDriver.RunspacePool;167 }168 }169 170 if (output != null)171 {172 output.DataAdded += (sender, args) =>173 {174 if (_localPowerShellOutput.IsOpen)175 {176 var items = output.ReadAll();177 foreach (var item in items)178 {179 _localPowerShellOutput.Add(item);180 }181 }182 };183 }184 }185 186 #endregion Constructors187 188 #region Internal Methods189 190 /// <summary>191 /// Input collection sync object.192 /// </summary>193 internal PSDataCollection<object> InputCollection { get; }194 195 /// <summary>196 /// Local PowerShell instance.197 /// </summary>198 internal PowerShell LocalPowerShell { get; }199 200 /// <summary>201 /// Instance id by which this powershell driver is202 /// identified. This is the same as the id of the203 /// powershell on the client side.204 /// </summary>205 internal Guid InstanceId { get; }206 207 /// <summary>208 /// Serialization options for the streams in this powershell.209 /// </summary>210 internal RemoteStreamOptions RemoteStreamOptions { get; }211 212 /// <summary>213 /// Id of the runspace pool driver which created214 /// this object. This is the same as the id of215 /// the runspace pool at the client side which216 /// is associated with the powershell on the217 /// client side.218 /// </summary>219 internal Guid RunspacePoolId { get; }220 221 /// <summary>222 /// ServerPowerShellDataStructureHandler associated with this223 /// powershell driver.224 /// </summary>225 internal ServerPowerShellDataStructureHandler DataStructureHandler { get; }226 227 private PSInvocationSettings PrepInvoke(bool startMainPowerShell)228 {229 if (startMainPowerShell)230 {231 // prepare transport manager for sending and receiving data.232 DataStructureHandler.Prepare();233 }234 235 PSInvocationSettings settings = new PSInvocationSettings();236 settings.ApartmentState = apartmentState;237 settings.Host = _remoteHost;238 239 // Flow the impersonation policy to pipeline execution thread240 // only if the current thread is impersonated (Delegation is241 // also a kind of impersonation).242 if (Platform.IsWindows)243 {244 WindowsIdentity currentThreadIdentity = WindowsIdentity.GetCurrent();245 switch (currentThreadIdentity.ImpersonationLevel)246 {247 case TokenImpersonationLevel.Impersonation:248 case TokenImpersonationLevel.Delegation:249 settings.FlowImpersonationPolicy = true;250 break;251 default:252 settings.FlowImpersonationPolicy = false;253 break;254 }255 }256 else257 {258 settings.FlowImpersonationPolicy = false;259 }260 261 settings.AddToHistory = _addToHistory;262 return settings;263 }264 265 private IAsyncResult Start(bool startMainPowerShell)266 {267 PSInvocationSettings settings = PrepInvoke(startMainPowerShell);268 269 if (startMainPowerShell)270 {271 return LocalPowerShell.BeginInvoke<object, PSObject>(InputCollection, _localPowerShellOutput, settings, null, null);272 }273 else274 {275 return _extraPowerShell.BeginInvoke<object, PSObject>(InputCollection, _localPowerShellOutput, settings, null, null);276 }277 }278 279 /// <summary>280 /// Invokes the powershell asynchronously.281 /// </summary>282 internal IAsyncResult Start()283 {284 return Start(true);285 }286 287 /// <summary>288 /// Runs no command but allows the PowerShell object on the client289 /// to complete. This is used for running "virtual" remote debug290 /// commands that sets debugger state but doesn't run any command291 /// on the server runspace.292 /// </summary>293 /// <param name="output">The output from preprocessing that we want to send to the client.</param>294 internal void RunNoOpCommand(IReadOnlyCollection<object> output)295 {296 if (LocalPowerShell != null)297 {298 System.Threading.ThreadPool.QueueUserWorkItem(299 (state) =>300 {301 LocalPowerShell.SetStateChanged(302 new PSInvocationStateInfo(303 PSInvocationState.Running, null));304 305 foreach (var item in output)306 {307 if (item != null)308 {309 _localPowerShellOutput.Add(PSObject.AsPSObject(item));310 }311 }312 313 LocalPowerShell.SetStateChanged(314 new PSInvocationStateInfo(315 PSInvocationState.Completed, null));316 });317 }318 }319 320 /// <summary>321 /// Invokes the Main PowerShell object synchronously.322 /// </summary>323 internal void InvokeMain()324 {325 PSInvocationSettings settings = PrepInvoke(true);326 327 Exception ex = null;328 try329 {330 LocalPowerShell.InvokeWithDebugger(InputCollection, _localPowerShellOutput, settings, true);331 }332 catch (Exception e)333 {334 ex = e;335 }336 337 if (ex != null)338 {339 // Since this is being invoked asynchronously on a single pipeline thread340 // any invoke failures (such as possible debugger failures) need to be341 // passed back to client or the original client invoke request will not respond.342 string failedCommand = LocalPowerShell.Commands.Commands[0].CommandText;343 LocalPowerShell.Commands.Clear();344 string msg = StringUtil.Format(345 RemotingErrorIdStrings.ServerSideNestedCommandInvokeFailed,346 failedCommand ?? string.Empty,347 ex.Message ?? string.Empty);348 349 LocalPowerShell.AddCommand("Write-Error").AddArgument(msg);350 LocalPowerShell.Invoke();351 }352 }353 354 #endregion Internal Methods355 356 #region Private Methods357 358 private void RegisterPowerShellEventHandlers(PowerShell powerShell)359 {360 powerShell.InvocationStateChanged += HandlePowerShellInvocationStateChanged;361 362 powerShell.Streams.Error.DataAdded += HandleErrorDataAdded;363 powerShell.Streams.Debug.DataAdded += HandleDebugAdded;364 powerShell.Streams.Verbose.DataAdded += HandleVerboseAdded;365 powerShell.Streams.Warning.DataAdded += HandleWarningAdded;366 powerShell.Streams.Progress.DataAdded += HandleProgressAdded;367 powerShell.Streams.Information.DataAdded += HandleInformationAdded;368 }369 370 private void UnregisterPowerShellEventHandlers(PowerShell powerShell)371 {372 powerShell.InvocationStateChanged -= HandlePowerShellInvocationStateChanged;373 374 powerShell.Streams.Error.DataAdded -= HandleErrorDataAdded;375 powerShell.Streams.Debug.DataAdded -= HandleDebugAdded;376 powerShell.Streams.Verbose.DataAdded -= HandleVerboseAdded;377 powerShell.Streams.Warning.DataAdded -= HandleWarningAdded;378 powerShell.Streams.Progress.DataAdded -= HandleProgressAdded;379 powerShell.Streams.Information.DataAdded -= HandleInformationAdded;380 }381 382 private void RegisterDataStructureHandlerEventHandlers(ServerPowerShellDataStructureHandler dsHandler)383 {384 dsHandler.InputEndReceived += HandleInputEndReceived;385 dsHandler.InputReceived += HandleInputReceived;386 dsHandler.StopPowerShellReceived += HandleStopReceived;387 dsHandler.HostResponseReceived += HandleHostResponseReceived;388 dsHandler.OnSessionConnected += HandleSessionConnected;389 }390 391 private void UnregisterDataStructureHandlerEventHandlers(ServerPowerShellDataStructureHandler dsHandler)392 {393 dsHandler.InputEndReceived -= HandleInputEndReceived;394 dsHandler.InputReceived -= HandleInputReceived;395 dsHandler.StopPowerShellReceived -= HandleStopReceived;396 dsHandler.HostResponseReceived -= HandleHostResponseReceived;397 dsHandler.OnSessionConnected -= HandleSessionConnected;398 }399 400 private void RegisterPipelineOutputEventHandlers(PSDataCollection<PSObject> pipelineOutput)401 {402 pipelineOutput.DataAdded += HandleOutputDataAdded;403 }404 405 private void UnregisterPipelineOutputEventHandlers(PSDataCollection<PSObject> pipelineOutput)406 {407 pipelineOutput.DataAdded -= HandleOutputDataAdded;408 }409 410 /// <summary>411 /// Handle state changed information from PowerShell412 /// and send it to the client.413 /// </summary>414 /// <param name="sender">Sender of this event.</param>415 /// <param name="eventArgs">arguments describing state changed416 /// information for this powershell</param>417 private void HandlePowerShellInvocationStateChanged(object sender,418 PSInvocationStateChangedEventArgs eventArgs)419 {420 PSInvocationState state = eventArgs.InvocationStateInfo.State;421 switch (state)422 {423 case PSInvocationState.Completed:424 case PSInvocationState.Failed:425 case PSInvocationState.Stopped:426 {427 if (LocalPowerShell.RunningExtraCommands)428 {429 // If completed successfully then allow extra commands to run.430 if (state == PSInvocationState.Completed)431 {432 return;433 }434 435 // For failed or stopped state, extra commands cannot run and436 // we allow this command invocation to finish.437 }438 439 // send the remaining data before sending in440 // state information. This is required because441 // the client side runspace pool will remove442 // the association with the client side powershell443 // once the powershell reaches a terminal state.444 // If the association is removed, then any data445 // sent to the powershell will be discarded by446 // the runspace pool data structure handler on the client side447 SendRemainingData();448 449 if (state == PSInvocationState.Completed &&450 (_extraPowerShell != null) &&451 !_extraPowerShellAlreadyScheduled)452 {453 _extraPowerShellAlreadyScheduled = true;454 Start(false);455 }456 else457 {458 DataStructureHandler.RaiseRemoveAssociationEvent();459 460 // send the state change notification to the client461 DataStructureHandler.SendStateChangedInformationToClient(462 eventArgs.InvocationStateInfo);463 464 UnregisterPowerShellEventHandlers(LocalPowerShell);465 if (_extraPowerShell != null)466 {467 UnregisterPowerShellEventHandlers(_extraPowerShell);468 }469 470 UnregisterDataStructureHandlerEventHandlers(DataStructureHandler);471 UnregisterPipelineOutputEventHandlers(_localPowerShellOutput);472 473 // BUGBUG: currently the local powershell cannot474 // be disposed as raising the events is475 // not done towards the end. Need to fix476 // powershell in order to get this enabled477 // localPowerShell.Dispose();478 }479 }480 481 break;482 483 case PSInvocationState.Stopping:484 {485 // abort all pending host calls486 _remoteHost.ServerMethodExecutor.AbortAllCalls();487 }488 489 break;490 }491 }492 493 /// <summary>494 /// Handles DataAdded event from the Output of the powershell.495 /// </summary>496 /// <param name="sender">Sender of this information.</param>497 /// <param name="e">Arguments describing this event.</param>498 private void HandleOutputDataAdded(object sender, DataAddedEventArgs e)499 {500 int index = e.Index;501 502 lock (_syncObject)503 {504 int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;505 if (!_datasent[indexIntoDataSent])506 {507 PSObject data = _localPowerShellOutput[index];508 // once send the output is removed so that the same509 // is not sent again by SendRemainingData() method510 _localPowerShellOutput.RemoveAt(index);511 512 // send the output data to the client513 DataStructureHandler.SendOutputDataToClient(data);514 }515 }516 }517 518 /// <summary>519 /// Handles DataAdded event from Error of the PowerShell.520 /// </summary>521 /// <param name="sender">Sender of this event.</param>522 /// <param name="e">Arguments describing this event.</param>523 private void HandleErrorDataAdded(object sender, DataAddedEventArgs e)524 {525 int index = e.Index;526 527 lock (_syncObject)528 {529 int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;530 if ((indexIntoDataSent == 0) && (!_datasent[indexIntoDataSent]))531 {532 ErrorRecord errorRecord = LocalPowerShell.Streams.Error[index];533 // once send the error record is removed so that the same534 // is not sent again by SendRemainingData() method535 LocalPowerShell.Streams.Error.RemoveAt(index);536 537 // send the error record to the client538 DataStructureHandler.SendErrorRecordToClient(errorRecord);539 }540 }541 }542 543 /// <summary>544 /// Handles DataAdded event from Progress of PowerShell.545 /// </summary>546 /// <param name="sender">Sender of this information, unused.</param>547 /// <param name="eventArgs">Arguments describing this event.</param>548 private void HandleProgressAdded(object sender, DataAddedEventArgs eventArgs)549 {550 int index = eventArgs.Index;551 552 lock (_syncObject)553 {554 int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;555 if ((indexIntoDataSent == 0) && (!_datasent[indexIntoDataSent]))556 {557 ProgressRecord data = LocalPowerShell.Streams.Progress[index];558 // once the debug message is sent, it is removed so that559 // the same is not sent again by SendRemainingData() method560 LocalPowerShell.Streams.Progress.RemoveAt(index);561 562 // send the output data to the client563 DataStructureHandler.SendProgressRecordToClient(data);564 }565 }566 }567 568 /// <summary>569 /// Handles DataAdded event from Warning of PowerShell.570 /// </summary>571 /// <param name="sender">Sender of this information, unused.</param>572 /// <param name="eventArgs">Arguments describing this event.</param>573 private void HandleWarningAdded(object sender, DataAddedEventArgs eventArgs)574 {575 int index = eventArgs.Index;576 577 lock (_syncObject)578 {579 int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;580 if ((indexIntoDataSent == 0) && (!_datasent[indexIntoDataSent]))581 {582 WarningRecord data = LocalPowerShell.Streams.Warning[index];583 // once the debug message is sent, it is removed so that584 // the same is not sent again by SendRemainingData() method585 LocalPowerShell.Streams.Warning.RemoveAt(index);586 587 // send the output data to the client588 DataStructureHandler.SendWarningRecordToClient(data);589 }590 }591 }592 593 /// <summary>594 /// Handles DataAdded from Verbose of PowerShell.595 /// </summary>596 /// <param name="sender">Sender of this information, unused.</param>597 /// <param name="eventArgs">Sender of this information.</param>598 private void HandleVerboseAdded(object sender, DataAddedEventArgs eventArgs)599 {600 int index = eventArgs.Index;601 602 lock (_syncObject)603 {604 int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;605 if ((indexIntoDataSent == 0) && (!_datasent[indexIntoDataSent]))606 {607 VerboseRecord data = LocalPowerShell.Streams.Verbose[index];608 // once the debug message is sent, it is removed so that609 // the same is not sent again by SendRemainingData() method610 LocalPowerShell.Streams.Verbose.RemoveAt(index);611 612 // send the output data to the client613 DataStructureHandler.SendVerboseRecordToClient(data);614 }615 }616 }617 618 /// <summary>619 /// Handles DataAdded from Debug of PowerShell.620 /// </summary>621 /// <param name="sender">Sender of this information, unused.</param>622 /// <param name="eventArgs">Sender of this information.</param>623 private void HandleDebugAdded(object sender, DataAddedEventArgs eventArgs)624 {625 int index = eventArgs.Index;626 627 lock (_syncObject)628 {629 int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;630 if ((indexIntoDataSent == 0) && (!_datasent[indexIntoDataSent]))631 {632 DebugRecord data = LocalPowerShell.Streams.Debug[index];633 // once the debug message is sent, it is removed so that634 // the same is not sent again by SendRemainingData() method635 LocalPowerShell.Streams.Debug.RemoveAt(index);636 637 // send the output data to the client638 DataStructureHandler.SendDebugRecordToClient(data);639 }640 }641 }642 643 /// <summary>644 /// Handles DataAdded from Information of PowerShell.645 /// </summary>646 /// <param name="sender">Sender of this information, unused.</param>647 /// <param name="eventArgs">Sender of this information.</param>648 private void HandleInformationAdded(object sender, DataAddedEventArgs eventArgs)649 {650 int index = eventArgs.Index;651 652 lock (_syncObject)653 {654 int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;655 if ((indexIntoDataSent == 0) && (!_datasent[indexIntoDataSent]))656 {657 InformationRecord data = LocalPowerShell.Streams.Information[index];658 // once the Information message is sent, it is removed so that659 // the same is not sent again by SendRemainingData() method660 LocalPowerShell.Streams.Information.RemoveAt(index);661 662 // send the output data to the client663 DataStructureHandler.SendInformationRecordToClient(data);664 }665 }666 }667 668 /// <summary>669 /// Send the remaining output and error information to670 /// client.671 /// </summary>672 /// <remarks>This method should be called before673 /// sending the state information. The client will674 /// remove the association between a powershell and675 /// runspace pool if it receives any of the terminal676 /// states. Hence all the remaining data should be677 /// sent before this happens. Else the data will be678 /// discarded</remarks>679 private void SendRemainingData()680 {681 int indexIntoDataSent = (!_extraPowerShellAlreadyScheduled) ? 0 : 1;682 lock (_syncObject)683 {684 _datasent[indexIntoDataSent] = true;685 }686 687 try688 {689 // BUGBUG: change this code to use enumerator690 // blocked on bug #108824, to be fixed by Kriscv691 for (int i = 0; i < _localPowerShellOutput.Count; i++)692 {693 PSObject data = _localPowerShellOutput[i];694 DataStructureHandler.SendOutputDataToClient(data);695 }696 697 _localPowerShellOutput.Clear();698 699 // foreach (ErrorRecord errorRecord in localPowerShell.Error)700 for (int i = 0; i < LocalPowerShell.Streams.Error.Count; i++)701 {702 ErrorRecord errorRecord = LocalPowerShell.Streams.Error[i];703 DataStructureHandler.SendErrorRecordToClient(errorRecord);704 }705 706 LocalPowerShell.Streams.Error.Clear();707 }708 finally709 {710 lock (_syncObject)711 {712 // reset to original state so other pipelines can stream.713 _datasent[indexIntoDataSent] = true;714 }715 }716 }717 718 /// <summary>719 /// Stop the local powershell.720 /// </summary>721 /// <param name="sender">Sender of this event, unused.</param>722 /// <param name="eventArgs">Unused.</param>723 private void HandleStopReceived(object sender, EventArgs eventArgs)724 {725 do // false loop726 {727 if (LocalPowerShell.InvocationStateInfo.State == PSInvocationState.Stopped ||728 LocalPowerShell.InvocationStateInfo.State == PSInvocationState.Completed ||729 LocalPowerShell.InvocationStateInfo.State == PSInvocationState.Failed ||730 LocalPowerShell.InvocationStateInfo.State == PSInvocationState.Stopping)731 {732 break;733 }734 else735 {736 // Ensure that the local PowerShell command is not stopped in debug mode.737 bool handledByDebugger = false;738 if (!LocalPowerShell.IsNested &&739 _psDriverInvoker != null)740 {741 handledByDebugger = _psDriverInvoker.HandleStopSignal();742 }743 744 if (!handledByDebugger)745 {746 LocalPowerShell.Stop();747 }748 }749 } while (false);750 751 if (_extraPowerShell != null)752 {753 do // false loop754 {755 if (_extraPowerShell.InvocationStateInfo.State == PSInvocationState.Stopped ||756 _extraPowerShell.InvocationStateInfo.State == PSInvocationState.Completed ||757 _extraPowerShell.InvocationStateInfo.State == PSInvocationState.Failed ||758 _extraPowerShell.InvocationStateInfo.State == PSInvocationState.Stopping)759 {760 break;761 }762 else763 {764 _extraPowerShell.Stop();765 }766 } while (false);767 }768 }769 770 /// <summary>771 /// Add input to the local powershell's input collection.772 /// </summary>773 /// <param name="sender">Sender of this event, unused.</param>774 /// <param name="eventArgs">Arguments describing this event.</param>775 private void HandleInputReceived(object sender, RemoteDataEventArgs<object> eventArgs)776 {777 // This can be called in pushed runspace scenarios for error reporting (pipeline stopped).778 // Ignore for noInput.779 if (!_noInput && (InputCollection != null))780 {781 InputCollection.Add(eventArgs.Data);782 }783 }784 785 /// <summary>786 /// Close the input collection of the local powershell.787 /// </summary>788 /// <param name="sender">Sender of this event, unused.</param>789 /// <param name="eventArgs">Arguments describing this event.</param>790 private void HandleInputEndReceived(object sender, EventArgs eventArgs)791 {792 // This can be called in pushed runspace scenarios for error reporting (pipeline stopped).793 // Ignore for noInput.794 if (!_noInput && (InputCollection != null))795 {796 InputCollection.Complete();797 }798 }799 800 private void HandleSessionConnected(object sender, EventArgs eventArgs)801 {802 // Close input if its active. no need to synchronize as input stream would have already been processed803 // when connect call came into PS plugin804 805 // TODO: Post an ETW event806 InputCollection?.Complete();807 }808 809 /// <summary>810 /// Handle a host message response received.811 /// </summary>812 /// <param name="sender">Sender of this event, unused.</param>813 /// <param name="eventArgs">Arguments describing this event.</param>814 private void HandleHostResponseReceived(object sender, RemoteDataEventArgs<RemoteHostResponse> eventArgs)815 {816 _remoteHost.ServerMethodExecutor.HandleRemoteHostResponseFromClient(eventArgs.Data);817 }818 819 /// <summary>820 /// Handles the PSDataCollection idle event.821 /// </summary>822 /// <param name="sender"></param>823 /// <param name="args"></param>824 private void HandleIdleEvent(object sender, EventArgs args)825 {826 Runspace rs = DataStructureHandler.RunspaceUsedToInvokePowerShell;827 if (rs != null)828 {829 PSLocalEventManager events = (object)rs.Events as PSLocalEventManager;830 831 if (events != null)832 {833 foreach (PSEventSubscriber subscriber in events.Subscribers)834 {835 // Use the synchronous version836 events.DrainPendingActions(subscriber);837 }838 }839 }840 }841 842 #endregion Private Methods843 }844}845 