If wget -O file.zip https://example.com/file.zip fails on Windows with a parameter error, you are not running wget. You are running PowerShell’s Invoke-WebRequest through an alias that shares the name and shares none of the flags.
This is the single most confusing thing about downloading files from a Windows command line, and it has caught out every person who has ever pasted a Linux install snippet into PowerShell. The command appears to exist. It even works for the simplest case. Then you add a flag and it falls over with an error about a parameter that cannot be found, which sends people looking for a broken wget install that was never there.
Table of contents
- Confirming what you are actually running
- curl.exe is already installed, and it is probably what you want
- Installing real wget
- Recursive download, the one thing only wget does
- Downloads inside scripts and CI
- A short table for translating between them
- How this fits the rest of the stack
- FAQ
Confirming what you are actually running
One command settles it.
Get-Command wget
If the CommandType column says Alias and the definition says Invoke-WebRequest, that is your answer. PowerShell ships aliases for wget and curl pointing at its own cmdlet, on the reasonable-sounding theory that people would find them familiar. In practice the flag vocabulary is completely different, so the familiarity is a trap.
The equivalent in Invoke-WebRequest terms looks like this:
Invoke-WebRequest -Uri https://example.com/file.zip -OutFile file.zip
That works and is perfectly good PowerShell. It is just not wget, and no amount of -O will make it so. Note also that in Windows PowerShell 5.1 Invoke-WebRequest parses the response into a DOM by default, which makes downloading a large file noticeably slower — -UseBasicParsing skips that.
curl.exe is already installed, and it is probably what you want
Since Windows 10 build 1803, a real curl.exe ships with the operating system in System32. It is genuine curl with genuine curl flags. The catch is the alias: typing curl in PowerShell hits the alias first, so you have to be explicit.
curl.exe -L -o file.zip https://example.com/file.zip
curl.exe -I https://example.com
curl.exe -s -H "Authorization: Bearer TOKEN" https://api.example.com/v1/status
The .exe is the whole trick. Write curl.exe and PowerShell skips the alias and runs the binary. In cmd.exe there is no alias at all, so plain curl works there.
-L is worth adding by habit. Download URLs redirect constantly — release assets, CDN handoffs, shortened links — and without -L curl writes the redirect body to your output file instead of following it. A 300-byte zip file that will not open is almost always a missing -L.
For most download tasks, curl covers it. wget’s genuinely distinct feature is recursive mirroring, and if that is what you need, no amount of curl flags substitutes.
Installing real wget
If you want actual GNU wget, the package managers handle it in one line each.
winget install --id GnuWin32.Wget
choco install wget
scoop install wget
winget ships with modern Windows. Chocolatey and Scoop need installing first but are worth having if you set up machines regularly. All three put a real wget.exe on the PATH.
After installing, the PowerShell alias still shadows the binary in that shell. Either call wget.exe explicitly, or remove the alias for your session:
Remove-Item Alias:wget -Force
Remove-Item Alias:curl -Force
To make that stick, put those lines in your PowerShell profile — $PROFILE tells you where it lives. It is a small change that stops a recurring annoyance permanently, and it makes pasted Linux snippets behave the way the person writing them expected.
The other route is WSL. If you already have a Linux subsystem installed, wsl wget https://example.com/file.zip runs the real thing with the real flags, though the file lands in the Linux filesystem unless you are careful about where you are working.
Recursive download, the one thing only wget does
This is why people specifically want wget rather than a substitute.
wget.exe -r -np -k -p -l 3 https://example.com/docs/
-rrecursive.-npno parent — stay under the starting path instead of wandering up and mirroring the whole site.-kconvert links so the local copy browses offline.-pfetch page requisites: images, stylesheets, scripts.-l 3depth limit. The default of 5 goes further than most people expect.
Add --wait=1 and --limit-rate=200k when mirroring anything you do not own. Hammering a server with parallel unthrottled requests is how you get an IP blocked, and it is impolite besides. Check the site’s terms before mirroring at all.
-c resumes a partial download, which matters on large files over an unreliable connection. -N only downloads when the remote file is newer than the local copy, which turns a mirror command into something you can safely re-run.
Downloads inside scripts and CI
In a build script the priority shifts from convenience to determinism. You want the command to fail loudly on an HTTP error rather than write an HTML error page to disk and carry on.
curl.exe --fail --location --silent --show-error \
--output artifact.zip https://example.com/releases/artifact.zip
--fail makes curl return a non-zero exit code on 4xx and 5xx instead of saving the error body. Without it, a 404 produces a file containing the words Not Found and a build that fails three steps later with something that looks unrelated. This is the flag that saves the most debugging time.
wget’s closest equivalents are --tries and --timeout for retry behaviour, and it already exits non-zero on server errors by default.
One more habit worth keeping: verify what you downloaded. A checksum comparison after the download is two extra lines and catches both corruption and a substituted artifact.
$hash = (Get-FileHash artifact.zip -Algorithm SHA256).Hash
if ($hash -ne $expected) { throw "checksum mismatch" }
A short table for translating between them
- Save to a named file: wget
-O name, curl-o name, PowerShell-OutFile name. - Follow redirects: wget does by default, curl needs
-L, PowerShell follows by default. - Headers only: wget
--spider -S, curl-I, PowerShell-Method Head. - Custom header: wget
--header=, curl-H, PowerShell-Headers @{}. - Resume: wget
-c, curl-C -, PowerShell has no direct equivalent. - Quiet: wget
-q, curl-s, PowerShell-UseBasicParsingplus redirecting output.
Keeping that mapping in your head is more useful than picking a favourite, because the machine you are on decides for you more often than you decide for it.
How this fits the rest of the stack
Downloading a build artifact by hand is usually a symptom rather than a task — something is being moved between machines because no pipeline is moving it. When a service builds from its repository, the artifact never needs fetching manually: the build runs on push, the log is attached to the deploy, and the previous deploy stays available to roll back to. Deploying from GitHub on RunxBuild covers connecting a repository and what happens on each push. If you are pricing that against a box you currently script by hand, the RunxBuild hosting calculator breaks out the service, database, storage, and bandwidth separately so the comparison is line by line rather than a single number.
Useful related references:
- What is SSH PuTTY? A 2026 Guide for the Windows User
- Set Up a Virtual Machine for Windows Development
- SSH Keygen on Windows: ssh-keygen, PuTTYgen, and WSL
- Services on RunxBuild
FAQ
Why does wget not work in PowerShell?
PowerShell defines wget as an alias for its own Invoke-WebRequest cmdlet, which uses completely different parameters. Flags like -O fail because that parameter does not exist on the cmdlet. Run Get-Command wget to confirm — if it reports an Alias, you are not running GNU wget.
Is curl available on Windows by default?
Yes. A real curl.exe has shipped in System32 since Windows 10 build 1803. In PowerShell you must type curl.exe explicitly, because the bare curl name hits the alias for Invoke-WebRequest first. In cmd.exe there is no alias, so plain curl works.
How do I install real wget on Windows?
Use a package manager: winget install --id GnuWin32.Wget, choco install wget, or scoop install wget. After installing, call wget.exe explicitly or run Remove-Item Alias:wget -Force to clear the PowerShell alias, and add that line to your $PROFILE to make it permanent.
Why is my downloaded file tiny and corrupted?
Almost always a missing redirect flag. Without -L, curl writes the redirect response body to your output file rather than following it to the real asset. Add -L for curl; wget follows redirects by default.
Can curl do recursive downloads like wget?
No. Recursive site mirroring is wget’s distinguishing feature and curl has no equivalent. If you need -r -np -k -p, install real wget or use WSL. For single-file downloads and API calls, curl is the better tool on Windows.