Powershell通过HTTPS调用RestMethod

时间:2015-09-02 14:13:29

标签: powershell ssl https self-signed invoke-command

我正在尝试通过powershell与服务进行通信但我失败了。我怀疑这是证书,我搜索了答案,找到了两个选项,其中没有一个对我有用。我也尝试将两者合并失败。

选项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"

选项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"

以下是错误消息:

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

我可以补充一下:

  • 使用网络浏览器直接浏览服务
  • 我也尝试过打开HTTP,这很有效。
  • 该服务使用的证书是自签名的,但我的机器通过root certficate信任(IE或Chrome中没有警告)
  • 我已完成网络捕获,并确保数据包确实到达服务器。

任何建议都赞赏!

亲切的问候, 帕特里克

以下关于树先生提出的建议的更新帖子:

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              :

根据树先生的评论更新2:

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

3 个答案:

答案 0 :(得分:36)

我在解决另一件事时解开了这个谜团。有问题的Web服务器仅支持TLS1.1和TLS1.2。 Powershell似乎并不支持这一点。如果我启用TLS1.0就可以了。

要强制使用TLS1.2,您可以使用以下行:

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

希望能帮助别人并感谢所有有用的评论!

/帕特里克

答案 1 :(得分:0)

您似乎正在尝试使用Invoke-RestMethod调用json API。根据{{​​3}}:

  

-ContentType

     

指定Web请求的内容类型。

     

如果省略此参数且请求方法为POST ,   Invoke-RestMethod将内容类型设置为   的"应用程序/ X WWW的窗体-urlencoded" 即可。否则,内容类型是   未在通话中指定。

要使用json正文,您需要使用Invoke-RestMethod -ContentType 'application/json' <other args>

答案 2 :(得分:0)

我最近经历了很多痛苦,以便克服类似的情况。我正在使用试用SaaS服务创建概念证明。该服务具有自签名SSL证书,因此我想在尝试向其调用POST方法时忽略证书错误(类似于curl的“-k”参数)。经过多次努力,我发现它需要两者 - (a)忽略证书验证错误的调用和(b)作为安全协议的TLS 1.2的显式设置。我认为后者是因为该服务可能正在减少使用任何其他协议进行连接的尝试。 (我花了太多时间尝试不同的变化来做各自的SOF线程建议,但独立......)

这是有效的代码......

重要:证书验证旁路纯粹是针对原型/ PoC。我们不打算在生产中这样做(你也不应该这样做!)。

$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
}

还想补充一点,首选的安全协议会随着各种漏洞的发现和修复的实施而不断变化。此外,不同的系统(客户端操作系统和服务器/服务中的SSL / TLS堆栈)通常会有最新的/最安全的选项。因此,确切地说哪个标志可能起作用将是客户端和服务器系统以及时间的函数(因为几个月之后TLS1.2可能不会保持优先)。理想情况下,根本不需要指定标志。有关详情,请参阅this MSDN document中的“备注”部分。