通过 .lnk 文件管道进入可执行文件

Pipe into executable through .lnk file

我在 C:\Very\Long\Path\StreamToClipboard.exe
有一个可执行文件 文件 C:\InPath\StreamToClipboard.lnk 指向该可执行文件。
目录 C:\InPath 在我的 PATH 变量中,.lnk 在我的 PATHEXT 变量中。

在常规 cmd 中,我可以执行以下任何命令:
echo Hello | C:\Very\Long\Path\StreamToClipboard.exe
echo Hello | C:\InPath\StreamToClipboard.lnk
echo Hello | StreamToClipboard.lnk
echo Hello | StreamToClipboard
并且可执行文件已启动,文本“Hello”被正确地传送到该进程中。

在 PowerShell 中,我可以执行 echo Hello | C:\Very\Long\Path\StreamToClipboard.exe,它也能正常工作。但是所有其他命令都不起作用:

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

(以及各自的路径)
大致翻译为 Error while executing "StreamToClipboard.lnk": The specified executable file is not a valid application for this operating system plattform.

请注意,echo Hello | "C:\Very\Long\Path\StreamToClipboard.exe" 也不起作用,出现不同的错误消息:

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

大致翻译为Expressions are only valid as the first element in a pipeline

如果我不创建 .lnk 文件,而是将整个可执行文件复制到 C:\InPath\StreamToClipboard.exe,那么这些命令:
echo Hello | C:\InPath\StreamToClipboard.exe
echo Hello | StreamToClipboard.exe
echo Hello | StreamToClipboard
工作正常。

如何让 PowerShell 接受 echo Hello | StreamToClipboard(这是一个 .lnk 文件),或者至少接受 echo Hello | StreamToClipboard.lnk

  • cmd.exe 不同,PowerShell 支持调用快捷方式文件 (.lnk),例如 控制台应用程序;反而:
    • A new 控制台 window 打开,异步.

    • 新控制台中的进程 window 不接收 stdin 输入(通过管道):

      • 如果使用 命令 - 例如 echo hello,使用 PowerShell 的 built-in echo 别名 (很少需要)Write-Output cmdlet - 发生以下 错误 ,从 Windows PowerShell v5.1 / PowerShell (Core) 7.2.4 开始:

        • Cannot run a document in the middle of a pipeline
      • 如果使用 表达式 - 例如 'hello' -,不会发生错误,但输入实际上被 忽略.

    • 换句话说:PowerShell 考虑 .lnk 文件 文档 ,而不是可执行文件,并遵循 Windows (GUI) shell 用于打开它们;[1] 实际上,调用 .lnk 文件就像将其传递给 Invoke-Item or Start-Process;向后者添加 -Wait 使调用同步,但仍然在单独的 window 中运行并且不支持标准输入;尝试使用 -NoNewWindow and/or
      -RedirectStandardInput(通过 文件 提供标准输入)导致 error,和你看到的类似:[2]

      • This command cannot be run due to the error: %1 is not a valid Win32 application.

解决方法

  • 在你的管道中直接调用目标.exe文件,如果你的路径是 quoted and/or 包含变量引用或表达式 - 需要使用 &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"

注意:为简单起见,您可以选择在调用外部程序时总是使用&,但这只是必需的 在上述情况下,在 .

中有更详细的讨论
  • 通过cmd /c调用快捷方式(.lnk)文件:
'Hello' | cmd /c C:\InPath\StreamToClipboard.lnk

请注意,在这两种变通方法中,可能会出现 字符编码问题,因为数据正在发送到 外部程序

  • $OutputEncoding preference variable 控制用于将数据 发送到 外部程序的编码。

  • 存储在 [Console]::OutputEncoding 中的编码决定了 PowerShell 如何解码从 外部程序接收到的数据。

  • 有关详细信息,请参阅


[1] 请注意,(暂时)将 ";.LNK" 附加到 $env:PATHEXT 的值,该环境变量列出了属于 的所有文件扩展名可执行文件没有帮助。

[2]原因是这些参数导致Start-ProcessShellExecuteWinAPI函数切换到CreateProcess,后者只对实际有效可执行文件。