Environment Variables, the System PATH & Software Installation
How Windows finds programs, why “not recognized” happens, and how to install software the programmer’s way with winget.
Module 3 · OverviewBy the end of this module you can…
- Describe what happens between typing a command and it running
- Explain environment variables and read them with
$env: - Read, edit, and repair your
PATH— GUI and PowerShell - Tell user variables from system variables
- Diagnose “is not recognized” errors methodically
- Recognize executable types and set a sensible execution policy
- Install software with installers and with
winget
How Windows Finds Programs
You type python. What actually happens?
The lookupWhat happens when you press Enter
python a PowerShell alias, function, or cmdlet?PATH, in orderpython.exe, .cmd, .bat, .ps1…Nothing found in any folder?python: The term 'python' is not recognized as a name of a cmdlet, function, script file, or executable program.
PowerShell does not look in the current folder. To run build.ps1 sitting right here, type .\build.ps1.
ConceptEnvironment variables
Named text values that every program inherits when it starts — shared settings for the whole session.
PS> $env:USERNAME
Jane
PS> $env:USERPROFILE
C:\Users\Jane
PS> ls env: # list them all
| Variable | Typical value |
|---|---|
USERPROFILE | C:\Users\Jane |
APPDATA | …\AppData\Roaming |
LOCALAPPDATA | …\AppData\Local |
TEMP | …\AppData\Local\Temp |
COMPUTERNAME | LAPTOP-7F3K |
PATH | the list of program folders |
Syntax differs by shell: $env:TEMP in PowerShell, %TEMP% in cmd & Explorer, os.environ["TEMP"] in Python.
ConceptPATH: the phone book for programs
One long string of folders separated by ;
Windows reads it top to bottom and runs the first match.
Split it into lines to make it readable:$env:PATH -split ';'
PS> $env:PATH -split ';'
C:\Program Files\PowerShell\7
C:\WINDOWS\system32
C:\WINDOWS
C:\WINDOWS\System32\WindowsPowerShell\v1.0\
C:\Program Files\Git\cmd
C:\Users\Jane\.local\bin
C:\Users\Jane\AppData\Local\Microsoft\WindowsApps
C:\Users\Jane\AppData\Local\Programs\Microsoft VS Code\bin
ConceptOrder matters: the case of the fake python
Fresh Windows installs contain a stub python.exe in WindowsApps that just opens the Microsoft Store.
Ask PowerShell which one wins:
PS> Get-Command python -All | Select-Object Source
Source
------
C:\Users\Jane\AppData\Local\Microsoft\WindowsApps\python.exe
where.exe python does the same job and works in cmd too.
Get-Command answers the question “which program will actually run?” — the first thing to check whenever a tool behaves strangely.
Turn the stub off: Settings → Apps → Advanced app settings → App execution aliases → switch off python.exe and python3.exe. In Module 4, uv will give us real Pythons.
ScopeUser variables vs. system variables
User variables
- Apply only to you
- Edit without admin rights
- Where per-user tools (uv, VS Code) add themselves
- This is where we work.
System variables
- Apply to every user on the PC
- Require administrator rights
- Where machine-wide installs (Git, Windows) live
- Look, don’t touch.
LifetimeChanges only reach new windows
Each program copies the environment when it starts. After you change a variable permanently:
- Terminals already open still have the old copy
- VS Code (and its terminals) still has the old copy
Changed PATH? Close and reopen the terminal — every time.
| Set with… | Lasts |
|---|---|
$env:X = "…" | This terminal window only — gone when closed |
| Environment Variables dialog | Permanent, all future programs |
[Environment]::SetEnvironmentVariable(…, "User") | Permanent, all future programs |
EditingThe GUI way
- Press Win, type “environment”, choose Edit environment variables for your account (no admin needed)
- Top half = User variables. Select
Path→ Edit… - New → paste a folder path → Move Up/Down to set priority
- OK, OK — then open a new terminal
Shortcuts that open the same dialog:
rundll32 sysdm.cpl,EditEnvironmentVariables
sysdm.cpl → Advanced tab → Environment Variables… (this route shows System variables too, which need admin to change)
Never paste over the whole Path value. Add or remove one entry at a time.
EditingThe PowerShell way
# Read
$env:PATH -split ';'
[Environment]::GetEnvironmentVariable("Path", "User") -split ';' # just the User part
# Temporary — this window only (great for experiments)
$env:PATH = "C:\actuarial_work\bin;" + $env:PATH
$env:MY_DATA_DIR = "C:\actuarial_work\data"
# Permanent — append a folder to the USER Path
$bin = "C:\actuarial_work\bin"
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
[Environment]::SetEnvironmentVariable("Path", "$userPath;$bin", "User")
The permanent version writes to the registry, exactly like the GUI. Run it once; running it twice adds the folder twice (harmless, but messy).
Troubleshooting“… is not recognized” — a diagnostic checklist
- Typo? Try Tab-completing the command name.
- Installed? Find the actual
.exeon disk (installer docs,winget list). - Which folder? Note the folder that contains it, e.g.
C:\Users\Jane\.local\bin. - On PATH?
$env:PATH -split ';'— is that folder listed? - Stale window? Open a new terminal and try again.
- Still no? Add the folder to your User
Pathand repeat step 5.
PS> uv --version
uv: The term 'uv' is not recognized…
PS> Test-Path ~\.local\bin\uv.exe
True
PS> $env:PATH -split ';' |
>> Select-String local
(nothing)
Diagnosis: installed, but its folder isn’t on PATH in this window.
ExecutablesWhat counts as a “program”?
| Extension | What it is | Run by |
|---|---|---|
.exe | Compiled program — python.exe, git.exe, uv.exe | Windows directly |
.cmd / .bat | Batch script — old-style command list | cmd.exe |
.ps1 | PowerShell script | PowerShell — if execution policy allows |
.py | Python script | Python: python script.py / uv run script.py |
The variable PATHEXT lists which extensions Windows tries automatically: $env:PATHEXT → .COM;.EXE;.BAT;.CMD;…
ExecutablesExecution policy: why your .ps1 won’t run
PS> .\mkproj.ps1
.\mkproj.ps1 cannot be loaded because running
scripts is disabled on this system.
Windows client PCs default to Restricted. The recommended setting for developers:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
Get-ExecutionPolicy -List # verify
| Policy | Meaning |
|---|---|
| Restricted | No scripts at all |
| RemoteSigned | Your own scripts run; downloaded scripts must be signed |
| Unrestricted | Everything runs (warns on downloads) |
| Bypass | No checks — used for one-off commands |
-Scope CurrentUser = no admin needed, affects only you. On managed work PCs, IT policy may override this.
Installing Software
Point-and-click installers vs. the winget package manager.
InstallingTwo ways to install
Downloadable installer (.exe / .msi)
- Find the official site, pick the right download
- Click through a wizard — some screens matter (e.g. “Add to PATH”)
- Updates: remember to come back
- Easy to grab a fake from a search ad
Package manager (winget)
- One command; built into Windows 10/11
- Pulls from a curated catalog of official installers
winget upgrade --allupdates everything- Scriptable — a whole setup in one file
Either way, most installers edit your PATH. That’s why this lives in the PATH module — and why you open a new terminal after every install.
wingetEveryday winget
winget search pandoc # find packages
winget show --id JohnMacFarlane.Pandoc # details
winget install --id JohnMacFarlane.Pandoc -e
winget list # what's installed
winget upgrade # what's out of date
winget upgrade --all # update everything
winget uninstall --id JohnMacFarlane.Pandoc
IDs we’ll use in this course
Microsoft.PowerShell |
astral-sh.uv |
Git.Git |
JohnMacFarlane.Pandoc |
Microsoft.VisualStudioCode |
--id … -e means “this exact ID”, avoiding look-alike packages. The first run may ask you to accept the source agreements — read, then type Y.
Hands-on Lab · 35 minBuild your own global command
Goal: type mkproj pricing_2026 from any folder and get a ready-made project skeleton.
- Create a personal script folder:
C:\actuarial_work\bin - Allow your own scripts to run (execution policy)
- Write the tiny utility
mkproj.ps1 - Add the folder to your User
PATH - Open a new terminal and call it from anywhere
Lab · Steps 1–3Folder, policy, script
mkdir C:\actuarial_work\bin
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
notepad C:\actuarial_work\bin\mkproj.ps1 # say "Yes" to create the file
Type this into Notepad and save:
# mkproj.ps1 — create a standard actuarial project skeleton
param([Parameter(Mandatory)] [string] $Name)
$folders = "data", "notebooks", "src", "output", "tests"
foreach ($f in $folders) {
New-Item -ItemType Directory -Force -Path (Join-Path $Name $f) | Out-Null
}
Write-Host "Created $Name with: $($folders -join ', ')" -ForegroundColor Green
Check with ls C:\actuarial_work\bin that it’s mkproj.ps1 — not mkproj.ps1.txt (Module 1 flashback!).
Lab · Steps 4–5Put it on the PATH and test
4 · Add to User PATH (pick one)
GUI: Edit environment variables for your account → Path → New → C:\actuarial_work\bin
PowerShell:
$bin = "C:\actuarial_work\bin"
$u = [Environment]::GetEnvironmentVariable("Path","User")
[Environment]::SetEnvironmentVariable("Path","$u;$bin","User")
5 · New terminal, then:
PS C:\Users\Jane> cd C:\actuarial_work
PS C:\actuarial_work> mkproj pricing_2026
Created pricing_2026 with: data, notebooks,
src, output, tests
PS C:\actuarial_work> Get-Command mkproj
CommandType Name Source
----------- ---- ------
ExternalScript mkproj.ps1 C:\actuarial_work\bin\mkproj.ps1
Bonus: install something with winget (e.g. winget install --id JohnMacFarlane.Pandoc -e — we need it in Module 6), then find which PATH entry it added.
RecapModule 3 checklist
- I can explain how a command name becomes a running program
- I can list environment variables and print one with
$env:NAME - I can read my
PATHone entry per line - I know user vs. system variables, and I edit only user ones
- After changing
PATHor installing software, I open a new terminal - I can diagnose “not recognized” with
Get-CommandandTest-Path - My execution policy is
RemoteSignedfor CurrentUser - I can install, list, and upgrade software with
winget mkprojworks from any folder
Next-Gen Python Tooling with uv
Python itself, virtual environments, and reproducible packages — installed per-user, no admin, no PATH surgery.