App, Utility and Function Launcher for PowerShell.
PowerShellRun is a PowerShell module that lets you fuzzy search applications, utilities and functions you define and launch them with ease. It is a customizable launcher app on the PowerShell terminal.
Install-Module -Name PowerShellRun -Scope CurrentUser
- Windows or macOS
- PowerShell 7.2 or newer
Enable-PSRunEntry -Category All
Invoke-PSRun
This code enables entries of all categories and opens up this TUI:
Type characters to search entries and hit Enter
to launch the selected item. There are some other actions that can be performed depending on the item. Hit Ctrl+k
to open the Action Window and see what actions are available.
You can assign a shortcut key to quickly launch PowerShellRun.
Set-PSRunPSReadLineKeyHandler -InvokePsRunChord 'Ctrl+j'
There are some entry categories that you can selectively enable by passing an array of the category names to Enable-PSRunEntry
.
Enable-PSRunEntry -Category Function, Favorite
Installed applications are listed by the Application
category. You can launch (or launch as admin on Windows) the application by pressing the action key.
Executable files under the PATH are listed by Executable
category. You can invoke them on the same console where PowerShellRun is running.
File Manager (PSRun)
navigates the folder hierarchy from the current directory using the PowerShellRun TUI.
On the file entries, there is an action described as "Edit with Default Editor"
. You can customize the script for this action like below:
Set-PSRunDefaultEditorScript -ScriptBlock {
param ($path)
& code $path
}
WinGet (PSRun)
helps you install, upgrade and uninstall applications using winget. You need winget and Microsoft.WinGet.Client module installed to use this utility entry.
You can register folders or files that you frequently access. The available actions are the same as the ones in File Manager (PSRun)
.
Add-PSRunFavoriteFolder -Path 'D:/PowerShellRun'
Add-PSRunFavoriteFile -Path 'D:/PowerShellRun/README.md' -Icon '📖' -Preview @"
-------------------------------
💖 This is a custom preview 💖
-------------------------------
"@
The ability to call PowerShell functions is what makes PowerShellRun special. The functions defined between Start-PSRunFunctionRegistration
and Stop-PSRunFunctionRegistration
are registered as entries. The scope of the functions needs to be global so that PowerShellRun can call them.
Start-PSRunFunctionRegistration
#.SYNOPSIS
# git pull with rebase option.
function global:GitPullRebase() {
git pull --rebase
}
# ... Define functions here as many as you want.
Stop-PSRunFunctionRegistration
SYNOPSIS
or DESCRIPTION
in the comment based help is used as a description of the entry. You can also optionally specify parameters using the COMPONENT
. It uses ConvertFrom-StringData to extract the parameters.
<#
.SYNOPSIS
git pull with rebase option.
.COMPONENT
PSRun(
Icon = 🌿
Preview = This is a custom preview.\nNew lines need to be written like this.)
#>
function global:GitPullRebase() {
git pull --rebase
}
It's even possible to open PowerShellRun's TUI inside a registered function entry using the commands described in the following section. To create a pseudo nested menu, we recommend that you use Restore-PSRunParentSelector
command to restore the parent menu with Backspace
key. File Manager (PSRun)
is a good example of the nested menu.
function global:OpenNestedMenu() {
$option = Get-PSRunDefaultSelectorOption
$option.QuitWithBackspaceOnEmptyQuery = $true
$result = Get-ChildItem | ForEach-Object {
$entry = [PowerShellRun.SelectorEntry]::new()
$entry.UserData = $_
$entry.Name = $_.Name
$entry
} | Invoke-PSRunSelectorCustom -Option $option
if ($result.KeyCombination -eq 'Backspace') {
Restore-PSRunParentSelector
return
}
# ... Other key handlings here
}
If you don't want to use the global scope to define function entries, you can use script entries. Add-PSRunScriptBlock
adds a ScriptBlock and Add-PSRunScriptFile
adds a .ps1
file as an entry. They are invoked by pressing Enter
.
Add-PSRunScriptBlock -Name 'Test ScriptBlock' -ScriptBlock {
'This is a test ScriptBlock'
}
Add-PSRunScriptFile -Path 'D:\PowerShellRun\tests\TestScriptFile.ps1' -Icon '💎'
History search functionality is provided outside the PowerShellRun menu using PSReadLineKeyHandler. It searches PSReadLine history. Multi-line entries are also supported. You can enable it with the following command:
Set-PSRunPSReadLineKeyHandler -PSReadLineHistoryChord 'Ctrl+r'
You can customize PowerShellRun's behavior and themes through options. Create a SelectorOption
instance and pass it to Set-PSRunDefaultSelectorOption
.
$option = [PowerShellRun.SelectorOption]::new()
$option.Prompt = 'Type words👉 '
$option.QuitWithBackspaceOnEmptyQuery = $true
Set-PSRunDefaultSelectorOption $option
Invoke-PSRun
The option you set as default can be returned by Get-PSRunDefaultSelectorOption
. Note that the returned option is always deep cloned. It is useful when you create a nested menu.
$option = Get-PSRunDefaultSelectorOption
$option.Prompt = 'Nested menu prompt > '
$option.QuitWithBackspaceOnEmptyQuery = $true
'a', 'b' | Invoke-PSRunSelector -Option $option
Key bindings are stored in $option.KeyBinding
. You can set a string of KeyModifier
and Key
concatenated with +
to the key.
$keyBinding = $option.KeyBinding
$keyBinding.QuitKeys = @(
'Escape'
'Ctrl+j'
)
$keyBinding.MarkerKeys = 'Ctrl+f'
There are two key binding modes, Normal Mode
and Key Remap Mode
. You can toggle the remap mode by pressing RemapModeEnterKeys
and RemapModeExitKeys
. In Key Remap mode, the keys you specify are remapped to other keys. This is useful if you'd like to achieve something like Vim Normal mode and Insert mode. Vim style hjkl
navigation is set up like this:
$theme.KeyRemapModeConsoleCursorShape = 'BlinkingBlock'
$keyBinding.InitialRemapMode = $true
$keyBinding.EnableTextInputInRemapMode = $false
$keyBinding.RemapModeEnterKeys = 'Escape'
$keyBinding.RemapModeExitKeys = 'i'
$keyBinding.RemapKeys = @(
[PowerShellRun.RemapKey]::new('h', 'LeftArrow')
[PowerShellRun.RemapKey]::new('j', 'DownArrow')
[PowerShellRun.RemapKey]::new('k', 'UpArrow')
[PowerShellRun.RemapKey]::new('l', 'RightArrow')
[PowerShellRun.RemapKey]::new('Shift+j', 'Shift+DownArrow')
[PowerShellRun.RemapKey]::new('Shift+k', 'Shift+UpArrow')
)
It starts in Key Remap mode, and hjkl
keys are remapped to arrow keys. i
key enables typing, and you can go back to the hjkl
navigation by Escape
key.
The theme can be customized with $option.Theme
property. We hope someone creates a cool theme library for PowerShellRun🙏.
$default = [PowerShellRun.FontColor]::FromHex('#CBCCC6')
$gray = [PowerShellRun.FontColor]::FromHex('#707070')
$highlight = [PowerShellRun.FontColor]::FromHex('#61FFCA')
$focusHighlight = [PowerShellRun.FontColor]::FromHex('#4CBF99')
$roundBorder = [PowerShellRun.BorderSymbol]::new()
$roundBorder.TopLeft = '╭'
$roundBorder.TopRight = '╮'
$roundBorder.BottomLeft = '╰'
$roundBorder.BottomRight = '╯'
$option.Prompt = ' '
$theme = $option.Theme
$theme.CanvasHeightPercentage = 80
$theme.Cursor = '▸ '
$theme.IconEnable = $false
$theme.PreviewPosition = [PowerShellRun.PreviewPosition]::Right
$theme.CanvasBorderFlags = [PowerShellRun.BorderFlag]::All
$theme.SearchBarBorderFlags = [PowerShellRun.BorderFlag]::None
$theme.CanvasBorderSymbol = $roundBorder
$theme.PreviewBorderSymbol = $roundBorder
$theme.DefaultForegroundColor = $default
$theme.CanvasBorderForegroundColor = $gray
$theme.PromptForegroundColor = $gray
$theme.PreviewBorderForegroundColor = $gray
$theme.EntryScrollBarForegroundColor = $gray
$theme.PreviewScrollBarForegroundColor = $gray
$theme.CursorForegroundColor = $highlight
$theme.NameHighlightForegroundColor = $highlight
$theme.DescriptionHighlightForegroundColor = $highlight
$theme.NameFocusHighlightBackgroundColor = $focusHighlight
$theme.DescriptionFocusHighlightBackgroundColor = $focusHighlight
The underlying fuzzy selector in PowerShellRun is accessible with the following commands.
Invoke-PSRunSelector
is designed to be used interactively on the terminal. It takes an array of objects and returns objects. It uses Name
, Description
and Preview
properties of the object by default but you can change them with parameters like -NameProperty
, -DescriptionProperty
and -PreviewProperty
.
Get-ChildItem | Invoke-PSRunSelector -DescriptionProperty FullName -MultiSelection
-Expression
parameter is useful if you need to build custom strings.
Get-ChildItem | Invoke-PSRunSelector -Expression {@{
Name = $_.Name
Preview = Get-Item $_ | Out-String
}}
Invoke-PSRunSelectorCustom
offers you a full access to the selector and is designed to create your own tool. It takes an array of SelectorEntry
instances and returns a SelectorResult
object. A SelectorResult
object holds information such as the selected entry and the pressed key.
PS> Get-ChildItem | ForEach-Object {
$entry = [PowerShellRun.SelectorEntry]::new()
$entry.UserData = $_
$entry.Name = $_.Name
$entry.Preview = $_.FullName
$entry
} | Invoke-PSRunSelectorCustom
FocusedEntry MarkedEntries KeyCombination Context
------------ ------------- -------------- -------
PowerShellRun.SelectorEntry Enter PowerShellRun.SelectorContext
By using PreviewAsyncScript
, it's even possible to show information that takes some time to generate without blocking the UI. If you have bat installed for syntax highlighting, you can build a Select-String viewer with this script:
$word = Read-Host 'Type word to search for'
$filter = Read-Host 'Type path filter (e.g. "*.cs")'
$option = [PowerShellRun.SelectorOption]::new()
$option.Prompt = "Searching for word '{0}'> " -f $word
$matchLines = Get-ChildItem $filter -Recurse | Select-String $word
$result = $matchLines | ForEach-Object {
$entry = [PowerShellRun.SelectorEntry]::new()
$entry.UserData = $_
$entry.Name = '{0}:{1}' -f $_.Filename, $_.LineNumber
$entry.Description = $_.Path
$entry.PreviewAsyncScript = {
param($match)
& bat --color=always --highlight-line $match.LineNumber $match.Path
}
$entry.PreviewAsyncScriptArgumentList = $_
$entry.PreviewInitialVerticalScroll = $_.LineNumber
$entry
} | Invoke-PSRunSelectorCustom -Option $option
$match = $result.FocusedEntry.UserData
if ($match -and ($result.KeyCombination -eq 'Enter')) {
$argument = '{0}:{1}' -f $match.Path, $match.LineNumber
code --goto $argument
}
You can set Regex pattern to NameSearchablePattern
and DescriptionSearchablePattern
properties to define which parts of a string are hit by query.
# 'bbb' and 'eee' are searchable.
$pattern = [Regex]::new('(?<=^\S*\s).*?(?=\s|$)')
'aaa bbb ccc', 'ddd eee fff' | ForEach-Object {
$entry = [PowerShellRun.SelectorEntry]::new()
$entry.Name = $_
$entry.NameSearchablePattern = $pattern
$entry
} | Invoke-PSRunSelectorCustom
# 'bbb', 'ccc' and 'ddd' are searchable.
$pattern = [Regex]::new('(?<=\[).*?(?=\])')
'aaa [bbb] [ccc]', '[ddd] eee fff' | ForEach-Object {
$entry = [PowerShellRun.SelectorEntry]::new()
$entry.Name = $_
$entry.NameSearchablePattern = $pattern
$entry
} | Invoke-PSRunSelectorCustom
Invoke-PSRunPrompt
can be used to get user input in the same style as Invoke-PSRunSelectorCustom
but without any entries. It reflects SelectorOption
and returns the input, KeyCombination
and the context. WinGet (PSRun)
is a practical example.
Invoke-PSRunPrompt
Input KeyCombination Context
----- -------------- -------
hello Enter PowerShellRun.PromptContext
- No history support
- Some emojis break the rendering
Changelog is available here.
Please read our Code of Conduct to foster a welcoming environment. By participating in this project, you are expected to uphold this code.
Please come to our Discussions page and avoid filing an issue to ask a question.
Please see our Contribution Guidelines.
PowerShellRun uses:
Heavily inspired by: