Windows PowerShell vs CMD: Key Differences With Examples

Windows PowerShell vs CMD comes down to one difference: CMD passes plain text between commands, while PowerShell passes .NET objects you can filter, sort and format. For anything beyond a quick one-liner, PowerShell is the better choice.

CMD (cmd.exe, the Command Prompt) is still around for batch files and old habits. Below I compare the two side by side with commands I ran in PowerShell 7.6, Windows PowerShell 5.1 and CMD on Windows 11.

PowerShell vs CMD at a glance

CMDPowerShell
OutputPlain text.NET objects
CommandsBuilt-in commands and .exe toolsCmdlets, functions and .exe tools
Scripts.bat and .cmd.ps1
Environment variables%PATH%$env:PATH
Last exit code%ERRORLEVEL%$LASTEXITCODE
Remote managementSeparate toolsBuilt in (Invoke-Command)
Runs onWindows onlyWindows; PowerShell 7 also on macOS and Linux

Both shells run regular programs like ipconfig, ping and robocopy the same way. The real gap is what happens to the output.

Text vs objects: the key difference

Ask both shells for a folder listing and look at what comes back. CMD gives you strings, and PowerShell gives you file and folder objects:

$fromCmd = cmd.exe /c "dir /b C:\psfaqs\Compare"
$fromPs = Get-ChildItem -Path C:\psfaqs\Compare

"CMD returns:        $($fromCmd[0].GetType().Name) -> '$($fromCmd[0])'"
"PowerShell returns: $($fromPs[0].GetType().Name) -> Name, Length, LastWriteTime and more"

Output:

CMD returns:        String -> 'logs'
PowerShell returns: DirectoryInfo -> Name, Length, LastWriteTime and more
PowerShell vs CMD output type, string vs DirectoryInfo object
CMD returns a string, and PowerShell returns a DirectoryInfo object (PowerShell 7)

With text, you’d have to cut columns out of each line to get a file size. With objects, the size is already a number in the Length property.

Filter and sort without parsing text

Here I list every file over 10 KB, largest first. In CMD this needs a FOR loop and string parsing. In PowerShell it’s one pipeline:

Get-ChildItem -Path C:\psfaqs\Compare -File -Recurse |
    Where-Object Length -GT 10KB |
    Sort-Object -Property Length -Descending |
    ForEach-Object { '{0,-11} {1,8:N0} KB' -f $_.Name, ($_.Length / 1KB) }

Output:

app.log          244 KB
report.csv        47 KB
PowerShell filter and sort files by size with Where-Object and Sort-Object
Files over 10 KB sorted by size, in one pipeline (Windows PowerShell 5.1)

Sorting files by date uses the same idea with LastWriteTime instead of Length.

Familiar CMD commands in PowerShell

PowerShell includes aliases, so dir, cd, copy and del still work. Each one points to a cmdlet:

Get-Alias -Name dir, cd, copy, del, type, cls, md |
    ForEach-Object { '{0,-5} -> {1}' -f $_.Name, $_.Definition }

Output:

dir   -> Get-ChildItem
cd    -> Set-Location
copy  -> Copy-Item
del   -> Remove-Item
type  -> Get-Content
cls   -> Clear-Host
md    -> mkdir

The catch is that aliases take PowerShell parameters, not CMD switches. dir /s fails, because PowerShell reads /s as a path:

try { dir /s C:\psfaqs\Compare -ErrorAction Stop | Out-Null; 'dir /s worked' }
catch { "dir /s: Failed. $($_.Exception.Message)" }

"Get-ChildItem -Recurse found $((Get-ChildItem -Path C:\psfaqs\Compare -Recurse -File).Count) files"

Output:

dir /s: Failed. Cannot find path 'C:\s' because it does not exist.
Get-ChildItem -Recurse found 3 files
PowerShell dir /s error compared with Get-ChildItem -Recurse
dir /s fails in PowerShell, and Get-ChildItem -Recurse does the same job (PowerShell 7)

Use -Recurse instead of /s, -Force instead of /a and -Name instead of /b.

Environment variables and exit codes

Both shells read the same environment variables, just with different syntax:

"CMD syntax:        $(cmd.exe /c 'echo %OS%')"
"PowerShell syntax: $env:OS"

Output:

CMD syntax:        Windows_NT
PowerShell syntax: Windows_NT

Exit codes work the same way too. CMD stores the last one in %ERRORLEVEL%, and PowerShell puts a program’s exit code in $LASTEXITCODE:

cmd.exe /c "exit 3"
"Exit code from CMD: $LASTEXITCODE"
cmd.exe /c "dir C:\psfaqs\Compare >nul"
"After a successful command: $LASTEXITCODE"

Output:

Exit code from CMD: 3
After a successful command: 0

Setting environment variables in PowerShell covers changing them for the session, the user or the machine.

Run CMD commands from PowerShell

Built-in CMD commands such as dir, echo and mklink live inside cmd.exe, so call them with cmd /c. Running a .bat file from PowerShell starts cmd.exe for you:

cmd /c "dir /s /b C:\Reports"
.\Build.bat
cmd /c mklink /J C:\Data\Current C:\Data\2026-09

For programs with tricky arguments, the stop-parsing token --% passes the rest of the line as is. Microsoft explains it in about_Parsing.

When to use CMD and when to use PowerShell

Use PowerShell for new scripts, admin tasks, working with files and services, Active Directory, Microsoft 365 and Azure. Its objects, error handling and remoting make scripts shorter and safer.

Use CMD when you run or maintain existing .bat files, or in recovery and setup environments where PowerShell isn’t available. Microsoft documents every CMD command in the Windows commands reference.

Windows PowerShell 5.1 or PowerShell 7?

Windows PowerShell 5.1 ships with Windows. PowerShell 7 is the newer, cross-platform version you install separately, and it runs side by side with 5.1. Microsoft’s What is PowerShell? overview covers both.

Frequently Asked Questions

What is the difference between PowerShell and CMD?

CMD passes plain text between commands. PowerShell passes .NET objects, so you can filter, sort and format results without parsing text.

Can PowerShell run CMD commands?

Yes. Programs like ipconfig and ping run directly. Built-in CMD commands and switches need cmd /c, for example cmd /c "dir /s /b".

Is PowerShell replacing CMD?

PowerShell is the recommended shell for automation, but cmd.exe still ships with Windows for batch files and compatibility.

Why does dir /s not work in PowerShell?

In PowerShell, dir is an alias for Get-ChildItem, which doesn’t use CMD switches. Use Get-ChildItem -Recurse instead.

Can I run a .bat file in PowerShell?

Yes. Type its path, such as .\Build.bat, and PowerShell runs it with cmd.exe.

Where to go next with PowerShell: