---
title: "PowerShell vs. Curl: A Side-by-Side Comparison"
description: "Compare PowerShell and curl to discover the best tool for various contexts. Enhance your IT toolkit and optimize your workflow."
canonical: "https://adamtheautomator.com/powershell-curl/"
---

# PowerShell vs. Curl: A Side-by-Side Comparison

> Compare PowerShell and curl to discover the best tool for various contexts. Enhance your IT toolkit and optimize your workflow.

Source: https://adamtheautomator.com/powershell-curl/

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![PowerShell vs. Curl: A Side-by-Side Comparison](https://adamtheautomator.com/wp-content/uploads/2019/12/website-4396924_1920.jpg)

# PowerShell vs. Curl: A Side-by-Side Comparison

[![](https://secure.gravatar.com/avatar/27e51fdfdee0acb33447a19c501780e43dec078b24bd8d9d9c10fd1c11a6b21c?s=192&d=mm&r=g)Devin Rich](https://adamtheautomator.com/author/devin/)18 December 20198 min. read

Categories: [IT Ops](/category/it-ops/)

Tags:[Curl](/tag/curl/)[PowerShell](/tag/powershell/)

Table of Contents

*   [Myth Busting: PowerShell Cmdlets <> Curl](#myth-busting-powershell-cmdlets-curl)
*   [Long Parameters in Bash vs. PowerShell](#long-parameters-in-bash-vs-powershell)
*   [Working with REST APIs](#working-with-rest-apis)
*   [Getting Data From a REST API](#getting-data-from-a-rest-api)
*   [Submitting Data to a REST API](#submitting-data-to-a-rest-api)
*   [Using Custom Headers](#using-custom-headers)
*   [Parsing the HTTP Response](#parsing-the-http-response)
*   [Scraping a Webpage](#scraping-a-webpage)
*   [Submitting a Form](#submitting-a-form)
*   [Using a Web Session / Cookies](#using-a-web-session-cookies)
*   [Summary](#summary)
*   [Related Links](#related-links)

[Curl](https://curl.haxx.se/) is a versatile tool that allows you to make HTTP calls across a wide range of situations. It’s been around mostly in the Linux world for many years but more recently in Windows 10. But the scripting language PowerShell can accomplish similar tasks that curl can. Is PowerShell a good alternative to curl? What are the differences? Let’s find out!

In this article, let’s compare PowerShell and curl side-by-side to discover which one works best in various contexts. We’ll also compare each in various use cases for you to make the best decision based on your personal situation.

## Myth Busting: PowerShell Cmdlets <> Curl

Before we get too deep into this article, let’s bust a popular myth that PowerShell’s [Invoke-WebRequest](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest) or [Invoke-RestMethod](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod) cmdlets are “replacements” for curl. This simply isn’t true. By looking at the help content for these commands, it’s clear each has different capabilities and use cases.

Take a look at what the curl documentation says:

> _curl is a tool to transfer data from or to a server, using one of the supported protocols (DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET and TFTP)._
> 
> _The command is designed to work without user interaction. Curl offers a busload of useful tricks like proxy support, user authentication, FTP upload, HTTP post, SSL connections, cookies, file transfer resume, Metalink, and more._

Now compare that to the [`Invoke-WebRequest`](https://adamtheautomator.com/invoke-webrequest/ "Invoke-WebRequest") and `Invoke-RestMethod` cmdlet help documentation.

> “_The Invoke-WebRequest cmdlet sends HTTP, HTTPS, FTP, and FILE requests to a web page or web service. It parses the response and returns collections of forms, links, images, and other significant HTML elements.”_
> 
> “_The Invoke-RestMethod cmdlet sends HTTP and HTTPS requests to Representational State Transfer (REST) web services that return richly structured data. PowerShell formats the response based on the data type. For an RSS or ATOM feed, PowerShell returns the Item or Entry XML nodes. For JavaScript Object Notation (JSON) or XML, PowerShell converts, or deserializes, the content into objects.”_

Breaking down how each tool is described, curl aims to be the premiere solution for transferring data from or to a server over many protocols.

Contrast that with the `Invoke-WebRequest` and `Invoke-RestMethod` PowerShell cmdlets that focus on more common communications with servers. These PowerShell cmdlets also provide a rich experience for working with returned data through PowerShell’s use of objects.

## Long Parameters in Bash vs. PowerShell

Since curl isn’t a scripting language like PowerShell is, it relies on the command shell it’s executed from. Most of the time that command shell is Bash.

Both the PowerShell cmdlets and curl both may require different parameters that may extend far past a terminal’s width. To make the syntax easier to read, each shell scripting language has its own way of handling this.

Take the below code for example. This example demonstrates sending an HTTP POST verb to a URL using a small bit of data. This code _could_ be placed on one line but it would soon begin to wrap the screen or require scrolling. To remediate this, in Bash, you can use backslashes to continue the command onto a new line.

```powershell
curl --header "Content-Type: application/json" \
      --request POST \
      --data '{"title":"test post","user":2}' \
        https://jsonplaceholder.typicode.com/posts
```

Contrast the line-wrapping method with PowerShell using either cmdlet. By using [splatting](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_splatting), you can structure the same request performing the same task.

```powershell
$param = @{
    Uri         = "<https://jsonplaceholder.typicode.com/posts>"
    Method      = "Post"
    Body        = '{"title":"test post","user":2}'
    ContentType = "application/json"
}
Invoke-RestMethod @param
```

You can also mix and match the splatted and named parameters as shown below.

```powershell
$main = @{
    Uri         = "<https://jsonplaceholder.typicode.com/posts>"
    ContentType = "application/json"
}
$param = @{
    Method      = "Post"
}

Invoke-RestMethod @main @param -Body '{"title":"test post","user":2}'
```

## Working with REST APIs

[REST APIs](https://www.smashingmagazine.com/2018/01/understanding-using-rest-api/) are a common feature tied to many products. Since querying REST APIs is a common use of both curl and the PowerShell cmdlets, let’s first compare and contrast the various ways these two tools handle them.

> _Note that the tasks you’ll be learning will work just as well with standard HTTP URIs. Both curl and the PowerShell cmdlets will work with any HTTP endpoint._

### Getting Data From a REST API

First up, the easiest task to demonstrate is getting a response from a REST API. Both curl and the PowerShell cmdlets can do this with a single URI parameter as shown below. You can see below that each immediately returns the JSON response’s body.

```powershell
> curl <https://jsonplaceholder.typicode.com/todos/1>
```

![JSON Response](https://adamtheautomator.com/wp-content/uploads/2020/06/Untitled-86.png)

JSON Response

```powershell
PS> Invoke-WebRequest '<https://jsonplaceholder.typicode.com/todos/1>'
PS> Invoke-RestMethod '<https://jsonplaceholder.typicode.com/todos/1>'
```

![Invoke-WebRequest](https://adamtheautomator.com/wp-content/uploads/2020/06/Untitled-87.png)

Invoke-WebRequest

The `Invoke-RestMethod` cmdlet, unlike `Invoke-WebRequest`, automatically converts response data from JSON to PowerShell objects. But you can do the same with `Invoke-WebRequest` by using the  `ConvertFrom-Json` cmdlet as shown below.

```powershell
(Invoke-WebRequest '<https://jsonplaceholder.typicode.com/todos/1>').Content |
    ConvertFrom-Json
```

### Submitting Data to a REST API

Curl and PowerShell cmdlets can also submit data to a URI using the POST verb. When submitting data via POST, you’ll usually include a body as well which both tools are capable of.

You can see below using the `--request` parameter for curl and the `Method` parameter with `Invoke-RestMethod`, you can specify the verb. For the body, you’ll use the `--data` parameter in curl and  the `Body` parameter with `Invoke-RestMethod`.

```powershell
curl <https://jsonplaceholder.typicode.com/posts> --request POST --data "title=test post&user=2"

Invoke-RestMethod <https://jsonplaceholder.typicode.com/posts> -Method Post -Body @{title="test post";user=2}
```

By default, curl and `Invoke-RestMethod` will send POST requests using a content type of `application/x-www-form-urlencoded.`

If the API only allows a specific content type or you’ll need to manually specify a one via a parameter. Below you can see that curl uses the more generic `header` parameter while the `Invoke-RestMethod` cmdlet allows you to specify the content type separately using the `ContentType` parameter.

```powershell
## Curl
--header "Content-Type: application/json"

## Invoke-RestMethod
-ContentType application/json
```

> _You can also use curl’s shortcut `-H` parameter instead of `--header`._

#### Using Custom Headers

In the above example, you saw how you could pass the content-type header to a URI using both curl and PowerShell. You can also add more at the same time if you’d wish.

To add more headers in curl, you’ll simply add another `--header` or `-H` providing the key and value of the header you’d like to send as shown below.

```powershell
curl -H "Content-Type: application/json" \
      -H "Accept: application/json" \
      --request POST \
      -d '{"title":"test post","user":2}' \
         https://jsonplaceholder.typicode.com/posts
```

You can do the same in PowerShell also as shown below. By passing a hashtable with headers’ key/value pairs to the `Headers` parameter, you can send as many headers as you’d like.

```powershell
$param = @{
    Uri     = "<https://jsonplaceholder.typicode.com/posts>"
    Body    = @{ title = "Test" }
    Method  = "Post"
}
Invoke-RestMethod @param -Headers @{ Accept = "application/json" }
```

### Parsing the HTTP Response

Now that you have seen how to get simple data, let’s extract some useful information from it.

One big advantage of using PowerShell vs. curl is the native ability to parse the response. Since curl is a utility and not a scripting language, you’ll typically need to use another utility to parse the response. To level the playing field, you’ll see many people parsing curl’s response using Python or Perl or using a tool called [jq](https://stedolan.github.io/jq/). Jq is a utility that allows you to parse JSON data.

To demonstrate parsing, using the previous example, perhaps you’d like to extract only the title from the response. The example below uses curl to explicitly specify to use the GET verb using the `--request` parameter (curl defaults all requests to GET). The example is also using the silent `-s` parameter to avoid some on-screen statistics.

```powershell
curl https://jsonplaceholder.typicode.com/todos/1 --request GET -s | jq .title
```

![Using Curl](https://adamtheautomator.com/wp-content/uploads/2020/06/Untitled-88.png)

Using Curl

Since you learned that the main difference between the `Invoke-WebRequest` cmdlet and the `Invoke-RestMethod` cmdlet is `Invoke-RestMethod`‘s native ability to parse the response, let’s skip `Invoke-WebRequest` in this example.

Below you will see, as with curl, explicitly specifying the GET method changes nothing. Also notice that the command and parameter is enclosed in parentheses. This allows you to then reference the object property `Title` using dot notation.

```powershell
(Invoke-RestMethod https://jsonplaceholder.typicode.com/todos/1 -Method Get).Title
```

![Using Invoke-RestMethod to query web page](https://adamtheautomator.com/wp-content/uploads/2020/06/Untitled-89.png)

Using Invoke-RestMethod to query web page

## Scraping a Webpage

When you pull data from a webpage, you will probably want to do additional processing on the output. In Bash, that may mean using an HTML parser like [`hxselect`](https://www.w3.org/Tools/HTML-XML-utils/man1/hxselect.html) provided by the package `html-xml-utils`. In contrast, PowerShell’s `Invoke-WebRequest` cmdlet can parse much of what you want automatically.

To demonstrate, let’s extract all HTML `<a>` references from [www.google.com](http://www.google.com/).

In Bash, you’ll need the `html-xml-utils` package installed. To query a webpage and parse it with `hxselect`, you have to normalize the web response to xhtml (`-x`) format. You’ll also need to use a text processing tool, like Grep to filter and select the output.

The example command below is using Grep’s Regex matching (`-P`) and only-matched (`-o`) to split out the results onto their own lines:

```powershell
curl https://www.google.com -s \
     | hxnormalize -x | hxselect "a" \
     | grep -Po '(?<=href=")[^\"]+(?=")'
```

![Scraping a web page with Curl](https://adamtheautomator.com/wp-content/uploads/2020/06/Untitled-91.png)

Scraping a web page with Curl

In PowerShell, you’ll only need to specify that you want the href property from the links in these `<a>` tags.

```powershell
(Invoke-WebRequest www.google.com).links.href
```

![Scraping a webpage with Invoke-WebRequest](https://adamtheautomator.com/wp-content/uploads/2020/06/Untitled-90-1.png)

Scraping a webpage with Invoke-WebRequest

## Submitting a Form

Forms are used for many things, such as login, search, uploads, etc. While PowerShell can easily select forms from a webpage and provide a hashtable to fill out, using Curl + Bash requires more work.

In PowerShell, you must first gather a form, fill it out, then submit it. The example below is calling  `$Form.fields` to view all of the available fields of the form. `$Result` is then populated with the response and you can inspect the google results through `$Result.links.`

```powershell
$Form = (Invoke-WebRequest www.google.com).forms[0]
$Form.fields['q'] = "Best PowerShell cmdlets"
$Result = Invoke-WebRequest -Uri "www.google.com$($Form.Action)" -Body $Form.Fields
```

Using Curl, you have to work to find the fields and then specify them yourself. The output of the first command shows me that there is a `q` form field I can use for search queries. I then specify data to be filled for that field when submitting the request:

```powershell
curl https://www.google.com -s \
      | hxnormalize -x | hxselect "form" | hxselect "input" \
      | grep -Po ""
 curl -F q="Curl is amazing at some things" https://www.google.com
```

![Using curl to submit a form](https://adamtheautomator.com/wp-content/uploads/2020/06/Untitled-92.png)

Using curl to submit a form

## Using a Web Session / Cookies

When you need to save cookies between commands, such as a website login to access private pages, you’ll also want your cookies saved between sessions.

Curl asks you to use a “cookie jar” to hold these cookies which you can then use as your input “cookies” once logged in. You’ll have to do some work to find the actual form submission data that you need.

Using curl, you can specify a username and password to authenticate and a place for the curl “cookie jar”. Then, using the cookie obtained from that call, specify the “cookie jar” in the subsequent call as shown below.

```powershell
curl --user <username>:<password> --cookie-jar ./filename <https://someSite.com>
curn --cookie ./filename <https://someSite.com/important>
```

PowerShell also allows you to store and use cookies/sessions as well using the `Invoke-WebRequest` cmdlet’s `SessionVariable` parameter.

The `SessionVariable` will store the cookie returned. Once complete, you can then use the `WebSession` parameter to pass that cookie to subsequent requests. Below you can see an example of filling out a form and using the same cookie returned when the form was queried earlier.

```powershell
$result = Invoke-WebRequest -Uri https://someSite.com  -SessionVariable ss
$LoginForm = $result.Forms[0]
$LoginForm.Fields["user"] = "username"
$LoginForm.Fields["password"] = "password"
$result = Invoke-WebRequest -Uri $LoginForm.Action -WebSession $ss -Method Post
```

## Summary

PowerShell’s web cmdlets `Invoke-WebRequest` and `Invoke-RestMethod` are useful web querying and parsing cmdlets. They hold some similarity to curl, but, as you’ve seen, both tools are different in their approach.

Since the cmdlets are part of the PowerShell scripting language, they are built with PowerShell in mind. The PowerShell approach differs from the curl utility in that regard because curl has to rely on other languages and tools to perform the same tasks.

## Related Links

For a handy PowerShell module that will convert many curl commands to PowerShell format, please check out [Curl2PS](https://github.com/ThePoShWolf/Curl2PS).

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-curl%2F&text=PowerShell%20vs.%20Curl%3A%20A%20Side-by-Side%20Comparison)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-curl%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fpowershell-curl%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/publisher/3ec5d9c85b2b8183bec6e5cc0f0356c5/a323a4d03629188de1d5ed18ca60a64a65f94bef73d5390488bde5511859fa05.webp)

### [AZ-800 vs. AZ-802: Avoid the Wrong Windows Server Exam](/az-800-vs-az-802/)

See what the AZ-800 retirement means for your Windows Server certification path and how to re-weight your study plan around the current AZ-802 exam.

![](https://adamtheautomator.com/wp-content/uploads/publisher/3ec5d9c85b2b811089d5d31807a89aa3/4f6fca0bf1e9083ef5217f16ceed8f939aa4f322e0b4be8d8e3dbb7be8ca3114.webp)

### [Automate Windows 11 Context Menu Actions with Registry](/automate-windows-11-context-menu-registry/)

Add custom right-click actions to Windows 11 context menus by editing registry verbs, deploying .reg files, and scripting with PowerShell.

![](https://adamtheautomator.com/wp-content/uploads/publisher/3ec5d9c85b2b81d9ab7cd5dbb6caf044/21b786d67f19d1813150edf9871e36ead78714b63880de8c6161c7fde11a9769.webp)

### [Pktmon: Capture Windows Traffic Without a Third-Party Driver](/pktmon-capture-windows-traffic/)

Use the in-box Windows Pktmon tool to capture packets and packet-drop reasons, then convert the ETL to pcapng and text for offline analysis.

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
