PowerShellでREST APIと連携する ── Invoke-RestMethodの実務

· · PowerShell, REST API, Windows, 自動化, 業務システム, 連携, JSON, 運用改善

更新履歴(初版のみ・2026年07月25日公開)
初版公開
この記事を引用する(DOI: 10.5281/zenodo.21547449)

この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。

小村 豪(2026)「PowerShellでREST APIと連携する ── Invoke-RestMethodの実務」合同会社小村ソフト. https://doi.org/10.5281/zenodo.21547449

DOI(最新版)
10.5281/zenodo.21547449
DOI(この版)
10.5281/zenodo.21547450

「基幹システムのWeb APIから受注データを取得して、社内のExcel帳票に落とす」「SaaSの勤怠APIを毎朝叩いて、当日の出勤予定を出力する」── PowerShellが業務で使われる場面のうち、ここ数年で明確に増えたのがREST API連携です。専用ツールを買うほどではないが、手作業では回らない。その隙間を埋める道具として、Invoke-RestMethod は非常に強力です。

一方で、動くところまでは簡単でも、運用に載せると途端に難しくなるのがAPI連携の特徴でもあります。日本語が文字化けする、エラー応答の中身が読めない、たまに429で失敗する、プロキシ環境で通らない、Windows PowerShell 5.1だけTLSで弾かれる。どれも「相手のあるシステム」ならではの問題です。

この記事では、社内でPowerShellからAPIを呼んでいる情シス・開発者に向けて、認証、JSON送受信、エラー処理、リトライ、ページング、そして5.1特有の落とし穴までを、実務で必要な順に整理します。

1. まず結論

  • JSON/XMLのAPIなら Invoke-RestMethod応答を自動でオブジェクト化します。ステータスコードやヘッダーが要るなら Invoke-WebRequest、または -StatusCodeVariable / -ResponseHeadersVariable を使います。12
  • 認証はヘッダーで渡すのが最も汎用的です。PowerShell 6以降は -Authentication Bearer -Token(SecureString)も使えます。1
  • 日本語JSONはUTF-8バイト配列で送るのが確実です。-ContentTypecharset=utf-8 を明示します。
  • ConvertTo-Json の既定の深さは2です。入れ子が深いオブジェクトは -Depth を指定しないと切り捨てられます。3
  • 4xx/5xxは終了エラーになります。PowerShell 7以降は $_.ErrorDetails.Message で本文を読めます。-SkipHttpErrorCheck で例外化を止める選択肢もあります。1
  • 429は Retry-After に従って待ちます。-MaximumRetryCount を指定すれば組み込みが自動追従します。ただし組み込みの再試行は400〜599(と304)すべてが対象で、401や404も再送されます。コード別の扱いや指数バックオフが必要なときだけ自前で実装します。1
  • POST のような非冪等な要求は自動再試行しないでください。通信エラーや5xxでもサーバー側は処理済みの場合があり、再送は二重登録になります。
  • Link ヘッダー方式のページングは -FollowRelLink で自動化できます。カーソル方式は自前ループです。1
  • Windows PowerShell 5.1には固有の落とし穴があります。-UseBasicParsing の要否、TLS 1.2の明示的な有効化、エンコーディングの扱いの3点です。4
  • -SkipCertificateCheck は恒久運用で使いません。社内CAを信頼させるのが正しい対処です。

2. Invoke-RestMethod と Invoke-WebRequest

まず違いを押さえます。12

  Invoke-RestMethod Invoke-WebRequest
応答の扱い JSON/XMLを自動でオブジェクト化 WebResponseObject(生の本文・ヘッダー・コード)
主な用途 REST API HTMLの取得、ステータスやヘッダーの参照
ステータスコード -StatusCodeVariable で取得(PS7+) .StatusCode
ヘッダー -ResponseHeadersVariable で取得(PS6+) .Headers

APIを叩くなら基本は Invoke-RestMethod です。ヘッダーやコードが必要な場面でも、専用の変数パラメーターで取得できます。

$data = Invoke-RestMethod -Uri 'https://api.example.co.jp/v1/orders' `
        -Headers @{ Authorization = "Bearer $token" } `
        -StatusCodeVariable status -ResponseHeadersVariable headers -TimeoutSec 30

"HTTP $status / 残りリクエスト数: $($headers['X-RateLimit-Remaining'])"
$data.items | Select-Object orderId, customerName, amount

3. 認証の渡し方

いちばん汎用的なのはヘッダーに直接書く方法で、5.1でも7でも同じように動きます。

# (1) Bearerトークン(最も一般的)
$headers = @{ Authorization = "Bearer $accessToken"; Accept = 'application/json' }
Invoke-RestMethod -Uri $uri -Headers $headers

# (2) APIキー(ヘッダー名は提供側の仕様に従う)
$headers = @{ 'X-Api-Key' = $apiKey }

# (3) Basic認証(PowerShell 6以降は -Authentication が使える)
Invoke-RestMethod -Uri $uri -Authentication Basic -Credential $cred

# (4) Bearerを -Token で渡す(PowerShell 6以降。SecureStringで扱える)
Invoke-RestMethod -Uri $uri -Authentication Bearer -Token $secureToken

# (5) クライアント証明書
Invoke-RestMethod -Uri $uri -Certificate $cert

-Authentication を使う場合、PowerShellはHTTPS以外での使用を既定で拒否します(-AllowUnencryptedAuthentication で回避できますが、平文で資格情報が流れるので使うべきではありません)。1

トークンやAPIキーをスクリプトに直接書かないことは大前提です。SecretManagementを使った保管方法は「PowerShellでの資格情報の安全な扱い」にまとめています。

4. JSONを送る ── 日本語と-Depthの罠

送信で確実に踏むのが文字化け入れ子の切り捨てです。

ConvertTo-Json-Depth既定が2で、それより深い階層は展開されずに型名の文字列などに置き換わります。3 入れ子のあるリクエストボディでは必ず指定してください。

$body = @{
    order = @{
        customer = @{ code = 'C001'; name = '株式会社サンプル' }   # 3階層目
        lines    = @( @{ item = 'A-100'; qty = 3 } )
    }
}

# 【NG】既定の -Depth 2 では customer や lines の中身が失われる
$json = $body | ConvertTo-Json

# 【OK】十分な深さを指定する
$json = $body | ConvertTo-Json -Depth 10

文字化け対策は、UTF-8のバイト配列にしてから送るのが最も確実です。

$json  = $body | ConvertTo-Json -Depth 10
$bytes = [System.Text.Encoding]::UTF8.GetBytes($json)

$res = Invoke-RestMethod -Uri $uri -Method Post `
       -Headers @{ Authorization = "Bearer $token" } `
       -ContentType 'application/json; charset=utf-8' `
       -Body $bytes -TimeoutSec 60

PowerShell 7では文字列をそのまま渡してもUTF-8で送られますが、5.1と共用するスクリプトではバイト配列にしておくと環境差を吸収できます。Windows全般の文字コード事情は「Windowsの文字コードと改行コード」を参照してください。

5. エラー処理 ── 本文が読めないと調査できない

Invoke-RestMethod は、4xx/5xxの応答を終了エラーとして扱います。つまり try/catch で捕まえられますが、APIが返したエラーメッセージ本文をどう読むかが問題になります。

try {
    $res = Invoke-RestMethod -Uri $uri -Method Post -Body $bytes `
           -ContentType 'application/json; charset=utf-8' -TimeoutSec 30
}
catch {
    $status = $_.Exception.Response.StatusCode      # 例: BadRequest / 400
    # PowerShell 7以降はレスポンス本文がここに入る(APIのエラーメッセージ)
    $detail = $_.ErrorDetails.Message
    Write-Warning "API失敗 ($status): $detail"
    throw
}

「HTTP 400が返ってきたが、なぜ拒否されたのか分からない」という調査で時間を溶かさないために、エラー本文は必ずログに残す設計にしてください。

ステータスコードで分岐したい処理では、-SkipHttpErrorCheck を使って例外化を止めるほうが素直に書けます(PowerShell 7以降)。1

$res = Invoke-RestMethod -Uri $uri -SkipHttpErrorCheck -StatusCodeVariable code -TimeoutSec 30
switch ($code) {
    200     { $res.items }
    404     { Write-Warning '対象が存在しません'; @() }
    { $_ -ge 500 } { throw "サーバー側エラー: $code" }
    default { throw "想定外の応答: $code" }
}

6. リトライ ── 429と一時的な失敗

PowerShell 6以降の Invoke-RestMethod には -MaximumRetryCount-RetryIntervalSec があり、失敗時に再試行します。しかも429応答に Retry-After が含まれる場合は、指定した間隔ではなくそのヘッダーの値が使われます1 つまり「レート制限に当たったら指示どおり待って再試行する」だけなら、組み込みの機能で足ります。

# レート制限対応だけなら、これで十分なことが多い
Invoke-RestMethod -Uri $uri -Headers $headers -MaximumRetryCount 4 -RetryIntervalSec 5

ただし、再試行の対象は429だけではありません。ドキュメントは「400〜599(および304)の失敗コードを受け取ったときに再試行する」と定めています。1 つまり401(認証エラー)、403(権限不足)、404(URLの誤り)のように、何度送っても直らない要求まで再試行されます。トークンの設定を間違えたまま無人実行すると、失敗と分かるまでに -MaximumRetryCount × -RetryIntervalSec 秒を空費し、APIには同じ無効な要求が繰り返し届きます。恒久的エラーで即座に止めたい場合は、この後の自前実装が必要です。

自前のリトライ関数が要るのは、次のような要求がある場合です。

  • ステータスコードごとに扱いを変えたい(400番台は即失敗、5xxだけ再試行など)
  • 指数バックオフにしたい(組み込みは指定間隔での再試行)
  • 失敗時にAPIのエラー本文をログへ残したい

以下はその形です。

function Invoke-KsApi {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)] [string] $Uri,
        [string] $Method = 'Get',
        [object] $Body,
        [hashtable] $Headers = @{},
        [ValidateRange(1, 10)] [int] $MaxAttempts = 4,
        # Retry-Afterがこれより長い待機を指示してきたら、待たずに中断する
        [ValidateRange(1, 86400)] [int] $MaxWaitSeconds = 300,
        # APIが冪等キーに対応している場合だけ、POSTなどの再試行を許可する
        [string] $IdempotencyKey
    )

    # 再試行してよいのは、同じ要求を2回受け取っても結果が変わらない場合だけ。
    # POST/PATCHは「サーバー側では成功したが応答が届かなかった」ケースがあり、
    # 単純に再送すると二重登録になる
    $idempotentMethods = 'Get', 'Head', 'Options', 'Put', 'Delete'
    $canRetry = ($Method -in $idempotentMethods) -or $IdempotencyKey
    if ($IdempotencyKey) { $Headers = $Headers + @{ 'Idempotency-Key' = $IdempotencyKey } }

    for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {
        $params = @{
            Uri                     = $Uri
            Method                  = $Method
            Headers                 = $Headers
            TimeoutSec              = 60
            SkipHttpErrorCheck      = $true          # コードで分岐したいので例外にしない
            StatusCodeVariable      = 'code'
            ResponseHeadersVariable = 'resHeaders'
        }
        # $Bodyの値が $false や 0、空文字列でも本文として送れるよう、
        # 真偽ではなく「引数が渡されたか」で判定する
        if ($PSBoundParameters.ContainsKey('Body')) {
            # パイプで渡すと空配列 @() が「入力0件」になり $null が返るため、
            # -InputObject で列挙させずにそのまま変換する(@() は [] になる)
            $json = ConvertTo-Json -InputObject $Body -Depth 10
            $params.Body        = [System.Text.Encoding]::UTF8.GetBytes($json)
            $params.ContentType = 'application/json; charset=utf-8'
        }

        # -SkipHttpErrorCheck が抑止するのはHTTPのエラー応答だけ。
        # タイムアウト・名前解決失敗・接続リセット・TLSエラーなど、応答が
        # 返ってこない通信エラーは例外として飛ぶので、ここで捕まえて再試行する
        try {
            $code = $null
            $res  = Invoke-RestMethod @params
        }
        catch {
            # 非冪等な要求は、応答が届かなかっただけでサーバー側は成功している
            # 可能性がある。自動再送せず、呼び出し元に判断を委ねる
            if (-not $canRetry) {
                throw "通信エラー($Method は再試行しません。処理済みかを確認してください): $($_.Exception.Message)"
            }
            if ($attempt -eq $MaxAttempts) { throw }
            $wait = [math]::Min([math]::Pow(2, $attempt), 60)
            Write-Warning "通信エラー: $($_.Exception.Message) ── $wait 秒後に再試行します ($attempt/$MaxAttempts)"
            Start-Sleep -Seconds $wait
            continue
        }

        if ($code -lt 400) { return $res }                    # 成功

        # 再試行する価値があるのは一時的エラーだけ。許可リスト方式で明示する
        # (405や415のような恒久的エラーを再試行すると、時間を浪費したうえ
        #  最後は「リトライ上限」という無関係なメッセージだけが残る)
        $retryable = @(408, 429, 500, 502, 503, 504)
        if ($code -notin $retryable) {
            throw "APIエラー ($code): $($res | ConvertTo-Json -Compress -Depth 3)"
        }
        # 5xxは「サーバー側で処理された後に失敗した」可能性があるため、
        # 非冪等な要求では再送しない。429も同様(処理前に弾かれたことの保証はない)
        if (-not $canRetry) {
            throw "APIエラー ($code)。$Method は自動再試行しません: $($res | ConvertTo-Json -Compress -Depth 3)"
        }

        if ($attempt -eq $MaxAttempts) {
            throw "リトライ上限に到達しました ($code): $($res | ConvertTo-Json -Compress -Depth 3)"
        }

        # Retry-Afterは「秒数」だけでなくHTTP日付形式で返ることもある。
        # そのまま[int]にキャストすると例外になり、リトライごと落ちる
        $wait = $null
        $retryAfter = if ($resHeaders) { $resHeaders['Retry-After'] | Select-Object -First 1 }
        if ($retryAfter) {
            $seconds = 0
            $date    = [datetime]::MinValue
            if ([int]::TryParse($retryAfter, [ref] $seconds)) {
                $wait = $seconds
            }
            elseif ([datetime]::TryParse($retryAfter,
                        [cultureinfo]::InvariantCulture,
                        [System.Globalization.DateTimeStyles]::AdjustToUniversal, [ref] $date)) {
                $wait = [math]::Max(0, [int]($date - [datetime]::UtcNow).TotalSeconds)
            }
        }
        if ($null -eq $wait) {
            $wait = [math]::Min([math]::Pow(2, $attempt), 60)             # 指数バックオフ(上限60秒)
        }
        elseif ($wait -gt $MaxWaitSeconds) {
            # サーバーの指示を勝手に切り詰めて早く再送すると、429を繰り返して
            # 上限に達するだけ。待てない長さなら、待ち時間を添えて呼び出し元に返す
            throw "レート制限中です。サーバーの指示した待機時間 $wait 秒が上限 $MaxWaitSeconds 秒を超えるため中断しました。時間をおいて再実行してください ($code)"
        }
        Write-Warning "HTTP $code ── $wait 秒後に再試行します ($attempt/$MaxAttempts)"
        Start-Sleep -Seconds $wait
    }
}

冪等性の扱いが2つ目のポイントです。GETPUT は同じ要求を2回受け取っても結果が変わりませんが、POST は違います。とくに「サーバー側では登録に成功したが、応答が返る前に通信が切れた」というケースでは、素朴に再送すると二重登録になります。上の実装では、冪等なメソッドか、APIが冪等キー(Idempotency-Key)に対応している場合だけ自動再試行を許可し、それ以外は「処理済みかを確認してください」と明示して止めています。

Retry-After を切り詰めないのも大事な点です。サーバーが「30分後に来い」と指示しているのに、上限を理由に5分で再送しても、返ってくるのは同じ429だけです。無駄な要求で試行回数を使い切ったうえ、最後には「リトライ上限」というメッセージしか残りません。上の実装では、指示された待機時間が -MaxWaitSeconds を超えたら短く待ち直すのではなく、待機時間を添えて即座に失敗させています。バッチ処理なら、この例外を受けて次回の実行に持ち越すか、指示どおりの時間だけ待つかを呼び出し元で選べます。

もうひとつのポイントは、再試行する対象を許可リストで明示していることです。「恒久的エラーだけを列挙して除外する」書き方にすると、そこに挙げ忘れたコード(405 Method Not Allowed、415 Unsupported Media Typeなど)が一時的エラー扱いになり、直るはずのない要求を繰り返したうえ、最後には「リトライ上限」という原因不明のメッセージだけが残ります。一時的だと分かっているコードだけを再試行し、それ以外はAPIのエラー内容ごと即座に失敗させるのが正解です。リトライ設計の一般論は「PowerShellのエラー処理と再実行設計」を参照してください。

7. ページング

APIが全件を一度に返すことはまずありません。方式は主に2つです。

(1) Link ヘッダー方式(GitHubなどが採用)は、-FollowRelLink で自動的に次ページをたどれます。1

# 次のページを自動でたどる(取得ページ数の上限も指定できる)
$all = Invoke-RestMethod -Uri $uri -Headers $headers -FollowRelLink -MaximumFollowRelLink 20

(2) カーソル/オフセット方式は自前でループします。

$items    = [System.Collections.Generic.List[object]]::new()
$cursor   = $null
$page     = 0
$maxPages = 100

do {
    $page++

    # 元のURIに既にクエリが付いているかで、区切り文字が変わる。
    # 常に ? を付けると .../items?status=active?cursor=... となり、
    # サーバーからはカーソルが status の値の一部に見えてしまう。
    # カーソル自体も不透明な文字列(+ & = # などを含みうる)なので必ずエンコードする
    $u = if ($cursor) {
        $sep = if ($uri.Contains('?')) { '&' } else { '?' }
        "$uri$sep" + "cursor=$([uri]::EscapeDataString($cursor))"
    }
    else { $uri }

    $res = Invoke-KsApi -Uri $u -Headers $headers
    $items.AddRange([object[]]$res.items)
    $cursor = $res.nextCursor

    # 打ち切りは必ず知らせる。黙って抜けると「全件取れた」と誤解される
    if ($page -ge $maxPages -and $cursor) {
        Write-Warning "ページ数の上限 ($maxPages) に達したため打ち切りました。取得漏れの可能性があります"
        break
    }
} while ($cursor)

"取得件数: $($items.Count)"

$itemsList[T] を使っているのは、+= による配列の再作成を避けるためです(「PowerShellスクリプトが遅いときに見るところ」)。

ページ数の上限を必ず設けるのも忘れないでください。サーバーが同じカーソルを返し続ける、あるいは nextCursor を空にし忘れる、という不具合は実際に起こります。上限がないと、そのときスクリプトは止まらないまま要求を投げ続けます。そして打ち切ったことは警告として表に出す必要があります。黙って break すると、呼び出し元は不完全な結果を全件だと思って処理してしまいます。

8. Windows PowerShell 5.1固有の落とし穴

5.1が残っている環境では、次の3点を最初に疑います。4

(1) TLS 1.2が有効でない。古い既定設定のままだと、TLS 1.2以上しか受け付けないAPIに接続できず、「基になる接続が閉じられました」というエラーになります。

# Windows PowerShell 5.1でのおまじない(スクリプト冒頭)
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

(2) -UseBasicParsing が必要になる場合がある。5.1の Invoke-WebRequest は既定でInternet Explorerのエンジンを使ってHTMLを解析するため、IEが初期化されていないアカウント(サービスアカウントなど)で失敗します。PowerShell 6以降ではこの依存がなくなり、-UseBasicParsing は指定しても無視されます。4

(3) -SkipHttpErrorCheck-Authentication が存在しない。5.1ではエラー本文を読むために応答ストリームを自分で読む必要があります。API連携を本格的にやるなら、PowerShell 7を導入するのが最も安上がりです(「Windows PowerShell 5.1とPowerShell 7の違い」)。

9. プロキシと証明書

社内からインターネット上のAPIを叩く場合、プロキシの通過が最初の関門になります。

# プロキシを明示し、ログオンユーザーの資格情報で認証する
Invoke-RestMethod -Uri $uri -Proxy 'http://proxy.example.co.jp:8080' -ProxyUseDefaultCredentials

タスクスケジューラのサービスアカウントで動かすと、対話ログオン時とはプロキシ設定が違うことがあります。「手元では動くのに夜間バッチだけ失敗する」の典型パターンです。実行アカウントを合わせて検証してください(「タスクスケジューラのタスクが実行されない」)。

証明書エラーに対して -SkipCertificateCheck を使うのは、検証環境の一時的な回避に限定してください。恒久的な対処は、社内CAの証明書を信頼されたルート証明機関ストアに配置し、サーバー証明書を正しく発行することです。

10. 実務の定石(判断表)

論点 選択肢 判断の目安
コマンドレット Invoke-RestMethod / Invoke-WebRequest JSON APIは前者。ヘッダー・コードは専用変数で取得12
認証 ヘッダー直書き / -Authentication 5.1と共用ならヘッダー方式。値はSecretManagementで保管
JSON送信 文字列 / UTF-8バイト配列 + charset明示 環境差による文字化けを避けられる
ConvertTo-Json 既定 / -Depth を明示 既定は2。入れ子は必ず指定3
エラー try/catchのみ / 本文もログに残す $_.ErrorDetails.Message(PS7)。原因究明の可否が変わる1
分岐が多い catch / -SkipHttpErrorCheck + コード分岐 ステータスで処理を分けるなら後者が素直1
リトライ -MaximumRetryCount / 自前 429のRetry-Afterには組み込みが自動追従する。ただし400〜599すべてを再試行するため、恒久的エラーで即失敗させたいときは自前1
POSTの再試行 冪等キーがある場合のみ 応答が届かなかっただけで登録は成功している場合があり、素朴な再送は二重登録になる
ページング -FollowRelLink / 自前ループ Link ヘッダー方式なら前者1
5.1環境 そのまま / TLS 1.2明示 + PS7導入検討 接続エラーの多くはTLS設定が原因4
証明書エラー -SkipCertificateCheck / 社内CAを信頼 恒久運用で検証を無効化しない

11. まとめ

  • JSON APIは Invoke-RestMethod が基本です。ヘッダーやステータスコードは -ResponseHeadersVariable / -StatusCodeVariable で取れます。
  • 日本語JSONはUTF-8バイト配列で送り、charset=utf-8 を明示します。ConvertTo-Json -Depth の指定漏れは入れ子の欠落を招きます。
  • 4xx/5xxは終了エラーです。$_.ErrorDetails.Message で本文を読み、ログに残してください。分岐が多いなら -SkipHttpErrorCheck が扱いやすくなります。
  • POST のような非冪等な要求を自動再試行しないでください。通信エラーや5xxは「サーバー側では処理済み」の可能性があり、再送すると二重登録になります。再試行するなら冪等キーの仕組みが必要です。
  • 429は Retry-After に従って待つのが基本です。-MaximumRetryCount を使えばこの追従は組み込みで行われます。ただし組み込みは400〜599すべてを再試行対象にするため、401や404を即失敗させたいなら自前のリトライが必要です。コード別の扱いや指数バックオフが要るときも同様で、恒久的エラーは再試行せず即失敗させます。
  • ページングは Link ヘッダー方式なら -FollowRelLink、カーソル方式は自前ループ。集約に += を使わないでください。
  • 5.1環境ではTLS 1.2の明示、IEエンジン依存、機能不足の3点が壁になります。API連携を継続するならPowerShell 7の導入が最短の解決です。

サンプルコードのダウンロード

この記事で扱ったコードは、そのまま動かせる形にまとめて配布しています。再試行・冪等性・ページングを実装したAPI呼び出しと、検証用のHTTPサーバーが入っています。

サンプルコードをダウンロード(zip)

この記事のサンプルは、PowerShell 7.6 で実際に実行して検証しています(Pester 21件)。zipに含まれる Invoke-SampleTests.ps1 を実行すれば、お手元でも同じ検証を再現できます。

# 構文解析 + 静的解析 + Pesterテスト
./Invoke-SampleTests.ps1

設定値(パス、サーバー名、テナントIDなど)は例です。そのまま本番環境で実行せず、自社の環境に合わせて読み替えてください。

関連記事

関連する相談領域

合同会社小村ソフトでは、基幹システムやSaaSのAPIを使った社内連携の設計・実装、既存の手作業をAPI連携に置き換える自動化、通信まわりの不具合調査を扱っています。

参考リンク

  1. Microsoft Learn, Invoke-RestMethod. RESTエンドポイントへ要求を送り、応答のJSON/XMLをPowerShellのオブジェクトに変換して返すこと、-Headers / -Body / -ContentType / -Method の指定、-Authentication(Basic / Bearer / OAuth)と-Token、HTTPS以外での認証が既定で拒否されること、-SkipHttpErrorCheckによる4xx/5xxの非例外化、-StatusCodeVariable および -ResponseHeadersVariable による取得、-MaximumRetryCount / -RetryIntervalSec による再試行、-FollowRelLink / -MaximumFollowRelLink によるLinkヘッダーのページング、-Proxy / -ProxyUseDefaultCredentials、-SkipCertificateCheck、-TimeoutSec について。  2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

  2. Microsoft Learn, Invoke-WebRequest. 応答をWebResponseObjectとして返し、StatusCode・Headers・Contentにアクセスできること、Windows PowerShell 5.1では既定でInternet Explorerのエンジンを用いてHTMLを解析し-UseBasicParsingで回避できること、PowerShell 6以降ではIEへの依存がなくなり-UseBasicParsingが無視されることについて。  2 3

  3. Microsoft Learn, ConvertTo-Json. -Depthの既定値が2であり、それより深い階層が変換されないこと、-Compressによる空白の除去について。  2 3

  4. Microsoft Learn, Differences between Windows PowerShell 5.1 and PowerShell 7.x. Web関連コマンドレットの挙動差、Windows PowerShell 5.1固有の制約、PowerShell 7で追加された機能について。あわせてServicePointManager.SecurityProtocol プロパティによるTLSバージョンの指定について。  2 3 4

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

Invoke-RestMethodとInvoke-WebRequestはどう使い分けますか?
APIのJSONやXMLを扱うならInvoke-RestMethodです。応答の本文を自動的に解析してPowerShellのオブジェクトに変換してくれるため、ConvertFrom-Jsonを自分で呼ぶ必要がありません。Invoke-WebRequestは応答をHtmlWebResponseObjectとして返し、ステータスコード・ヘッダー・生の本文にアクセスできます。ステータスコードやヘッダーを見たい場合、あるいはHTMLをそのまま扱いたい場合はInvoke-WebRequestを選びます。なお、PowerShell 6以降のInvoke-RestMethodには-ResponseHeadersVariableと-StatusCodeVariableがあるので、ヘッダーやコードが必要なだけならInvoke-RestMethodのままでも取得できます。
日本語を含むJSONを送ると、相手側で文字化けします。
本文のバイト列とContent-Typeの宣言が食い違っているためです。確実なのは、ConvertTo-Jsonで作った文字列をUTF-8のバイト配列に変換して-Bodyに渡し、-ContentTypeにcharset=utf-8を明示する方法です。Windows PowerShell 5.1では文字列をそのまま渡すと既定のエンコーディングで送られることがあるため、この対処が特に有効です。受信側の文字化けも同様に、応答のcharsetが正しく宣言されているかを疑ってください。
APIが404や500を返したときに、レスポンス本文のエラーメッセージを読みたいです。
PowerShell 7以降なら、catchブロックで$_.ErrorDetails.Messageを見るとレスポンス本文が入っています。ステータスコードは$_.Exception.Response.StatusCodeで取得できます。また、-SkipHttpErrorCheckを付けると4xx/5xxでも例外にせず通常の応答として受け取れるので、ステータスコードで分岐したい処理では扱いやすくなります。Windows PowerShell 5.1では応答ストリームを自分で読む必要があり、この点でも7の利用を推奨します。
APIから429(レート制限)が返ってきます。どう対処すべきですか?
応答のRetry-Afterヘッダーが示す秒数だけ待ってから再試行するのが基本です。ヘッダーがない場合は指数バックオフ(2秒、4秒、8秒…)で間隔を広げます。PowerShell 6以降には-MaximumRetryCountと-RetryIntervalSecがあり、429の応答にRetry-Afterが含まれる場合は指定した間隔ではなくそのヘッダーの値が使われるため、レート制限対応だけなら組み込みで足ります。ステータスコードごとに扱いを変えたい場合や指数バックオフが必要な場合だけ、自前のリトライ関数を使ってください。なお、POSTのような非冪等な要求の再試行は二重登録の恐れがあるため、冪等キーの仕組みがない限り避けてください。根本的には、呼び出し回数そのものを減らす(必要な項目だけ取る、一括取得のAPIを使う)ほうが確実です。
社内APIの自己署名証明書でエラーになります。-SkipCertificateCheckを使ってよいですか?
恒久的な運用では避けてください。証明書の検証を止めるということは、通信相手が本物かどうかを確認しないということで、社内ネットワークであっても中間者攻撃の余地を残します。正しい対処は、社内CAの証明書を実行環境の信頼されたルート証明機関ストアに配置し、サーバー証明書を正しく発行することです。検証環境で一時的に使う場合でも、本番スクリプトに混入しないよう、設定ファイルやパラメーターで明示的に切り替える形にしてください。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る