使用 PowerShell 执行可能位于两个不同位置的文件

Executing a file that may reside at two different locations using PowerShell

我的 $PROFILE 中有一个可爱的小脚本可以帮助我从显示我选择的文件的脚本中启动 Notepad++。

function Edit{
  param([string]$file = " ")
  Start-Process "C:\Program Files\Notepad++\notepad++.exe" -ArgumentList $file
}

直到最近,它一直运行良好,我在不同系统之间跳转。我发现 NPP 在某些系统上安装在 C:\Program Files 中,但在其他系统上安装在 C:\Program Files (x86) 中。我可以编辑脚本来适应它,但是这样做了无数次(即到目前为止 5 次),我厌倦了它,意识到我必须自动化这种疯狂。

对脚本知之甚少,我想知道我应该 Google 做什么。最佳实践是否规定使用 exception handling in such a case or is it more appropriate to go for

根据Get-Host | Select-对象版本 我是运行 5.1 版本,如果它有任何意义的话。也许有一种我不知道的更简洁的方法?依赖环境变量?我也宁愿不使用在 PS 的旧版本中有效的方法,尽管可以工作,如果在以后的版本中有更方便的方法。 (根据我在这方面的经验,我分不清鸭子和鹅。)

我会为此使用条件句。 如果您确定路径位于特定位置,一种选择是直接测试路径。

硬编码路径:

function Edit{
  param([string]$file = " ")

bit = "C:\Program Files (x86)\Notepad++\notepad++.exe"
bit = "C:\Program Files\Notepad++\notepad++.exe"

if (Test-Path bit) {Start-Process -FilePath bit -ArgumentList $file}
elseif (Test-Path bit) {Start-Process -FilePath bit -ArgumentList $file}
else {Write-Error -Exception "NotePad++ not found."}
}

另一个选项是从注册表项中提取路径信息,如果它们可用的话:

function Edit{
  param([string]$file = " ")

bit = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Notepad++\' -ErrorAction SilentlyContinue).("(default)")
bit = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\WOW6432Node\Notepad++\' -ErrorAction SilentlyContinue).("(default)")

if (bit) {Start-Process -FilePath "bit\notepad++.exe" -ArgumentList $file}
elseif (bit) {Start-Process -FilePath "bit\notepad++.exe" -ArgumentList $file}
else {Write-Error -Exception "NotePad++ not found."}
}

基于@BoogaRoo 的大力帮助(他应该得到一些 +1 的努力)并被问到 post 我自己的答案版本,我反对 post 由于强烈的粘性感回答了自己的问题。

我的最终版本,考虑到缺少 NP++ 但仍希望显示一些 种类的编辑器。

function Edit{
  param([string]$file = " ")

  $executable = "Notepad++\notepad++.exe"
  bit = "C:\Program Files (x86)\" + $executable
  bit = "C:\Program Files\" + $executable
  $target = "notepad"

  if(Test-Path bit) { $target = bit }
  if(Test-Path bit) { $target = bit }

  Start-Process $target -ArgumentList $file
}

我提供一个精简版,也支持传递多个文件:

function Edit {

  param(
   # Allow passing multiple files, both with explicit array syntax (`,`-separated)
   # or as indiv. arguments.
   [Parameter(ValueFromRemainingArguments)]
   [string[]] $File
  )

  # Construct the potential Notepad++ paths.
  # Note: `-replace '$'` is a trick to append a string to each element
  #       of an array.
  $exePaths = $env:ProgramFiles, ${env:ProgramFiles(x86)} -replace '$', '\Notepad++\notepad++.exe'

  # See which one, if any, exists, using Get-Command.
  $exeToUse = Get-Command -ErrorAction Ignore $exePaths | Select-Object -First 1

  # Fall back to Notepad.
  if (-not $exeToUse) { $exeToUse = 'notepad.exe' }

  # Invoke whatever editor was found with the optional file(s).
  # Note that both Notepad++ and NotePad can be invoked directly
  # without blocking subsequent commands, so there is no need for `Start-Process`,
  # whose argument processing is buggy.
  & $exeToUse $File

}
  • 一个数组潜在的可执行文件路径被传递给Get-Command,其中returns每个实际可执行文件的命令信息对象找到了,如果有的话。

    • -ErrorAction Ignore 安静地忽略任何错误。

    • Select-Object -First 1Get-Command 输出中提取 first 命令信息对象(如果存在);这是必要的,以防止可执行文件存在于两个位置的情况(可能不太可能)。

  • 如果 Get-Command 没有输出,
  • $exeToUse 接收 $null(有效),在这种情况下,布尔表达式 -not $exeToUse 的计算结果为 $true,导致回退到 notepad.exe 生效。

  • 命令名称(字符串)和命令信息对象System.Management.Automation.CommandInfo or derived classes, as returned by Get-Command) can be executed via &, the call operator 的实例)。