loctvl842
;
PowerShellWindowsTerminalOh My PoshDeveloper ToolsProductivityTutorialSetup Guide

Complete PowerShell Setup Guide for Windows

Complete PowerShell Setup Guide for Windows

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

  1. Prerequisites
  2. Installing Oh My Posh
  3. Installing Nerd Fonts
  4. Configuring Windows Terminal
  5. Setting Up PowerShell Profile
  6. Installing Essential Modules
  7. Configuring Auto-Completion and IntelliSense
  8. Setting Up Aliases
  9. Creating Custom Oh My Posh Theme
  10. VS Code Configuration
  11. 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

  1. Download from Nerd Fonts
  2. Extract the ZIP file
  3. Right-click .ttf or .otf files
  4. Select "Install for all users" (important!)
  5. Restart Windows Terminal

Configuring Windows Terminal

Quick Method (GUI)

  1. Open Windows Terminal
  2. Press Ctrl + , to open Settings
  3. Go to ProfilesPowerShell
  4. Scroll to Appearance
  5. Set Font face to JetBrainsMono Nerd Font
  6. Set Font size to 11 or 12
  7. 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

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
  • powerlevel10k_rainbow.omp.json - Colorful, information-rich
  • atomic.omp.json - Clean and minimal
  • tokyo.omp.json - Dark theme with Tokyo Night colors
  • paradox.omp.json - Two-line prompt
  • jandedobbeleer.omp.json - Creator's personal theme

Create Custom Theme

  1. Create theme directory:
New-Item -ItemType Directory -Path "$HOME\.config\oh-my-posh" -Force
  1. Create custom theme file:
notepad "$HOME\.config\oh-my-posh\custom.omp.json"
  1. 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
          }
        }
      ]
    }
  ]
}
  1. 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

  1. Check if Nerd Font is installed:
Get-ChildItem "C:\Windows\Fonts" | Where-Object { $_.Name -like "*Nerd*" }
  1. 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")

  2. 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


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


Enjoy your beautiful, productive PowerShell environment! 🚀