Press "Enter" to skip to content

Converting cURL to PowerShell for REST APIs

Joshua Stenhouse 0

Everyone has their preferred scripting language in which you are comfortable, others not so much, and this is especially true in the IT infrastructure space. I occasionally meet people who are proficient in many languages and these people tend to be programmers, annoying gits, or both (joking, it’s jealously really). Like many people who started out as windows admins I’m strong in PowerShell and I’ve learned how to work with REST APIs. But, what happens when you’re trying to use a modern REST API via swagger and the only example given is in cURL?  In this post I’m going to give you 2 simple solutions to this problem.

The first solution is a bit of a cheat and isn’t really converting it, but it is useful if you are running on Windows 10. You can simply install the Windows Subsystem for Linux, load the disti of your choice (I used Ubuntu) then copy the cURL example direct into the terminal/shell:

https://docs.microsoft.com/en-us/windows/wsl/install-win10

One catch is that I see many cURL examples from REST APIs don’t give you the full script needed to run the command. The curse of “presumed knowledge” in IT will catch you out. They think that you know exactly what else is required to get the cURL command to work, but you’re a PowerShell user. This isn’t your bag. So, here’s an example from the Rubrik swagger UI:

curl -X POST --header
'Content-Type: application/json' --header 'Accept: application/json' -d '{}'
'https://192.168.1.201/api/internal/managed_volume/ManagedVolume%3A%3A%3Ab03f6e8a-9690-49f2-9e6e-578204ce3e46/begin_snapshot'

This command is missing credentials for authentication and handling of an untrusted certificate (common in IT infrastructure). What you need is­­:

USER_PASS="admin:Srt1234!"
curl -u $USER_PASS -X POST --header 'Content-Type: application/json' --insecure -d '{}' 'https://192.168.1.201/api/internal/managed_volume/ManagedVolume%3A%3A%3Ab03f6e8a-9690-49f2-9e6e-578204ce3e46/begin_snapshot'

If you installed the Linux subsystem and followed my example you’ve now successfully run a cURL command in Windows. But I promised you conversion to PowerShell and so that’s what we will do next.

I recommend using PowerShell 6+ as it natively handles untrusted certificates and TLS 1.2. For interacting with REST APIs the equivalent of cURL in PowerShell is Invoke-RestMethod. Using this, here’s the same cURL command converted:

$Header =
@{"Authorization" = "Basic
"+[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("admin:Srt1234!"))}
Invoke-RestMethod -Method POST -Header $Header -ContentType "application/json" -SkipCertificateCheck -uri "https://192.168.1.201/api/internal/managed_volume/ManagedVolume:::b03f6e8a-9690-49f2-9e6e-578204ce3e46/begin_snapshot"

Let’s breakdown what I did here with the help of a diagram:

To explain:

  1. cURL natively converts credentials into a base64 string, in PowerShell you need to convert it with this command (this is the most complex difference) and embed the credentials in the header.
  2. The cURL equivalent for interacting with REST APIs in PowerShell is Invoke-RestMethod.
  3. With cURL the credentials are specified using -u which it in turns uses to construct the header, we already constructed the header in step 1 so we don’t need a credential flag in PowerShell.
  4. The method (GET ,POST, PUT etc) is signified by -X in cURL, in PowerShell its -Method.
  5. In cURL we are adding the content type to the header, in PowerShell we specify the content with -ContentType.
  6. To bypass warning on insecure certificates on the URL we are working with use –insecure in cURL, in PowerShell 6.0 we use -SkipCertificateCheck.
  7. In cURL we are just specifying the URL at the end of the command. In PowerShell you should specify it after -uri (Uniform Resource Identifier, this case the URL)
  8. The endpoint in my example doesn’t require any data so we are specifying null with -d. We could remove this section from cURL and if we were to specify this in PowerShell it would be with -Body.

Next time anybody says PowerShell isn’t as simple as cURL for working with REST APIs you can now call them out. The only major difference is PowerShell needs a little help converting the credentials to base64, whereas its native in a shell script.

The final example I’ll give covers converting cURL to PowerShell 5.1. Admittedly this isn’t as pretty if the endpoint is using an untrusted certificate and requires TLS 1.2, both native to PowerShell 6.0+. Accommodating for both these scenarios here is the script and cURL command converted to PowerShell 5.1:

# Adding certificate exception and TLS 1.2 
add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Now run the same command as PowerShell 6, minus the -SkipCertificateCheck flag
$Header = @{"Authorization" = "Basic "+[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("admin:Srt1234!"))}
Invoke-RestMethod -Method POST -Header $Header -ContentType "application/json" -uri "https://192.168.1.201/api/internal/managed_volume/ManagedVolume:::b03f6e8a-9690-49f2-9e6e-578204ce3e46/begin_snapshot"

I hope you found this useful. Let me know via the drift chat if you have any questions or need more examples. Happy scripting,

@JoshuaStenhouse

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: