Complete PowerShell Setup Guide for Windows
A comprehensive guide to setting up a beautiful, functional PowerShell environment with Oh My Posh, Nerd Fonts, aliases, auto-completion, and VS Code integration.
Table of Contents
- Prerequisites
- Installing Oh My Posh
- Installing Nerd Fonts
- Configuring Windows Terminal
- Setting Up PowerShell Profile
- Installing Essential Modules
- Configuring Auto-Completion and IntelliSense
- Setting Up Aliases
- Creating Custom Oh My Posh Theme
- VS Code Configuration
- Additional Tools
Prerequisites
- Windows 10/11 (comes with Windows Terminal and PowerShell pre-installed)
Upgrade PowerShell to the latest version (recommended):
winget upgrade Microsoft.PowerShell
Installing Oh My Posh
Oh My Posh is a prompt theme engine for PowerShell (similar to Powerlevel10k for Zsh).
# Install via winget (recommended)
winget install JanDeDobbeleer.OhMyPosh --source winget --scope user --force
Alternative installation via PowerShell Gallery:
Install-Module oh-my-posh -Scope CurrentUser -Force
Installing Nerd Fonts
Nerd Fonts include icons and glyphs needed for Oh My Posh themes.
Method 1: Using Oh My Posh (easiest)
# Install JetBrains Mono Nerd Font (recommended)
oh-my-posh font install JetBrainsMono
# Or browse and select from a list
oh-my-posh font install
Recommended Nerd Fonts:
- JetBrainsMono Nerd Font (excellent for coding, great ligatures) ⭐ Recommended
- FiraCode Nerd Font (includes ligatures)
- CascadiaCode Nerd Font (Microsoft's font)
- MesloLGM Nerd Font (most compatible)
Method 2: Manual Installation
- Download from Nerd Fonts
- Extract the ZIP file
- Right-click
.ttfor.otffiles - Select "Install for all users" (important!)
- Restart Windows Terminal
Configuring Windows Terminal
Quick Method (GUI)
- Open Windows Terminal
- Press
Ctrl + ,to open Settings - Go to Profiles → PowerShell
- Scroll to Appearance
- Set Font face to JetBrainsMono Nerd Font
- Set Font size to
11or12 - Click Save
Additional Customization
For more advanced customization options like themes, opacity, acrylic effects, and cursor styles, you can use the GUI settings interface. All appearance settings can be configured through the Settings UI without needing to edit JSON files directly, which is safer and more user-friendly.
For a complete guide on customizing fonts, themes, and terminal appearance, watch this tutorial: Windows Terminal Customization Guide
Setting Up PowerShell Profile
Your PowerShell profile is a script that runs every time you start PowerShell.
Create/Edit your profile:
# Check if profile exists
Test-Path $PROFILE
# Create if it doesn't exist
if (!(Test-Path $PROFILE)) {
New-Item -Path $PROFILE -Type File -Force
}
# Edit profile
notepad $PROFILE
Profile location: Usually at ~\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
Installing Essential Modules
# Install Terminal-Icons (shows file/folder icons)
Install-Module -Name Terminal-Icons -Repository PSGallery -Force
# Install posh-git (enhanced Git integration)
Install-Module posh-git -Scope CurrentUser -Force
# Install PSReadLine (already included in PowerShell 7, but update it)
Install-Module PSReadLine -Force -SkipPublisherCheck
# Install z (directory jumper like autojump/z in bash)
Install-Module -Name z -Force
Configuring Auto-Completion and IntelliSense
Add this to your PowerShell profile ($PROFILE):
# Oh My Posh initialization
oh-my-posh init pwsh --config "$env:POSH_THEMES_PATH\powerlevel10k_rainbow.omp.json" | Invoke-Expression
# Import modules
Import-Module Terminal-Icons
Import-Module posh-git
Import-Module z
# PSReadLine configuration for auto-completion
Set-PSReadLineOption -PredictionSource History
Set-PSReadLineOption -PredictionViewStyle ListView
Set-PSReadLineOption -EditMode Windows
Set-PSReadLineOption -BellStyle None
Set-PSReadLineOption -HistorySearchCursorMovesToEnd
# Tab completion for menu
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
# Accept suggestions
Set-PSReadLineKeyHandler -Key Ctrl+RightArrow -Function AcceptSuggestion
Set-PSReadLineKeyHandler -Key Ctrl+L -Function AcceptNextSuggestionWord
# Switch between inline and list view for predictions
Set-PSReadLineKeyHandler -Key F2 -Function SwitchPredictionView
# Custom colors for auto-complete
Set-PSReadLineOption -Colors @{
InlinePrediction = '#8A8A8A'
Command = 'Yellow'
Parameter = 'Green'
Operator = 'Magenta'
Variable = 'White'
String = 'Cyan'
Number = 'White'
}
Optional: Vi Mode Configuration
If you prefer Vi keybindings:
# Enable Vi mode with custom cursor control
Set-PSReadLineOption -EditMode Vi
Set-PSReadLineOption -ViModeIndicator Script -ViModeChangeHandler {
param($mode)
$ESC = [char]27
if ($mode -eq 'Command') {
# Command mode: steady block cursor
Write-Host -NoNewLine "$ESC[2 q"
} else {
# Insert mode: steady bar cursor
Write-Host -NoNewLine "$ESC[6 q"
}
}
Setting Up Aliases
Add these aliases to your profile for better productivity. Note: We remove PowerShell's built-in aliases to avoid conflicts with our custom commands and git shortcuts.
Aliases Reference Table
Navigation
| Alias | Command | Description |
|---|---|---|
.. |
Set-Location .. |
Go up one directory |
... |
Set-Location ..\.. |
Go up two directories |
File Operations (eza)
| Alias | Command | Description |
|---|---|---|
ls |
eza --icons --git |
List files with icons |
ll |
eza -l --icons |
Long listing with icons |
la |
eza -la --icons |
Long listing including hidden files |
lt |
eza --sort=modified |
List sorted by modification time |
tree |
eza --tree --level=2 |
Tree view (2 levels) |
ltree |
eza -l --tree |
Tree view with details |
Git - Everyday Workflow
| Alias | Command | Description |
|---|---|---|
g |
lazygit |
Launch lazygit TUI |
ga |
git add . |
Stage all changes |
gc |
git commit |
Commit staged changes |
gcm |
git commit -m |
Commit with message |
gp |
git push |
Push to remote |
gpl |
git pull |
Pull from remote |
gst |
git status |
Show working tree status |
gcb |
git checkout -b |
Create and checkout new branch |
gco |
git checkout |
Checkout branch or files |
gb |
git branch |
List or manage branches |
gl |
git log --oneline --graph |
Pretty git log |
gd |
git diff |
Show changes |
Git - Advanced
| Alias | Command | Description |
|---|---|---|
gds |
git diff --staged |
Show staged changes |
gundo |
git reset HEAD~1 |
Undo last commit (keep changes) |
gamend |
git commit --amend |
Amend last commit |
gstash |
git stash |
Stash current changes |
gstashp |
git stash pop |
Apply and remove latest stash |
grebase |
git rebase |
Rebase current branch |
grebasei |
git rebase -i |
Interactive rebase |
gmerged |
Delete merged branches | Clean up merged branches |
gfilelog |
git log --follow -p |
Show file history with diffs |
Utilities
| Alias | Command | Description |
|---|---|---|
which |
Get-Command |
Find command location |
ep |
notepad $PROFILE |
Edit profile |
rp |
. $PROFILE |
Reload profile |
c |
Clear-Host |
Clear screen |
ex |
explorer . |
Open current directory in Explorer |
mkcd |
Create and enter directory | Make directory and cd into it |
Alias Code for Profile
# ============================================
# Navigation
# ============================================
function .. { Set-Location .. }
function ... { Set-Location ..\.. }
# ============================================
# eza (modern ls with icons)
# ============================================
# Remove PowerShell's built-in aliases to avoid conflicts
Remove-Item Alias:ls -Force -ErrorAction SilentlyContinue
Remove-Item Alias:ll -Force -ErrorAction SilentlyContinue
Remove-Item Alias:la -Force -ErrorAction SilentlyContinue
# Shared parameters for consistency
$ezaParams = '--icons', '--git', '--group-directories-first'
function ls { eza @ezaParams @args }
function ll { eza @ezaParams -l --header @args }
function la { eza @ezaParams -la --header @args }
function lt { eza @ezaParams -la --header --sort=modified @args }
function tree { eza @ezaParams --tree --level=2 @args }
function ltree { eza @ezaParams -l --tree --level=2 @args }
# ============================================
# Git Aliases
# ============================================
# Remove PowerShell's built-in git aliases that conflict
Remove-Item Alias:gc -Force -ErrorAction SilentlyContinue
Remove-Item Alias:gcb -Force -ErrorAction SilentlyContinue
Remove-Item Alias:gcm -Force -ErrorAction SilentlyContinue
Remove-Item Alias:gm -Force -ErrorAction SilentlyContinue
Remove-Item Alias:gp -Force -ErrorAction SilentlyContinue
Remove-Item Alias:gl -Force -ErrorAction SilentlyContinue
# Everyday Workflow
function g { lazygit @args } # Requires: winget install jesseduffield.lazygit
function ga { git add . @args }
function gc { git commit @args }
function gcm { git commit -m @args }
function gp { git push @args }
function gpl { git pull @args }
function gst { git status @args }
function gcb { git checkout -b @args }
function gco { git checkout @args }
function gb { git branch @args }
function gl { git log --oneline --graph --decorate @args }
function gd { git diff @args }
# Advanced Operations
function gds { git diff --staged @args }
function gundo { git reset HEAD~1 @args }
function gamend { git commit --amend @args }
function gstash { git stash @args }
function gstashp { git stash pop @args }
function grebase { git rebase @args }
function grebasei { git rebase -i @args }
function gmerged {
git branch --merged |
Select-String -NotMatch "(\*|main|master)" |
ForEach-Object { git branch -d $_.Line.Trim() }
}
function gfilelog {
param($file)
git log --follow -p -- $file
}
# ============================================
# Utilities
# ============================================
function which($command) {
Get-Command -Name $command -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty Path -ErrorAction SilentlyContinue
}
function ep { notepad $PROFILE }
function rp { . $PROFILE }
function c { Clear-Host }
function ex { explorer . }
function mkcd($dir) {
New-Item -ItemType Directory -Path $dir -Force | Out-Null
Set-Location $dir
}
Usage Examples
# Navigation
.. # Go up one directory
... # Go up two directories
# File operations
ls # List files with icons
ll # Detailed list
la # Show hidden files too
tree # Tree view (2 levels deep)
ltree # Tree with file details
# Git everyday workflow
ga # Stage all changes
gcm "fix: bug" # Commit with message
gp # Push to remote
gst # Check status
gl # View commit graph
# Git advanced
gds # View staged changes
gamend # Amend last commit
gstash # Stash changes
grebasei # Interactive rebase
gmerged # Delete merged branches
gfilelog app.js # View file history
# Utilities
which git # Find git executable path
mkcd newfolder # Create and enter "newfolder"
Prerequisites
Make sure to install these tools first:
# Install eza (modern ls)
winget install eza-community.eza
# Install lazygit (for 'g' alias)
winget install jesseduffield.lazygit
Creating Custom Oh My Posh Theme
Browse Available Themes
# View all available themes
cd $env:POSH_THEMES_PATH
ls
# Try a theme temporarily
oh-my-posh init pwsh --config "$env:POSH_THEMES_PATH\atomic.omp.json" | Invoke-Expression
Popular Themes
powerlevel10k_rainbow.omp.json- Colorful, information-richatomic.omp.json- Clean and minimaltokyo.omp.json- Dark theme with Tokyo Night colorsparadox.omp.json- Two-line promptjandedobbeleer.omp.json- Creator's personal theme
Create Custom Theme
- Create theme directory:
New-Item -ItemType Directory -Path "$HOME\.config\oh-my-posh" -Force
- Create custom theme file:
notepad "$HOME\.config\oh-my-posh\custom.omp.json"
- Sample Custom Theme (Two-line with Git and Python):
{
"$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
"version": 2,
"final_space": true,
"console_title_template": "{{ .Shell }} in {{ .Folder }}",
"blocks": [
{
"type": "prompt",
"alignment": "left",
"newline": true,
"segments": [
{
"type": "os",
"style": "diamond",
"leading_diamond": "╭─",
"trailing_diamond": "",
"foreground": "#26C6DA",
"background": "#546E7A",
"template": " {{ if .WSL }}WSL at {{ end }}{{.Icon}} "
},
{
"type": "path",
"style": "powerline",
"powerline_symbol": "",
"foreground": "#E4E4E4",
"background": "#444444",
"properties": {
"style": "full",
"folder_icon": " ",
"folder_separator_icon": " "
},
"template": " {{ .Path }} "
},
{
"type": "git",
"style": "powerline",
"powerline_symbol": "",
"foreground": "#011627",
"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 }}"
],
"template": " {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} {{ .Staging.String }}{{ end }} ",
"properties": {
"branch_icon": " ",
"fetch_status": true,
"fetch_upstream_icon": true
}
},
{
"type": "python",
"style": "powerline",
"powerline_symbol": "",
"foreground": "#011627",
"background": "#FFDE57",
"template": " {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} "
},
{
"type": "time",
"style": "diamond",
"trailing_diamond": " ─╮",
"foreground": "#E4E4E4",
"background": "#40c4ff",
"template": " {{ .CurrentDate | date .Format }} "
}
]
},
{
"type": "prompt",
"alignment": "left",
"newline": true,
"segments": [
{
"type": "text",
"style": "plain",
"foreground": "#E4E4E4",
"template": "╰─"
},
{
"type": "exit",
"style": "plain",
"foreground": "#00ff00",
"foreground_templates": ["{{ if gt .Code 0 }}#ff0000{{ end }}"],
"template": " {{ if gt .Code 0 }}✘{{ else }}✔{{ end }} ",
"properties": {
"always_enabled": true
}
}
]
}
]
}
- Update profile to use custom theme:
oh-my-posh init pwsh --config "$HOME\.config\oh-my-posh\custom.omp.json" | Invoke-Expression
VS Code Configuration
1. Set Default Terminal to PowerShell
Open VS Code settings (Ctrl + ,) and search for "terminal default":
{
"terminal.integrated.defaultProfile.windows": "PowerShell",
"terminal.integrated.profiles.windows": {
"PowerShell": {
"source": "PowerShell",
"icon": "terminal-powershell",
"args": ["-NoLogo"]
}
}
}
2. Configure Font in Integrated Terminal
{
"terminal.integrated.fontFamily": "JetBrainsMono Nerd Font",
"terminal.integrated.fontSize": 11,
"terminal.integrated.lineHeight": 1.2,
"editor.fontFamily": "JetBrainsMono Nerd Font, Consolas, 'Courier New', monospace",
"editor.fontLigatures": true,
"editor.fontSize": 13
}
3. Complete VS Code Settings Example
Create/edit .vscode/settings.json in your workspace:
{
"terminal.integrated.defaultProfile.windows": "PowerShell",
"terminal.integrated.fontFamily": "JetBrainsMono Nerd Font",
"terminal.integrated.fontSize": 11,
"terminal.integrated.cursorBlinking": true,
"terminal.integrated.cursorStyle": "line",
"terminal.integrated.scrollback": 10000,
"editor.fontFamily": "JetBrainsMono Nerd Font, Consolas",
"editor.fontLigatures": true,
"editor.fontSize": 13,
"editor.lineHeight": 20,
"workbench.colorTheme": "Monokai Pro"
}
Additional Tools
Modern CLI Tools to Install
# eza - modern ls replacement with icons
winget install eza-community.eza
# bat - cat with syntax highlighting
winget install sharkdp.bat
# fd - faster find alternative
winget install sharkdp.fd
# ripgrep - faster grep
winget install BurntSushi.ripgrep.MSVC
# fzf - fuzzy finder
winget install fzf
# git-delta - better git diff
winget install dandavison.delta
# zoxide - smarter cd (alternative to z module)
winget install ajeetdsouza.zoxide
Configure Tools in Profile
# Initialize zoxide (if using instead of z module)
Invoke-Expression (& { (zoxide init powershell | Out-String) })
# fzf configuration
Set-PSReadLineKeyHandler -Key Ctrl+r -ScriptBlock {
$command = Get-Content (Get-PSReadLineOption).HistorySavePath |
fzf --height 40% --reverse --border
if ($command) {
[Microsoft.PowerShell.PSConsoleReadLine]::Insert($command)
}
}
Complete Profile Example
For a complete, production-ready PowerShell profile, check out my personal configuration:
View my PowerShell Profile on GitHub
Git Aliases Reference
Everyday Workflow
| Alias | Command | Description |
|---|---|---|
g |
lazygit |
Launch lazygit TUI (requires install) |
ga |
git add . |
Stage all changes |
gc |
git commit |
Commit staged changes |
gcm |
git commit -m |
Commit with message |
gp |
git push |
Push to remote |
gpl |
git pull |
Pull from remote |
gst |
git status |
Show working tree status |
gcb |
git checkout -b |
Create and checkout new branch |
gco |
git checkout |
Checkout branch or files |
gb |
git branch |
List or manage branches |
gl |
git log --oneline --graph |
Show commit history graph |
gd |
git diff |
Show changes |
Advanced Operations
| Alias | Command | Description |
|---|---|---|
gds |
git diff --staged |
Show staged changes |
gundo |
git reset HEAD~1 |
Undo last commit (keep changes) |
gamend |
git commit --amend |
Amend last commit |
gstash |
git stash |
Stash current changes |
gstashp |
git stash pop |
Apply and remove latest stash |
grebase |
git rebase |
Rebase current branch |
grebasei |
git rebase -i |
Interactive rebase |
gmerged |
Delete merged branches | Clean up merged branches |
gfilelog |
git log --follow -p |
Show file history with diffs |
Note: lazygit requires separate installation:
winget install jesseduffield.lazygit
Windows vs Cross-Platform Paths
In PowerShell, you can use either:
$HOME- Cross-platform friendly (works on Windows, Linux, macOS)$env:USERPROFILE- Windows-specific
For maximum compatibility, prefer $HOME in your profile scripts.
Quick Debug Commands
Check Profile Paths
# See all profile paths and details
$PROFILE | Select-Object *
# Check if your profile exists
Test-Path $PROFILE
# See current profile path
$PROFILE
Check Environment Variables
# View all PATH entries (one per line)
$env:PATH -split ';'
# Check important paths
$env:POSH_THEMES_PATH
$env:USERPROFILE
$PSHOME
Check Installed Modules
# See what modules are currently loaded
Get-Module
# See all available modules
Get-Module -ListAvailable
# Check specific module
Get-Module -ListAvailable Terminal-Icons
Find Command Locations
# Find where a command is installed (like 'which' in Linux)
Get-Command oh-my-posh
Get-Command git
Get-Command eza
# Shorter version
gcm oh-my-posh
Check PowerShell Info
# PowerShell version
$PSVersionTable
# Execution policy
Get-ExecutionPolicy
Check Fonts
# Check installed Nerd Fonts
Get-ChildItem "C:\Windows\Fonts" | Where-Object { $_.Name -like "*Nerd*" }
# Check user-installed fonts
Get-ChildItem "$env:LOCALAPPDATA\Microsoft\Windows\Fonts" | Where-Object { $_.Name -like "*Nerd*" }
Check Oh My Posh Themes
# Navigate to themes directory and list all available themes
cd $env:POSH_THEMES_PATH
ls
Troubleshooting
Icons Not Showing
- Check if Nerd Font is installed:
Get-ChildItem "C:\Windows\Fonts" | Where-Object { $_.Name -like "*Nerd*" }
-
Verify Windows Terminal font setting: Open Windows Terminal settings (
Ctrl + ,) and ensure the font is set to a Nerd Font (e.g., "JetBrainsMono Nerd Font") -
Restart Windows Terminal after installing fonts or changing settings
Advanced Features & Cool Tricks
🚀 Ctrl+F: Fuzzy Directory Jump with fzf
Jump to any directory quickly using fuzzy search (like Telescope in Neovim).
Prerequisites:
# Install fd and fzf
winget install sharkdp.fd
winget install fzf
Add to your profile:
# Ctrl+F: Fuzzy find and jump to directory
Set-PSReadLineKeyHandler -Key Ctrl+f -ScriptBlock {
# Customize these directories to search
$searchDirs = @(
"$env:USERPROFILE\Documents",
"$env:USERPROFILE\Downloads",
"$env:USERPROFILE\Desktop",
"$env:USERPROFILE\Projects"
)
# Collect all directories using fd
$allDirs = @()
foreach ($dir in $searchDirs) {
if (Test-Path $dir) {
$foundDirs = fd --type d --hidden --exclude .git --follow . $dir 2>$null
if ($foundDirs) {
$allDirs += $foundDirs
}
}
}
# Use fzf to select directory
if ($allDirs.Count -gt 0) {
$targetDir = $allDirs | fzf --height 40% --reverse --prompt="Jump to: "
if ($targetDir) {
[Microsoft.PowerShell.PSConsoleReadLine]::RevertLine()
[Microsoft.PowerShell.PSConsoleReadLine]::Insert("Set-Location '$targetDir'")
[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
}
}
}
Usage: Press Ctrl+F, type to filter directories, press Enter to jump!
🎨 Enhanced Auto-Completion Colors
Make your auto-completion more colorful and readable.
Set-PSReadLineOption -Colors @{
Command = 'Yellow'
Parameter = 'Green'
Operator = 'Magenta'
Variable = 'White'
String = 'Cyan'
Number = 'White'
Type = 'Gray'
Comment = 'DarkGray'
InlinePrediction = '#8A8A8A'
ListPrediction = 'Yellow'
ListPredictionSelected = 'DarkBlue'
}
🗑️ Better Remove Command with Confirmation
Create a safer rm that asks for confirmation.
function rm {
param(
[Parameter(Mandatory=$true)]
[string]$path,
[switch]$r, # recursive
[switch]$f # force
)
if (-not (Test-Path $path)) {
Write-Host "Path not found: $path" -ForegroundColor Red
return
}
if ($f) {
# Force remove without confirmation
Remove-Item -Path $path -Recurse:$r -Force
Write-Host "Removed: $path" -ForegroundColor Yellow
} else {
# Ask for confirmation
$item = Get-Item $path
$isDir = $item.PSIsContainer
$type = if ($isDir) { "directory" } else { "file" }
Write-Host "Remove $type: " -NoNewline -ForegroundColor Yellow
Write-Host $path -ForegroundColor Cyan
$confirm = Read-Host "Are you sure? (y/n)"
if ($confirm -eq 'y') {
Remove-Item -Path $path -Recurse:$r -Force
Write-Host "Removed!" -ForegroundColor Green
} else {
Write-Host "Cancelled" -ForegroundColor Red
}
}
}
Usage:
rm file.txt # Asks for confirmation
rm folder -r # Remove directory recursively
rm file.txt -f # Force remove without asking
- Oh My Posh Documentation
- Nerd Fonts
- PSReadLine Documentation
- Windows Terminal Documentation
- PowerShell Gallery
Advanced Features Summary
| Feature | Keybinding/Command | Description |
|---|---|---|
| Fuzzy Directory Jump | Ctrl+F |
Jump to any directory with fuzzy search |
| Safe Remove | rm file |
Remove with confirmation |
Resources
- Oh My Posh Documentation
- Nerd Fonts
- PSReadLine Documentation
- Windows Terminal Documentation
- PowerShell Gallery
Enjoy your beautiful, productive PowerShell environment! 🚀