PowershellのInvoke-RestMethodをhttpsに実施すると失敗する

PowershellのInvoke-RestMethodでhtppsのuriにRESTしようとしたらはまったのでメモ。Invoke-RestMethod自体はかなり便利でちょっと感動したので、前半はその紹介です。

Invoke-RestMethod

Powershell3.0からInvoke-RestMethodが追加され、WindowsからもLinux系でいうCurlのようなことができるようになりました。最近PowershellでInvoke-RestMethodを使ったスクリプトを書いたのですが、json形式のデータをRESTで取得してゴニョゴニョするのはLinuxからCurlよりもはるかに簡単だと思います。
例えば、RESTで以下のようなjson形式のデータを取得する場合は、

{"name":"John","age":"25"}

こんな感じで書くことができます。

>$var = Invoke-RestMethod -Uri http://xxxxxx/api/userlist -Method Get
>echo $var.name
John

jsonのデータはPowershell側で勝手にパースしてくれます。Linuxからbashでやろうと思うとcurlでとってきたものをawkして…とかやらないとだめですが、Powershellなら不要です。

httpsのURLにInvoke-RestMethodをする場合の注意点

自分はこれで結構はまってしまいました。問題の切り分けができなくて半日くらいかかったと思います…
具体的にはInvoke-RestMethodのuriがhttpsで、かつ相手のSSLサーバ証明書が自己証明書の場合には以下のようなエラーが起こります。私の場合は内部の管理サーバ(自己証明書)に向けてInvoke-RestMethodしてたのでエラーになりました。

 Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
 At line:8 char:11

ググってみると以下のようにすればOK!と結構いろいろなところに書いてありますが、これだけではダメでした。

 [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

実際にこの状態で実行すると以下のようにエラーの表示が変わるだけ。

Invoke-WebRequest : The underlying connection was closed: An unexpected error occurred on a send. 

さらにググるとこんなページが!この人、自分とまったく同じ状況やんけ!

.net - Powershell v3 Invoke-WebRequest HTTPS error - Stack Overflow

結局、解としては以下のようです。

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

httpsの場合にはSSLサーバ証明書のチェックをしていて自己証明書の場合は弾くのがデフォルトのようです。
上のコードではCertificatePolicyの「CheckValidationResult」メソッドを上書きして無条件にTrueを返すようにしている…といった感じでしょうか。上記をスクリプトに追加したところhttpsでも問題なく動作するようになりました。