Skip to main content

Setting Up a Modern Windows PowerShell Environment

·1485 words·7 mins
Thorsten Lenzen
Author
Thorsten Lenzen
Coding, Devops and Homelab maniac…

While Windows has come a long way with PowerShell, the default terminal experience can still feel dated compared to modern CLI setups. The good news? You can bring the same productivity-boosting tools that Linux users enjoy to your Windows environment.

In this guide, I’ll show you how to transform your PowerShell into a modern, efficient development environment using tools like fuzzy finding, syntax highlighting, and smart navigation—all native to Windows, no WSL required.

Table of Contents
#

  1. Prerequisites: Package Managers
  2. Fuzzy Finding with fzf, fd, and bat
  3. Smart Navigation with zoxide
  4. Better Directory Listings with eza
  5. Putting It All Together

Prerequisites: Package Managers
#

Before we begin, you’ll need either Chocolatey or winget installed. These are package managers for Windows that make installing and updating software much easier.

Chocolatey
#

If you don’t have Chocolatey yet, install it from chocolatey.org by running this in an elevated PowerShell:

Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

winget
#

Windows 11 comes with winget pre-installed. For Windows 10, you can install it from the Microsoft Store by installing “App Installer.”

Fuzzy Finding with fzf, fd, and bat
#

What Are These Tools?
#

If you’ve used a modern code editor, you’re familiar with fuzzy finding—type a few characters and instantly filter through thousands of files. These three tools bring that power to your command line:

  • fzf: The fuzzy finder itself—a fast, interactive filter for any list
  • fd: A modern, user-friendly alternative to the find command
  • bat: A cat clone with syntax highlighting and Git integration

Together, they create a powerful search experience with beautiful previews.

Installation
#

Install all three tools using Chocolatey:

choco install fzf
choco install fd
choco install bat

PowerShell Integration
#

To make fzf work seamlessly with PowerShell, you need the PSFzf module:

Install-Module -Name PSFzf -Scope CurrentUser -Force

Configuring Your PowerShell Profile
#

Your PowerShell profile is like the .bashrc or .zshrc on Linux—it runs every time you start a new PowerShell session. Let’s configure it to integrate these tools.

First, open your PowerShell profile (it will create it if it doesn’t exist):

notepad $PROFILE

Add the following configuration:

# Import necessary modules
Import-Module PSReadLine
Import-Module PSFzf

# Manually bind Ctrl+t to the Search-Files function
Set-PSReadLineKeyHandler -Chord 'Ctrl+t' -ScriptBlock {
    Search-Files
}

# Bind Ctrl+r for reverse command history with fzf
Set-PSReadLineKeyHandler -Chord 'Ctrl+r' -ScriptBlock {
    $selectedCommand = Get-History | Sort-Object -Property Id -Descending | ForEach-Object { "$($_.Id)  $($_.CommandLine)" } |
                        fzf --height=40% --reverse --prompt "History> " |
                        ForEach-Object { ($_ -split '\s{2,}', 2)[1] } # Extract the command

    if ($selectedCommand) {
        [Microsoft.PowerShell.PSConsoleReadLine]::Insert($selectedCommand)
    }
}

# Define the Search-Files function
function Search-Files {
    fd --type file --hidden --exclude .git | fzf --prompt "Files> " --preview "bat --style=numbers --color=always --line-range :500 {}"
}

This configuration does three important things:

  1. Ctrl+T: Opens a fuzzy file finder with syntax-highlighted previews
  2. Ctrl+R: Searches through your command history interactively
  3. Search-Files function: Combines fd for finding files and bat for previewing them

Save the file and restart PowerShell (or run . $PROFILE to reload it).

Customizing bat with Themes
#

By default, bat looks great, but you can customize it with themes. The Tokyo Night theme is particularly popular.

Create the themes directory if it doesn’t exist:

mkdir C:\Users\thors\AppData\Roaming\bat\themes

Download your preferred theme file (.tmTheme format) and place it in that directory. Then rebuild the cache:

bat cache --build

To use the theme, add this to your PowerShell profile:

$env:BAT_THEME = "tokyonight_night"

Using fzf
#

Once configured, here are the key combinations you’ll use:

Key CombinationDescription
CTRL-tLook for files and directories
CTRL-rLook through command history
EnterSelect the item
Ctrl-j or Ctrl-n or Down arrowGo down one result
Ctrl-k or Ctrl-p or Up arrowGo up one result
TabMark a result
Shift-TabUnmark a result
cd **TabOpen up fzf to find directory
export **TabLook for env variable to export
unset **TabLook for env variable to unset
unalias **TabLook for alias to unalias
ssh **TabLook for recently visited host names
kill -9 **TabLook for process name to kill to get pid
any command (like nvim or code) + **TabLook for files & directories to complete command

Pro tip: Press Ctrl+T, start typing part of a filename, and watch as fzf instantly filters through your entire directory tree. The preview pane on the right shows you the file contents with syntax highlighting!

Smart Navigation with zoxide
#

What is zoxide?
#

zoxide is a smarter cd command that learns from your habits. Instead of typing full paths, you can jump to frequently-used directories with just a few characters. Think of it as autocomplete for your entire file system.

For example, after visiting D:\Repositories\my-project a few times, you can jump there with just cd proj.

Installation
#

Install zoxide using Chocolatey:

choco install zoxide

Configuration
#

Add this to your PowerShell profile:

Invoke-Expression (& { (zoxide init powershell | Out-String) })

Remove-Item Alias:cd
function cd {
    param (
        [string]$path
    )
    if ($path -eq "repo") {
        Set-Location "D:\Repositories"
    } elseif ($path -eq "gitlab") {
        Set-Location "D:\Repositories\toto-gitlab"
    } else {
        z $path
    }
}

This configuration does two clever things:

  1. Integrates zoxide as the backend for the cd command
  2. Adds custom shortcuts: cd repo and cd gitlab jump directly to your most-used directories

How It Works
#

  • First time: cd D:\Repositories\my-project\src\components (zoxide learns)
  • After a few visits: cd comp (instantly jumps to the components directory)
  • The more you use directories, the higher they rank in zoxide’s scoring

Better Directory Listings with eza
#

What is eza?
#

eza is a modern replacement for ls (or dir on Windows) with colors, icons, Git integration, and better formatting. It makes understanding directory contents much faster and more pleasant.

Installation
#

Install eza using winget:

winget install eza-community.eza

Configuration
#

Add this to your PowerShell profile to replace both ls and dir:

Remove-Item Alias:ls
function ls {
    eza --color=always --long --git --all --icons=always --no-time
}

Remove-Item Alias:dir
function dir {
    eza --color=always --long --git --all --icons=always --no-time
}

Now when you run ls or dir, you’ll see:

  • Color-coded file types: directories, executables, images, etc.
  • Icons: visual indicators for different file types
  • Git status: see which files are modified, staged, or ignored
  • Better formatting: easier to read with proper alignment

Command Breakdown
#

Let’s understand the flags we’re using:

  • --color=always: Enable colors
  • --long: Show detailed information (size, permissions)
  • --git: Display Git status for files
  • --all: Include hidden files
  • --icons=always: Show icons for file types (requires a Nerd Font)
  • --no-time: Hide timestamps for a cleaner view

Note: For icons to display properly, you’ll need to install a Nerd Font in your terminal. Popular choices include “FiraCode Nerd Font” or “JetBrains Mono Nerd Font.”

Putting It All Together
#

Your Complete PowerShell Profile
#

Here’s what your complete $PROFILE file should look like with all the configurations:

# Import necessary modules
Import-Module PSReadLine
Import-Module PSFzf

# fzf key bindings
Set-PSReadLineKeyHandler -Chord 'Ctrl+t' -ScriptBlock {
    Search-Files
}

Set-PSReadLineKeyHandler -Chord 'Ctrl+r' -ScriptBlock {
    $selectedCommand = Get-History | Sort-Object -Property Id -Descending | ForEach-Object { "$($_.Id)  $($_.CommandLine)" } |
                        fzf --height=40% --reverse --prompt "History> " |
                        ForEach-Object { ($_ -split '\s{2,}', 2)[1] }

    if ($selectedCommand) {
        [Microsoft.PowerShell.PSConsoleReadLine]::Insert($selectedCommand)
    }
}

function Search-Files {
    fd --type file --hidden --exclude .git | fzf --prompt "Files> " --preview "bat --style=numbers --color=always --line-range :500 {}"
}

# bat theme
$env:BAT_THEME = "tokyonight_night"

# zoxide integration
Invoke-Expression (& { (zoxide init powershell | Out-String) })

Remove-Item Alias:cd
function cd {
    param (
        [string]$path
    )
    if ($path -eq "repo") {
        Set-Location "D:\Repositories"
    } elseif ($path -eq "gitlab") {
        Set-Location "D:\Repositories\toto-gitlab"
    } else {
        z $path
    }
}

# eza (better ls/dir)
Remove-Item Alias:ls
function ls {
    eza --color=always --long --git --all --icons=always --no-time
}

Remove-Item Alias:dir
function dir {
    eza --color=always --long --git --all --icons=always --no-time
}

Testing Your Setup
#

After saving your profile and reloading PowerShell, try these commands:

  1. Press Ctrl+T and start typing a filename
  2. Run ls to see your new directory listing
  3. Navigate with cd to a directory, then later type just part of its name
  4. Press Ctrl+R and search through your command history

Conclusion
#

You now have a modern, productive PowerShell environment that rivals any Linux terminal setup! Here’s what you’ve gained:

  • Lightning-fast file finding with fzf and fd
  • Beautiful syntax highlighting with bat
  • Intelligent navigation with zoxide
  • Information-rich directory listings with eza
  • Seamless PowerShell integration for all tools

Next Steps
#

  • Explore fzf further: Try creating custom functions for project switching or log searching
  • Customize eza: Experiment with different flags and create aliases for specific views
  • Install a Nerd Font: Get proper icon support in your terminal
  • Consider Windows Terminal: Microsoft’s modern terminal app with tabs, themes, and better rendering
  • Share your dotfiles: Put your PowerShell profile in version control

The beauty of this setup is that these are native Windows tools with Windows-native installation—no virtualization, no compatibility layers, just pure PowerShell power.

Happy scripting!