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