从PowerShell中按名称运行程序(与运行框类似)

时间:2014-10-16 21:29:00

标签: powershell

在Windows中,我们使用Windows Key + R访问运行框。然后我们可以按名称运行程序(例如firefox,snippingtool)。有没有办法按名称从PowerShell运行程序?

> run firefox
> run snippingtool

我已经尝试过Start-Process firefox但它不起作用。

修改

奇怪的是,从PowerShell和Run框中,只需键入notepad即可打开记事本。但是,键入firefoxsnippingtool仅适用于“运行”框,而不适用于PowerShell。

2 个答案:

答案 0 :(得分:3)

运行框使用PATH环境变量,但它也使用一组注册表项。

HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths包含具有某些应用程序名称的子键,每个子键都有一个名为Path的字符串值,其中包含可执行文件的路径。 Powershell和命令提示符不能使用它们。

在Powershell中模拟

$allCommands = Get-Command -CommandType All | Select-Object -ExpandProperty Name

Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths' | Where-Object { $_.Property -icontains 'Path' } | ForEach-Object {
    $executable = $_.Name | Split-Path -Leaf
    $shortName = $executable -creplace '\.[^.]*$',''
    $path = $_ | Get-ItemProperty | Select-Object -ExpandProperty Path
    $fqPath = $path | Join-Path -ChildPath $executable

    if ( ($allCommands -icontains $executable) -or ($allCommands -icontains $shortName) ) {
        Write-Verbose "Skipping $executable and $shortName because a command already exists with that name."
    } else {
        Write-Verbose "Creating aliases for $executable."
        New-Alias -Name $executable -Value $fqPath
        New-Alias -Name $shortName -Value $fqPath
    }
}

此代码段将读取注册表并将所有这些条目添加为别名。它还添加了没有.exe的EXE名称,以便您可以使用短名称。

它会事先检查现有命令,以确保它不会破坏任何现有命令(任何类型)。

修改

我还创建了一个可用于执行任意应用程序的函数,而无需修改整个环境:

function Run-Application {
[CmdletBinding(SupportsShouldProcess=$true)]
param(
    [Parameter(
        Mandatory=$true,
        ValueFromPipeline=$true
    )]
    [ValidateNotNullOrEmpty()]
    [String[]]
    $Name ,

    [Parameter()]
    [Switch]
    $NoExtension
)

    Begin {
        if (!$NoExtension -and $env:PATHEXT) {
            $exts = $env:PATHEXT -csplit ';'
        } else {
            $exts = @()
        }

        $regStub = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths'
    }

    Process {
        :outer 
        foreach($app in $Name) {
            $cmd2run = $app
            if (Get-Command -Name $cmd2run -ErrorAction Ignore) {
                if ($PSCmdlet.ShouldProcess($cmd2run)) {
                    & $cmd2run
                }
                continue :outer
            } elseif ($app -cnotlike '*.*') {
                foreach($ext in $exts) {
                    $cmd2run = "$app$ext"
                    if (Get-Command -Name $cmd2run -ErrorAction Ignore) {
                        if ($PSCmdlet.ShouldProcess($cmd2run)) {
                            & $cmd2run
                        }
                        continue :outer
                    }
                }
            } 
            $thisReg = $regStub | Join-Path -ChildPath $cmd2run
            $regItem = $thisReg | Get-Item -ErrorAction Ignore
            if ($regItem -and $regItem.Property -icontains 'Path') {
                $thisPath = $regItem | Get-ItemProperty | Select-Object -ExpandProperty Path | Join-Path -ChildPath $cmd2run
                if ($PSCmdlet.ShouldProcess($thisPath)) {
                    & $thisPath
                }
                continue :outer
            } elseif ($app -cnotlike '*.*') {
                foreach($ext in $exts) {
                    $cmd2run = "$app$ext"
                    $thisReg = $regStub | Join-Path -ChildPath $cmd2run
                    $regItem = $thisReg | Get-Item -ErrorAction Ignore
                    if ($regItem -and $regItem.Property -icontains 'Path') {
                        $thisPath = $regItem | Get-ItemProperty | Select-Object -ExpandProperty Path | Join-Path -ChildPath $cmd2run
                        if ($PSCmdlet.ShouldProcess($thisPath)) {
                            & $thisPath
                        }
                        continue :outer
                    }                    
                }
            }
        }
    }
}

您可以通过参数或通过管道提供一个或多个名称,包括或不包含扩展名。

如果该值没有扩展名,则使用PATHEXT并尝试每种组合。您也可以使用-NoExtension停用该功能。

我将Run-Application用于动词 - 名词语法,但如果需要,您可以随时将其别名为run

我不确定如果你对其他代码有问题它是否适合你,但它对我来说效果很好,而且我很乐意写它。希望它对您或其他人有所帮助。

编辑2

固定功能,因此它支持-WhatIf

实施例

Run-Application notepad

Run-Application firefox,chrome.exe

'notepad.exe','firefox.exe','snippingtool' | Run-Application -Whatif

Run-Application firefox -NoExtension # Should fail

答案 1 :(得分:3)

正如@briantist在他的回答(+1)中提到的那样:" Run"对话框(probably calls the ShellExecuteEx function)除App Paths环境变量中的路径外,还检查$env:PATH注册表项的子项。

用于模拟" Run"的行为。然而,我会将文件夹添加到$env:PATH,而不是为每个可执行文件创建别名:

$regkey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths'

$appPaths = Get-ChildItem $regkey |
  Get-ItemProperty |
  ? { $_.'(default)' } |
  select -Expand '(default)' |
  Split-Path -Parent |
  % { [Environment]::ExpandEnvironmentVariables($_.TrimStart('"')) } |
  select -Unique

$env:PATH += ';' + ($appPaths -join ';')

通过将此添加到PowerShell profile(例如您的个人资料%UserProfile%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1),您启动的每个PowerShell实例的变量$env:PATH都会使用注册表中的其他路径进行更新。但请注意,通过添加太多文件夹,您可能会遇到length restrictions