Skip to content

Instantly share code, notes, and snippets.

@rheone
Last active May 11, 2025 19:27
Show Gist options
  • Save rheone/37ce8d64a21b95c0b94911a7c35d58f2 to your computer and use it in GitHub Desktop.
Save rheone/37ce8d64a21b95c0b94911a7c35d58f2 to your computer and use it in GitHub Desktop.
Powershell Profile with customization - Oh My PoSH - Terminal Icons - PSReadLine - Zoxide & themeing

PowerShell Profile with Custom Oh My Posh Theme: rheone

See https://gist.github.com/rheone/37ce8d64a21b95c0b94911a7c35d58f2 for latest version

This Gist contains a personalized PowerShell setup that includes:

  • A custom PowerShell profile script (profile.ps1)
  • A custom Oh My Posh theme (rheone.omp.json)

✨ Features

🎆 rheone.omp.json Theme Highlights

  • Git-aware prompt with dynamic background color reflecting repository status:
  • Technology indicators for: .NET, Node.js, Python, NPM, Angular
  • Execution time tracking
  • Success/Failure status using 👍 / 👎 instead of "human heart"
  • Right-aligned shell name, battery status, and time (local & UTC)
  • Folder path in a visually distinct lower prompt line

🧑‍💻 profile.ps1

This script:

  • Initializes up Terminal Icons, PSReadline, Zoxide, fzf, and oh-my-posh
  • Loads the oh-my-posh theme
  • Configures aliases to navigate to common directories
    • go-home ➡️ go to home
    • go-code ➡️ go to ~home\code -- this is not a standard directory
    • go-desk ➡️ go to desktop
    • go-docs ➡️ go to documents folder
  • Enables some macros
    • Open current directory in Visual Studio Code : Ctrl+Shift+c
    • Open current directory in Explorer (via start) : Ctrl+Shift+e
    • Open current directory's git url in browser : Ctrl+Shift+g
    • Clear Powershell History : Ctrl+Shift+h
    • Reload powershell profile $profile : Ctrl+Shift+F5
  • see source for details...

⏮️ Prerequisites

📖 Recommended Resources

Note: some of the info may be a bit outdated, but will provide a a general approach to the solution

# Powershell Profile
# 2025-05-11
# See <https://gist.github.com/rheone/37ce8d64a21b95c0b94911a7c35d58f2> for latest version
################################################################
# MODULES #
################################################################
# Terminal Icons - A PowerShell module to show file and folder icons in the terminal.
# - <https://github.com/devblackops/Terminal-Icons>
# - requires Nerd Fonts <https://www.nerdfonts.com/>; I like `FiraCode Nerd Font Mono`
if (Get-Module -ListAvailable -Name Terminal-Icons) {
Import-Module -Name Terminal-Icons
Write-Output " ✅ 'Terminal-Icons' present."
}
else {
Write-Warning " 👎 Module 'Terminal-Icons' is not installed."
}
# PSReadLine - Predictive IntelliSense
# - <https://github.com/PowerShell/PSReadLine>
# - <https://www.powershellgallery.com/packages/Terminal-Icons/>
# - <https://www.hanselman.com/blog/adding-predictive-intellisense-to-my-windows-terminal-powershell-prompt-with-psreadline>
if (Get-Module -ListAvailable -Name PSReadLine) {
Import-Module PSReadLine
Set-PSReadLineOption -PredictionSource History
Set-PSReadLineOption -PredictionViewStyle ListView
Set-PSReadLineOption -EditMode Windows
Write-Output " ✅ 'PSReadLine' present."
}
else {
Write-Warning " 👎 Module 'PSReadLine' is not installed."
}
# DockerCompletion - Docker command completion for PowerShell.
# - <https://github.com/matt9ucci/DockerCompletion>
# - <https://www.powershellgallery.com/packages/DockerCompletion/>
if (Get-Module -ListAvailable -Name DockerCompletion) {
Import-Module -Name DockerCompletion
Write-Output " ✅ 'DockerCompletion' present."
}
else {
Write-Warning " 👎 Module 'DockerCompletion' is not installed."
}
# posh-npm-completion - A npm tab completion for PowerShell.
# - <https://github.com/PowerShell-Completion/npm-completion>
# - <https://www.powershellgallery.com/packages/npm-completion/>
if (Get-Module -ListAvailable -Name npm-completion) {
Import-Module -Name npm-completion
Write-Output " ✅ 'npm-completion' present."
}
else {
Write-Warning " 👎 Module 'npm-completion' is not installed."
}
# posh-git - Provides prompt with Git status summary information and tab completion for Git commands, parameters, remotes and branch names.
# - <https://github.com/dahlbyk/posh-git>
# - <https://www.powershellgallery.com/packages/posh-git/>
if (Get-Module -ListAvailable -Name posh-git) {
Import-Module -Name posh-git
Write-Output " ✅ 'posh-git' present."
}
else {
Write-Warning " 👎 Module 'posh-git' is not installed."
}
################################################################
# COMMANDS #
################################################################
# Zoxide - A smarter cd command
# fzf - A command-line fuzzy finder
# - <https://github.com/ajeetdsouza/zoxide>
# - <https://github.com/junegunn/fzf>
if (Get-Command zoxide -ErrorAction SilentlyContinue) {
Invoke-Expression (& { (zoxide init powershell | Out-String) })
Write-Output " ✅ 'zoxide' present."
if (Get-Command fzf -ErrorAction SilentlyContinue) {
Write-Output " ✅ 'fzf' present."
}
else {
Write-Warning " 👎 'fzf' is not installed or not in PATH."
}
}
else {
Write-Warning " 👎 'zoxide' is not installed or not in PATH."
}
# Oh My PoSH
# - <https://www.ohmyposh.dev/>
# - <https://github.com/jandedobbeleer/oh-my-posh>
# - Themes located in `$env:POSH_THEMES_PATH`
# - <https://www.hanselman.com/blog/my-ultimate-powershell-prompt-with-oh-my-posh-and-the-windows-terminal>
if (Get-Command oh-my-posh -ErrorAction SilentlyContinue) {
Write-Output " ✅ 'oh-my-posh' present."
if (Test-Path -Path ~\.oh-my-posh\themes\rheone.omp.json) {
oh-my-posh --init --shell pwsh --config ~\.oh-my-posh\themes\rheone.omp.json | Invoke-Expression
}
else {
Write-Warning " 👎 failed to find custom oh-my-posh theme; using default."
oh-my-posh --init --shell pwsh | Invoke-Expression
}
}
else {
Write-Warning " 👎 Module 'oh-my-posh' is not installed."
}
################################################################
# Functions #
################################################################
# see <https://learn.microsoft.com/en-us/dotnet/api/system.environment.specialfolder?view=net-9.0> for special paths
function GoToHomeDirectory {
Set-Location $([System.Environment]::GetFolderPath('UserProfile'))
}
function GoToCodeDirectory {
Set-Location (Join-Path ([System.Environment]::GetFolderPath('UserProfile')) 'code')
}
function GoToDirectoryDesktop {
Set-Location $([System.Environment]::GetFolderPath('Desktop'))
}
function GoToDirectoryDocuments {
Set-Location $([System.Environment]::GetFolderPath('Personal'))
}
################################################################
# Argument Completers #
################################################################
# PowerShell parameter completion shim for the dotnet CLI
# <https://www.hanselman.com/blog/how-to-use-autocomplete-at-the-command-line-for-dotnet-git-winget-and-more>
Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock {
param($commandName, $wordToComplete, $cursorPosition)
dotnet complete --position $cursorPosition "$wordToComplete" | ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
}
# winget parameter completion
# <https://gist.github.com/shanselman/25f5550ad186189e0e68916c6d7f44c3>
Register-ArgumentCompleter -Native -CommandName winget -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)
[Console]::InputEncoding = [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new()
$Local:word = $wordToComplete.Replace('"', '""')
$Local:ast = $commandAst.ToString().Replace('"', '""')
winget complete --word="$Local:word" --commandline "$Local:ast" --position $cursorPosition | ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
}
}
################################################################
# Aliases #
################################################################
Set-Alias -Name go-home -Value GoToHomeDirectory # goto home directory
Set-Alias -Name go-code -Value GoToCodeDirectory # goto code directory
Set-Alias -Name go-desk -Value GoToDirectoryDesktop # goto desktop directory
Set-Alias -Name go-docs -Value GoToDirectoryDocuments #goto documents directory
Set-Alias -Name vscode -Value code #ope vs code with 'code'
################################################################
# MACROS #
################################################################
# MACRO: Open Current Directory in Visual Studio Code `Ctrl+Shift+c`
Set-PSReadLineKeyHandler -Key Ctrl+Shift+c `
-BriefDescription OpenCurrentDirectoryInVsCode `
-LongDescription "Open Current Directory in Visual Studio Code" `
-ScriptBlock {
[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
[Microsoft.PowerShell.PSConsoleReadLine]::Insert("code .")
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
Write-Host "Opening in Visual Studio Code..." -ForegroundColor Green
}
# MACRO: Open Current Directory in Explorer `Ctrl+Shift+e`
Set-PSReadLineKeyHandler -Key Ctrl+Shift+e `
-BriefDescription OpenCurrentDirectoryInVsExplorer `
-LongDescription "Open Current Directory in Explorer" `
-ScriptBlock {
[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
[Microsoft.PowerShell.PSConsoleReadLine]::Insert("start .")
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
Write-Host "Opening in Explorer..." -ForegroundColor Green
}
# MACRO: Clear History `Ctrl+Shift+h`
Set-PSReadLineKeyHandler -Key Ctrl+Shift+h `
-BriefDescription ClearHistory `
-LongDescription "Clear History" `
-ScriptBlock {
[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
[Microsoft.PowerShell.PSConsoleReadLine]::Insert("Clear-Content (Get-PSReadlineOption).HistorySavePath")
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
Write-Host "History cleared." -ForegroundColor Green
}
# MACRO: Reload profile `Ctrl+Shift+F5`
Set-PSReadLineKeyHandler -Key Ctrl+Shift+F5 `
-BriefDescription ReloadPowershellProfile `
-LongDescription "Reload Powershell Profile" `
-ScriptBlock {
. $PROFILE
[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
Write-Host "PowerShell profile reloaded." -ForegroundColor Green
}
# MACRO: Follow Git URL `Ctrl+Shift+g`
Set-PSReadLineKeyHandler -Key Ctrl+Shift+g `
-BriefDescription OpenGitUrlInBrowser `
-LongDescription "Open Git URL In Browser" `
-ScriptBlock {
[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
try {
$gitUrl = git config --get remote.origin.url 2>$null
if (-not $gitUrl) {
Write-Host "No Git remote URL found in this directory." -ForegroundColor Red
return
}
# Convert SSH URL to HTTPS if needed
if ($gitUrl -match '^git@([^:]+):(.+?)(\.git)?$') {
$domain = $matches[1]
$path = $matches[2]
$gitUrl = "https://$domain/$path"
}
# Ensure it looks like a URL
if ($gitUrl -match '^(https?://[^\s]+)$') {
Write-Host "Opening Git URL: $gitUrl" -ForegroundColor Green
Start-Process $gitUrl
}
else {
Write-Host "Unrecognized or unsupported Git remote URL: $gitUrl" -ForegroundColor Red
}
}
catch {
Write-Host "Failed to open Git URL: $_" -ForegroundColor Red
}
}
// based loosely on the `JanDeDobbeleer.omp.json` theme
// 2025-05-11
// see <https://gist.github.com/rheone/37ce8d64a21b95c0b94911a7c35d58f2> for latest version
{
"$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
"blocks": [
{
"alignment": "left",
"type": "prompt",
"segments": [
{
"background": "#c386f1",
"foreground": "#ffffff",
"leading_diamond": "\ue0b6",
"style": "diamond",
"template": " {{ .UserName }} ",
"trailing_diamond": "\ue0b0",
"type": "session"
},
{
"background": "#ffff66",
"foreground": "#111111",
"powerline_symbol": "\ue0b0",
"style": "powerline",
"template": " \uf0ad ",
"type": "root"
},
{
"background": "#fffb38",
"background_templates": [
"{{ if or (.Working.Changed) (.Staging.Changed) }}#FF9248{{ end }}",
"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#ff4500{{ end }}",
"{{ if gt .Ahead 0 }}#B388FF{{ end }}",
"{{ if gt .Behind 0 }}#B388FF{{ end }}"
],
"foreground": "#193549",
"leading_diamond": "\ue0b6",
"powerline_symbol": "\ue0b0",
"properties": {
"branch_max_length": 25,
"fetch_stash_count": true,
"fetch_status": true,
"fetch_upstream_icon": true
},
"style": "powerline",
"template": " {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \ueb4b {{ .StashCount }}{{ end }} ",
"trailing_diamond": "\ue0b4",
"type": "git"
},
{
"background": "#ffeb3b",
"foreground": "#193549",
"leading_powerline_symbol": "\ue0b6",
"powerline_symbol": "\ue0b0",
"style": "powerline",
"template": " {{ if .Error }}{{ .Error }}{{ else }}{{ if .Version }}\ueb29 {{.Version}}{{ end }} {{ if .Name }}{{ .Name }}{{ end }}{{ end }} ",
"type": "project"
},
{
"background": "#6CA35E",
"foreground": "#ffffff",
"powerline_symbol": "\ue0b0",
"properties": {
"fetch_version": true
},
"style": "powerline",
"template": " \ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} ",
"type": "node"
},
{
"background": "#FFDE57",
"foreground": "#111111",
"powerline_symbol": "\ue0b0",
"properties": {
"display_mode": "files",
"fetch_virtual_env": false
},
"style": "powerline",
"template": " \ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} ",
"type": "python"
},
{
// Custom .NET
"background": "#4122aa",
"foreground": "#ffffff",
"powerline_symbol": "\ue0c0",
"style": "powerline",
"template": " \udb82\udeae {{ .Full }} ",
"type": "dotnet"
},
{
// Custom NPM
"background": "#ffeb3b",
"foreground": "#193549",
"powerline_symbol": "\ue0c0",
"style": "powerline",
"template": " {{ .Full }} ",
"type": "npm"
},
{
// Custom angular
"background": "#1976d2",
"foreground": "#000000",
"powerline_symbol": "\ue0c0",
"style": "powerline",
"template": " \ue71c {{ .Full }} ",
"type": "angular"
},
{
// Custom status block that shows thumbs up/down rather than heart
"background": "#00897b",
"background_templates": [
"{{ if gt .Code 0 }}#e91e63{{ else }}#00897b{{ end }}"
],
"foreground": "#ffffff",
"properties": {
"always_enabled": true
},
"style": "diamond",
"template": "{{ if gt .Code 0 }}👎{{ else }}👍{{ end }}",
"trailing_diamond": "\ue0b4",
"type": "status"
}
]
},
{
"alignment": "right",
"type": "prompt",
"segments": [
{
"background": "#0077c2",
"foreground": "#ffffff",
"style": "diamond",
"trailing_diamond": "\ue0c6",
"leading_diamond": "\ue0c7",
"template": " \udb81\udfb7 {{ .Name }} ",
"type": "shell"
},
{
"background": "#f36943",
"background_templates": [
"{{if eq \"Charging\" .State.String}}#40c4ff{{end}}",
"{{if eq \"Discharging\" .State.String}}#ff5722{{end}}",
"{{if eq \"Full\" .State.String}}#4caf50{{end}}"
],
"foreground": "#ffffff",
"invert_powerline": true,
"powerline_symbol": "\ue0b2",
"properties": {
"charged_icon": "\ue22f ",
"charging_icon": "\ue234 ",
"discharging_icon": "\ue231 "
},
"style": "powerline",
"template": " {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\uf295 ",
"type": "battery"
},
{
"background": "#83769c",
"foreground": "#ffffff",
"properties": {
"always_enabled": true
},
"style": "diamond",
"trailing_diamond": "\ue0b4",
"leading_diamond": "\ue0b6",
"template": "⌛{{ .FormattedMs }}",
"type": "executiontime"
},
{
// Local Time
"background": "#2e9599",
"foreground": "#111111",
"invert_powerline": true,
"style": "diamond",
"trailing_diamond": "\ue0b4",
"leading_diamond": "\ue0b6",
// silly unnecessary show a clock face appropriate for the hour
"template": "{{ if eq (.CurrentDate | date \"3\") \"1\" }}🕐{{ else if eq (.CurrentDate | date \"3\") \"2\" }}🕑{{ else if eq (.CurrentDate | date \"3\") \"3\" }}🕒{{ else if eq (.CurrentDate | date \"3\") \"4\" }}🕓{{ else if eq (.CurrentDate | date \"3\") \"5\" }}🕔{{ else if eq (.CurrentDate | date \"3\") \"6\" }}🕕{{ else if eq (.CurrentDate | date \"3\") \"7\" }}🕖{{ else if eq (.CurrentDate | date \"3\") \"8\" }}🕗{{ else if eq (.CurrentDate | date \"3\") \"9\" }}🕘{{ else if eq (.CurrentDate | date \"3\") \"10\" }}🕙{{ else if eq (.CurrentDate | date \"3\") \"11\" }}🕚{{ else }}🕛{{ end }}{{ .CurrentDate | date \"03:04pm\" }}",
"type": "time"
},
{
// UTC DateTime
"background": "#2e9599",
"foreground": "#111111",
"invert_powerline": true,
"style": "diamond",
"trailing_diamond": "\ue0b4",
"leading_diamond": "\ue0b6",
"template": "🌎{{ dateInZone \"2006-01-02T15:04:05Z07:00\" .CurrentDate \"UTC\" }}",
"type": "time"
}
]
},
{
"alignment": "left",
"newline": true,
"segments": [
{
"background": "#ff479c",
"foreground": "#ffffff",
"powerline_symbol": "\ue0b0",
"properties": {
"folder_separator_icon": "\ue216",
"home_icon": "\udb81\udf25",
"style": "full"
},
"style": "powerline",
"template": " \uea83 {{ .Path }} ",
"type": "path"
}
],
"type": "prompt"
}
],
"console_title_template": "{{ .Shell }} in {{ .Folder }}",
"final_space": true,
"version": 3
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment