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.Internal;11using System.Management.Automation.Remoting;12using System.Management.Automation.Remoting.Internal;13using System.Management.Automation.Runspaces;14using System.Management.Automation.Runspaces.Internal;15using System.Threading;16 17using Dbg = System.Management.Automation.Diagnostics;18 19namespace Microsoft.PowerShell.Commands20{21 /// <summary>22 /// This cmdlet executes a specified script block on one or more23 /// remote machines. The expression or command, as they will be24 /// interchangeably called, need to be contained in a script25 /// block. This is to ensure two things:26 /// 1. The expression that the user has entered is27 /// syntactically correct (its compiled)28 /// 2. The scriptblock can be converted to a powershell29 /// object before transmitting it to the remote end30 /// so that it can be run on constrained runspaces in31 /// the no language mode32 ///33 /// In general, the command script block is executed as if34 /// the user had typed it at the command line. The output of the35 /// command is the output of the cmdlet. However, since36 /// invoke-command is a cmdlet, it will unravel its output:37 /// - if the command outputs an empty array, invoke-command38 /// will output $null39 /// - if the command outputs a single-element array, invoke-command40 /// will output that single element.41 ///42 /// Additionally, the command will be run on a remote system.43 ///44 /// This cmdlet can be called in the following different ways:45 ///46 /// Execute a command in a remote machine by specifying the command47 /// and machine name48 /// invoke-command -Command {get-process} -computername "server1"49 ///50 /// Execute a command in a set of remote machines by specifying the51 /// command and the list of machines52 /// $servers = 1..10 | ForEach-Object {"Server${_}"}53 /// invoke-command -command {get-process} -computername $servers54 ///55 /// Create a new runspace and use it to execute a command on a remote machine56 /// $runspace = New-PSSession -computername "Server1"57 /// $credential = get-credential "user01"58 /// invoke-command -command {get-process} -Session $runspace -credential $credential59 ///60 /// Execute a command in a set of remote machines by specifying the61 /// complete uri for the machines62 /// $uri = "http://hostedservices.microsoft.com/someservice"63 /// invoke-command -command { get-mail } - uri $uri64 ///65 /// Create a collection of runspaces and use it to execute a command on a set66 /// of remote machines67 ///68 /// $serveruris = 1..8 | ForEach-Object {"http://Server${_}/"}69 /// $runspaces = New-PSSession -URI $serveruris70 /// invoke-command -command {get-process} -Session $runspaces71 ///72 /// The cmdlet can also be invoked in the asynchronous mode.73 ///74 /// invoke-command -command {get-process} -computername $servers -asjob75 ///76 /// When the -AsJob switch is used, the cmdlet will emit an PSJob Object.77 /// The user can then use the other job cmdlets to work with this object78 ///79 /// Note there are two types of errors:80 /// 1. Remote invocation errors81 /// 2. Local errors.82 ///83 /// Both types of errors will be available when the user invokes84 /// a receive operation.85 ///86 /// The PSJob object has its own throttling mechanism.87 /// The result object will be stored in a global cache. If a user wants to88 /// retrieve data from the result object the user should be able to do so89 /// using the Receive-PSJob cmdlet90 ///91 /// The following needs to be noted about exception/error reporting in this92 /// cmdlet:93 /// The exception objects that are thrown by underlying layers will be94 /// written as errors, to avoid stopping the entire cmdlet in case of95 /// multi-computername or multi-Session usage (for consistency, this96 /// is true even when done using one computername or runspace)97 ///98 /// Only one expression may be executed at a time in any single runspace.99 /// Attempts to invoke an expression on a runspace that is already executing100 /// an expression shall return an error with ErrorCategory ResourceNotAvailable101 /// and notify the user that the runspace is currently busy.102 ///103 /// Some additional notes:104 /// - invoke-command issues a single scriptblock to the computer or105 /// runspace. If a runspace is specified and a command is already running106 /// in that runspace, then the second command will fail107 /// - The files necessary to execute the command (cmdlets, scripts, data108 /// files, etc) must be present on the remote system; the cmdlet is not109 /// responsible for copying them over110 /// - The entire input stream is collected and sent to the remote system111 /// before execution of the command begins (no input streaming)112 /// - Input shall be available as $input. Remote Runspaces must reference113 /// $input explicitly (input will not automatically be available)114 /// - Output from the command streams back to the client as it is115 /// available116 /// - Ctrl-C and pause/resume are supported; the client will send a117 /// message to the remote powershell instance.118 /// - By default if no -credential is specified, the host will impersonate119 /// the current user on the client when executing the command120 /// - The standard output of invoke-command is the output of the121 /// last element of the remote pipeline, with some extra properties added122 /// - If -Shell is not specified, then the value of the environment123 /// variable DEFAULTREMOTESHELLNAME is used. If this is not set, then124 /// "Microsoft.PowerShell" is used.125 /// </summary>126 [Cmdlet(VerbsLifecycle.Invoke, "Command", DefaultParameterSetName = InvokeCommandCommand.InProcParameterSet,127 HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096789", RemotingCapability = RemotingCapability.OwnedByCommand)]128 public class InvokeCommandCommand : PSExecutionCmdlet, IDisposable129 {130 #region Parameters131 132 /// <summary>133 /// The PSSession object describing the remote runspace134 /// using which the specified cmdlet operation will be performed.135 /// </summary>136 [Parameter(Position = 0,137 ParameterSetName = InvokeCommandCommand.SessionParameterSet)]138 [Parameter(Position = 0,139 ParameterSetName = InvokeCommandCommand.FilePathSessionParameterSet)]140 [ValidateNotNullOrEmpty]141 public override PSSession[] Session142 {143 get144 {145 return base.Session;146 }147 148 set149 {150 base.Session = value;151 }152 }153 154 /// <summary>155 /// This parameter represents the address(es) of the remote156 /// computer(s). The following formats are supported:157 /// (a) Computer name158 /// (b) IPv4 address : 132.3.4.5159 /// (c) IPv6 address: 3ffe:8311:ffff:f70f:0:5efe:172.30.162.18.160 /// </summary>161 [Parameter(Position = 0,162 ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]163 [Parameter(Position = 0,164 ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]165 [Alias("Cn")]166 [ValidateNotNullOrEmpty]167 public override string[] ComputerName168 {169 get170 {171 return base.ComputerName;172 }173 174 set175 {176 base.ComputerName = value;177 }178 }179 180 /// <summary>181 /// Specifies the credentials of the user to impersonate in the182 /// remote machine. If this parameter is not specified then the183 /// credentials of the current user process will be assumed.184 /// </summary>185 [Parameter(ValueFromPipelineByPropertyName = true,186 ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]187 [Parameter(ValueFromPipelineByPropertyName = true,188 ParameterSetName = InvokeCommandCommand.UriParameterSet)]189 [Parameter(ValueFromPipelineByPropertyName = true,190 ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]191 [Parameter(ValueFromPipelineByPropertyName = true,192 ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]193 [Parameter(ValueFromPipelineByPropertyName = true, Mandatory = true,194 ParameterSetName = InvokeCommandCommand.VMIdParameterSet)]195 [Parameter(ValueFromPipelineByPropertyName = true, Mandatory = true,196 ParameterSetName = InvokeCommandCommand.VMNameParameterSet)]197 [Parameter(ValueFromPipelineByPropertyName = true, Mandatory = true,198 ParameterSetName = InvokeCommandCommand.FilePathVMIdParameterSet)]199 [Parameter(ValueFromPipelineByPropertyName = true, Mandatory = true,200 ParameterSetName = InvokeCommandCommand.FilePathVMNameParameterSet)]201 [Credential]202 public override PSCredential Credential203 {204 get205 {206 return base.Credential;207 }208 209 set210 {211 base.Credential = value;212 }213 }214 215 /// <summary>216 /// Port specifies the alternate port to be used in case the217 /// default ports are not used for the transport mechanism218 /// (port 80 for http and port 443 for useSSL)219 /// </summary>220 /// <remarks>221 /// Currently this is being accepted as a parameter. But in future222 /// support will be added to make this a part of a policy setting.223 /// When a policy setting is in place this parameter can be used224 /// to override the policy setting225 /// </remarks>226 [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]227 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]228 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]229 [ValidateRange((int)1, (int)UInt16.MaxValue)]230 public override int Port231 {232 get233 {234 return base.Port;235 }236 237 set238 {239 base.Port = value;240 }241 }242 243 /// <summary>244 /// This parameter suggests that the transport scheme to be used for245 /// remote connections is useSSL instead of the default http.Since246 /// there are only two possible transport schemes that are possible247 /// at this point, a SwitchParameter is being used to switch between248 /// the two.249 /// </summary>250 [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]251 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]252 [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SSL")]253 public override SwitchParameter UseSSL254 {255 get256 {257 return base.UseSSL;258 }259 260 set261 {262 base.UseSSL = value;263 }264 }265 266 /// <summary>267 /// For WSMan session:268 /// If this parameter is not specified then the value specified in269 /// the environment variable DEFAULTREMOTESHELLNAME will be used. If270 /// this is not set as well, then Microsoft.PowerShell is used.271 ///272 /// For VM/Container sessions:273 /// If this parameter is not specified then no configuration is used.274 /// </summary>275 [Parameter(ValueFromPipelineByPropertyName = true,276 ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]277 [Parameter(ValueFromPipelineByPropertyName = true,278 ParameterSetName = InvokeCommandCommand.UriParameterSet)]279 [Parameter(ValueFromPipelineByPropertyName = true,280 ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]281 [Parameter(ValueFromPipelineByPropertyName = true,282 ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]283 [Parameter(ValueFromPipelineByPropertyName = true,284 ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)]285 [Parameter(ValueFromPipelineByPropertyName = true,286 ParameterSetName = InvokeCommandCommand.VMIdParameterSet)]287 [Parameter(ValueFromPipelineByPropertyName = true,288 ParameterSetName = InvokeCommandCommand.VMNameParameterSet)]289 [Parameter(ValueFromPipelineByPropertyName = true,290 ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)]291 [Parameter(ValueFromPipelineByPropertyName = true,292 ParameterSetName = InvokeCommandCommand.FilePathVMIdParameterSet)]293 [Parameter(ValueFromPipelineByPropertyName = true,294 ParameterSetName = InvokeCommandCommand.FilePathVMNameParameterSet)]295 public override string ConfigurationName296 {297 get298 {299 return base.ConfigurationName;300 }301 302 set303 {304 base.ConfigurationName = value;305 }306 }307 308 /// <summary>309 /// This parameters specifies the appname which identifies the connection310 /// end point on the remote machine. If this parameter is not specified311 /// then the value specified in DEFAULTREMOTEAPPNAME will be used. If that's312 /// not specified as well, then "WSMAN" will be used.313 /// </summary>314 [Parameter(ValueFromPipelineByPropertyName = true,315 ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]316 [Parameter(ValueFromPipelineByPropertyName = true,317 ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]318 public override string ApplicationName319 {320 get321 {322 return base.ApplicationName;323 }324 325 set326 {327 base.ApplicationName = value;328 }329 }330 331 /// <summary>332 /// Allows the user of the cmdlet to specify a throttling value333 /// for throttling the number of remote operations that can334 /// be executed simultaneously.335 /// </summary>336 [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]337 [Parameter(ParameterSetName = InvokeCommandCommand.SessionParameterSet)]338 [Parameter(ParameterSetName = InvokeCommandCommand.UriParameterSet)]339 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]340 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSessionParameterSet)]341 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]342 [Parameter(ParameterSetName = InvokeCommandCommand.VMIdParameterSet)]343 [Parameter(ParameterSetName = InvokeCommandCommand.VMNameParameterSet)]344 [Parameter(ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)]345 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathVMIdParameterSet)]346 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathVMNameParameterSet)]347 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)]348 public override int ThrottleLimit349 {350 get351 {352 return base.ThrottleLimit;353 }354 355 set356 {357 base.ThrottleLimit = value;358 }359 }360 361 /// <summary>362 /// A complete URI(s) specified for the remote computer and shell to363 /// connect to and create runspace for.364 /// </summary>365 [Parameter(Position = 0,366 ParameterSetName = InvokeCommandCommand.UriParameterSet)]367 [Parameter(Position = 0,368 ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]369 [ValidateNotNullOrEmpty]370 [Alias("URI", "CU")]371 public override Uri[] ConnectionUri372 {373 get374 {375 return base.ConnectionUri;376 }377 378 set379 {380 base.ConnectionUri = value;381 }382 }383 384 /// <summary>385 /// Specifies if the cmdlet needs to be run asynchronously.386 /// </summary>387 [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]388 [Parameter(ParameterSetName = InvokeCommandCommand.SessionParameterSet)]389 [Parameter(ParameterSetName = InvokeCommandCommand.UriParameterSet)]390 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]391 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSessionParameterSet)]392 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]393 [Parameter(ParameterSetName = InvokeCommandCommand.VMIdParameterSet)]394 [Parameter(ParameterSetName = InvokeCommandCommand.VMNameParameterSet)]395 [Parameter(ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)]396 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathVMIdParameterSet)]397 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathVMNameParameterSet)]398 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)]399 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]400 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostHashParameterSet)]401 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]402 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostHashParameterSet)]403 public SwitchParameter AsJob404 {405 get406 {407 return _asjob;408 }409 410 set411 {412 _asjob = value;413 }414 }415 416 private bool _asjob = false;417 418 /// <summary>419 /// Specifies that after the command is invoked on a remote computer the420 /// remote session should be disconnected.421 /// </summary>422 [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]423 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]424 [Parameter(ParameterSetName = InvokeCommandCommand.UriParameterSet)]425 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]426 [Alias("Disconnected")]427 public SwitchParameter InDisconnectedSession428 {429 get { return InvokeAndDisconnect; }430 431 set { InvokeAndDisconnect = value; }432 }433 434 /// <summary>435 /// Specifies the name of the returned session when the InDisconnectedSession switch436 /// is used.437 /// </summary>438 [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]439 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]440 [ValidateNotNullOrEmpty]441 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]442 public string[] SessionName443 {444 get { return DisconnectedSessionName; }445 446 set { DisconnectedSessionName = value; }447 }448 449 /// <summary>450 /// Hide/Show computername of the remote objects.451 /// </summary>452 [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]453 [Parameter(ParameterSetName = InvokeCommandCommand.SessionParameterSet)]454 [Parameter(ParameterSetName = InvokeCommandCommand.UriParameterSet)]455 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]456 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSessionParameterSet)]457 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]458 [Parameter(ParameterSetName = InvokeCommandCommand.VMIdParameterSet)]459 [Parameter(ParameterSetName = InvokeCommandCommand.VMNameParameterSet)]460 [Parameter(ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)]461 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathVMIdParameterSet)]462 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathVMNameParameterSet)]463 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)]464 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]465 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostHashParameterSet)]466 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]467 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostHashParameterSet)]468 [Alias("HCN")]469 public SwitchParameter HideComputerName470 {471 get { return _hideComputerName; }472 473 set { _hideComputerName = value; }474 }475 476 private bool _hideComputerName;477 478 /// <summary>479 /// Friendly name for the job object if AsJob is used.480 /// </summary>481 [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]482 [Parameter(ParameterSetName = InvokeCommandCommand.SessionParameterSet)]483 [Parameter(ParameterSetName = InvokeCommandCommand.UriParameterSet)]484 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]485 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSessionParameterSet)]486 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]487 [Parameter(ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)]488 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)]489 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostHashParameterSet)]490 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]491 public string JobName492 {493 get494 {495 return _name;496 }497 498 set499 {500 if (!string.IsNullOrEmpty(value))501 {502 _name = value;503 _asjob = true;504 }505 }506 }507 508 private string _name = string.Empty;509 510 /// <summary>511 /// The script block that the user has specified in the512 /// cmdlet. This will be converted to a powershell before513 /// its actually sent to the remote end.514 /// </summary>515 [Parameter(Position = 1,516 Mandatory = true,517 ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]518 [Parameter(Position = 1,519 Mandatory = true,520 ParameterSetName = InvokeCommandCommand.SessionParameterSet)]521 [Parameter(Position = 1,522 Mandatory = true,523 ParameterSetName = InvokeCommandCommand.UriParameterSet)]524 [Parameter(Position = 0,525 Mandatory = true,526 ParameterSetName = InvokeCommandCommand.InProcParameterSet)]527 [Parameter(Position = 1,528 Mandatory = true,529 ParameterSetName = InvokeCommandCommand.VMIdParameterSet)]530 [Parameter(Position = 1,531 Mandatory = true,532 ParameterSetName = InvokeCommandCommand.VMNameParameterSet)]533 [Parameter(Position = 1,534 Mandatory = true,535 ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)]536 [Parameter(Position = 1,537 Mandatory = true,538 ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]539 [Parameter(Position = 1,540 Mandatory = true,541 ParameterSetName = InvokeCommandCommand.SSHHostHashParameterSet)]542 [ValidateNotNull]543 [Alias("Command")]544 public override ScriptBlock ScriptBlock545 {546 get547 {548 return base.ScriptBlock;549 }550 551 set552 {553 base.ScriptBlock = value;554 }555 }556 557 /// <summary>558 /// When executing a scriptblock in the current session, tell the cmdlet not to create a new scope.559 /// </summary>560 [Parameter(ParameterSetName = InvokeCommandCommand.InProcParameterSet)]561 public SwitchParameter NoNewScope { get; set; }562 563 /// <summary>564 /// The script block that the user has specified in the565 /// cmdlet. This will be converted to a powershell before566 /// its actually sent to the remote end.567 /// </summary>568 [Parameter(Position = 1,569 Mandatory = true,570 ParameterSetName = FilePathComputerNameParameterSet)]571 [Parameter(Position = 1,572 Mandatory = true,573 ParameterSetName = FilePathSessionParameterSet)]574 [Parameter(Position = 1,575 Mandatory = true,576 ParameterSetName = FilePathUriParameterSet)]577 [Parameter(Position = 1,578 Mandatory = true,579 ParameterSetName = FilePathVMIdParameterSet)]580 [Parameter(Position = 1,581 Mandatory = true,582 ParameterSetName = FilePathVMNameParameterSet)]583 [Parameter(Position = 1,584 Mandatory = true,585 ParameterSetName = FilePathContainerIdParameterSet)]586 [Parameter(Mandatory = true,587 ParameterSetName = FilePathSSHHostParameterSet)]588 [Parameter(Mandatory = true,589 ParameterSetName = FilePathSSHHostHashParameterSet)]590 [ValidateNotNull]591 [Alias("PSPath")]592 public override string FilePath593 {594 get595 {596 return base.FilePath;597 }598 599 set600 {601 base.FilePath = value;602 }603 }604 605 /// <summary>606 /// The AllowRedirection parameter enables the implicit redirection functionality.607 /// </summary>608 [Parameter(ParameterSetName = InvokeCommandCommand.UriParameterSet)]609 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]610 public override SwitchParameter AllowRedirection611 {612 get613 {614 return base.AllowRedirection;615 }616 617 set618 {619 base.AllowRedirection = value;620 }621 }622 623 /// <summary>624 /// Extended Session Options for controlling the session creation. Use625 /// "New-WSManSessionOption" cmdlet to supply value for this parameter.626 /// </summary>627 [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]628 [Parameter(ParameterSetName = InvokeCommandCommand.UriParameterSet)]629 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]630 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]631 public override PSSessionOption SessionOption632 {633 get634 {635 return base.SessionOption;636 }637 638 set639 {640 base.SessionOption = value;641 }642 }643 644 /// <summary>645 /// Authentication mechanism to authenticate the user.646 /// </summary>647 [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]648 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]649 [Parameter(ParameterSetName = InvokeCommandCommand.UriParameterSet)]650 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]651 public override AuthenticationMechanism Authentication652 {653 get654 {655 return base.Authentication;656 }657 658 set659 {660 base.Authentication = value;661 }662 }663 664 /// <summary>665 /// When set and in loopback scenario (localhost) this enables creation of WSMan666 /// host process with the user interactive token, allowing PowerShell script network access,667 /// i.e., allows going off box. When this property is true and a PSSession is disconnected,668 /// reconnection is allowed only if reconnecting from a PowerShell session on the same box.669 /// </summary>670 [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]671 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]672 [Parameter(ParameterSetName = InvokeCommandCommand.UriParameterSet)]673 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]674 public override SwitchParameter EnableNetworkAccess675 {676 get { return base.EnableNetworkAccess; }677 678 set { base.EnableNetworkAccess = value; }679 }680 681 /// <summary>682 /// When set, PowerShell process inside container will be launched with683 /// high privileged account.684 /// Otherwise (default case), PowerShell process inside container will be launched685 /// with low privileged account.686 /// </summary>687 [Parameter(ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)]688 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)]689 public override SwitchParameter RunAsAdministrator690 {691 get { return base.RunAsAdministrator; }692 693 set { base.RunAsAdministrator = value; }694 }695 696 #region SSH Parameters697 698 /// <summary>699 /// Host name for an SSH remote connection.700 /// </summary>701 [Parameter(Mandatory = true,702 ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]703 [Parameter(Mandatory = true,704 ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]705 [ValidateNotNullOrEmpty]706 public override string[] HostName707 {708 get { return base.HostName; }709 710 set { base.HostName = value; }711 }712 713 /// <summary>714 /// User Name.715 /// </summary>716 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]717 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]718 [ValidateNotNullOrEmpty]719 public override string UserName720 {721 get { return base.UserName; }722 723 set { base.UserName = value; }724 }725 726 /// <summary>727 /// Key Path.728 /// </summary>729 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]730 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]731 [ValidateNotNullOrEmpty]732 [Alias("IdentityFilePath")]733 public override string KeyFilePath734 {735 get { return base.KeyFilePath; }736 737 set { base.KeyFilePath = value; }738 }739 740 /// <summary>741 /// Gets and sets a value for the SSH subsystem to use for the remote connection.742 /// </summary>743 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]744 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]745 public override string Subsystem746 {747 get { return base.Subsystem; }748 749 set { base.Subsystem = value; }750 }751 752 /// <summary>753 /// Gets and sets a value in milliseconds that limits the time allowed for an SSH connection to be established.754 /// </summary>755 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]756 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]757 public override int ConnectingTimeout758 {759 get { return base.ConnectingTimeout; }760 761 set { base.ConnectingTimeout = value; }762 }763 764 /// <summary>765 /// This parameter specifies that SSH is used to establish the remote766 /// connection and act as the remoting transport. By default WinRM is used767 /// as the remoting transport. Using the SSH transport requires that SSH is768 /// installed and PowerShell remoting is enabled on both client and remote machines.769 /// </summary>770 [Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]771 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]772 [ValidateSet("true")]773 public override SwitchParameter SSHTransport774 {775 get { return base.SSHTransport; }776 777 set { base.SSHTransport = value; }778 }779 780 /// <summary>781 /// Hashtable array containing SSH connection parameters for each remote target782 /// ComputerName (Alias: HostName) (required)783 /// UserName (optional)784 /// KeyFilePath (Alias: IdentityFilePath) (optional)785 /// </summary>786 [Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostHashParameterSet, Mandatory = true)]787 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostHashParameterSet, Mandatory = true)]788 [ValidateNotNullOrEmpty]789 public override Hashtable[] SSHConnection790 {791 get;792 set;793 }794 795 /// <summary>796 /// Hashtable containing options to be passed to OpenSSH.797 /// </summary>798 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]799 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]800 [ValidateNotNullOrEmpty]801 public override Hashtable Options802 {803 get 804 {805 return base.Options;806 }807 808 set 809 {810 base.Options = value;811 }812 }813 814 #endregion815 816 #region Remote Debug Parameters817 818 /// <summary>819 /// When selected this parameter causes a debugger Step-Into action for each running remote session.820 /// </summary>821 [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]822 [Parameter(ParameterSetName = InvokeCommandCommand.SessionParameterSet)]823 [Parameter(ParameterSetName = InvokeCommandCommand.UriParameterSet)]824 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]825 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSessionParameterSet)]826 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]827 [Parameter(ParameterSetName = InvokeCommandCommand.VMIdParameterSet)]828 [Parameter(ParameterSetName = InvokeCommandCommand.VMNameParameterSet)]829 [Parameter(ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)]830 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathVMIdParameterSet)]831 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathVMNameParameterSet)]832 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)]833 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]834 [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostHashParameterSet)]835 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]836 [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostHashParameterSet)]837 public virtual SwitchParameter RemoteDebug838 {839 get;840 set;841 }842 843 #endregion844 845 #endregion Parameters846 847 #region Overrides848 849 /// <summary>850 /// Creates the helper classes for the specified851 /// parameter set.852 /// </summary>853 protected override void BeginProcessing()854 {855 if (this.InvokeAndDisconnect && _asjob)856 {857 // The -AsJob and -InDisconnectedSession parameter switches are mutually exclusive.858 throw new InvalidOperationException(RemotingErrorIdStrings.AsJobAndDisconnectedError);859 }860 861 if (MyInvocation.BoundParameters.ContainsKey(nameof(SessionName)) && !this.InvokeAndDisconnect)862 {863 throw new InvalidOperationException(RemotingErrorIdStrings.SessionNameWithoutInvokeDisconnected);864 }865 866 // Adjust RemoteDebug value based on current state867 var hostDebugger = GetHostDebugger();868 if (hostDebugger == null)869 {870 // Do not allow RemoteDebug if there is no host debugger available. Otherwise script will not respond indefinitely.871 RemoteDebug = false;872 }873 else if (hostDebugger.IsDebuggerSteppingEnabled)874 {875 // If host debugger is in step-in mode then always make RemoteDebug true876 RemoteDebug = true;877 }878 879 // Checking session's availability and reporting errors in early stage, unless '-AsJob' is specified.880 // When '-AsJob' is specified, Invoke-Command should return a job object without throwing error, even881 // if the session is not in available state -- this is the PSv3 behavior and we should not break it.882 if (!_asjob && (ParameterSetName.Equals(InvokeCommandCommand.SessionParameterSet) ||883 ParameterSetName.Equals(InvokeCommandCommand.FilePathSessionParameterSet)))884 {885 long localPipelineId =886 ((LocalRunspace)this.Context.CurrentRunspace).GetCurrentlyRunningPipeline().InstanceId;887 888 // Check for sessions in invalid state for running commands.889 List<PSSession> availableSessions = new List<PSSession>();890 foreach (var session in Session)891 {892 if (session.Runspace.RunspaceStateInfo.State != RunspaceState.Opened)893 {894 // Session not in Opened state.895 string msg = StringUtil.Format(RemotingErrorIdStrings.ICMInvalidSessionState,896 session.Name, session.InstanceId, session.ComputerName, session.Runspace.RunspaceStateInfo.State);897 898 WriteError(new ErrorRecord(899 new InvalidRunspaceStateException(msg),900 "InvokeCommandCommandInvalidSessionState",901 ErrorCategory.InvalidOperation,902 session));903 }904 else if (session.Runspace.RunspaceAvailability != RunspaceAvailability.Available)905 {906 // Check to see if this is a steppable pipeline case.907 RemoteRunspace remoteRunspace = session.Runspace as RemoteRunspace;908 if ((remoteRunspace != null) &&909 (remoteRunspace.RunspaceAvailability == RunspaceAvailability.Busy) &&910 (remoteRunspace.IsAnotherInvokeCommandExecuting(this, localPipelineId)))911 {912 // Valid steppable pipeline session.913 availableSessions.Add(session);914 }915 else916 {917 // Session not Available.918 string msg = StringUtil.Format(RemotingErrorIdStrings.ICMInvalidSessionAvailability,919 session.Name, session.InstanceId, session.ComputerName, session.Runspace.RunspaceAvailability);920 921 WriteError(new ErrorRecord(922 new InvalidRunspaceStateException(msg),923 "InvokeCommandCommandInvalidSessionAvailability",924 ErrorCategory.InvalidOperation,925 session));926 }927 }928 else929 {930 availableSessions.Add(session);931 }932 }933 934 if (availableSessions.Count == 0)935 {936 throw new PSInvalidOperationException(StringUtil.Format(RemotingErrorIdStrings.ICMNoValidRunspaces));937 }938 939 if (availableSessions.Count < Session.Length)940 {941 Session = availableSessions.ToArray();942 }943 }944 945 if (ParameterSetName.Equals(InvokeCommandCommand.InProcParameterSet))946 {947 if (FilePath != null)948 {949 ScriptBlock = GetScriptBlockFromFile(FilePath, false);950 }951 952 if (this.MyInvocation.ExpectingInput)953 {954 if (!ScriptBlock.IsUsingDollarInput())955 {956 try957 {958 _steppablePipeline = ScriptBlock.GetSteppablePipeline(CommandOrigin.Internal, ArgumentList);959 _steppablePipeline.Begin(this);960 }961 catch (InvalidOperationException)962 {963 // ignore exception and don't do any streaming if can't convert to steppable pipeline964 }965 }966 }967 968 return;969 }970 971 if (string.IsNullOrEmpty(ConfigurationName))972 {973 if ((ParameterSetName == InvokeCommandCommand.ComputerNameParameterSet) ||974 (ParameterSetName == InvokeCommandCommand.UriParameterSet) ||975 (ParameterSetName == InvokeCommandCommand.FilePathComputerNameParameterSet) ||976 (ParameterSetName == InvokeCommandCommand.FilePathUriParameterSet))977 {978 // set to default value for WSMan session979 ConfigurationName = ResolveShell(null);980 }981 else982 {983 // convert null to string.Empty for VM/Container session984 ConfigurationName = string.Empty;985 }986 }987 988 base.BeginProcessing();989 990 // create collection of input writers here991 foreach (IThrottleOperation operation in Operations)992 {993 _inputWriters.Add(((ExecutionCmdletHelper)operation).Pipeline.Input);994 }995 996 // we need to verify, if this Invoke-Command is the first997 // instance within the current local pipeline. If not, then998 // we need to collect all the data and run the invoke-command999 // when the remote runspace is free1000 1001 // We also need to worry about it only in the case of1002 // runspace parameter set - for all else we will never hit1003 // this scenario1004 if (ParameterSetName.Equals(InvokeCommandCommand.SessionParameterSet))1005 {1006 long localPipelineId =1007 ((LocalRunspace)this.Context.CurrentRunspace).GetCurrentlyRunningPipeline().InstanceId;1008 foreach (PSSession runspaceInfo in Session)1009 {1010 RemoteRunspace remoteRunspace = (RemoteRunspace)runspaceInfo.Runspace;1011 if (remoteRunspace.IsAnotherInvokeCommandExecuting(this, localPipelineId))1012 {1013 // Use remote steppable pipeline only for non-input piping case.1014 // Win8 Bug:898011 - We are restricting remote steppable pipeline because1015 // of this bug in Win8 where not responding can occur during data piping.1016 // We are reverting to Win7 behavior for {icm | icm} and {proxycommand | proxycommand}1017 // cases. For ICM | % ICM case, we are using remote steppable pipeline.1018 if ((MyInvocation != null) && (MyInvocation.PipelinePosition == 1) && !MyInvocation.ExpectingInput)1019 {1020 PSPrimitiveDictionary table = (object)runspaceInfo.ApplicationPrivateData[PSVersionInfo.PSVersionTableName] as PSPrimitiveDictionary;1021 if (table != null)1022 {1023 Version version = (object)table[PSVersionInfo.PSRemotingProtocolVersionName] as Version;1024 1025 if (version != null)1026 {1027 // In order to support foreach remoting properly ( icm | % { icm } ), the server must1028 // be using protocol version 2.2. Otherwise, we skip this and assume the old behavior.1029 if (version >= RemotingConstants.ProtocolVersion_2_2)1030 {1031 // Suppress collection behavior1032 _needToCollect = false;1033 _needToStartSteppablePipelineOnServer = true;1034 break;1035 }1036 }1037 }1038 }1039 1040 // Either version table is null or the server is not version 2.2 and beyond, we need to collect1041 _needToCollect = true;1042 _needToStartSteppablePipelineOnServer = false;1043 break;1044 }1045 }1046 }1047 1048 if (_needToStartSteppablePipelineOnServer)1049 {1050 // create collection of input writers here1051 foreach (IThrottleOperation operation in Operations)1052 {1053 if (operation is not ExecutionCmdletHelperRunspace ecHelper)1054 {1055 // either all the operations will be of type ExecutionCmdletHelperRunspace1056 // or not...there is no mix.1057 break;1058 }1059 1060 ecHelper.ShouldUseSteppablePipelineOnServer = true;1061 }1062 }1063 else1064 {1065 // RemoteRunspace must be holding this InvokeCommand..So release1066 // this at dispose time1067 _clearInvokeCommandOnRunspace = true;1068 }1069 1070 // check if we need to propagate terminating errors1071 DetermineThrowStatementBehavior();1072 }1073 1074 /// <summary>1075 /// The expression will be executed in the remote computer if a1076 /// remote runspace parameter or computer name or uri is specified.1077 /// </summary>1078 /// <remarks>1079 /// 1. Identify if the command belongs to the same pipeline1080 /// 2. If so, use the same GUID to create Pipeline/PowerShell1081 /// </remarks>1082 protected override void ProcessRecord()1083 {1084 // we should create the pipeline on first instance1085 // and if there are no invoke-commands running1086 // ahead in the pipeline1087 if (!_pipelineinvoked && !_needToCollect)1088 {1089 _pipelineinvoked = true;1090 1091 if (InputObject == AutomationNull.Value)1092 {1093 CloseAllInputStreams();1094 _inputStreamClosed = true;1095 }1096 1097 if (!ParameterSetName.Equals(InProcParameterSet))1098 {1099 // at this point there is nothing to do for1100 // inproc case. The script block is executed1101 // in EndProcessing1102 if (!_asjob)1103 {1104 CreateAndRunSyncJob();1105 }1106 else1107 {1108 switch (ParameterSetName)1109 {1110 case InvokeCommandCommand.ComputerNameParameterSet:1111 case InvokeCommandCommand.FilePathComputerNameParameterSet:1112 case InvokeCommandCommand.VMIdParameterSet:1113 case InvokeCommandCommand.VMNameParameterSet:1114 case InvokeCommandCommand.ContainerIdParameterSet:1115 case InvokeCommandCommand.FilePathVMIdParameterSet:1116 case InvokeCommandCommand.FilePathVMNameParameterSet:1117 case InvokeCommandCommand.FilePathContainerIdParameterSet:1118 case InvokeCommandCommand.SSHHostParameterSet:1119 case InvokeCommandCommand.FilePathSSHHostParameterSet:1120 case InvokeCommandCommand.SSHHostHashParameterSet:1121 case InvokeCommandCommand.FilePathSSHHostHashParameterSet:1122 {1123 if (ResolvedComputerNames.Length != 0 && Operations.Count > 0)1124 {1125 PSRemotingJob job = new PSRemotingJob(ResolvedComputerNames, Operations,1126 ScriptBlock.ToString(), ThrottleLimit, _name);1127 job.PSJobTypeName = RemoteJobType;1128 job.HideComputerName = _hideComputerName;1129 this.JobRepository.Add(job);1130 WriteObject(job);1131 }1132 }1133 1134 break;1135 1136 case InvokeCommandCommand.SessionParameterSet:1137 case InvokeCommandCommand.FilePathSessionParameterSet:1138 {1139 PSRemotingJob job = new PSRemotingJob(Session, Operations,1140 ScriptBlock.ToString(), ThrottleLimit, _name);1141 job.PSJobTypeName = RemoteJobType;1142 job.HideComputerName = _hideComputerName;1143 this.JobRepository.Add(job);1144 WriteObject(job);1145 }1146 1147 break;1148 1149 case InvokeCommandCommand.UriParameterSet:1150 case InvokeCommandCommand.FilePathUriParameterSet:1151 {1152 if (Operations.Count > 0)1153 {1154 string[] locations = new string[ConnectionUri.Length];1155 for (int i = 0; i < locations.Length; i++)1156 {1157 locations[i] = ConnectionUri[i].ToString();1158 }1159 1160 PSRemotingJob job = new PSRemotingJob(locations, Operations,1161 ScriptBlock.ToString(), ThrottleLimit, _name);1162 job.PSJobTypeName = RemoteJobType;1163 job.HideComputerName = _hideComputerName;1164 this.JobRepository.Add(job);1165 WriteObject(job);1166 }1167 }1168 1169 break;1170 }1171 }1172 }1173 }1174 1175 if (InputObject != AutomationNull.Value && !_inputStreamClosed)1176 {1177 if ((ParameterSetName.Equals(InvokeCommandCommand.InProcParameterSet) && (_steppablePipeline == null)) ||1178 _needToCollect)1179 {1180 _input.Add(InputObject);1181 }1182 else if (ParameterSetName.Equals(InvokeCommandCommand.InProcParameterSet) && (_steppablePipeline != null))1183 {1184 _steppablePipeline.Process(InputObject);1185 }1186 else1187 {1188 WriteInput(InputObject);1189 1190 // if not a job write out the results available thus far1191 if (!_asjob)1192 {1193 WriteJobResults(true);1194 }1195 }1196 }1197 }1198 1199 /// <summary>1200 /// InvokeAsync would have been called in ProcessRecord. Wait here