MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.Generic;6using System.Collections.ObjectModel;7using System.Diagnostics.CodeAnalysis;8using System.Management.Automation;9using System.Management.Automation.Internal;10using System.Management.Automation.Remoting;11using System.Management.Automation.Remoting.Client;12using System.Management.Automation.Runspaces;13using System.Management.Automation.Runspaces.Internal;14using System.Threading;15 16using Dbg = System.Management.Automation.Diagnostics;17 18namespace Microsoft.PowerShell.Commands19{20 /// <summary>21 /// This cmdlet establishes a new Runspace either on the local machine or22 /// on the specified remote machine(s). The runspace established can be used23 /// to invoke expressions remotely.24 ///25 /// The cmdlet can be used in the following ways:26 ///27 /// Open a local runspace28 /// $rs = New-PSSession29 ///30 /// Open a runspace to a remote system.31 /// $rs = New-PSSession -Machine PowerShellWorld32 ///33 /// Create a runspace specifying that it is globally scoped.34 /// $global:rs = New-PSSession -Machine PowerShellWorld35 ///36 /// Create a collection of runspaces37 /// $runspaces = New-PSSession -Machine PowerShellWorld,PowerShellPublish,PowerShellRepo38 ///39 /// Create a set of Runspaces using the Secure Socket Layer by specifying the URI form.40 /// This assumes that an shell by the name of E12 exists on the remote server.41 /// $serverURIs = 1..8 | ForEach-Object { "SSL://server${_}:443/E12" }42 /// $rs = New-PSSession -URI $serverURIs43 ///44 /// Create a runspace by connecting to port 8081 on servers s1, s2 and s345 /// $rs = New-PSSession -computername s1,s2,s3 -port 808146 ///47 /// Create a runspace by connecting to port 443 using ssl on servers s1, s2 and s348 /// $rs = New-PSSession -computername s1,s2,s3 -port 443 -useSSL49 ///50 /// Create a runspace by connecting to port 8081 on server s1 and run shell named E12.51 /// This assumes that a shell by the name E12 exists on the remote server52 /// $rs = New-PSSession -computername s1 -port 8061 -ShellName E12.53 /// </summary>54 [Cmdlet(VerbsCommon.New, "PSSession", DefaultParameterSetName = "ComputerName",55 HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096484", RemotingCapability = RemotingCapability.OwnedByCommand)]56 [OutputType(typeof(PSSession))]57 public class NewPSSessionCommand : PSRemotingBaseCmdlet, IDisposable58 {59 #region Parameters60 61 /// <summary>62 /// This parameter represents the address(es) of the remote63 /// computer(s). The following formats are supported:64 /// (a) Computer name65 /// (b) IPv4 address : 132.3.4.566 /// (c) IPv6 address: 3ffe:8311:ffff:f70f:0:5efe:172.30.162.18.67 /// </summary>68 [Parameter(Position = 0,69 ValueFromPipeline = true,70 ValueFromPipelineByPropertyName = true,71 ParameterSetName = NewPSSessionCommand.ComputerNameParameterSet)]72 [Alias("Cn")]73 [ValidateNotNullOrEmpty]74 public override string[] ComputerName { get; set; }75 76 /// <summary>77 /// Specifies the credentials of the user to impersonate in the78 /// remote machine. If this parameter is not specified then the79 /// credentials of the current user process will be assumed.80 /// </summary>81 [Parameter(ValueFromPipelineByPropertyName = true,82 ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)]83 [Parameter(ValueFromPipelineByPropertyName = true,84 ParameterSetName = PSRemotingBaseCmdlet.UriParameterSet)]85 [Parameter(Mandatory = true,86 ValueFromPipelineByPropertyName = true,87 ParameterSetName = PSRemotingBaseCmdlet.VMIdParameterSet)]88 [Parameter(Mandatory = true,89 ValueFromPipelineByPropertyName = true,90 ParameterSetName = PSRemotingBaseCmdlet.VMNameParameterSet)]91 [Credential]92 public override PSCredential Credential93 {94 get95 {96 return base.Credential;97 }98 99 set100 {101 base.Credential = value;102 }103 }104 105 /// <summary>106 /// The PSSession object describing the remote runspace107 /// using which the specified cmdlet operation will be performed.108 /// </summary>109 [Parameter(Position = 0,110 ValueFromPipelineByPropertyName = true,111 ValueFromPipeline = true,112 ParameterSetName = NewPSSessionCommand.SessionParameterSet)]113 [ValidateNotNullOrEmpty]114 public override PSSession[] Session115 {116 get117 {118 return _remoteRunspaceInfos;119 }120 121 set122 {123 _remoteRunspaceInfos = value;124 }125 }126 127 private PSSession[] _remoteRunspaceInfos;128 129 /// <summary>130 /// Friendly names for the new PSSessions.131 /// </summary>132 [Parameter]133 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]134 public string[] Name { get; set; }135 136 /// <summary>137 /// When set and in loopback scenario (localhost) this enables creation of WSMan138 /// host process with the user interactive token, allowing PowerShell script network access,139 /// i.e., allows going off box. When this property is true and a PSSession is disconnected,140 /// reconnection is allowed only if reconnecting from a PowerShell session on the same box.141 /// </summary>142 [Parameter(ParameterSetName = NewPSSessionCommand.ComputerNameParameterSet)]143 [Parameter(ParameterSetName = NewPSSessionCommand.SessionParameterSet)]144 [Parameter(ParameterSetName = NewPSSessionCommand.UriParameterSet)]145 public SwitchParameter EnableNetworkAccess { get; set; }146 147 /// <summary>148 /// For WSMan sessions:149 /// If this parameter is not specified then the value specified in150 /// the environment variable DEFAULTREMOTESHELLNAME will be used. If151 /// this is not set as well, then Microsoft.PowerShell is used.152 ///153 /// For VM/Container sessions:154 /// If this parameter is not specified then no configuration is used.155 /// </summary>156 [Parameter(ValueFromPipelineByPropertyName = true,157 ParameterSetName = NewPSSessionCommand.ComputerNameParameterSet)]158 [Parameter(ValueFromPipelineByPropertyName = true,159 ParameterSetName = NewPSSessionCommand.UriParameterSet)]160 [Parameter(ValueFromPipelineByPropertyName = true,161 ParameterSetName = NewPSSessionCommand.ContainerIdParameterSet)]162 [Parameter(ValueFromPipelineByPropertyName = true,163 ParameterSetName = NewPSSessionCommand.VMIdParameterSet)]164 [Parameter(ValueFromPipelineByPropertyName = true,165 ParameterSetName = NewPSSessionCommand.VMNameParameterSet)]166 public string ConfigurationName { get; set; }167 168 /// <summary>169 /// Gets or sets parameter value that creates connection to a Windows PowerShell process.170 /// </summary>171 [Parameter(Mandatory = true, ParameterSetName = NewPSSessionCommand.UseWindowsPowerShellParameterSet)]172 public SwitchParameter UseWindowsPowerShell { get; set; }173 174 #endregion Parameters175 176 #region Cmdlet Overrides177 178 /// <summary>179 /// The throttle limit will be set here as it needs to be done180 /// only once per cmdlet and not for every call.181 /// </summary>182 protected override void BeginProcessing()183 {184 base.BeginProcessing();185 _operationsComplete.Reset();186 _throttleManager.ThrottleLimit = ThrottleLimit;187 _throttleManager.ThrottleComplete += HandleThrottleComplete;188 189 if (string.IsNullOrEmpty(ConfigurationName))190 {191 if ((ParameterSetName == NewPSSessionCommand.ComputerNameParameterSet) ||192 (ParameterSetName == NewPSSessionCommand.UriParameterSet))193 {194 // set to default value for WSMan session195 ConfigurationName = ResolveShell(null);196 }197 else198 {199 // convert null to string.Empty for VM/Container session200 ConfigurationName = string.Empty;201 }202 }203 }204 205 /// <summary>206 /// The runspace objects will be created using OpenAsync.207 /// At the end, the method will check if any runspace208 /// opened has already become available. If so, then it209 /// will be written to the pipeline.210 /// </summary>211 protected override void ProcessRecord()212 {213 List<RemoteRunspace> remoteRunspaces = null;214 List<IThrottleOperation> operations = new List<IThrottleOperation>();215 216 switch (ParameterSetName)217 {218 case NewPSSessionCommand.SessionParameterSet:219 {220 remoteRunspaces = CreateRunspacesWhenRunspaceParameterSpecified();221 }222 223 break;224 225 case "Uri":226 {227 remoteRunspaces = CreateRunspacesWhenUriParameterSpecified();228 }229 230 break;231 232 case NewPSSessionCommand.ComputerNameParameterSet:233 {234 remoteRunspaces = CreateRunspacesWhenComputerNameParameterSpecified();235 }236 237 break;238 239 case NewPSSessionCommand.VMIdParameterSet:240 case NewPSSessionCommand.VMNameParameterSet:241 {242 remoteRunspaces = CreateRunspacesWhenVMParameterSpecified();243 }244 245 break;246 247 case NewPSSessionCommand.ContainerIdParameterSet:248 {249 remoteRunspaces = CreateRunspacesWhenContainerParameterSpecified();250 }251 252 break;253 254 case NewPSSessionCommand.SSHHostParameterSet:255 {256 remoteRunspaces = CreateRunspacesForSSHHostParameterSet();257 }258 259 break;260 261 case NewPSSessionCommand.SSHHostHashParameterSet:262 {263 remoteRunspaces = CreateRunspacesForSSHHostHashParameterSet();264 }265 266 break;267 268 case NewPSSessionCommand.UseWindowsPowerShellParameterSet:269 {270 if (UseWindowsPowerShell)271 {272 remoteRunspaces = CreateRunspacesForUseWindowsPowerShellParameterSet();273 }274 else275 {276 // When -UseWindowsPowerShell:$false is explicitly specified,277 // fall back to the default ComputerName parameter set behavior278 goto case NewPSSessionCommand.ComputerNameParameterSet;279 }280 }281 282 break;283 284 default:285 {286 Dbg.Assert(false, "Missing parameter set in switch statement");287 remoteRunspaces = new List<RemoteRunspace>(); // added to avoid prefast warning288 }289 290 break;291 }292 293 foreach (RemoteRunspace remoteRunspace in remoteRunspaces)294 {295 remoteRunspace.Events.ReceivedEvents.PSEventReceived += OnRunspacePSEventReceived;296 297 OpenRunspaceOperation operation = new OpenRunspaceOperation(remoteRunspace);298 // HandleRunspaceStateChanged callback is added before ThrottleManager complete299 // callback handlers so HandleRunspaceStateChanged will always be called first.300 operation.OperationComplete += HandleRunspaceStateChanged;301 remoteRunspace.URIRedirectionReported += HandleURIDirectionReported;302 operations.Add(operation);303 }304 305 // submit list of operations to throttle manager to start opening306 // runspaces307 _throttleManager.SubmitOperations(operations);308 309 // Add to list for clean up.310 _allOperations.Add(operations);311 312 // If there are any runspaces opened asynchronously313 // that are ready now, check their status and do314 // necessary action. If there are any error records315 // or verbose messages write them as well316 Collection<object> streamObjects =317 _stream.ObjectReader.NonBlockingRead();318 319 foreach (object streamObject in streamObjects)320 {321 WriteStreamObject((Action<Cmdlet>)streamObject);322 }323 }324 325 /// <summary>326 /// OpenAsync would have been called from ProcessRecord. This method327 /// will wait until all runspaces are opened and then write them to328 /// the pipeline as and when they become available.329 /// </summary>330 protected override void EndProcessing()331 {332 // signal to throttle manager end of submit operations333 _throttleManager.EndSubmitOperations();334 335 while (true)336 {337 // Keep reading objects until end of pipeline is encountered338 _stream.ObjectReader.WaitHandle.WaitOne();339 340 if (!_stream.ObjectReader.EndOfPipeline)341 {342 object streamObject = _stream.ObjectReader.Read();343 WriteStreamObject((Action<Cmdlet>)streamObject);344 }345 else346 {347 break;348 }349 }350 }351 352 /// <summary>353 /// This method is called when the user sends a stop signal to the354 /// cmdlet. The cmdlet will not exit until it has completed355 /// creating all the runspaces (basically the runspaces its356 /// waiting on OpenAsync is made available). However, when a stop357 /// signal is sent, CloseAsyn needs to be called to close all the358 /// pending runspaces.359 /// </summary>360 /// <remarks>This is called from a separate thread so need to worry361 /// about concurrency issues362 /// </remarks>363 protected override void StopProcessing()364 {365 // close the outputStream so that further writes to the outputStream366 // are not possible367 _stream.ObjectWriter.Close();368 369 // for all the runspaces that have been submitted for opening370 // call StopOperation on each object and quit371 _throttleManager.StopAllOperations();372 }373 374 #endregion Cmdlet Overrides375 376 #region IDisposable Overrides377 378 /// <summary>379 /// Dispose method of IDisposable. Gets called in the following cases:380 /// 1. Pipeline explicitly calls dispose on cmdlets381 /// 2. Called by the garbage collector.382 /// </summary>383 public void Dispose()384 {385 Dispose(true);386 387 GC.SuppressFinalize(this);388 }389 390 #endregion IDisposable Overrides391 392 #region Private Methods393 394 /// <summary>395 /// Adds forwarded events to the local queue.396 /// </summary>397 private void OnRunspacePSEventReceived(object sender, PSEventArgs e) => this.Events?.AddForwardedEvent(e);398 399 /// <summary>400 /// When the client remote session reports a URI redirection, this method will report the401 /// message to the user as a Warning using Host method calls.402 /// </summary>403 /// <param name="sender"></param>404 /// <param name="eventArgs"></param>405 private void HandleURIDirectionReported(object sender, RemoteDataEventArgs<Uri> eventArgs)406 {407 string message = StringUtil.Format(RemotingErrorIdStrings.URIRedirectWarningToHost, eventArgs.Data.OriginalString);408 Action<Cmdlet> warningWriter = (Cmdlet cmdlet) => cmdlet.WriteWarning(message);409 _stream.Write(warningWriter);410 }411 412 /// <summary>413 /// Handles state changes for Runspace.414 /// </summary>415 /// <param name="sender">Sender of this event.</param>416 /// <param name="stateEventArgs">Event information object which describes417 /// the event which triggered this method</param>418 private void HandleRunspaceStateChanged(object sender, OperationStateEventArgs stateEventArgs)419 {420 if (sender == null)421 {422 throw PSTraceSource.NewArgumentNullException(nameof(sender));423 }424 425 if (stateEventArgs == null)426 {427 throw PSTraceSource.NewArgumentNullException(nameof(stateEventArgs));428 }429 430 RunspaceStateEventArgs runspaceStateEventArgs =431 stateEventArgs.BaseEvent as RunspaceStateEventArgs;432 RunspaceStateInfo stateInfo = runspaceStateEventArgs.RunspaceStateInfo;433 RunspaceState state = stateInfo.State;434 OpenRunspaceOperation operation = sender as OpenRunspaceOperation;435 RemoteRunspace remoteRunspace = operation.OperatedRunspace;436 437 // since we got state changed event..we dont need to listen on438 // URI redirections anymore439 if (remoteRunspace != null)440 {441 remoteRunspace.URIRedirectionReported -= HandleURIDirectionReported;442 }443 444 PipelineWriter writer = _stream.ObjectWriter;445 Exception reason = runspaceStateEventArgs.RunspaceStateInfo.Reason;446 447 switch (state)448 {449 case RunspaceState.Opened:450 {451 // Indicates that runspace is successfully opened452 // Write it to PipelineWriter to be handled in453 // HandleRemoteRunspace454 PSSession remoteRunspaceInfo = new PSSession(remoteRunspace);455 456 this.RunspaceRepository.Add(remoteRunspaceInfo);457 458 Action<Cmdlet> outputWriter = (Cmdlet cmdlet) => cmdlet.WriteObject(remoteRunspaceInfo);459 if (writer.IsOpen)460 {461 writer.Write(outputWriter);462 }463 }464 465 break;466 467 case RunspaceState.Broken:468 {469 // Open resulted in a broken state. Extract reason470 // and write an error record471 472 // set the transport message in the error detail so that473 // the user can directly get to see the message without474 // having to mine through the error record details475 PSRemotingTransportException transException =476 reason as PSRemotingTransportException;477 string errorDetails = null;478 int transErrorCode = 0;479 if (transException != null)480 {481 OpenRunspaceOperation senderAsOp = sender as OpenRunspaceOperation;482 transErrorCode = transException.ErrorCode;483 if (senderAsOp != null)484 {485 string host = senderAsOp.OperatedRunspace.ConnectionInfo.ComputerName;486 487 if (transException.ErrorCode ==488 System.Management.Automation.Remoting.Client.WSManNativeApi.ERROR_WSMAN_REDIRECT_REQUESTED)489 {490 // Handling a special case for redirection..we should talk about491 // AllowRedirection parameter and WSManMaxRedirectionCount preference492 // variables493 string message = PSRemotingErrorInvariants.FormatResourceString(494 RemotingErrorIdStrings.URIRedirectionReported,495 transException.Message,496 "MaximumConnectionRedirectionCount",497 Microsoft.PowerShell.Commands.PSRemotingBaseCmdlet.DEFAULT_SESSION_OPTION,498 "AllowRedirection");499 500 errorDetails = "[" + host + "] " + message;501 }502 else503 {504 errorDetails = "[" + host + "] ";505 if (!string.IsNullOrEmpty(transException.Message))506 {507 errorDetails += transException.Message;508 }509 else if (!string.IsNullOrEmpty(transException.TransportMessage))510 {511 errorDetails += transException.TransportMessage;512 }513 }514 }515 }516 517 // add host identification information in data structure handler message518 PSRemotingDataStructureException protoException = reason as PSRemotingDataStructureException;519 520 if (protoException != null)521 {522 OpenRunspaceOperation senderAsOp = sender as OpenRunspaceOperation;523 524 if (senderAsOp != null)525 {526 string host = senderAsOp.OperatedRunspace.ConnectionInfo.ComputerName;527 528 errorDetails = "[" + host + "] " + protoException.Message;529 }530 }531 532 reason ??= new RuntimeException(this.GetMessage(RemotingErrorIdStrings.RemoteRunspaceOpenUnknownState, state));533 534 string fullyQualifiedErrorId = WSManTransportManagerUtils.GetFQEIDFromTransportError(535 transErrorCode,536 _defaultFQEID);537 538 if (transErrorCode == WSManNativeApi.ERROR_WSMAN_NO_LOGON_SESSION_EXIST)539 {540 errorDetails += System.Environment.NewLine + string.Format(System.Globalization.CultureInfo.CurrentCulture, RemotingErrorIdStrings.RemotingErrorNoLogonSessionExist);541 }542 543 ErrorRecord errorRecord = new ErrorRecord(reason,544 remoteRunspace, fullyQualifiedErrorId,545 ErrorCategory.OpenError, null, null,546 null, null, null, errorDetails, null);547 548 Action<Cmdlet> errorWriter = (Cmdlet cmdlet) =>549 {550 //551 // In case of PSDirectException, we should output the precise error message552 // in inner exception instead of the generic one in outer exception.553 //554 if ((errorRecord.Exception != null) &&555 (errorRecord.Exception.InnerException != null))556 {557 PSDirectException ex = errorRecord.Exception.InnerException as PSDirectException;558 if (ex != null)559 {560 errorRecord = new ErrorRecord(errorRecord.Exception.InnerException,561 errorRecord.FullyQualifiedErrorId,562 errorRecord.CategoryInfo.Category,563 errorRecord.TargetObject);564 }565 }566 567 cmdlet.WriteError(errorRecord);568 };569 if (writer.IsOpen)570 {571 writer.Write(errorWriter);572 }573 574 _toDispose.Add(remoteRunspace);575 }576 577 break;578 579 case RunspaceState.Closed:580 {581 // The runspace was closed possibly because the user582 // hit ctrl-C when runspaces were being opened or Dispose has been583 // called when there are open runspaces584 Uri connectionUri = WSManConnectionInfo.ExtractPropertyAsWsManConnectionInfo<Uri>(remoteRunspace.ConnectionInfo,585 "ConnectionUri", null);586 string message =587 GetMessage(RemotingErrorIdStrings.RemoteRunspaceClosed,588 (connectionUri != null) ?589 connectionUri.AbsoluteUri : string.Empty);590 591 Action<Cmdlet> verboseWriter = (Cmdlet cmdlet) => cmdlet.WriteVerbose(message);592 if (writer.IsOpen)593 {594 writer.Write(verboseWriter);595 }596 597 // runspace may not have been opened in certain cases598 // like when the max memory is set to 25MB, in such599 // cases write an error record600 if (reason != null)601 {602 ErrorRecord errorRecord = new ErrorRecord(reason,603 "PSSessionStateClosed",604 ErrorCategory.OpenError, remoteRunspace);605 606 Action<Cmdlet> errorWriter = (Cmdlet cmdlet) => cmdlet.WriteError(errorRecord);607 if (writer.IsOpen)608 {609 writer.Write(errorWriter);610 }611 }612 }613 614 break;615 }616 }617 618 /// <summary>619 /// Creates the remote runspace objects when PSSession620 /// parameter is specified621 /// It now supports PSSession based on VM/container connection info as well.622 /// </summary>623 [SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")]624 private List<RemoteRunspace> CreateRunspacesWhenRunspaceParameterSpecified()625 {626 List<RemoteRunspace> remoteRunspaces = new List<RemoteRunspace>();627 628 // validate the runspaces specified before processing them.629 // The function will result in terminating errors, if any630 // validation failure is encountered631 ValidateRemoteRunspacesSpecified();632 633 int rsIndex = 0;634 foreach (PSSession remoteRunspaceInfo in _remoteRunspaceInfos)635 {636 if (remoteRunspaceInfo == null || remoteRunspaceInfo.Runspace == null)637 {638 ThrowTerminatingError(new ErrorRecord(639 new ArgumentNullException("PSSession"), "PSSessionArgumentNull",640 ErrorCategory.InvalidArgument, null));641 }642 else643 {644 // clone the object based on what's specified in the input parameter645 try646 {647 RemoteRunspace remoteRunspace = (RemoteRunspace)remoteRunspaceInfo.Runspace;648 RunspaceConnectionInfo newConnectionInfo = null;649 650 if (remoteRunspace.ConnectionInfo is VMConnectionInfo)651 {652 newConnectionInfo = remoteRunspace.ConnectionInfo.Clone();653 }654 else if (remoteRunspace.ConnectionInfo is ContainerConnectionInfo)655 {656 ContainerConnectionInfo newContainerConnectionInfo = remoteRunspace.ConnectionInfo.Clone() as ContainerConnectionInfo;657 newContainerConnectionInfo.CreateContainerProcess();658 newConnectionInfo = newContainerConnectionInfo;659 }660 else661 {662 // WSMan case663 WSManConnectionInfo originalWSManConnectionInfo = remoteRunspace.ConnectionInfo as WSManConnectionInfo;664 WSManConnectionInfo newWSManConnectionInfo = null;665 666 if (originalWSManConnectionInfo != null)667 {668 newWSManConnectionInfo = originalWSManConnectionInfo.Copy();669 newWSManConnectionInfo.EnableNetworkAccess = newWSManConnectionInfo.EnableNetworkAccess || EnableNetworkAccess;670 newConnectionInfo = newWSManConnectionInfo;671 }672 else673 {674 Uri connectionUri = WSManConnectionInfo.ExtractPropertyAsWsManConnectionInfo<Uri>(remoteRunspace.ConnectionInfo,675 "ConnectionUri", null);676 string shellUri = WSManConnectionInfo.ExtractPropertyAsWsManConnectionInfo<string>(remoteRunspace.ConnectionInfo,677 "ShellUri", string.Empty);678 newWSManConnectionInfo = new WSManConnectionInfo(connectionUri,679 shellUri,680 remoteRunspace.ConnectionInfo.Credential);681 UpdateConnectionInfo(newWSManConnectionInfo);682 newWSManConnectionInfo.EnableNetworkAccess = EnableNetworkAccess;683 newConnectionInfo = newWSManConnectionInfo;684 }685 }686 687 RemoteRunspacePoolInternal rrsPool = remoteRunspace.RunspacePool.RemoteRunspacePoolInternal;688 TypeTable typeTable = null;689 if ((rrsPool != null) &&690 (rrsPool.DataStructureHandler != null) &&691 (rrsPool.DataStructureHandler.TransportManager != null))692 {693 typeTable = rrsPool.DataStructureHandler.TransportManager.Fragmentor.TypeTable;694 }695 696 // Create new remote runspace with name and Id.697 int rsId;698 string rsName = GetRunspaceName(rsIndex, out rsId);699 RemoteRunspace newRemoteRunspace = new RemoteRunspace(700 typeTable, newConnectionInfo, this.Host, this.SessionOption.ApplicationArguments,701 rsName, rsId);702 703 remoteRunspaces.Add(newRemoteRunspace);704 }705 catch (UriFormatException e)706 {707 PipelineWriter writer = _stream.ObjectWriter;708 709 ErrorRecord errorRecord = new ErrorRecord(e, "CreateRemoteRunspaceFailed",710 ErrorCategory.InvalidArgument, remoteRunspaceInfo);711 712 Action<Cmdlet> errorWriter = (Cmdlet cmdlet) => cmdlet.WriteError(errorRecord);713 writer.Write(errorWriter);714 }715 }716 717 ++rsIndex;718 }719 720 return remoteRunspaces;721 }722 723 /// <summary>724 /// Creates the remote runspace objects when the URI parameter725 /// is specified.726 /// </summary>727 private List<RemoteRunspace> CreateRunspacesWhenUriParameterSpecified()728 {729 List<RemoteRunspace> remoteRunspaces = new List<RemoteRunspace>();730 731 // parse the Uri to obtain information about the runspace732 // required733 for (int i = 0; i < ConnectionUri.Length; i++)734 {735 try736 {737 WSManConnectionInfo connectionInfo = new WSManConnectionInfo();738 connectionInfo.ConnectionUri = ConnectionUri[i];739 connectionInfo.ShellUri = ConfigurationName;740 if (CertificateThumbprint != null)741 {742 connectionInfo.CertificateThumbprint = CertificateThumbprint;743 }744 else745 {746 connectionInfo.Credential = Credential;747 }748 749 connectionInfo.AuthenticationMechanism = Authentication;750 UpdateConnectionInfo(connectionInfo);751 752 connectionInfo.EnableNetworkAccess = EnableNetworkAccess;753 754 // Create new remote runspace with name and Id.755 int rsId;756 string rsName = GetRunspaceName(i, out rsId);757 RemoteRunspace remoteRunspace = new RemoteRunspace(758 Utils.GetTypeTableFromExecutionContextTLS(), connectionInfo, this.Host,759 this.SessionOption.ApplicationArguments, rsName, rsId);760 761 Dbg.Assert(remoteRunspace != null,762 "RemoteRunspace object created using URI is null");763 764 remoteRunspaces.Add(remoteRunspace);765 }766 catch (UriFormatException e)767 {768 WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri[i]);769 }770 catch (InvalidOperationException e)771 {772 WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri[i]);773 }774 catch (ArgumentException e)775 {776 WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri[i]);777 }778 catch (NotSupportedException e)779 {780 WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri[i]);781 }782 }783 784 return remoteRunspaces;785 }786 787 /// <summary>788 /// Creates the remote runspace objects when the ComputerName parameter789 /// is specified.790 /// </summary>791 private List<RemoteRunspace> CreateRunspacesWhenComputerNameParameterSpecified()792 {793 List<RemoteRunspace> remoteRunspaces =794 new List<RemoteRunspace>();795 796 // Resolve all the machine names797 string[] resolvedComputerNames;798 799 ResolveComputerNames(ComputerName, out resolvedComputerNames);800 801 ValidateComputerName(resolvedComputerNames);802 803 // Do for each machine804 for (int i = 0; i < resolvedComputerNames.Length; i++)805 {806 try807 {808 WSManConnectionInfo connectionInfo = null;809 connectionInfo = new WSManConnectionInfo();810 string scheme = UseSSL.IsPresent ? WSManConnectionInfo.HttpsScheme : WSManConnectionInfo.HttpScheme;811 connectionInfo.ComputerName = resolvedComputerNames[i];812 connectionInfo.Port = Port;813 connectionInfo.AppName = ApplicationName;814 connectionInfo.ShellUri = ConfigurationName;815 connectionInfo.Scheme = scheme;816 if (CertificateThumbprint != null)817 {818 connectionInfo.CertificateThumbprint = CertificateThumbprint;819 }820 else821 {822 connectionInfo.Credential = Credential;823 }824 825 connectionInfo.AuthenticationMechanism = Authentication;826 UpdateConnectionInfo(connectionInfo);827 828 connectionInfo.EnableNetworkAccess = EnableNetworkAccess;829 830 // Create new remote runspace with name and Id.831 int rsId;832 string rsName = GetRunspaceName(i, out rsId);833 RemoteRunspace runspace = new RemoteRunspace(834 Utils.GetTypeTableFromExecutionContextTLS(), connectionInfo, this.Host,835 this.SessionOption.ApplicationArguments, rsName, rsId);836 837 remoteRunspaces.Add(runspace);838 }839 catch (UriFormatException e)840 {841 PipelineWriter writer = _stream.ObjectWriter;842 843 ErrorRecord errorRecord = new ErrorRecord(e, "CreateRemoteRunspaceFailed",844 ErrorCategory.InvalidArgument, resolvedComputerNames[i]);845 846 Action<Cmdlet> errorWriter = (Cmdlet cmdlet) => cmdlet.WriteError(errorRecord);847 writer.Write(errorWriter);848 }849 }850 851 return remoteRunspaces;852 }853 854 /// <summary>855 /// Creates the remote runspace objects when the VMId or VMName parameter856 /// is specified.857 /// </summary>858 private List<RemoteRunspace> CreateRunspacesWhenVMParameterSpecified()859 {860 int inputArraySize;861 bool isVMIdSet = false;862 int index;863 string command;864 Collection<PSObject> results;865 List<RemoteRunspace> remoteRunspaces = new List<RemoteRunspace>();866 867 if (ParameterSetName == PSExecutionCmdlet.VMIdParameterSet)868 {869 isVMIdSet = true;870 inputArraySize = this.VMId.Length;871 this.VMName = new string[inputArraySize];872 command = "Get-VM -Id $args[0]";873 }874 else875 {876 Dbg.Assert((ParameterSetName == PSExecutionCmdlet.VMNameParameterSet),877 "Expected ParameterSetName == VMId or VMName");878 879 inputArraySize = this.VMName.Length;880 this.VMId = new Guid[inputArraySize];881 command = "Get-VM -Name $args";882 }883 884 for (index = 0; index < inputArraySize; index++)885 {886 try887 {888 results = this.InvokeCommand.InvokeScript(889 command, false, PipelineResultTypes.None, null,890 isVMIdSet ? this.VMId[index].ToString() : this.VMName[index]);891 }892 catch (CommandNotFoundException)893 {894 ThrowTerminatingError(895 new ErrorRecord(896 new ArgumentException(RemotingErrorIdStrings.HyperVModuleNotAvailable),897 nameof(PSRemotingErrorId.HyperVModuleNotAvailable),898 ErrorCategory.NotInstalled,899 null));900 901 return null;902 }903 904 // handle invalid input905 if (results.Count != 1)906 {907 if (isVMIdSet)908 {909 this.VMName[index] = string.Empty;910 911 WriteError(912 new ErrorRecord(913 new ArgumentException(GetMessage(RemotingErrorIdStrings.InvalidVMIdNotSingle,914 this.VMId[index].ToString(null))),915 nameof(PSRemotingErrorId.InvalidVMIdNotSingle),916 ErrorCategory.InvalidArgument,917 null));918 919 continue;920 }921 else922 {923 this.VMId[index] = Guid.Empty;924 925 WriteError(926 new ErrorRecord(927 new ArgumentException(GetMessage(RemotingErrorIdStrings.InvalidVMNameNotSingle,928 this.VMName[index])),929 nameof(PSRemotingErrorId.InvalidVMNameNotSingle),930 ErrorCategory.InvalidArgument,931 null));932 933 continue;934 }935 }936 else937 {938 this.VMId[index] = (Guid)results[0].Properties["VMId"].Value;939 this.VMName[index] = (string)results[0].Properties["VMName"].Value;940 941 //942 // VM should be in running state.943 //944 if (GetVMStateProperty(results[0]) != VMState.Running)945 {946 WriteError(947 new ErrorRecord(948 new ArgumentException(GetMessage(RemotingErrorIdStrings.InvalidVMState,949 this.VMName[index])),950 nameof(PSRemotingErrorId.InvalidVMState),951 ErrorCategory.InvalidArgument,952 null));953 954 continue;955 }956 }957 958 // create helper objects for VM GUIDs or names959 RemoteRunspace runspace = null;960 VMConnectionInfo connectionInfo;961 int rsId;962 string rsName = GetRunspaceName(index, out rsId);963 964 try965 {966 connectionInfo = new VMConnectionInfo(this.Credential, this.VMId[index], this.VMName[index], this.ConfigurationName);967 968 runspace = new RemoteRunspace(Utils.GetTypeTableFromExecutionContextTLS(),969 connectionInfo, this.Host, null, rsName, rsId);970 971 remoteRunspaces.Add(runspace);972 }973 catch (InvalidOperationException e)974 {975 ErrorRecord errorRecord = new ErrorRecord(e,976 "CreateRemoteRunspaceForVMFailed",977 ErrorCategory.InvalidOperation,978 null);979 980 WriteError(errorRecord);981 }982 catch (ArgumentException e)983 {984 ErrorRecord errorRecord = new ErrorRecord(e,985 "CreateRemoteRunspaceForVMFailed",986 ErrorCategory.InvalidArgument,987 null);988 989 WriteError(errorRecord);990 }991 }992 993 ResolvedComputerNames = this.VMName;994 995 return remoteRunspaces;996 }997 998 /// <summary>999 /// Creates the remote runspace objects when the ContainerId parameter is specified.1000 /// </summary>1001 private List<RemoteRunspace> CreateRunspacesWhenContainerParameterSpecified()1002 {1003 int index = 0;1004 List<string> resolvedNameList = new List<string>();1005 List<RemoteRunspace> remoteRunspaces = new List<RemoteRunspace>();1006 1007 Dbg.Assert((ParameterSetName == PSExecutionCmdlet.ContainerIdParameterSet),1008 "Expected ParameterSetName == ContainerId");1009 1010 foreach (var input in ContainerId)1011 {1012 //1013 // Create helper objects for container ID or name.1014 //1015 RemoteRunspace runspace = null;1016 ContainerConnectionInfo connectionInfo = null;1017 int rsId;1018 string rsName = GetRunspaceName(index, out rsId);1019 index++;1020 1021 try1022 {1023 //1024 // Hyper-V container uses Hype-V socket as transport.1025 // Windows Server container uses named pipe as transport.1026 //1027 connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfo(input, RunAsAdministrator.IsPresent, this.ConfigurationName);1028 1029 resolvedNameList.Add(connectionInfo.ComputerName);1030 1031 connectionInfo.CreateContainerProcess();1032 1033 runspace = new RemoteRunspace(Utils.GetTypeTableFromExecutionContextTLS(),1034 connectionInfo, this.Host, null, rsName, rsId);1035 1036 remoteRunspaces.Add(runspace);1037 }1038 catch (InvalidOperationException e)1039 {1040 ErrorRecord errorRecord = new ErrorRecord(e,1041 "CreateRemoteRunspaceForContainerFailed",1042 ErrorCategory.InvalidOperation,1043 null);1044 1045 WriteError(errorRecord);1046 continue;1047 }1048 catch (ArgumentException e)1049 {1050 ErrorRecord errorRecord = new ErrorRecord(e,1051 "CreateRemoteRunspaceForContainerFailed",1052 ErrorCategory.InvalidArgument,1053 null);1054 1055 WriteError(errorRecord);1056 continue;1057 }1058 catch (Exception e)1059 {1060 ErrorRecord errorRecord = new ErrorRecord(e,1061 "CreateRemoteRunspaceForContainerFailed",1062 ErrorCategory.InvalidOperation,1063 null);1064 1065 WriteError(errorRecord);1066 continue;1067 }1068 }1069 1070 ResolvedComputerNames = resolvedNameList.ToArray();1071 1072 return remoteRunspaces;1073 }1074 1075 /// <summary>1076 /// CreateRunspacesForSSHHostParameterSet.1077 /// </summary>1078 /// <returns></returns>1079 private List<RemoteRunspace> CreateRunspacesForSSHHostParameterSet()1080 {1081 // Resolve all the machine names1082 string[] resolvedComputerNames;1083 1084 ResolveComputerNames(HostName, out resolvedComputerNames);1085 1086 var remoteRunspaces = new List<RemoteRunspace>();1087 int index = 0;1088 foreach (var computerName in resolvedComputerNames)1089 {1090 ParseSshHostName(computerName, out string host, out string userName, out int port);1091 1092 var sshConnectionInfo = new SSHConnectionInfo(1093 userName,1094 host,1095 this.KeyFilePath,1096 port,1097 Subsystem,1098 ConnectingTimeout,1099 Options);1100 var typeTable = TypeTable.LoadDefaultTypeFiles();1101 string rsName = GetRunspaceName(index, out int rsIdUnused);1102 index++;1103 remoteRunspaces.Add(RunspaceFactory.CreateRunspace(connectionInfo: sshConnectionInfo,1104 host: this.Host,1105 typeTable: typeTable,1106 applicationArguments: null,1107 name: rsName) as RemoteRunspace);1108 }1109 1110 return remoteRunspaces;1111 }1112 1113 private List<RemoteRunspace> CreateRunspacesForSSHHostHashParameterSet()1114 {1115 var sshConnections = ParseSSHConnectionHashTable();1116 var remoteRunspaces = new List<RemoteRunspace>();1117 int index = 0;1118 foreach (var sshConnection in sshConnections)1119 {1120 var sshConnectionInfo = new SSHConnectionInfo(1121 sshConnection.UserName,1122 sshConnection.ComputerName,1123 sshConnection.KeyFilePath,1124 sshConnection.Port,1125 sshConnection.Subsystem,1126 sshConnection.ConnectingTimeout,1127 sshConnection.Options);1128 var typeTable = TypeTable.LoadDefaultTypeFiles();1129 string rsName = GetRunspaceName(index, out int rsIdUnused);1130 index++;1131 remoteRunspaces.Add(RunspaceFactory.CreateRunspace(connectionInfo: sshConnectionInfo,1132 host: this.Host,1133 typeTable: typeTable,1134 applicationArguments: null,1135 name: rsName) as RemoteRunspace);1136 }1137 1138 return remoteRunspaces;1139 }1140 1141 /// <summary>1142 /// Helper method to create remote runspace based on UseWindowsPowerShell parameter set.1143 /// </summary>1144 /// <returns>Remote runspace that was created.</returns>1145 private List<RemoteRunspace> CreateRunspacesForUseWindowsPowerShellParameterSet()1146 {1147 var remoteRunspaces = new List<RemoteRunspace>();1148 1149 NewProcessConnectionInfo connectionInfo = new NewProcessConnectionInfo(this.Credential);1150 connectionInfo.AuthenticationMechanism = this.Authentication;1151#if !UNIX1152 connectionInfo.PSVersion = new Version(5, 1);1153#endif1154 var typeTable = TypeTable.LoadDefaultTypeFiles();1155 string runspaceName = GetRunspaceName(0, out int runspaceIdUnused);1156 remoteRunspaces.Add(RunspaceFactory.CreateRunspace(connectionInfo: connectionInfo,1157 host: this.Host,1158 typeTable: typeTable,1159 applicationArguments: null,1160 name: runspaceName) as RemoteRunspace);1161 return remoteRunspaces;1162 }1163 1164 /// <summary>1165 /// Helper method to either get a user supplied runspace/session name1166 /// or to generate one along with a unique Id.1167 /// </summary>1168 /// <param name="rsIndex">Runspace name array index.</param>1169 /// <param name="rsId">Runspace Id.</param>1170 /// <returns>Runspace name.</returns>1171 private string GetRunspaceName(int rsIndex, out int rsId)1172 {1173 // Get a unique session/runspace Id and default Name.1174 string rsName = PSSession.GenerateRunspaceName(out rsId);1175 1176 // If there is a friendly name for the runspace, we need to pass it to the1177 // runspace pool object, which in turn passes it on to the server during1178 // construction. This way the friendly name can be returned when querying1179 // the sever for disconnected sessions/runspaces.1180 if (Name != null && rsIndex < Name.Length)1181 {1182 rsName = Name[rsIndex];1183 }1184 1185 return rsName;1186 }1187 1188 /// <summary>1189 /// Internal dispose method which does the actual1190 /// dispose operations and finalize suppressions.1191 /// </summary>1192 /// <param name="disposing">Whether method is called1193 /// from Dispose or destructor</param>1194 protected void Dispose(bool disposing)1195 {1196 if (disposing)1197 {1198 _throttleManager.Dispose();1199 1200 // wait for all runspace operations to be complete