-
Notifications
You must be signed in to change notification settings - Fork 0
PowerShell
PowerShell 7 profile and prompt for Windows (and Linux where applicable).
| Tool | Purpose | Install |
|---|---|---|
| PowerShell 7+ | Shell | winget install Microsoft.PowerShell |
| PSReadLine 2.2+ | Line editing | ships with pwsh 7; update via Install-Module PSReadLine
|
| PSFzf | Fzf integration | Install-Module PSFzf |
| git-completion | Git tab completion | Install-Module git-completion |
| fzf | Fuzzy finder | winget install junegunn.fzf |
| zoxide | Smart cd
|
winget install ajeetdsouza.zoxide |
| Az.Tools.Predictor | Azure command prediction | Install-Module Az.Tools.Predictor |
| WinGet.CommandNotFound | Package suggestions | installed via Microsoft Store |
| jujutsu (jj) | Optional — jj VCS segment in the prompt | winget install jj-vcs.jj |
| File | Notes |
|---|---|
Microsoft.PowerShell_profile.ps1 |
Shared profile — used on all machines |
Profile/Set-Prompt.ps1 |
Prompt definition (jj/git + Azure context) |
Profile/AzCliAccount.ps1 |
az CLI profile switcher (azs) — see below |
The installer generates a stub at ~/Documents/PowerShell/Microsoft.PowerShell_profile.ps1
that dot-sources the repo file — changes are live immediately without re-running setup.
Standalone PowerShell tools (not loaded by the profile — run on demand). Each has
comment-based help; run Get-Help .\Scripts\<Name>.ps1 -Full.
| Script | Purpose |
|---|---|
Set-CodingFont.ps1 |
Switch the coding font across all dotfiles targets at once — Windows Terminal (live + repo), VS Code (live + repo snapshot), and Vim guifont. Set-CodingFont commit
|
Install-CodingFont.ps1 |
Download + per-user install + session-activate Nerd Font (Mono) faces from the nerd-fonts release. Install-CodingFont CommitMono
|
New-FontComparison.ps1 |
Self-contained side-by-side HTML/PNG comparison of the candidate fonts with a PowerShell/C#/Bicep language switcher. -Fonts filters the set |
New-FontGlyphTest.ps1 |
Glyph-separation torture test (rn/m, cl/d, vv/w, 1lI|, 0O) across Commit/JetBrains/0xProto |
New-FontLigatureTest.ps1 |
Ligatures-on vs -off comparison so you can see what each font actually fuses |
The New-Font* tools subset each font to the sample glyphs and embed them as base64 woff2,
so the output HTML renders the real fonts in any browser. They need Python with
fonttools + brotli (pip install fonttools brotli) for subsetting and Edge for the PNG.
Generated .font-*.html/.png land at the repo root and are git-ignored.
The profile is structured in three phases to keep startup fast:
Phase 1 — blocking (runs before first prompt):
Single PSModulePath scan into $global:ProfileModules cache, PSReadLine
with PredictionSource History, all key bindings, prompt definition.
Sets RIPGREP_CONFIG_PATH and FZF_DEFAULT_OPTS_FILE pointing at repo files
(no copy needed). Reads AppsUseLightTheme from the registry once into
$_isDark, then sets FZF_DEFAULT_OPTS, LG_CONFIG_FILE (lazygit base +
theme), and EZA_CONFIG_DIR (eza theme dir) to catppuccin mocha or latte —
mirrors nvim's theme detection.
Sets _ZO_RESOLVE_SYMLINKS=1 so zoxide stores resolved paths; prevents
duplicate database entries when navigating through junctions.
Phase 2a — first idle:
PSFzf, zoxide, upgrade to PredictionSource HistoryAndPlugin, the fd-backed
FZF_*_COMMAND vars (kept separate from ripgreprc so pickers stay
.gitignore-clean while rg search stays exhaustive), the eza ll/la/lt
helpers, and the Azure context timer (Initialize-AzTimer, moved off the load
path). Guarded by
$global:ProfileDeferredDone. Interactive tools needed immediately.
Phase 2b — next idle:
az + zellij tab-completers, git-completion (+ g alias registration), WinGet
CommandNotFound. Guarded by $global:ProfileDeferredSecondaryDone. Split from 2a
so the first keypress isn't blocked by their import cost.
Phase 3 — async (background runspace):
Azure context refresh on a 60-second timer. The timer is created in Phase 2a
(Initialize-AzTimer); the refresh itself runs in a background runspace wired up
in Set-Prompt.ps1.
| Chord | Action |
|---|---|
Ctrl+r |
Reverse history search (fzf) |
Ctrl+t |
FZF file picker |
Alt+f |
FZF ripgrep search |
Alt+b |
FZF git branch switcher |
Alt+g |
FZF git worktree switcher |
Ctrl+f |
Forward char |
Ctrl+b |
Backward char |
Ctrl+p / Ctrl+n
|
Previous / next history |
Ctrl+a / Ctrl+e
|
Beginning / end of line |
Ctrl+w |
Delete word backward |
Ctrl+u |
Delete line backward |
Ctrl+Space / Shift+Tab
|
Menu complete |
Ctrl+[ (Oem4) |
Vi command mode |
- jj (Jujutsu) change-id, closest bookmark, ahead count, and state — shown instead of git in jj repos (takes precedence in colocated repos; toggle
ShowJj). Gate is a filesystem walk; up to 3 jj processes, all--ignore-working-copy. Rendersjj:<change-id> <bookmark> ↑<dist> *<files> ∅ ✎(∅empty,✎no description,!conflict) - Git branch and status — synchronous, 3 git processes per prompt (used when not in a jj repo)
- Azure subscription context — async via background runspace, refreshed every 60s
- az CLI profile tag (
az:<name>/az:default) — see az CLI profile switcher below - Last command exit status (colour coded) and execution time
- Truncated path for long directories
- Windows Terminal OSC 9;9 CWD tracking; also syncs the Win32 process CWD so Zellij opens new panes in the current directory
Switch-AzProfile (alias azs) switches the Azure CLI between named
profiles, each a self-contained AZURE_CONFIG_DIR under
~/.azure-profiles/<name>. The point is one identity per profile directory —
see "why one identity per profile" below.
-
Switch by name:
azs work,azs personal— creates~/.azure-profiles/<name>if it doesn't exist yet and pointsAZURE_CONFIG_DIRat it. -
Switch with a picker:
azswith no argument opens an fzf picker listing every known profile plusdefault, with a preview column showing each profile's cached identity (or "not logged in" if it's never been used). The preview readsazureProfile.jsondirectly — noazprocess per keystroke. -
defaultis the reserved name for az's own~/.azure— it meansAZURE_CONFIG_DIRis unset. It's deliberately left alone rather than managed as a profile directory: on Windows~/.azureis a single case-insensitive folder shared with Azure PowerShell (Get-Az*readsAzureRmContext.jsonfrom the same directory), so anything that swapped or redirected it would silently change the Az PowerShell context too. -
Adding a new profile is just
azs <newname>followed byaz login— there's no manifest file to edit. The directory is the source of truth. -
The prompt shows the active profile as
az:<name>(oraz:default), read straight from$env:AZURE_CONFIG_DIR— noazprocess, so it's always in sync with a silent shell-startup restore.
az devops (and some other extensions) build their auth candidate list from
whatever subscriptions/identities are cached in the current config dir, and
use the first one that can successfully list a project — not necessarily
the one you meant to use. A config directory holding two or more logged-in
identities can therefore authenticate az devops calls as an account you
didn't select, with no error or warning. Keeping exactly one identity per
profile directory (log in once per profile, never share a dir between
accounts) removes that ambiguity entirely.
All profiles share one AZURE_EXTENSION_DIR (pointed at the existing
~/.azure/cliextensions), set unconditionally regardless of which profile is
active. Without this, a non-default profile's fresh config dir has zero
installed extensions, and az devops / az graph simply don't work under it.
Earlier versions of this profile used an asymmetric two-account scheme
(azw/azp: one alias unset AZURE_CONFIG_DIR for "work", the other pointed
it at ~/.azure-personal for "personal"). That's gone — it couldn't express
more than two accounts, and "work" was really just "whatever's logged into
the default dir on this machine," which didn't travel between machines. If
you're migrating:
- Move
~/.azure-personalto~/.azure-profiles/personal. - For every other account, run
azs <name>(creates an empty profile dir), thenaz loginonce inside it — start each profile empty so it never caches more than one identity. - Leave
~/.azureas-is; it keeps whatever the Azure PowerShell context and your "default" CLI login already are. - Run
azsonce after migrating so the state file (~/.azure-active-profile) picks up the new layout.
There is a single shared profile — no per-machine variants. Machine-specific behaviour (work git identity, Azure subscription) is handled at other layers:
- Git identity via
[includeIf]ingit/gitconfig - Az context loaded async in
Profile/Set-Prompt.ps1
./setup.ps1 -Module powershellStubs the profile into the pwsh 7 and VSCode profile locations (both under
~/Documents/PowerShell/) and junctions ~/Documents/PowerShell/Profile →
powershell/Profile/. Windows PowerShell 5.1 is not targeted — the shared
profile is #Requires -Version 7. The installer warns about (but never deletes)
orphaned PS5 stubs under ~/Documents/WindowsPowerShell/ from older runs so you
can remove them manually.
Source: powershell/README.md in the dotfiles repo.
Getting started
Core (Windows)
Cross-platform
Claude Code & AI
Reference
Legacy (Linux)
Troubleshooting