【PowerShell】Webからファイルをダウンロードする方法|Invoke-WebRequest・高速化・TLS1.2

Webからファイルをダウンロードしたいとき、PowerShellならInvoke-WebRequestコマンド1つで実現できます。wgetcurlのように、URLを指定してファイルを保存できます。インストーラーやデータファイルの自動取得、スクリプトでの定期ダウンロードなどに便利です。

ただしWindows PowerShell 5.1には、知らないとハマる3つの落とし穴があります。①進捗バーのせいで極端に遅くなる-UseBasicParsingを付けないとエラーになる③HTTPSサイトでTLS 1.2を明示しないと接続できないことです。この記事では、実機のWindows PowerShell 5.1で実際にダウンロードしながら、これらの対策を整理します。

先に結論

  • 基本はInvoke-WebRequest -Uri "URL" -OutFile "保存先"です。
  • $ProgressPreference = "SilentlyContinue"で劇的に速くなります(進捗バーが重い)。
  • Windows PowerShell 5.1では-UseBasicParsingが必須(無いとエラーになることがある)。
  • HTTPSは[Net.ServicePointManager]::SecurityProtocolでTLS 1.2を明示します。
  • APIのJSONを取得するならInvoke-RestMethod(自動でオブジェクト化)。
  • 失敗に備えてtry-catchとリトライを入れると安定します。

保存先の確認はファイル・フォルダ操作(Test-Path)、APIのJSON処理はJSONを読み書きする(ConvertFrom-Json)、失敗時の対処はtry-catchでのエラー処理もあわせて参考になります。

スポンサーリンク

基本:Invoke-WebRequestでダウンロード

もっとも基本的な使い方は、-UriにURL、-OutFileに保存先を指定します。これだけでファイルがダウンロードされ、保存されます。

基本のダウンロード
# URL を指定してファイルを保存
Invoke-WebRequest -Uri "https://example.com/file.zip" -OutFile "C:\temp\file.zip"

# iwr というエイリアス(短縮名)でも書ける
iwr "https://example.com/file.zip" -OutFile "C:\temp\file.zip" 

実機でも、Invoke-WebRequest -Uri "URL" -OutFile "保存先"で、3,662バイトのファイルが正しくダウンロード・保存されることを確認しました。-OutFileを指定するとファイルに保存され、指定しない場合はレスポンスの内容がメモリ上に返ります。iwrという短い別名も使えます。基本はこれだけですが、Windows PowerShell 5.1では次の対策が重要になります。

【高速化】$ProgressPreferenceで劇的に速くなる

Windows PowerShell 5.1のInvoke-WebRequestは、ダウンロード中に進捗バーを描画するのですが、これが非常に重く、ダウンロードを何倍も遅くします。進捗バーを止めるだけで、驚くほど速くなります。

進捗バーを止めて高速化
# これを実行する前に1行入れるだけで劇的に速くなる
$ProgressPreference = "SilentlyContinue"

Invoke-WebRequest -Uri "https://example.com/big.zip" -OutFile "C:\temp\big.zip" -UseBasicParsing

# 元に戻したいときは
# $ProgressPreference = "Continue" 
進捗バーを消すだけで約10倍速くなった

実機で同じファイルを、進捗バーあり・なしでダウンロードして時間を比較したところ、進捗バーあり=154ミリ秒、進捗バーなし=14ミリ秒と、約11倍の差が出ました(小さなファイルでもこれだけ違い、大きなファイルではさらに差が広がります)。原因は、Windows PowerShell 5.1のInvoke-WebRequestが、ダウンロードの進捗バーを頻繁に再描画するためです。$ProgressPreference = "SilentlyContinue"を1行入れて進捗バーを止めるだけで、この描画コストが無くなり、本来の速度でダウンロードできます。大きなファイルや複数ファイルをダウンロードするスクリプトでは、必ず入れておきたい一行です。

【PS5.1必須】-UseBasicParsing

Windows PowerShell 5.1のInvoke-WebRequestは、標準ではInternet Explorerのエンジンを使ってHTMLを解析しようとします。そのため、IEが使えない環境では-UseBasicParsingを付けないとエラーになることがあります。

-UseBasicParsing を付ける
# -UseBasicParsing を付けるとIEに依存せず動く(PS5.1では実質必須)
$resp = Invoke-WebRequest -Uri "https://example.com/" -UseBasicParsing
$resp.StatusCode    # 200
$resp.Content       # 本文(HTMLやテキスト)

# 付けないと「オブジェクト参照がインスタンスに設定されていません」
# のようなエラーになることがある
-UseBasicParsingが無いとエラーになる

実機で確認したところ、-UseBasicParsingを付けずにInvoke-WebRequestのレスポンス内容(.Content)にアクセスしようとすると、オブジェクト参照がオブジェクト インスタンスに設定されていませんというエラーになりました。これは、Windows PowerShell 5.1がIEのHTML解析エンジンを使おうとして、それが利用できないために起こります。-UseBasicParsingを付けると、IEに依存しない簡易パーサーが使われ、正しく動作します(StatusCode=200、本文も取得できました)。Windows PowerShell 5.1では-UseBasicParsingを常に付けると覚えておくと安全です。なお、ファイルへ保存する-OutFileだけなら付けなくても動くことがありますが、付けておいて損はありません。

【HTTPS】TLS 1.2を有効にする

もう1つのハマりどころがTLS(暗号化通信)のバージョンです。Windows PowerShell 5.1は、環境によっては古いTLS 1.0で接続しようとするため、TLS 1.2以上しか受け付けない最近のHTTPSサイトに接続できず、エラーになることがあります。接続前にTLS 1.2を明示します。

TLS 1.2 を明示する
# HTTPS接続の前に、TLS 1.2 を使うよう設定する
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

# これで TLS 1.2 必須のサイトにも接続できる
Invoke-WebRequest -Uri "https://example.com/file.zip" -OutFile "C:\temp\file.zip" -UseBasicParsing

実機でも、TLS 1.2を明示してからHTTPSのURLにアクセスすると、正しくダウンロードできました(GitHubの生ファイルなど、TLS 1.2が必要なサイトでも成功)。「要求が中止されました: SSL/TLS のセキュリティで保護されているチャネルを作成できませんでした」のようなエラーが出たら、このTLS 1.2の設定が抜けていないか確認してください。HTTPSサイトを扱うスクリプトでは、冒頭でTLS 1.2を設定しておくと安心です。

APIのJSONを取得する Invoke-RestMethod

Web APIからJSONを取得したい場合は、Invoke-WebRequestではなくInvoke-RestMethodが便利です。JSONを自動でPowerShellのオブジェクトに変換してくれるため、そのままプロパティにアクセスできます。

Invoke-RestMethod でAPI取得
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

# JSON を返す API を呼ぶ → 自動でオブジェクトになる
$data = Invoke-RestMethod -Uri "https://api.github.com/repos/git/git" `
    -Headers @{ "User-Agent" = "PowerShell" } -UseBasicParsing

$data.name        # git
$data.language    # C
$data.stargazers_count   # スター数

実機でも、Invoke-RestMethodでGitHub APIを呼ぶと、JSONが自動でオブジェクトに変換され、$data.namegit$data.languageCのように、プロパティに直接アクセスできました。Invoke-WebRequestはレスポンス全体(ヘッダーや本文の文字列)を返すのに対し、Invoke-RestMethodはJSONを解析した結果を返す点が違います。APIを叩くならInvoke-RestMethod、ファイルを落とすならInvoke-WebRequest -OutFile、と使い分けます。なお、多くのAPIはUser-Agentヘッダーが無いと拒否するため、付けておくと安全です。取得したJSONの扱いはJSONを読み書きする方法も参考になります。

エラー処理とリトライ

ネットワークは失敗することがあります。try-catchで囲み、失敗したら少し待ってリトライ(再試行)する仕組みを入れると、スクリプトが安定します。

リトライ付きダウンロード
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$ProgressPreference = "SilentlyContinue"

$url = "https://example.com/file.zip"
$out = "C:\temp\file.zip"
$maxRetry = 3

for ($i = 1; $i -le $maxRetry; $i++) {
    try {
        Invoke-WebRequest -Uri $url -OutFile $out -UseBasicParsing -ErrorAction Stop
        Write-Host "ダウンロード成功"
        break
    } catch {
        Write-Host "失敗($i 回目): $($_.Exception.Message)"
        if ($i -lt $maxRetry) { Start-Sleep -Seconds 3 }  # 3秒待って再試行
    }
}

forループで最大3回までリトライし、成功したらbreakで抜けます。失敗するたびにStart-Sleepで少し待つと、一時的なネットワークの不調を乗り越えやすくなります。-ErrorAction Stopを付けることで、ネットワークエラーがcatchで確実に捕まえられます(詳しくはtry-catchでのエラー処理を参照)。

主なポイントまとめ

PowerShellでのダウンロードの要点をまとめます。

項目 対策
基本 Invoke-WebRequest -Uri URL -OutFile 保存先
速度が遅い $ProgressPreference = "SilentlyContinue"
エラーになる(PS5.1) -UseBasicParsingを付ける
HTTPSで接続できない TLS 1.2を明示する
APIのJSON取得 Invoke-RestMethodを使う
失敗に備える try-catch+リトライ

よくある失敗

ダウンロードが異常に遅い

進捗バーの描画が原因です。$ProgressPreference = "SilentlyContinue"を入れます。

オブジェクト参照のエラーが出る

PS5.1のIE依存が原因です。-UseBasicParsingを付けます。

HTTPSサイトに接続できない

TLS 1.2が有効でない可能性があります。SecurityProtocolでTLS 1.2を明示します。

APIのレスポンスが文字列で扱いにくい

Invoke-RestMethodを使うとJSONが自動でオブジェクトになります。

一時的なエラーで止まる

try-catchとリトライを入れて、再試行で乗り越えます。

よくある質問

QPowerShellでファイルをダウンロードするには?
AInvoke-WebRequest -Uri "URL" -OutFile "保存先"を使います。URLのファイルが保存先にダウンロードされます。Windows PowerShell 5.1では、速度のために$ProgressPreference = "SilentlyContinue"、安定のために-UseBasicParsingを付けるのがおすすめです。
Qダウンロードがとても遅いのですが?
AWindows PowerShell 5.1のInvoke-WebRequestは、進捗バーの描画が重く、ダウンロードを何倍も遅くします。実機でも進捗バーあり/なしで約11倍の差が出ました。$ProgressPreference = "SilentlyContinue"を1行入れて進捗バーを止めると、劇的に速くなります。
Q「オブジェクト参照が…」というエラーが出ます。
AWindows PowerShell 5.1のInvoke-WebRequestがIE(Internet Explorer)の解析エンジンに依存しているためです。-UseBasicParsingを付けると、IEに依存しない簡易パーサーが使われ、エラーを回避できます。PS5.1では常に付けておくと安全です。
QHTTPSのサイトに接続できません。
AWindows PowerShell 5.1が古いTLSで接続しようとしている可能性があります。接続前に[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12を実行してTLS 1.2を明示してください。最近のHTTPSサイトはTLS 1.2以上が必須のことが多いです。
QInvoke-WebRequestとInvoke-RestMethodの違いは?
AInvoke-WebRequestはレスポンス全体(ヘッダーや本文の文字列、ステータスコード)を返します。Invoke-RestMethodはJSONを自動でオブジェクトに変換して返すため、APIを叩くのに向いています。ファイルを保存するならInvoke-WebRequest -OutFile、JSONを扱うならInvoke-RestMethodを使い分けます。

まとめ

  • 基本はInvoke-WebRequest -Uri URL -OutFile 保存先です。
  • 速度は$ProgressPreference = "SilentlyContinue"で約10倍改善します。
  • PS5.1では-UseBasicParsingを付けてIE依存を回避します。
  • HTTPSはTLS 1.2を明示して接続エラーを防ぎます。
  • APIのJSONはInvoke-RestMethod、失敗対策はtry-catch+リトライ。

PowerShellでのダウンロードはInvoke-WebRequest一発でできますが、Windows PowerShell 5.1では「進捗バーを止める」「-UseBasicParsing」「TLS 1.2」の3点を押さえることが安定と速度のカギです。これらをスクリプトの冒頭に入れておけば、ファイル取得やAPI連携を快適に自動化できます。なお、PowerShell 7ではこれらの対策はほぼ不要(既定で速く、TLS 1.2、IE非依存)になっています。