PowerShell: curl is an alias for Invoke-WebRequest (why -I and Unix flags break)
You typed <code>curl -I https://example.com</code> the way every README shows, and PowerShell complained about an ambiguous parameter or returned a huge object instead of headers. On Windows, <code>curl</code> is often not curl at all.
Prove it in one line
Get-Alias curl -ErrorAction SilentlyContinue
# Windows PowerShell 5.1 typically prints:
# Alias curl -> Invoke-WebRequest
Get-Command curl* | Format-Table Name, CommandType, Source
If you see an alias, every curl … you type is rewritten to Invoke-WebRequest … before it runs. PowerShell 7 on Windows usually prefers real curl.exe when it is on PATH, but do not assume — check.
Why Unix examples explode
| You typed (Unix curl) | What 5.1 actually ran | Typical result |
|---|---|---|
curl -I https://… | Invoke-WebRequest -I … | Ambiguous parameter -I (matches -InFile / others) |
curl -s https://…/api.json | Invoke-WebRequest -s … | Unknown / wrong parameter; or a full response object |
curl -o out.zip URL | Alias + -o | Not the same as curl’s output file flag |
curl -H "Accept: …" URL | Alias + -H | Does not map to -Headers automatically |
# What people usually wanted (headers only):
curl.exe -sI https://example.com
# PowerShell-native equivalent:
Invoke-WebRequest -Uri https://example.com -Method Head |
Select-Object StatusCode, Headers
curl.exe vs the alias
curl.exe— the real binary Microsoft ships in modern Windows (and the one from curl.se). Same flags as Linux docs:-I,-L,-H,-d,--json.curl— in 5.1, almost always the alias. Sayingcurl.exebypasses the alias.- Remove the alias in your profile only if you know you will not break scripts that expect
Invoke-WebRequest:Remove-Item Alias:curl -ErrorAction SilentlyContinue.
# Download a file the PowerShell way
Invoke-WebRequest -Uri https://example.com/file.zip -OutFile .\file.zip
# Same with real curl
curl.exe -fsSL -o file.zip https://example.com/file.zip
JSON APIs: prefer Invoke-RestMethod
Invoke-WebRequest gives you a response object (.StatusCode, .Content, .Headers). For JSON APIs, Invoke-RestMethod parses the body into objects automatically:
# Pretty-print JSON from an API (PowerShell)
Invoke-RestMethod -Uri https://api.oddlathe.com/v1/uuid?n=2 |
ConvertTo-Json -Depth 5
# Real curl + pipe to a formatter elsewhere
curl.exe -s "https://api.oddlathe.com/v1/uuid?n=2"
Paste awkward JSON into the JSON formatter when a terminal dump is hard to read. Encode query strings safely with the URL encoder before you stick them on a curl line.
Inspect a link without fetching it
When you only need to understand a URL (host, path, lookalike characters, sketchy query params), you do not need curl at all:
- Browser: Tooltern URL encoder & decoder (breakdown stays on your machine).
- API: Anvil /v1/url/inspect — structure and warnings only; it does not request the target site.
curl.exe -sG https://api.oddlathe.com/v1/url/inspect \
--data-urlencode "url=https://example.com/path?q=1"
Related
&& is not a valid statement separator · Running scripts is disabled · Unexpected token in JSON · TypeError: fetch failed · JSON formatter · URL encoder · Anvil URL inspect
Questions
Why does curl -I fail in PowerShell?
On Windows PowerShell 5.1, curl is an alias for Invoke-WebRequest, so -I is not the Unix "headers only" flag. Call curl.exe -sI or use Invoke-WebRequest -Method Head.
How do I run the real curl on Windows?
Type curl.exe (with the .exe). That skips the PowerShell alias. Confirm with Get-Command curl.exe.
What is the PowerShell equivalent of curl for JSON?
Invoke-RestMethod -Uri https://… parses JSON into objects. Invoke-WebRequest keeps the raw .Content string.
Is wget also broken?
In Windows PowerShell 5.1, wget is also an alias for Invoke-WebRequest. Use wget.exe if you installed a real one, or stick to Invoke-WebRequest / curl.exe.
Does PowerShell 7 still alias curl?
Often no — pwsh prefers curl.exe when present — but check Get-Alias curl. Writing curl.exe is always unambiguous.
Published .