I have an executable at C:\Very\Long\Path\StreamToClipboard.exe
The file C:\InPath\StreamToClipboard.lnk
points to that executable.
The directory C:\InPath
is in my PATH variable, and .lnk
is in my PATHEXT variable.
In regular cmd, I can execute any of these commands:
echo Hello | C:\Very\Long\Path\StreamToClipboard.exe
echo Hello | C:\InPath\StreamToClipboard.lnk
echo Hello | StreamToClipboard.lnk
echo Hello | StreamToClipboard
and the the executable is started, the text "Hello" is correctly piped into that process.
In PowerShell, I can execute echo Hello | C:\Very\Long\Path\StreamToClipboard.exe
and it works too. But all of the other commands don't work:
Fehler beim Ausführen des Programms "StreamToClipboard.lnk": Die angegebene ausführbare Datei ist keine gültige
Anwendung für diese Betriebssystemplattform.In Zeile:1 Zeichen:12
echo foo | C:\InPath\StreamToClipboard.lnk
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.
In Zeile:1 Zeichen:1
echo foo | C:\InPath\StreamToClipboard.lnk
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
FullyQualifiedErrorId : NativeCommandFailed
(and respective paths)
Which roughly translates to Error while executing "StreamToClipboard.lnk": The specified executable file is not a valid application for this operating system plattform
.
Note that echo Hello | "C:\Very\Long\Path\StreamToClipboard.exe"
also does not work, with a different error message:
In Zeile:1 Zeichen:14
... cho Hello | "C:\Very\Long\Path\StreamToClipboard.exe"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ausdrücke sind nur als erstes Element einer Pipeline zulässig.
CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
FullyQualifiedErrorId : ExpressionsMustBeFirstInPipeline
Roughly translates to Expressions are only valid as the first element in a pipeline
.
If I, instead of creating the .lnk file, copy the entire executable to C:\InPath\StreamToClipboard.exe
, then these commands:
echo Hello | C:\InPath\StreamToClipboard.exe
echo Hello | StreamToClipboard.exe
echo Hello | StreamToClipboard
work fine.
How can I get PowerShell to accept echo Hello | StreamToClipboard
(where it's an .lnk file), or at least echo Hello | StreamToClipboard.lnk
?
CodePudding user response:
- Unlike
cmd.exe
, PowerShell does not support invoking shortcut files (.lnk
) like console applications; instead:A new console window opens, asynchronously.
The process in the new console window does NOT receive stdin input (via the pipeline):
If a command is used - such as
echo hello
, using the built-inecho
alias for PowerShell's (rarely needed)Write-Output
cmdlet - the following error occurs, as of Windows PowerShell v5.1 / PowerShell (Core) 7.2.4:Cannot run a document in the middle of a pipeline
If an expression - such as
'hello'
- is used, no error occurs, but the input is effectively ignored.
In other words: PowerShell considers
.lnk
files documents, not executables, and defers to Windows (GUI) shell for opening them;[1] in effect, invoking a.lnk
file is like passing it toInvoke-Item
orStart-Process
; adding-Wait
to the latter makes the invocation synchronous, but still runs in a separate window and doesn't support stdin input; attempting to use-NoNewWindow
and/or-RedirectStandardInput
(to provide stdin input via a file) results in an error, similar to the one you saw:[2]This command cannot be run due to the error: %1 is not a valid Win32 application.
Workarounds:
- Call the target
.exe
file directly in your pipeline, which - if your path is quoted and/or contains variable references or expressions - requires use of&
, the call operator:
# & is required, because the executable path is quoted.
# Note: 'Hello' is the PowerShell-idiomatic equivalent of
# echo Hello
'Hello' | & "C:\Very\Long\Path\StreamToClipboard.exe"
Note: For simplicity, you may choose to always use &
when invoking external programs, but it is only required in the cases mentioned above, discussed in more detail in this answer.
- Invoke the shortcut (
.lnk
) file viacmd /c
:
'Hello' | cmd /c C:\InPath\StreamToClipboard.lnk
Note that, in both workarounds, character encoding issues may arise, given that data is being sent to an external program:
The
$OutputEncoding
preference variable controls what encoding is used to send data to an external program.The encoding stored in
[Console]::OutputEncoding
determines how PowerShell decodes data received from external programs.See this answer for more information.
[1] Note that (temporarily) appending ";.LNK"
to the value of $env:PATHEXT
, the environment variable that lists all filename extensions that belong to executables, does not help.
[2] The reason is that these parameters cause Start-Process
to switch from the ShellExecute
WinAPI function to CreateProcess
, and the latter only works with actual executables.