4

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?

0

5 Answers 5

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).

    • The -FilePath parameter by design works with remote invocations only - see the bottom section for details.
  • 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, which would again make use of Invoke-Command unnecessary).

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

Caveat:

  • Invoke-Command does not apply the common -ErrorAction parameter to errors that occur inside 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.

  • More generally, none of the stream-output-controlling common parameters apply to the script block's output; see this comment on GitHub issue #24016 for background information.


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 already 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).

Sign up to request clarification or add additional context in comments.

4 Comments

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, 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.
We can also get through it without using the -ComputerName argument and instead pass an existing PSSession as argument.
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.
4

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

2 Comments

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.)
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.
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.

1 Comment

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.
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.

2 Comments

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. That is, even in the rare cases where its use is both justified and necessary, advising against its use in general is called for.
I agree with that for production scripts but for testing with trusted sources it's fine.
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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.