Profiles, Customization & Productivity

PowerShell Intermediate/Advanced

Chapter 11 · Profiles, Customization & Productivity

Fundamentals 11 introduced $PROFILE just far enough to make the ll function persistent. That was only ever a quarter of the real picture — $PROFILE is actually four distinct scripts, and picking the wrong one is exactly why a customization can work perfectly in one PowerShell window and mysteriously not exist in another.

$PROFILE Isn't Just One File — It's Four

$PROFILE # same as CurrentUserCurrentHost — the one Fundamentals 11 used $PROFILE.CurrentUserCurrentHost # this user, this specific host only $PROFILE.CurrentUserAllHosts # this user, EVERY host — console, VS Code, ISE, Windows Terminal $PROFILE.AllUsersCurrentHost # every user, this specific host only — needs admin rights $PROFILE.AllUsersAllHosts # every user, every host — needs admin rights

"Host" here means the actual application running PowerShell — the classic console, VS Code's own integrated terminal, the ISE, Windows Terminal — and PowerShell treats each one as genuinely separate, even though the underlying engine is identical.

"It works in the console but not in VS Code" is a profile-scope problem
Editing $PROFILE (which really means CurrentUserCurrentHost) only affects one specific host. A customization saved there correctly, working perfectly in the classic console, can appear to simply not exist the moment the exact same account opens VS Code's integrated terminal instead — because that's a different host, reading a different file. This isn't a bug; it's four separate files behaving exactly as documented, once you know they're separate.

Which One Should You Actually Edit?

if (-not (Test-Path $PROFILE.CurrentUserAllHosts)) { New-Item -ItemType File -Path $PROFILE.CurrentUserAllHosts -Force } notepad $PROFILE.CurrentUserAllHosts

For anything meant to follow you everywhere — Fundamentals 11's own ll function among them — CurrentUserAllHosts is almost always the right target, not the plain $PROFILE shorthand.

Customizing the Prompt: prompt Is Just a Function

function prompt { "PS $($PWD.Path)> " }

Nothing special about prompt beyond its exact reserved name — PowerShell calls it automatically before displaying every new command line, and whatever string it returns becomes the prompt text.

Fundamentals 7's own rule, now with real visible stakes
Fundamentals 7 established that every uncaptured line inside a function joins its return value — here, that rule applies directly to the one function PowerShell calls constantly, in front of you, every single time. A stray Write-Output "checking git..." left inside a custom prompt function wouldn't just quietly pollute a variable somewhere — it would visibly break your actual prompt, printing extra unwanted text before it, on every single command. This is the same gotcha as always, just with the highest-visibility consequence possible.

A slightly fancier version, showing the current git branch when there is one:

function prompt { $path = $PWD.Path $branch = git branch --show-current 2>$null if ($branch) { "PS $path [$branch]> " } else { "PS $path> " } }

PSReadLine: the Engine Behind Your Interactive Session

Tab completion, syntax highlighting as you type, and multi-line editing all come from PSReadLine, a module loaded by default in every modern PowerShell session:

Set-PSReadLineOption -PredictionSource History # ghost-text suggestions pulled from your own command history Set-PSReadLineOption -EditMode Windows # or Emacs, or Vi — controls the actual keybinding scheme Set-PSReadLineOption -Colors @{ Command = 'Cyan'; String = 'Green' }

Prediction, History Search & Key Handlers

Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete # Tab now shows a selectable completion menu instead of just cycling through options one at a time

Set-PSReadLineKeyHandler remaps individual keys to built-in editing functions — a genuinely deep customization surface, useful even at this single, well-chosen example's level.

Beyond this chapter
A whole ecosystem of third-party prompt theming exists outside core PowerShell — Oh My Posh being the best-known example, adding icons, git status, and full visual themes well beyond what a hand-written prompt function alone typically attempts. Worth knowing it exists; genuinely outside this course's own PowerShell-core scope.

Putting It Together

# $PROFILE.CurrentUserAllHosts — applies everywhere, for this user function ll { Get-ChildItem -Force @args } # Fundamentals 11's own payoff, now formalized here function prompt { $branch = git branch --show-current 2>$null if ($branch) { "PS $($PWD.Path) [$branch]> " } else { "PS $($PWD.Path)> " } } Set-PSReadLineOption -PredictionSource History

Hands-On Exercises

Exercise 1

A user reports that customizations saved to $PROFILE work perfectly in the regular PowerShell console but don't appear at all in VS Code's integrated terminal. Explain exactly why, and name the specific $PROFILE property that fixes it.

📄 View solution
Exercise 2

Explain what the prompt function actually is, and why a stray Write-Output line inside a custom prompt function would visibly break what your prompt looks like — referencing Fundamentals 7's own uncaptured-output rule directly.

📄 View solution
Exercise 3

Write a function prompt that shows the current path, and — only when inside a git repository — the current branch name in brackets right after it.

📄 View solution

Chapter 11 Quick Reference

  • $PROFILE is four files — CurrentUserCurrentHost (the default shorthand), CurrentUserAllHosts, AllUsersCurrentHost, AllUsersAllHosts
  • "Host" — the actual application running PowerShell (console, VS Code terminal, ISE, Windows Terminal); each is genuinely separate
  • $PROFILE.CurrentUserAllHosts — the right target for anything meant to follow you across every host
  • function prompt { ... } — a specially-named function PowerShell calls before every command line; its return value becomes the prompt text
  • Fundamentals 7's uncaptured-output rule applies to prompt directly — a stray line there visibly corrupts your actual prompt, every time
  • PSReadLine — the module behind tab completion, syntax highlighting, and history-based prediction (Set-PSReadLineOption, Set-PSReadLineKeyHandler)
  • Next chapter: Capstone — A Multi-System Automation & Reporting Tool