powershell:不带扩展名运行可执行文件

7tofc5zh  于 2023-10-18  发布在  Shell
关注(0)|答案(2)|浏览(151)

我有一个powershell脚本,需要运行一些可执行文件。
可执行文件没有扩展名,因此无法重命名。
格式为<something>_test
当我尝试使用powershell运行它们时:

& $test_bin | Tee-Object -FilePath $log_output_file

它失败并返回错误

Cannot run a document in the middle of a pipeline

我尝试设置PATH($env:PATHEXT="$env:PATHEXT;_test"),但没有帮助。我猜它只支持实际的扩展。
有没有办法告诉windows一个特定的文件是可执行文件,或者告诉powershell执行一个文件,即使它认为它是一个文档?

a6b3iqyw

a6b3iqyw1#

范例:

# Define a function which executes any file
function Start-ProcessEx ($filePath)
{
    $psi = [System.Diagnostics.ProcessStartInfo]::new()
    $psi.FileName = $filePath
    $psi.UseShellExecute = $false # This is the key to run file as executable when it has non-executable extension
    return [System.Diagnostics.Process]::Start($psi)
}

Start-ProcessEx -filePath 'C:\Program Files\Speedtest\Speedtest.randomextension'

应该有更多的方法来执行具有不可执行扩展名的文件,这是变体之一。

6vl6ewon

6vl6ewon2#

我尝试设置PATHEXT($env:PATHEXT="$env:PATHEXT;_test"),但没有帮助

  • 您必须使用.来表示没有扩展名的文件

$env:PATHEXT="$env:PATHEXT;."

  • 此外,您还必须定义一个 * 文件类型 *(例如:通过cmd.exe的内部assocftype命令),其调用助手应用程序以便于执行。
  • This answer在模拟Windows上的shebang行支持的上下文中显示了这样一个定义,但它最终不会帮助您-请参阅下一点。
  • 然而,从PowerShell(Core)7.3.x开始,即使这还不够,因为PowerShell -不像cmd.exe-然后在新窗口中调用助手应用程序 *;这种有问题的行为是GitHub issue #9430的主题。
    解决方法
  • 如果只支持将可执行文件的输出重定向到 files(并在 separate files中捕获stdout和stderr)就足够了-可以使用Start-Process-NoNewWindow开关以及-RedirectStandardOutput-RedirectStandardError参数;例如:
Start-Process -Wait -NoNewWindow $test_bin -RedirectStandardOutput $log_output_file
    • 编译器编码警告:* 它是存储在[Console]::OutputEncoding中的编码,用于-RedirectStandardOutput-RedirectStandardError创建的文件,默认为旧系统区域设置的OEM代码页;(临时)根据需要将[Console]::OutputEncoding设置为所需的编码。这同样适用于PowerShell直接从外部程序接收的标准输出(参见下一点)。
  • 如果您想要通常的PowerShell体验-在同一窗口中同步执行,可执行进程的标准流(stdin,stdout,stderr)连接到PowerShell的流-需要更多的工作:
  • 下面的帮助函数Invoke-ExtensionLess(源代码)是一个 * 简单 * 的概念验证,它使用.NET API(System.Diagnostics.ProcessSystem.Diagnostics.ProcessStartInfo)来支持直接将可执行文件的 stdout 输出流到PowerShell管道,但它缺乏对流管道(stdin)* 输入 * 的支持(添加此类支持需要更多的工作)。
  • 示例调用如下所示:
Invoke-ExtensionLess $test_bin arg1 arg2 | 
  ForEach-Object { "[$_]" } # sample pipeline processing.

Invoke-ExtensionLess源代码

# Note: No support for stdin input.
function Invoke-ExtensionLess {
  param($exe)
  # Find the executable's full path
  $exePath = if (Test-Path -LiteralPath $exe) { Convert-Path -LiteralPath $exe } else { (Get-Command -ErrorAction Stop -Type Application $exe).Path }
  $process = [System.Diagnostics.Process]::Start(
    [System.Diagnostics.ProcessStartInfo] @{
      FileName = $exePath
      Arguments = $args.ForEach({ $a = $_ -replace '(?<!\\)(\\*)"', '$1$1\"'; ($a, "`"$a`"")[$_ -match ' '] }) -join ' '
      UseShellExecute = $false
      RedirectStandardOutput = $true
      RedirectStandardError = $false
    }
  )
  # Relay stdout output to the pipeline line by line (while not redirecting stderr output).
  while (-not $process.StandardOutput.EndOfStream) {
    $process.StandardOutput.ReadLine()
  }
  # Wait for the process to exit...
  $process.WaitForExit()
  # ... and report its exit code.
  $global:LASTEXITCODE = $process.ExitCode
}

相关问题