Loosely Decoupled
AnswerPowerShellAutomation

How to Show File Extensions in File Explorer with PowerShell

HideFileExt set to 0 shows file extensions for your account, and one Active Setup entry sets it for every account on the machine at its next sign-in.

At a cloakroom counter a young woman pulls a cord that flips open the tag on every coat. One plain grey coat's tag unrolls far longer than the rest, down over the counter, while a small monkey with an ID badge peers out from behind it. The long tag is cyan.

TL;DR

For the account you are signed in as:

PowerShell
$advanced = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced'
Set-ItemProperty -Path $advanced -Name HideFileExt -Value 0 -Type DWord
Stop-Process -Name explorer -Force

Windows restarts the shell, and every window now shows report.txt.exe as what it is. Run it unelevated: the setting is per user and lives in the hive of whoever runs the command, and an unelevated session can only stop its own Explorer.

Windows hides the extension of known file types by default, so invoice.pdf and invoice.pdf.exe look the same in Explorer. Turning that off is the first thing to do on any machine you’ll administer from the desktop, and the setting is one DWORD.

Where the setting lives

Text
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced
    HideFileExt    REG_DWORD    0 = show extensions, 1 = hide

Explorer reads the value when it starts, which is why the answer restarts it: a write from PowerShell notifies nothing, and open windows stay as they were. Stopping it with Stop-Process -Name explorer ends the shell process; Winlogon relaunches it (AutoRestartShell, on by default), so the taskbar is back within a second or two.

Warning

Elevated, Stop-Process -Name explorer -Force stops every user’s Explorer on the machine, not only yours — on a server with other people signed in over RDP, that is their desktop vanishing. From an elevated session, stop only the one in your session:

PowerShell
Get-Process -Name explorer |
    Where-Object SessionId -eq (Get-Process -Id $PID).SessionId |
    Stop-Process -Force

For every account, including ones that do not exist yet

HKCU is the current user’s hive, so the command above changes one account. On a server where several administrators sign in, put the same command where Windows runs it once for each user at their next sign-in, before Explorer starts. That is Active Setup, and it is a key under HKLM, so it is set with the registry provider from an elevated session:

PowerShell
$stub = 'HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\ShowFileExtensions'

New-Item -Path $stub -Force | Out-Null
Set-ItemProperty -Path $stub -Name '(Default)'   -Value 'Show file extensions'
Set-ItemProperty -Path $stub -Name 'IsInstalled' -Value 1 -Type DWord
Set-ItemProperty -Path $stub -Name 'Version'     -Value '1'
$advanced = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced'
$command = "Set-ItemProperty -Path '$advanced' -Name HideFileExt -Value 0"
Set-ItemProperty -Path $stub -Name 'StubPath' -Value (
    'powershell.exe -NoProfile -WindowStyle Hidden -Command "' + $command + '"'
)

At each sign-in Windows compares Version here against the copy under that user’s HKCU\Software\Microsoft\Active Setup\Installed Components. When the user has none, or an older one, it runs StubPath as that user and records the version. So the command runs once per account: existing accounts at their next sign-in, new accounts at their first. It runs while the shell is still starting, before the desktop is shown, so the first Explorer window a user opens already shows extensions. To run it again for everyone, raise Version; to stop it running for anyone new, delete the key under HKLM. Users who already ran it keep the setting either way.

A console window can flash for a moment at sign-in while the stub runs; -WindowStyle Hidden hides it as soon as PowerShell has started, not before.

This is the whole mechanism Windows uses to seed per-user settings from a machine-wide install. It is the one route to “every account” that needs no hive loading and no tool outside PowerShell. Group Policy Preferences does the same job on a domain-joined machine.

Common failures

Value is 0 and extensions are still hidden

You ran the command elevated as a different account. An elevated PowerShell opened with “Run as administrator” and a second set of credentials writes to that account’s HKCU, not yours. Run it unelevated in your own session.

Taskbar didn’t come back after Stop-Process

AutoRestartShell is off on that machine, or the process was ended from outside the session it belonged to. Start it by hand:

PowerShell
Start-Process explorer

On Server Core there’s no Explorer to stop and no setting to change; Stop-Process reports that no such process exists.

Extensions still hidden for another user

The user hasn’t signed out and in since it was written; Active Setup runs at sign-in and nowhere else. Or the stub ran under a policy that blocks powershell.exe for that user. Check HKCU\Software\Microsoft\Active Setup\Installed Components\ShowFileExtensions in their hive: present means the stub was launched, absent means it wasn’t.

New articles, by email.

A short note when something new is published.