3

I want to run a script in file on the local machine using Invoke-Command so I can pass in parameters with -ArgumentList. I've been getting an error I don't understand, so I simplified my command. When I do this:

Invoke-Command -FilePath 'getprocess.ps1'

The content of getprocess.ps1 is:

Get-Process

The error message I get is:

Invoke-Command : Parameter set cannot be resolved using the specified named parameters.

At line:1 char:1

+ Invoke-Command -FilePath 'getprocess.ps1'

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ParameterBindingException

+ FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.InvokeCommandCommand

I'm baffled by this error message. What does it mean? How do I get this to work?

BigScary
  • 530
  • 1
  • 6
  • 19

5 Answers5

7

tl;dr:

  • Generally, do not use Invoke-Command for local invocations - while technically possible, there's only one specific use case where doing so is called for (see below).

  • Instead, invoke scripts directly:

.\getprocess.ps1

Note: Unlike cmd.exe, PowerShell by design requires .\ in order to execute an executable located in the current directory. That is, to avoid accidental execution of executables in the current directory rather than from a directory listed in $env:Path, PowerShell, as a security feature, requires you to signal the intent to execute something in the current directory (.) explicitly.

For script blocks ({ ... }), use &, the call operator (e.g., & { Get-Date }).

For syntactic reasons alone, you situationally also need & for script-file paths if they're specified either as a quoted path (e.g., & '.\getprocess.ps1') and/or if the path involves variable references (e.g.,
& $HOME\getprocess.ps1).

(Separately, . , the dot-sourcing operator is needed in both cases in order to execute a script [block] directly in the caller's scope rather in a child scope).


Note that you can technically combine passing a script block to Invoke-Command (parameter -ScriptBlock) with invoking a local script:

# The script block positionally binds to the -ScriptBlock parameter.
# This is essentially the more expensive equivalent of:
#     & .\getprocess.ps1
Invoke-Command { .\getprocess.ps1 }

This is slower and offers NO advantage over direct invocation
(.\getprocess.ps1 or & .\getprocess.ps1)
.

However, there is one conceivable use case:

If the script isn't an advanced script and you wanted to take advantage of Invoke-Command's stream-output-collecting common parameters, such as -ErrorVariable (if the script or function being invoked is advanced, it supports these common parameters itself).

# Invoke locally and collect errors in $errs
Invoke-Command { .\getprocess.ps1 } -ErrorVariable errs

Caveat: At least as of PowerShell 7.2, Invoke-Command does not apply the common -ErrorAction parameter to errors that occur in the script block, so it cannot be used to control error handling; e.g., -ErrorAction Stop has no effect on the commands in the script block.


As for what you tried:

Indeed, as you point out in your own answer, -FilePath must be combined with the
-ComputerName parameter
(that the error message is so generic is unfortunate).

  • More generally, -FilePath must be combined with any of the parameters that request remote execution, which includes -Session, -ConnectionUri, -VmId / -VmName, and, on Unix-like platforms, -HostName, and -SSHConnection.

The purpose of parameter -FilePath is to copy the content of a local script (*.ps1 file) to a remote computer for execution there. That is, it is a convenient mechanism of executing the code of a script that is (only) available locally on a remote machine.

While you can technically target the local computer via -ComputerName localhost (or, more succinctly, via -ComputerName . / -cn .), this does not amount to a local call:

Whenever -ComputerName is specified - even with -ComputerName localhost - PowerShell's remoting infrastructure is used, which has major implications:

  • The target computer - even if it is the local one - must be set up for PowerShell remoting - see about_Remote_Requirements.

  • If you target the local machine specifically, you must be running in an elevated session (running as administrator).

  • Execution will be much slower than direct (local) invocation.

  • Type fidelity can be lost for both input and output data, given that cross-process marshaling via PowerShell's XML-based serialization infrastructure is involved - see this answer.


That said, if the intent is to locally test remote execution of your script, and your local machine is set up as a remoting target, then use of -ComputerName localhost (-ComputerName . / -cn .) makes perfect sense, given that PowerShell's remoting infrastructure is then involved in the same way it would be in a truly remote call.

Note, however, that such "loopback remoting" calls require elevation (running as admin).

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • This would be a great answer for a more general "What's the recommended approach to invoke scripts on the local machine, when those scripts are in files on the local machine?" But my question was about using Invoke-Command, which I needed for my specific case. I didn't want to bloat my question with a paragraph of motivational background information, lest the conversation become about my motivations instead of my question. Looks like it did anyway. – BigScary May 10 '21 at 17:21
  • @BigScary, `Invoke-Command` is _generally the wrong tool_ to use for invocation of _local script files_. My answer focuses on that, because that is the information that matters most to future readers. However, I've added one use case to the answer where local use of `Invoke-Command` may make sense, but it requires use of a different parameter, namely `-ScriptBlock` with a script block from which the script file is invoked. – mklement0 May 10 '21 at 18:10
  • We can also get through it without using the -ComputerName argument and instead pass an existing PSSession as argument. – P-L Nov 30 '22 at 01:31
  • 1
    Thanks, @P-L. More generally, `-FilePath` must be combined with *any* of the parameters that request _remote_ execution, which not only includes `-Session`, but also `-ConnectionUri`, `-VmId` / `-VmName`, and, on Unix-like platforms, `-HostName`, and `-SSHConnection` - I've updated the answer accordingly. – mklement0 Nov 30 '22 at 02:34
3

Although the error message doesn't make it clear, the -FilePath parameter makes the -ComputerName parameter required. To explicitly target the local computer, use -ComputerName localhost.

Invoke-Command -FilePath 'getprocess.ps1' -ComputerName localhost
mklement0
  • 382,024
  • 64
  • 607
  • 775
BigScary
  • 530
  • 1
  • 6
  • 19
  • Your answer is technically correct (which is why I up-voted it), but it is misleading to present `-ComputerName localhost` as a _local_ invocation, for the reasons detailed in my answer. The short of it is that there's never a good reason to use `Invoke-Command` for local invocations. (In case it was you who down-voted my answer, I invite you to dispute its specific points.) – mklement0 Apr 02 '20 at 14:32
  • On second thought, I think that creating the misleading the impression that `-ComputerName localhost` is suitable for local invocation of scripts outweighs the technical correctness of the information about the required combination of parameters. – mklement0 Apr 03 '20 at 18:56
0

I can't really use invoke-command locally. You use that when you're trying to run a command on a remote PC.

For example, you would want to run something like:

invoke-Command -ComputerName REMOTE-PC -Credentials $credential -Scriptblock {Get-Process}

That error is basically telling you that you need to fill out more parameters that are tied to that command.

try running Get-Help Invoke-Command to see some info on the command and how to run it.

ingenium21
  • 55
  • 1
  • 10
  • To be clear: It wasn't I who down-voted (on the contrary). You're right that `Invoke-Command` is primarily useful for _remote_ invocations, but you _can_ use it to invoke a command locally, namely if a _script block_ is passed to `-ScriptBlock`, whereas `-FilePath` indeed requires the use of `-ComputerName`. That said, there is _no good reason_ to use `Invoke-Command` locally. – mklement0 Apr 02 '20 at 01:37
0

You must have a computername.

$parameters = @{
    ComputerName = '255.255.255.255'
    FilePath = 'getprocess.ps1'
    Credential = 'Domain01\User01'
}

invoke-command @parameters

Use your IP :) To allow that you must also include -credential

If that doesn't do it... invoke-expression may be a semi-suitable replacement for testing until you are ready to invoke-command on the remote machine.

shadow2020
  • 1,315
  • 1
  • 8
  • 30
  • It sounds like the OP's intent was to invoke _locally_, in which case `Invoke-Command` is the wrong tool altogether. Suggesting use of `Invoke-Expression` is problematic, not only because it isn't necessary in this scenario, but because [it should generally be avoided](https://blogs.msdn.microsoft.com/powershell/2011/06/03/invoke-expression-considered-harmful/). That is, even in the rare cases where its use is both justified and necessary, advising against its use _in general_ is called for. – mklement0 Apr 02 '20 at 01:30
  • I agree with that for production scripts but for testing with trusted sources it's fine. – shadow2020 Apr 02 '20 at 15:05
0

You could run it locally like this, but you'd have to be at the administrator (elevated) prompt. It's nice to be able to run it as a test.

invoke-command localhost getprocess.ps1

You can actually do a strange form of parallelism too:

invoke-command localhost,localhost,localhost getprocess.ps1
js2010
  • 23,033
  • 6
  • 64
  • 66