I'm trying to communicate with a service over powershell but I am failing miserably. I suspect it is the certificate and I have googled for the answer and found two options, none of which worked for me. I have also tried to combine the two unsuccessfully.
Option 1:
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
$urlJSON = "https://internal.ad.local/path/api_jsonrpc.php"
#Create authentication JSON object using ConvertTo-JSON
$objAuth = (New-Object PSObject | Add-Member -PassThru NoteProperty jsonrpc '2.0' |
Add-Member -PassThru NoteProperty method 'user.authenticate' |
Add-Member -PassThru NoteProperty params @{user="user";password="password"} |
Add-Member -PassThru NoteProperty id '2') | ConvertTo-Json
Invoke-RestMethod -Uri $urlJSON -body $objAuth -method "Post"
Option 2:
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
$urlJSON = "https://internal.ad.local/path/api_jsonrpc.php"
#Create authentication JSON object using ConvertTo-JSON
$objAuth = (New-Object PSObject | Add-Member -PassThru NoteProperty jsonrpc '2.0' |
Add-Member -PassThru NoteProperty method 'user.authenticate' |
Add-Member -PassThru NoteProperty params @{user="user";password="password"} |
Add-Member -PassThru NoteProperty id '2') | ConvertTo-Json
Invoke-RestMethod -Uri $urlJSON -body $objAuth -method "Post"
Here's the error message:
Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
At C:\Users\user\AppData\Local\Temp\46eaa6f7-62a0-4c10-88d1-79212d652bc9.ps1:24 char:1
+ Invoke-RestMethod -Uri $urlJSON -body $objAuth -method "Post"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
I might add:
- surfing directly to the service works with a web browser
- I tried opening up to HTTP as well, and that worked
- The certificate used by the service is self-signed but trusted by my machine via a root certficate (no warnings is issues in IE or Chrome)
- I have done network captures and made sure that a packets does indeed reach the server.
Any suggestions appreciated!
Kind regards, Patrik
Updated post as to suggestions made by Mr Tree below:
Name : lambda_method
DeclaringType :
ReflectedType :
Module : RefEmit_InMemoryManifestModule
MethodHandle :
Attributes : PrivateScope, Public, Static
CallingConvention : Standard
IsSecurityCritical : False
IsSecuritySafeCritical : False
IsSecurityTransparent : True
ReturnType : System.Boolean
ReturnParameter :
ReturnTypeCustomAttributes : System.Reflection.Emit.DynamicMethod+RTDynamicMethod+EmptyCAHolder
MemberType : Method
MethodImplementationFlags : NoInlining
IsGenericMethodDefinition : False
ContainsGenericParameters : False
IsGenericMethod : False
IsPublic : True
IsPrivate : False
IsFamily : False
IsAssembly : False
IsFamilyAndAssembly : False
IsFamilyOrAssembly : False
IsStatic : True
IsFinal : False
IsVirtual : False
IsHideBySig : False
IsAbstract : False
IsSpecialName : False
IsConstructor : False
CustomAttributes :
MetadataToken :
Update 2 based on a comment by Mr Tree:
Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
At C:\Users\user\AppData\Local\Temp\ff47910e-fd8e-4be8-9241-99322144976a.ps1:13 char:1
+ Invoke-RestMethod -Uri $urlJSON -body $objAuth -method "Post"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
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 = $null
try
{
#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.
来源:https://stackoverflow.com/questions/32355556/powershell-invoke-restmethod-over-https