Powershell Invoke-RestMethod over HTTPS Powershell Invoke-RestMethod over HTTPS powershell powershell

Powershell Invoke-RestMethod over HTTPS


I solved the mystery while troubleshooting another thing. The web server in question only supported TLS1.1 and TLS1.2. Powershell does NOT seem to support that. If I enabled TLS1.0 it worked.

To force TLS1.2 you can use this line:

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

Hope that helps someone else and thanks for all helpful comments!

/Patrik


It appears you're trying to invoke a json API with Invoke-RestMethod. According to the documentation:

-ContentType

Specifies the content type of the web request.

If this parameter is omitted and the request method is POST, Invoke-RestMethod sets the content type to "application/x-www-form-urlencoded". Otherwise, the content type is not specified in the call.

To use a json body, you will need to use Invoke-RestMethod -ContentType 'application/json' <other args>


I went through a lot of pain recently in order to get past a similar situation. I was creating a proof of concept using a trial SaaS service. The service had a self-signed SSL certificate so I wanted to ignore certificate errors while attempting to invoke a POST method to it (similar to the "-k" parameter for curl). After much struggle, I found that it needed both - (a) the call to ignore cert validation errors and (b) an explicit setting for TLS 1.2 as the security protocol. I think the latter because the service was perhaps declining attempts to connect using any of the other protocols. (I spent too much time trying the different variations for doing each as suggested on various SOF threads but independently...)

Here's the code that worked...

Important: The cert validation bypass is purely for the prototype/PoC. We do not intent to do this in production (and you shouldn't either!).

$defaultSecurityProtocol = $nulltry{       #BUGBUG, TODO: Disabling cert validation for the duration of this call...('trial' version cert is self-signed.)    #Remove this after the PoC.    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }     #Cache the previous protocol setting and explicitly require TLS 1.2     $defaultSecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol    [System.Net.ServicePointManager]::SecurityProtocol = `                [System.Net.SecurityProtocolType]::Tls12    if (-not [String]::IsNullOrWhiteSpace($authZHeaderValue))    {        $response = Invoke-WebRequest `                    -Uri $webhookUrl `                    -Method "Post" `                    -Body $eventJson `                    -Header @{ $authZHeaderName = $authZHeaderValue}     }    else     {        $response = Invoke-WebRequest `                    -Uri $webhookUrl `                    -Method "Post" `                    -Body $eventJson    }}catch {    $msg = $_.Exception.Message    $status = $_.Exception.Status    $hr = "{0:x8}" -f ($_.Exception.HResult)    $innerException = $_.Exception.InnerException    #Just issue a warning about being unable to send the notification...    Write-Warning("`n`t[$status] `n`t[0x$hr] `n`t[$msg] `n`t[$innerException]")}finally {    # Set securityProtocol and CertValidation behavior back to the previous state.    [System.Net.ServicePointManager]::SecurityProtocol = $defaultSecurityProtocol        [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $null}

Also want to add that the preferred security protocols keep changing as various vulnerabilities are discovered and fixes implemented. Moreover, different systems (SSL/TLS stacks in client OSes and servers/services) often have their own catching up to do with the latest/most secure options. Thus exactly which flag might work will be a function of the client and server systems and also of time (in that TLS1.2 might not remain preferred a few months later). Ideally one shouldn't need to specify a flag at all. Please see the "Remarks" section in this MSDN document for more.