MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections;6using System.Collections.Generic;7using System.Collections.ObjectModel;8using System.Diagnostics.CodeAnalysis;9using System.Management.Automation;10using System.Management.Automation.Host;11using System.Management.Automation.Internal;12using System.Management.Automation.Remoting;13using System.Management.Automation.Runspaces;14using System.Threading;15 16using Microsoft.PowerShell.Commands.Internal.Format;17 18using Dbg = System.Management.Automation.Diagnostics;19 20namespace Microsoft.PowerShell.Commands21{22 /// <summary>23 /// Enter-PSSession cmdlet.24 /// </summary>25 [Cmdlet(VerbsCommon.Enter, "PSSession", DefaultParameterSetName = "ComputerName",26 HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096695", RemotingCapability = RemotingCapability.OwnedByCommand)]27 public class EnterPSSessionCommand : PSRemotingBaseCmdlet28 {29 #region Strings30 31 private const string InstanceIdParameterSet = "InstanceId";32 private const string IdParameterSet = "Id";33 private const string NameParameterSet = "Name";34 35 #endregion36 37 #region Members38 39 /// <summary>40 /// Disable ThrottleLimit parameter inherited from base class.41 /// </summary>42 public new int ThrottleLimit { get { return 0; } set { } }43 44 private ObjectStream _stream;45 private RemoteRunspace _tempRunspace;46 47 #endregion48 49 #region Parameters50 51 #region SSH Parameter Set52 53 /// <summary>54 /// Host name for an SSH remote connection.55 /// </summary>56 [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true,57 ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]58 [ValidateNotNullOrEmpty]59 public new string HostName { get; set; }60 61 /// <summary>62 /// Gets or sets the Hashtable containing options to be passed to OpenSSH.63 /// </summary>64 [Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]65 [ValidateNotNullOrEmpty]66 public override Hashtable Options 67 { 68 get 69 {70 return base.Options;71 }72 73 set74 {75 base.Options = value;76 }77 }78 79 #endregion80 81 /// <summary>82 /// Computer name parameter.83 /// </summary>84 [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true,85 ValueFromPipelineByPropertyName = true, ParameterSetName = ComputerNameParameterSet)]86 [Alias("Cn")]87 [ValidateNotNullOrEmpty]88 public new string ComputerName { get; set; }89 90 /// <summary>91 /// Runspace parameter.92 /// </summary>93 [Parameter(Position = 0, ValueFromPipelineByPropertyName = true,94 ValueFromPipeline = true, ParameterSetName = SessionParameterSet)]95 [ValidateNotNullOrEmpty]96 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspace")]97 public new PSSession Session { get; set; }98 99 /// <summary>100 /// ConnectionUri parameter.101 /// </summary>102 [Parameter(Position = 1, ValueFromPipelineByPropertyName = true,103 ParameterSetName = UriParameterSet)]104 [ValidateNotNullOrEmpty]105 [Alias("URI", "CU")]106 public new Uri ConnectionUri { get; set; }107 108 /// <summary>109 /// RemoteRunspaceId of the remote runspace info object.110 /// </summary>111 [Parameter(ValueFromPipelineByPropertyName = true,112 ParameterSetName = InstanceIdParameterSet)]113 [ValidateNotNull]114 [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspace")]115 public Guid InstanceId { get; set; }116 117 /// <summary>118 /// SessionId of the remote runspace info object.119 /// </summary>120 [Parameter(Position = 0,121 ValueFromPipelineByPropertyName = true,122 ParameterSetName = IdParameterSet)]123 [ValidateNotNull]124 public int Id { get; set; }125 126 /// <summary>127 /// Name of the remote runspace info object.128 /// </summary>129 [Parameter(ValueFromPipelineByPropertyName = true,130 ParameterSetName = NameParameterSet)]131 public string Name { get; set; }132 133 /// <summary>134 /// When set and in loopback scenario (localhost) this enables creation of WSMan135 /// host process with the user interactive token, allowing PowerShell script network access,136 /// i.e., allows going off box. When this property is true and a PSSession is disconnected,137 /// reconnection is allowed only if reconnecting from a PowerShell session on the same box.138 /// </summary>139 [Parameter(ParameterSetName = ComputerNameParameterSet)]140 [Parameter(ParameterSetName = UriParameterSet)]141 public SwitchParameter EnableNetworkAccess { get; set; }142 143 /// <summary>144 /// Virtual machine ID.145 /// </summary>146 [ValidateNotNullOrEmpty]147 [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true,148 ValueFromPipelineByPropertyName = true, ParameterSetName = VMIdParameterSet)]149 [Alias("VMGuid")]150 public new Guid VMId { get; set; }151 152 /// <summary>153 /// Virtual machine name.154 /// </summary>155 [ValidateNotNullOrEmpty]156 [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true,157 ValueFromPipelineByPropertyName = true, ParameterSetName = VMNameParameterSet)]158 public new string VMName { get; set; }159 160 /// <summary>161 /// Specifies the credentials of the user to impersonate in the162 /// virtual machine. If this parameter is not specified then the163 /// credentials of the current user process will be assumed.164 /// </summary>165 [Parameter(ValueFromPipelineByPropertyName = true,166 ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)]167 [Parameter(ValueFromPipelineByPropertyName = true,168 ParameterSetName = PSRemotingBaseCmdlet.UriParameterSet)]169 [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true,170 ParameterSetName = VMIdParameterSet)]171 [Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true,172 ParameterSetName = VMNameParameterSet)]173 [Credential]174 public override PSCredential Credential175 {176 get { return base.Credential; }177 178 set { base.Credential = value; }179 }180 181 /// <summary>182 /// The Id of the target container.183 /// </summary>184 [ValidateNotNullOrEmpty]185 [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true,186 ValueFromPipelineByPropertyName = true, ParameterSetName = ContainerIdParameterSet)]187 public new string ContainerId { get; set; }188 189 /// <summary>190 /// For WSMan sessions:191 /// If this parameter is not specified then the value specified in192 /// the environment variable DEFAULTREMOTESHELLNAME will be used. If193 /// this is not set as well, then Microsoft.PowerShell is used.194 ///195 /// For VM/Container sessions:196 /// If this parameter is not specified then no configuration is used.197 /// </summary>198 [Parameter(ValueFromPipelineByPropertyName = true,199 ParameterSetName = EnterPSSessionCommand.ComputerNameParameterSet)]200 [Parameter(ValueFromPipelineByPropertyName = true,201 ParameterSetName = EnterPSSessionCommand.UriParameterSet)]202 [Parameter(ValueFromPipelineByPropertyName = true,203 ParameterSetName = EnterPSSessionCommand.ContainerIdParameterSet)]204 [Parameter(ValueFromPipelineByPropertyName = true,205 ParameterSetName = EnterPSSessionCommand.VMIdParameterSet)]206 [Parameter(ValueFromPipelineByPropertyName = true,207 ParameterSetName = EnterPSSessionCommand.VMNameParameterSet)]208 public string ConfigurationName { get; set; }209 210 #region Suppress PSRemotingBaseCmdlet SSH hash parameter set211 212 /// <summary>213 /// Suppress SSHConnection parameter set.214 /// </summary>215 public override Hashtable[] SSHConnection216 {217 get { return null; }218 }219 220 #endregion221 222 #endregion223 224 #region Overrides225 226 /// <summary>227 /// Resolves shellname and appname.228 /// </summary>229 protected override void BeginProcessing()230 {231 base.BeginProcessing();232 233 if (string.IsNullOrEmpty(ConfigurationName))234 {235 if ((ParameterSetName == EnterPSSessionCommand.ComputerNameParameterSet) ||236 (ParameterSetName == EnterPSSessionCommand.UriParameterSet))237 {238 // set to default value for WSMan session239 ConfigurationName = ResolveShell(null);240 }241 else242 {243 // convert null to string.Empty for VM/Container session244 ConfigurationName = string.Empty;245 }246 }247 }248 249 /// <summary>250 /// Process record.251 /// </summary>252 protected override void ProcessRecord()253 {254 // Push the remote runspace on the local host.255 IHostSupportsInteractiveSession host = this.Host as IHostSupportsInteractiveSession;256 if (host == null)257 {258 WriteError(259 new ErrorRecord(260 new ArgumentException(GetMessage(RemotingErrorIdStrings.HostDoesNotSupportPushRunspace)),261 nameof(PSRemotingErrorId.HostDoesNotSupportPushRunspace),262 ErrorCategory.InvalidArgument,263 null));264 return;265 }266 267 // for the console host and Graphical PowerShell host268 // we want to skip pushing into the runspace if269 // the host is in a nested prompt270 System.Management.Automation.Internal.Host.InternalHost chost =271 this.Host as System.Management.Automation.Internal.Host.InternalHost;272 273 if (!IsParameterSetForVM() &&274 !IsParameterSetForContainer() &&275 !IsParameterSetForVMContainerSession() &&276 chost != null && chost.HostInNestedPrompt())277 {278 ThrowTerminatingError(new ErrorRecord(279 new InvalidOperationException(PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HostInNestedPrompt)),280 "HostInNestedPrompt", ErrorCategory.InvalidOperation, chost));281 }282 283 /*Microsoft.Windows.PowerShell.Gui.Internal.GPSHost ghost = this.Host as Microsoft.Windows.PowerShell.Gui.Internal.GPSHost;284 285 if (ghost != null && ghost.HostInNestedPrompt())286 {287 ThrowTerminatingError(new ErrorRecord(288 new InvalidOperationException(PSRemotingErrorInvariants.FormatResourceString(PSRemotingErrorId.HostInNestedPrompt)),289 "HostInNestedPrompt", ErrorCategory.InvalidOperation, wpshost));290 }*/291 292 // Get the remote runspace.293 RemoteRunspace remoteRunspace = null;294 switch (ParameterSetName)295 {296 case ComputerNameParameterSet:297 remoteRunspace = CreateRunspaceWhenComputerNameParameterSpecified();298 break;299 300 case UriParameterSet:301 remoteRunspace = CreateRunspaceWhenUriParameterSpecified();302 break;303 304 case SessionParameterSet:305 remoteRunspace = (RemoteRunspace)Session.Runspace;306 break;307 308 case InstanceIdParameterSet:309 remoteRunspace = GetRunspaceMatchingRunspaceId(this.InstanceId);310 break;311 312 case IdParameterSet:313 remoteRunspace = GetRunspaceMatchingSessionId(this.Id);314 break;315 316 case NameParameterSet:317 remoteRunspace = GetRunspaceMatchingName(this.Name);318 break;319 320 case VMIdParameterSet:321 case VMNameParameterSet:322 remoteRunspace = GetRunspaceForVMSession();323 break;324 325 case ContainerIdParameterSet:326 remoteRunspace = GetRunspaceForContainerSession();327 break;328 329 case SSHHostParameterSet:330 remoteRunspace = GetRunspaceForSSHSession();331 break;332 }333 334 // If runspace is null then the error record has already been written and we can exit.335 if (remoteRunspace == null)336 {337 return;338 }339 340 // If the runspace is in a disconnected state try to connect.341 bool runspaceConnected = false;342 if (remoteRunspace.RunspaceStateInfo.State == RunspaceState.Disconnected)343 {344 if (!remoteRunspace.CanConnect)345 {346 string message = StringUtil.Format(RemotingErrorIdStrings.SessionNotAvailableForConnection);347 WriteError(348 new ErrorRecord(349 new RuntimeException(message), "EnterPSSessionCannotConnectDisconnectedSession",350 ErrorCategory.InvalidOperation, remoteRunspace));351 352 return;353 }354 355 // Connect the runspace.356 Exception ex = null;357 try358 {359 remoteRunspace.Connect();360 runspaceConnected = true;361 }362 catch (System.Management.Automation.Remoting.PSRemotingTransportException e)363 {364 ex = e;365 }366 catch (PSInvalidOperationException e)367 {368 ex = e;369 }370 catch (InvalidRunspacePoolStateException e)371 {372 ex = e;373 }374 375 if (ex != null)376 {377 string message = StringUtil.Format(RemotingErrorIdStrings.SessionConnectFailed);378 WriteError(379 new ErrorRecord(380 new RuntimeException(message, ex), "EnterPSSessionConnectSessionFailed",381 ErrorCategory.InvalidOperation, remoteRunspace));382 383 return;384 }385 }386 387 // Verify that the runspace is open.388 if (remoteRunspace.RunspaceStateInfo.State != RunspaceState.Opened)389 {390 if (ParameterSetName == SessionParameterSet)391 {392 string sessionName = (Session != null) ? Session.Name : string.Empty;393 WriteError(394 new ErrorRecord(395 new ArgumentException(GetMessage(RemotingErrorIdStrings.EnterPSSessionBrokenSession,396 sessionName, remoteRunspace.ConnectionInfo.ComputerName, remoteRunspace.InstanceId)),397 nameof(PSRemotingErrorId.PushedRunspaceMustBeOpen),398 ErrorCategory.InvalidArgument,399 null));400 }401 else402 {403 WriteError(404 new ErrorRecord(405 new ArgumentException(GetMessage(RemotingErrorIdStrings.PushedRunspaceMustBeOpen)),406 nameof(PSRemotingErrorId.PushedRunspaceMustBeOpen),407 ErrorCategory.InvalidArgument,408 null));409 }410 411 return;412 }413 414 Debugger debugger = null;415 try416 {417 if (host.Runspace != null)418 {419 debugger = host.Runspace.Debugger;420 }421 }422 catch (PSNotImplementedException) { }423 424 bool supportRunningCommand = ((debugger != null) && ((debugger.DebugMode & DebugModes.RemoteScript) == DebugModes.RemoteScript));425 if (remoteRunspace.RunspaceAvailability != RunspaceAvailability.Available)426 {427 // Session has running command.428 if (!supportRunningCommand)429 {430 // Host does not support remote debug and cannot connect to running command.431 if (runspaceConnected)432 {433 // If we succeeded connecting the session (runspace) but it is already running a command,434 // emit an error for this case because since it is disconnected this session object will435 // never complete and the user must use *reconstruct* scenario to retrieve data.436 string message = StringUtil.Format(RemotingErrorIdStrings.EnterPSSessionDisconnected,437 remoteRunspace.PSSessionName);438 WriteError(439 new ErrorRecord(440 new RuntimeException(message), "EnterPSSessionConnectSessionNotAvailable",441 ErrorCategory.InvalidOperation, Session));442 443 // Leave session in original disconnected state.444 remoteRunspace.DisconnectAsync();445 446 return;447 }448 else449 {450 // If the remote runspace is currently not available then let user know that this command451 // will not complete until it becomes available.452 WriteWarning(GetMessage(RunspaceStrings.RunspaceNotReady));453 }454 }455 else456 {457 // Running commands supported.458 // Warn user that they are entering a session that is running a command and output may459 // be going to a job object.460 Job job = FindJobForRunspace(remoteRunspace.InstanceId);461 string msg;462 if (job != null)463 {464 msg = StringUtil.Format(465 RunspaceStrings.RunningCmdWithJob,466 (!string.IsNullOrEmpty(job.Name)) ? job.Name : string.Empty);467 }468 else469 {470 if (remoteRunspace.RunspaceAvailability == RunspaceAvailability.RemoteDebug)471 {472 msg = StringUtil.Format(473 RunspaceStrings.RunningCmdDebugStop);474 }475 else476 {477 msg = StringUtil.Format(478 RunspaceStrings.RunningCmdWithoutJob);479 }480 }481 482 WriteWarning(msg);483 }484 }485 486 // Make sure any PSSession object passed in is saved in the local runspace repository.487 if (Session != null)488 {489 this.RunspaceRepository.AddOrReplace(Session);490 }491 492 // prepare runspace for prompt493 SetRunspacePrompt(remoteRunspace);494 495 try496 {497 host.PushRunspace(remoteRunspace);498 }499 catch (Exception)500 {501 // A third-party host can throw any exception here..we should502 // clean the runspace created in this case.503 if ((remoteRunspace != null) && (remoteRunspace.ShouldCloseOnPop))504 {505 remoteRunspace.Close();506 }507 508 // rethrow the exception after cleanup.509 throw;510 }511 }512 513 /// <summary>514 /// This method will until the runspace is opened and warnings if any515 /// are reported.516 /// </summary>517 protected override void EndProcessing()518 {519 if (_stream != null)520 {521 while (true)522 {523 // Keep reading objects until end of stream is encountered524 _stream.ObjectReader.WaitHandle.WaitOne();525 526 if (!_stream.ObjectReader.EndOfPipeline)527 {528 object streamObject = _stream.ObjectReader.Read();529 WriteStreamObject((Action<Cmdlet>)streamObject);530 }531 else532 {533 break;534 }535 }536 }537 }538 539 /// <summary>540 /// </summary>541 protected override void StopProcessing()542 {543 var remoteRunspace = _tempRunspace;544 if (remoteRunspace != null)545 {546 try547 {548 remoteRunspace.CloseAsync();549 }550 catch (InvalidRunspaceStateException) { }551 552 return;553 }554 555 IHostSupportsInteractiveSession host = this.Host as IHostSupportsInteractiveSession;556 if (host == null)557 {558 WriteError(559 new ErrorRecord(560 new ArgumentException(GetMessage(RemotingErrorIdStrings.HostDoesNotSupportPushRunspace)),561 nameof(PSRemotingErrorId.HostDoesNotSupportPushRunspace),562 ErrorCategory.InvalidArgument,563 null));564 return;565 }566 567 host.PopRunspace();568 }569 570 #endregion571 572 #region Private Methods573 574 /// <summary>575 /// Create temporary remote runspace.576 /// </summary>577 private RemoteRunspace CreateTemporaryRemoteRunspace(PSHost host, WSManConnectionInfo connectionInfo)578 {579 // Create and open the runspace.580 int rsId;581 string rsName = PSSession.GenerateRunspaceName(out rsId);582 RemoteRunspace remoteRunspace = new RemoteRunspace(583 Utils.GetTypeTableFromExecutionContextTLS(),584 connectionInfo,585 host,586 this.SessionOption.ApplicationArguments,587 rsName,588 rsId);589 Dbg.Assert(remoteRunspace != null, "Expected remoteRunspace != null");590 remoteRunspace.URIRedirectionReported += HandleURIDirectionReported;591 592 _stream = new ObjectStream();593 try594 {595 remoteRunspace.Open();596 597 // Mark this temporary runspace so that it closes on pop.598 remoteRunspace.ShouldCloseOnPop = true;599 }600 finally601 {602 // unregister uri redirection handler603 remoteRunspace.URIRedirectionReported -= HandleURIDirectionReported;604 // close the internal object stream after runspace is opened605 // Runspace.Open() might throw exceptions..this will make sure606 // the stream is always closed.607 _stream.ObjectWriter.Close();608 609 // make sure we dispose the temporary runspace if something bad happens610 if (remoteRunspace.RunspaceStateInfo.State != RunspaceState.Opened)611 {612 remoteRunspace.Dispose();613 remoteRunspace = null;614 }615 }616 617 return remoteRunspace;618 }619 620 /// <summary>621 /// Write error create remote runspace failed.622 /// </summary>623 private void WriteErrorCreateRemoteRunspaceFailed(Exception exception, object argument)624 {625 // set the transport message in the error detail so that626 // the user can directly get to see the message without627 // having to mine through the error record details628 PSRemotingTransportException transException =629 exception as PSRemotingTransportException;630 string errorDetails = null;631 if ((transException != null) &&632 (transException.ErrorCode ==633 System.Management.Automation.Remoting.Client.WSManNativeApi.ERROR_WSMAN_REDIRECT_REQUESTED))634 {635 // Handling a special case for redirection..we should talk about636 // AllowRedirection parameter and WSManMaxRedirectionCount preference637 // variables638 string message = PSRemotingErrorInvariants.FormatResourceString(639 RemotingErrorIdStrings.URIRedirectionReported,640 transException.Message,641 "MaximumConnectionRedirectionCount",642 Microsoft.PowerShell.Commands.PSRemotingBaseCmdlet.DEFAULT_SESSION_OPTION,643 "AllowRedirection");644 645 errorDetails = message;646 }647 648 ErrorRecord errorRecord = new ErrorRecord(exception, argument,649 "CreateRemoteRunspaceFailed",650 ErrorCategory.InvalidArgument,651 null, null, null, null, null, errorDetails, null);652 653 WriteError(errorRecord);654 }655 656 /// <summary>657 /// Write invalid argument error.658 /// </summary>659 private void WriteInvalidArgumentError(PSRemotingErrorId errorId, string resourceString, object errorArgument)660 {661 string message = GetMessage(resourceString, errorArgument);662 WriteError(new ErrorRecord(new ArgumentException(message), errorId.ToString(),663 ErrorCategory.InvalidArgument, errorArgument));664 }665 666 /// <summary>667 /// When the client remote session reports a URI redirection, this method will report the668 /// message to the user as a Warning using Host method calls.669 /// </summary>670 /// <param name="sender"></param>671 /// <param name="eventArgs"></param>672 private void HandleURIDirectionReported(object sender, RemoteDataEventArgs<Uri> eventArgs)673 {674 string message = StringUtil.Format(RemotingErrorIdStrings.URIRedirectWarningToHost, eventArgs.Data.OriginalString);675 Action<Cmdlet> streamObject = (Cmdlet cmdlet) => cmdlet.WriteWarning(message);676 _stream.Write(streamObject);677 }678 679 /// <summary>680 /// Create runspace when computer name parameter specified.681 /// </summary>682 private RemoteRunspace CreateRunspaceWhenComputerNameParameterSpecified()683 {684 RemoteRunspace remoteRunspace = null;685 string resolvedComputerName = ResolveComputerName(ComputerName);686 try687 {688 WSManConnectionInfo connectionInfo = null;689 connectionInfo = new WSManConnectionInfo();690 string scheme = UseSSL.IsPresent ? WSManConnectionInfo.HttpsScheme : WSManConnectionInfo.HttpScheme;691 connectionInfo.ComputerName = resolvedComputerName;692 connectionInfo.Port = Port;693 connectionInfo.AppName = ApplicationName;694 connectionInfo.ShellUri = ConfigurationName;695 connectionInfo.Scheme = scheme;696 if (CertificateThumbprint != null)697 {698 connectionInfo.CertificateThumbprint = CertificateThumbprint;699 }700 else701 {702 connectionInfo.Credential = Credential;703 }704 705 connectionInfo.AuthenticationMechanism = Authentication;706 UpdateConnectionInfo(connectionInfo);707 708 connectionInfo.EnableNetworkAccess = EnableNetworkAccess;709 710 remoteRunspace = CreateTemporaryRemoteRunspace(this.Host, connectionInfo);711 }712 catch (InvalidOperationException e)713 {714 WriteErrorCreateRemoteRunspaceFailed(e, resolvedComputerName);715 }716 catch (ArgumentException e)717 {718 WriteErrorCreateRemoteRunspaceFailed(e, resolvedComputerName);719 }720 catch (PSRemotingTransportException e)721 {722 WriteErrorCreateRemoteRunspaceFailed(e, resolvedComputerName);723 }724 725 return remoteRunspace;726 }727 728 /// <summary>729 /// Create runspace when uri parameter specified.730 /// </summary>731 private RemoteRunspace CreateRunspaceWhenUriParameterSpecified()732 {733 RemoteRunspace remoteRunspace = null;734 try735 {736 WSManConnectionInfo connectionInfo = new WSManConnectionInfo();737 connectionInfo.ConnectionUri = ConnectionUri;738 connectionInfo.ShellUri = ConfigurationName;739 if (CertificateThumbprint != null)740 {741 connectionInfo.CertificateThumbprint = CertificateThumbprint;742 }743 else744 {745 connectionInfo.Credential = Credential;746 }747 748 connectionInfo.AuthenticationMechanism = Authentication;749 UpdateConnectionInfo(connectionInfo);750 connectionInfo.EnableNetworkAccess = EnableNetworkAccess;751 remoteRunspace = CreateTemporaryRemoteRunspace(this.Host, connectionInfo);752 }753 catch (UriFormatException e)754 {755 WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri);756 }757 catch (InvalidOperationException e)758 {759 WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri);760 }761 catch (ArgumentException e)762 {763 WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri);764 }765 catch (PSRemotingTransportException e)766 {767 WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri);768 }769 catch (NotSupportedException e)770 {771 WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri);772 }773 774 return remoteRunspace;775 }776 777 /// <summary>778 /// Get runspace matching condition.779 /// </summary>780 private RemoteRunspace GetRunspaceMatchingCondition(781 Predicate<PSSession> condition,782 PSRemotingErrorId tooFew,783 PSRemotingErrorId tooMany,784 string tooFewResourceString,785 string tooManyResourceString,786 object errorArgument)787 {788 // Find matches.789 List<PSSession> matches = this.RunspaceRepository.Runspaces.FindAll(condition);790 791 // Validate.792 RemoteRunspace remoteRunspace = null;793 if (matches.Count == 0)794 {795 WriteInvalidArgumentError(tooFew, tooFewResourceString, errorArgument);796 }797 else if (matches.Count > 1)798 {799 WriteInvalidArgumentError(tooMany, tooManyResourceString, errorArgument);800 }801 else802 {803 remoteRunspace = (RemoteRunspace)matches[0].Runspace;804 Dbg.Assert(remoteRunspace != null, "Expected remoteRunspace != null");805 }806 807 return remoteRunspace;808 }809 810 /// <summary>811 /// Get runspace matching runspace id.812 /// </summary>813 private RemoteRunspace GetRunspaceMatchingRunspaceId(Guid remoteRunspaceId)814 {815 return GetRunspaceMatchingCondition(816 condition: info => info.InstanceId == remoteRunspaceId,817 tooFew: PSRemotingErrorId.RemoteRunspaceNotAvailableForSpecifiedRunspaceId,818 tooMany: PSRemotingErrorId.RemoteRunspaceHasMultipleMatchesForSpecifiedRunspaceId,819 tooFewResourceString: RemotingErrorIdStrings.RemoteRunspaceNotAvailableForSpecifiedRunspaceId,820 tooManyResourceString: RemotingErrorIdStrings.RemoteRunspaceHasMultipleMatchesForSpecifiedRunspaceId,821 errorArgument: remoteRunspaceId);822 }823 824 /// <summary>825 /// Get runspace matching session id.826 /// </summary>827 private RemoteRunspace GetRunspaceMatchingSessionId(int sessionId)828 {829 return GetRunspaceMatchingCondition(830 condition: info => info.Id == sessionId,831 tooFew: PSRemotingErrorId.RemoteRunspaceNotAvailableForSpecifiedSessionId,832 tooMany: PSRemotingErrorId.RemoteRunspaceHasMultipleMatchesForSpecifiedSessionId,833 tooFewResourceString: RemotingErrorIdStrings.RemoteRunspaceNotAvailableForSpecifiedSessionId,834 tooManyResourceString: RemotingErrorIdStrings.RemoteRunspaceHasMultipleMatchesForSpecifiedSessionId,835 errorArgument: sessionId);836 }837 838 /// <summary>839 /// Get runspace matching name.840 /// </summary>841 private RemoteRunspace GetRunspaceMatchingName(string name)842 {843 return GetRunspaceMatchingCondition(844 condition: info => info.Name.Equals(name, StringComparison.OrdinalIgnoreCase),845 tooFew: PSRemotingErrorId.RemoteRunspaceNotAvailableForSpecifiedName,846 tooMany: PSRemotingErrorId.RemoteRunspaceHasMultipleMatchesForSpecifiedName,847 tooFewResourceString: RemotingErrorIdStrings.RemoteRunspaceNotAvailableForSpecifiedName,848 tooManyResourceString: RemotingErrorIdStrings.RemoteRunspaceHasMultipleMatchesForSpecifiedName,849 errorArgument: name);850 }851 852 private Job FindJobForRunspace(Guid id)853 {854 foreach (var repJob in this.JobRepository.Jobs)855 {856 foreach (Job childJob in repJob.ChildJobs)857 {858 PSRemotingChildJob remotingChildJob = childJob as PSRemotingChildJob;859 860 if (remotingChildJob != null &&861 remotingChildJob.Runspace != null &&862 remotingChildJob.JobStateInfo.State == JobState.Running &&863 remotingChildJob.Runspace.InstanceId.Equals(id))864 {865 return repJob;866 }867 }868 }869 870 return null;871 }872 873 private bool IsParameterSetForVM()874 {875 return ((ParameterSetName == VMIdParameterSet) ||876 (ParameterSetName == VMNameParameterSet));877 }878 879 private bool IsParameterSetForContainer()880 {881 return (ParameterSetName == ContainerIdParameterSet);882 }883 884 /// <summary>885 /// Whether the input is a session object or property that corresponds to886 /// VM or container.887 /// </summary>888 private bool IsParameterSetForVMContainerSession()889 {890 RemoteRunspace remoteRunspace = null;891 892 switch (ParameterSetName)893 {894 case SessionParameterSet:895 if (this.Session != null)896 {897 remoteRunspace = (RemoteRunspace)this.Session.Runspace;898 }899 900 break;901 902 case InstanceIdParameterSet:903 remoteRunspace = GetRunspaceMatchingRunspaceId(this.InstanceId);904 break;905 906 case IdParameterSet:907 remoteRunspace = GetRunspaceMatchingSessionId(this.Id);908 break;909 910 case NameParameterSet:911 remoteRunspace = GetRunspaceMatchingName(this.Name);912 break;913 914 default:915 break;916 }917 918 if ((remoteRunspace != null) &&919 (remoteRunspace.ConnectionInfo != null))920 {921 if ((remoteRunspace.ConnectionInfo is VMConnectionInfo) ||922 (remoteRunspace.ConnectionInfo is ContainerConnectionInfo))923 {924 return true;925 }926 }927 928 return false;929 }930 931 /// <summary>932 /// Create runspace for VM session.933 /// </summary>934 private RemoteRunspace GetRunspaceForVMSession()935 {936 RemoteRunspace remoteRunspace = null;937 string command;938 Collection<PSObject> results;939 940 if (ParameterSetName == VMIdParameterSet)941 {942 command = "Get-VM -Id $args[0]";943 944 try945 {946 results = this.InvokeCommand.InvokeScript(947 command, false, PipelineResultTypes.None, null, this.VMId);948 }949 catch (CommandNotFoundException)950 {951 WriteError(952 new ErrorRecord(953 new ArgumentException(RemotingErrorIdStrings.HyperVModuleNotAvailable),954 nameof(PSRemotingErrorId.HyperVModuleNotAvailable),955 ErrorCategory.NotInstalled,956 null));957 958 return null;959 }960 961 if (results.Count != 1)962 {963 WriteError(964 new ErrorRecord(965 new ArgumentException(RemotingErrorIdStrings.InvalidVMId),966 nameof(PSRemotingErrorId.InvalidVMId),967 ErrorCategory.InvalidArgument,968 null));969 970 return null;971 }972 973 this.VMName = (string)results[0].Properties["VMName"].Value;974 }975 else976 {977 Dbg.Assert(ParameterSetName == VMNameParameterSet, "Expected ParameterSetName == VMName");978 979 command = "Get-VM -Name $args";980 981 try982 {983 results = this.InvokeCommand.InvokeScript(984 command, false, PipelineResultTypes.None, null, this.VMName);985 }986 catch (CommandNotFoundException)987 {988 WriteError(989 new ErrorRecord(990 new ArgumentException(RemotingErrorIdStrings.HyperVModuleNotAvailable),991 nameof(PSRemotingErrorId.HyperVModuleNotAvailable),992 ErrorCategory.NotInstalled,993 null));994 995 return null;996 }997 998 if (results.Count == 0)999 {1000 WriteError(1001 new ErrorRecord(1002 new ArgumentException(RemotingErrorIdStrings.InvalidVMNameNoVM),1003 nameof(PSRemotingErrorId.InvalidVMNameNoVM),1004 ErrorCategory.InvalidArgument,1005 null));1006 1007 return null;1008 }1009 else if (results.Count > 1)1010 {1011 WriteError(1012 new ErrorRecord(1013 new ArgumentException(RemotingErrorIdStrings.InvalidVMNameMultipleVM),1014 nameof(PSRemotingErrorId.InvalidVMNameMultipleVM),1015 ErrorCategory.InvalidArgument,1016 null));1017 1018 return null;1019 }1020 1021 this.VMId = (Guid)results[0].Properties["VMId"].Value;1022 this.VMName = (string)results[0].Properties["VMName"].Value;1023 }1024 1025 //1026 // VM should be in running state.1027 //1028 if (GetVMStateProperty(results[0]) != VMState.Running)1029 {1030 WriteError(1031 new ErrorRecord(1032 new ArgumentException(GetMessage(RemotingErrorIdStrings.InvalidVMState,1033 this.VMName)),1034 nameof(PSRemotingErrorId.InvalidVMState),1035 ErrorCategory.InvalidArgument,1036 null));1037 1038 return null;1039 }1040 1041 try1042 {1043 VMConnectionInfo connectionInfo;1044 connectionInfo = new VMConnectionInfo(this.Credential, this.VMId, this.VMName, this.ConfigurationName);1045 1046 remoteRunspace = CreateTemporaryRemoteRunspaceForPowerShellDirect(this.Host, connectionInfo);1047 }1048 catch (InvalidOperationException e)1049 {1050 ErrorRecord errorRecord = new ErrorRecord(e,1051 "CreateRemoteRunspaceForVMFailed",1052 ErrorCategory.InvalidOperation,1053 null);1054 1055 WriteError(errorRecord);1056 }1057 catch (ArgumentException e)1058 {1059 ErrorRecord errorRecord = new ErrorRecord(e,1060 "CreateRemoteRunspaceForVMFailed",1061 ErrorCategory.InvalidArgument,1062 null);1063 1064 WriteError(errorRecord);1065 }1066 catch (PSRemotingDataStructureException e)1067 {1068 ErrorRecord errorRecord;1069 1070 //1071 // In case of PSDirectException, we should output the precise error message1072 // in inner exception instead of the generic one in outer exception.1073 //1074 if ((e.InnerException != null) && (e.InnerException is PSDirectException))1075 {1076 errorRecord = new ErrorRecord(e.InnerException,1077 "CreateRemoteRunspaceForVMFailed",1078 ErrorCategory.InvalidArgument,1079 null);1080 }1081 else1082 {1083 errorRecord = new ErrorRecord(e,1084 "CreateRemoteRunspaceForVMFailed",1085 ErrorCategory.InvalidOperation,1086 null);1087 }1088 1089 WriteError(errorRecord);1090 }1091 catch (Exception e)1092 {1093 ErrorRecord errorRecord = new ErrorRecord(e,1094 "CreateRemoteRunspaceForVMFailed",1095 ErrorCategory.InvalidOperation,1096 null);1097 1098 WriteError(errorRecord);1099 }1100 1101 return remoteRunspace;1102 }1103 1104 /// <summary>1105 /// Create temporary remote runspace.1106 /// </summary>1107 private static RemoteRunspace CreateTemporaryRemoteRunspaceForPowerShellDirect(PSHost host, RunspaceConnectionInfo connectionInfo)1108 {1109 // Create and open the runspace.1110 TypeTable typeTable = TypeTable.LoadDefaultTypeFiles();1111 RemoteRunspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo, host, typeTable) as RemoteRunspace;1112 remoteRunspace.Name = "PowerShellDirectAttach";1113 1114 Dbg.Assert(remoteRunspace != null, "Expected remoteRunspace != null");1115 try1116 {1117 remoteRunspace.Open();1118 1119 // Mark this temporary runspace so that it closes on pop.1120 remoteRunspace.ShouldCloseOnPop = true;1121 }1122 finally1123 {1124 // Make sure we dispose the temporary runspace if something bad happens.1125 if (remoteRunspace.RunspaceStateInfo.State != RunspaceState.Opened)1126 {1127 remoteRunspace.Dispose();1128 remoteRunspace = null;1129 }1130 }1131 1132 return remoteRunspace;1133 }1134 1135 /// <summary>1136 /// Set prompt for VM/Container sessions.1137 /// </summary>1138 private void SetRunspacePrompt(RemoteRunspace remoteRunspace)1139 {1140 if (IsParameterSetForVM() ||1141 IsParameterSetForContainer() ||1142 IsParameterSetForVMContainerSession())1143 {1144 string targetName = string.Empty;1145 1146 switch (ParameterSetName)1147 {1148 case VMIdParameterSet:1149 case VMNameParameterSet:1150 targetName = this.VMName;1151 break;1152 1153 case ContainerIdParameterSet:1154 targetName = (this.ContainerId.Length <= 15) ? this.ContainerId1155 : this.ContainerId.Remove(14) + PSObjectHelper.Ellipsis;1156 break;1157 1158 case SessionParameterSet:1159 targetName = (this.Session != null) ? this.Session.ComputerName : string.Empty;1160 break;1161 1162 case InstanceIdParameterSet:1163 case IdParameterSet:1164 case NameParameterSet:1165 if ((remoteRunspace != null) &&1166 (remoteRunspace.ConnectionInfo != null))1167 {1168 targetName = remoteRunspace.ConnectionInfo.ComputerName;1169 }1170 1171 break;1172 1173 default:1174 Dbg.Assert(false, "Unrecognized parameter set.");1175 break;1176 }1177 1178 string promptFn = StringUtil.Format(RemotingErrorIdStrings.EnterVMSessionPrompt,1179 @"function global:prompt { """,1180 targetName,1181 @"PS $($executionContext.SessionState.Path.CurrentLocation)> "" }");1182 1183 // Set prompt in pushed named pipe runspace.1184 using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create())1185 {1186 ps.Runspace = remoteRunspace;1187 1188 try1189 {1190 // Set pushed runspace prompt.1191 ps.AddScript(promptFn).Invoke();1192 }1193 catch (Exception)1194 {1195 }1196 }1197 }1198 1199 return;1200 }