PowerShell Wget:簡単にファイルをダウンロードする

ウェブからファイルをダウンロードする必要がありますかが、リンクを繰り返しクリックするのが嫌ですか?定期的にウェブからファイルをダウンロードする仕事をしている場合、おそらくタスクを自動化したいと思うでしょう。なぜPowerShellを使用して、代替のPowerShell wgetのようにファイルをダウンロードしないのでしょうか?

Windows PowerShellとPowerShellにはファイルのダウンロード機能が備わっています。PowerShellを使用してファイルをダウンロードするには、どのコマンドレットや.NETクラスを使用し、それらをどのように使用するかを知っていることが重要です。

この記事では、ウェブからファイルをダウンロードするためのさまざまな方法を学びます。

前提条件

この記事は「実際にやってみることで学ぶ」というスタイルなので、例に従えるようにするための前提条件がいくつかあります。以下に基本的な要件を示します。

  • A computer that is running on Windows 10 or higher. This computer is where you will run the scripts/commands featured in this article.
  • Windows PowerShell 5.1またはPowerShell 7.1(推奨)が必要です。
    • Windows 10には既にWindows PowerShell 5.1が含まれています。
  • A web site that hosts the files to download.
    • 非認証のファイルダウンロードには、無料のTele2 Speedtestサイトを使用することを検討してください。
    • 認証付きのファイルダウンロードをテストしたい場合は、HTTPファイルサーバーを構築する必要があるかもしれません。無料のHTTPファイルサーバーの例としては、HFS by Rejettoがあります。

URLからファイルをダウンロードするためのPowerShellの使用方法:4つの方法

サードパーティツールに依存しないPowerShellを使用してファイルをダウンロードするための4つの方法があります。

  • Invoke-WebRequest
  • Invoke-RestMethod
  • Start-BitsTransfer
  • .NET WebClient クラス

これらの4つの方法のいずれを使用しても、動作させるためのロジックとコンポーネントは同じです。ファイルの場所を示すソースURLとダウンロードしたファイルを保存する宛先パスが必要です。Webサーバーによって要求される場合、資格情報も入力する必要があります。

次のセクションでは、これらの4つの方法のそれぞれが示されています。最終的には、PowerShellを使用してファイルをダウンロードする際にどの方法を適応するかはあなた次第です。

PowerShellの代替としてInvoke-WebRequestを使用する

ファイルをダウンロードするためのPowerShellの最初の方法は、Invoke-WebRequestコマンドレットを使用することです。おそらく、この記事で最も使用されるコマンドレットであるInvoke-WebRequestは、HTTP、HTTPS、およびFTPリンクをダウンロードすることができます。

ソースの場所にユーザーがログインを要求する場合、Invoke-WebRequestコマンドレットは資格情報を使用してリクエストを処理することができます。

ファイルをダウンロードするためには、以下の構文に示す最小限のパラメータを使用して目的の結果を達成します。

Invoke-WebRequest -Uri <source> -OutFile <destination>

たとえば、下記のコードは、ウェブサイトから10MB.zipという名前のファイルをダウンロードし、ダウンロードしたファイルをC:\dload\10MB.zipに保存します。以下のコードをコピーしてPowerShellセッションに貼り付けてテストできます。

# ソースファイルの場所
$source = 'http://speedtest.tele2.net/10MB.zip'
# ファイルを保存する先
$destination = 'c:\dload\10MB.zip'
# ファイルをダウンロードする
Invoke-WebRequest -Uri $source -OutFile $destination

以下のデモンストレーションは、PowerShellで上記のコードを実行した後の予想される結果を示しています。ご覧の通り、ファイルのダウンロードは成功しました。

PowerShell wget : Downloading a file using Invoke-WebRequest

もしソースにアクセスする前に認証が必要な場合はどうなるでしょうか?以下のコードでは、ユーザーがログインする必要があるプライベートウェブサイトからファイルをダウンロードします。

$source = 'https://mirror.lzex.ml/100MB.zip'
$destination = 'c:\dload\100MB.zip'
Invoke-WebRequest -Uri $source -OutFile $destination

しかし、認証に失敗したためダウンロードは失敗しました。

Downloading failed due to unauthorized access

認証が必要な場合は、-Credentialパラメータを使用してリクエストに資格情報を追加する必要があります。以下のコードの最初の行では、資格情報(ユーザー名とパスワード)の入力を求め、それを$credential変数に保存します。

$credential = Get-Credential
$source = 'https://mirror.lzex.ml/100MB.zip'
$destination = 'c:\dload\100MB.zip'
Invoke-WebRequest -Uri $source -OutFile $destination -Credential $credential

以下のデモンストレーションは、上記のコードをPowerShellで実行した場合の予想される表示結果を示しています。ご覧の通り、Get-CredentialコマンドレットはPowerShellの資格情報の要求を促しました。今回は、Invoke-WebRequestで資格情報を使用することで、ダウンロードが成功しました。

Downloading a file with authentication

関連記事: PowerShell Get-Credentialコマンドレットと資格情報に関するすべてのこと

Invoke-WebRequestを使用する際のパースエラーに注意してください。

A crucial thing to remember when using Invoke-WebRequest in Windows PowerShell is that, by default, this cmdlet uses the Internet Explorer engine to parse data. The error below may happen when using Invoke-WebRequest on computers without the Internet Explorer in it.

コマンドを再発行する必要がありますが、今回は-UseBasicParsingスイッチを含めてください。

Invoke-WebRequest -Uri <source> -OutFile <destination> -UseBasicParsing

Windows PowerShellでは、次のエラーメッセージが表示されることがあります。「インターネットエクスプローラのエンジンが利用できないため、応答コンテンツを解析できません。または、インターネットエクスプローラの初回起動構成が完了していません。UseBasicParsingパラメータを指定して、もう一度試してください。」

PowerShell Core 6.0以降、Invoke-WebRequestコマンドレットは基本的な解析のみを使用します。そのため、-UseBasicParsingパラメータはもはや必要ありません。

Invoke-RestMethodの使用

Invoke-RestMethodコマンドレットは、RESTful Webサービスに対してHTTPまたはHTTPSリクエストを送信することに関連しています。このコマンドレットは、MicrosoftのGraph APIなどのREST APIとのやり取りに適しています。

Webからファイルを直接ダウンロードする場合、Invoke-RestMethodは非常に便利です。他の方法であると誤解しないでください。ダイレクトなWebリンクからファイルをダウンロードする場合、Invoke-RestMethodInvoke-WebRequestの使用にはほとんど違いがありません。

Invoke-RestMethodを使用してファイルをダウンロードする

Invoke-RestMethodを使用してファイルをダウンロードするには、以下の構文を使用します。コマンドはInvoke-WebRequestと同じパラメータを使用することに注意してください。

Invoke-RestMethod -Uri <source> -OutFile <destination>

以下の例のコードでは、ファイルが$source変数のURLの値からダウンロードされ、$destination変数で定義されたパスに保存されます。

$source = 'http://speedtest.tele2.net/10MB.zip'
$destination = 'c:\dload\10MB.zip'
Invoke-RestMethod -Uri $source -OutFile $destination

ソースに認証が必要な場合、-Credentialパラメータを使用して資格情報を渡すことができます。以下の例では、資格情報を入力するようにプロンプトが表示され、それを$credential変数に格納します。そして、$credential変数の値が-Credentialパラメータに渡されます。

また、ファイルリンクがHTTPソースであり、HTTPSではないため、暗号化されていない認証が送信されていることを意味します。通常、セキュリティ上の理由からHTTPソースの使用は避けるべきです。ただし、HTTPソースを使用する必要がある場合は、コマンドに-AllowUnencryptedAuthenticationスイッチを追加する必要があります。

$credential = Get-Credential
$source = 'http://speedtest.tele2.net/10MB.zip'
$destination = 'c:\dload\10MB.zip'
Invoke-RestMethod -Uri $source -OutFile $destination -Credential $credential -AllowUnencryptedAuthentication

Start-BitsTransferの使用

Start-BitsTransferは、クライアントとサーバーのコンピュータ間でファイルを転送するために特に設計されたPowerShellコマンドレットです。このPowerShellコマンドレットは、Windowsオペレーティングシステムにネイティブに組み込まれているBackground Intelligent Transfer Service (BITS)に依存しています。

Start-BitsTransferはBITSが動作するため、このコマンドレットは非Windowsコンピュータでは利用できません。一方、Start-BitsTransferはBITSそのものの利点を享受しています。これらの利点には、次のようなものがあります:

  • ネットワーク帯域幅と使用状況の認識。
  • 中断処理(再開、自動再開、一時停止など)
  • 複数のファイルをバックグラウンドジョブとしてダウンロードすること。
  • ダウンロードジョブの優先順位の設定。

ファイルのダウンロード

PowerShellでStart-BitsTransferを使用してファイルをダウンロードするための基本的な方法は、ソースと宛先を指定することです。以下のスクリプトを使用すると、$source$destinationの値を必要に応じて変更するだけで済みます。

$source = 'http://speedtest.tele2.net/100MB.zip'
$destination = 'c:\dload\100MB.zip'
Start-BitsTransfer -Source $source -Destination $destination

以下のデモからわかるように、ファイルはパスc:\dload\100MB.zipにダウンロードされます。

Downloading a file using Start-BitsTransfer

宛先が指定されていない場合、Start-BitsTransferはファイルを現在の作業ディレクトリにダウンロードして保存します。たとえば、C:\dloadからStart-BitsTransferを実行すると、ファイルは同じディレクトリにダウンロードされます。

認証が必要なダウンロードの場合、Start-BitsTransferには-Credentialパラメータがあり、PSCredentialオブジェクトを受け入れます。

複数のファイルをダウンロードする

複数のファイルをダウンロードするデモを行うためには、2列のCSVファイルを作成する必要があります。ファイル名をfilelist.txtとします。最初の列にはソースへのリンクが、2番目の列には宛先パスが入る必要があります。ファイルの内容は以下のようになります。

# source,destination
http://speedtest.tele2.net/1MB.zip,c:\dload\1MB.zip
http://speedtest.tele2.net/10MB.zip,c:\dload\10MB.zip
http://speedtest.tele2.net/100MB.zip,c:\dload\100MB.zip

関連記事: PowerShellでCSVファイルを操作するImport-Csv

CSVファイルが準備できたら、以下のコマンドを使用してファイルのダウンロードを開始します。このコマンドは、Import-Csvを使用してCSVファイルをインポートし、その内容をStart-BitsTransferに渡します。

Import-Csv .\filelist.csv | Start-BitsTransfer

上記のコードの動作を確認するために、以下のデモを参照してください。ダウンロードが開始され、ダウンロードの進行状況が表示されます。ダウンロードプロセス中はPowerShellプロンプトは使用できません。

Starting a synchronous multiple file download

ダウンロードプロセスをバックグラウンドジョブとして開始したい場合は、Start-BitsTransferコマンドの最後に-Asynchronousスイッチを追加するだけです。

Import-Csv .\filelist.csv | Start-BitsTransfer -Asynchronous

最初は、各ジョブの状態は「接続中」と表示されます。以下のスクリーンショットには、各ファイルのダウンロードジョブIDが表示されています。

Starting file download as background jobs

ダウンロードプロセスを開始したので、ダウンロードが完了したかどうかを確認したいと思います。ダウンロードジョブのステータスを確認するには、Get-BitsTransferコマンドレットを使用します。以下のように、ダウンロードジョブのステータスが「転送済み」に変わっていることがわかります。

Viewing the file download job status

WebClientクラスとHttpClientクラスの使用(.NET Framework)

PowerShellは.NETに基づいており、その性質から、.NET自体の力を活用することができます。PowerShellでファイルをダウンロードするために使用できる2つの.NETクラスがあります。それがWebClientHttpClientです。

これら2つの.NETクラスについて、より開発と技術的な観点で詳しく知りたい場合は、次のように始めることができます→ WebClientとHttpClientとHttpWebRequestの使用方法次のセクションでは、PowerShellでWebからファイルをダウンロードする方法を学びます。

System.Net.WebClientを使用してファイルをダウンロードする

WebClientクラスを使用するには、System.Net.WebClientのオブジェクトを初期化する必要があります。以下の例では、$webClientは新しいSystem.Net.WebClientオブジェクトです。次に、DownloadFile()メソッドを使用して、ソースからファイルのダウンロードを開始します。

関連: PowerShellのデータ型アクセラレータを使用してコーディングを高速化する

以下のコードをコピーしてPowerShellセッションで実行してテストしてください。エラーがない限り、画面に進捗状況や出力は表示されません。ただし、ダウンロードが完了するまでPowerShellプロンプトはロックされます。

# ソースリンクと宛先パスを定義する
$source = 'http://speedtest.tele2.net/10MB.zip'
$destination = 'c:\dload\10MB.zip'
# 新しいWebClientを作成する
$webClient = [System.Net.WebClient]::new()
# ファイルをダウンロードする
$webClient.DownloadFile($source, $destination)

ソースが認証を必要とする場合、以下のコードを使用できます。最初の行では資格情報を入力し、$credentials 変数に格納します。その値はファイルのダウンロード要求に含まれます。

# ユーザー名とパスワードを入力
$credentials = Get-Credential
$source = 'http://speedtest.tele2.net/10MB.zip'
$destination = 'c:\dload\10MB.zip'
# 新しい WebClient を作成
$webClient = [System.Net.WebClient]::new()
# 資格情報を追加
$webClient.Credentials = $credentials
# ファイルをダウンロード
$webClient.DownloadFile($source, $destination)

このMicrosoft のドキュメントによると、「新しい開発には WebClient クラスの使用は推奨されません。代わりに System.Net.Http.HttpClient クラスを使用してください」とのことです。

WebClient クラスは非推奨であり、Microsoft が推奨している新しいクラスは HttpClient クラスです。しかし、心配する必要はありません。次のセクションでは、PowerShell で HttpClient クラスを使用してウェブからファイルをダウンロードする方法について説明しています。

System.Net.Http.HttpClient を使用してファイルをダウンロードする

WebClient クラスと同様に、まず System.Net.Http.HttpClient を作成する必要があります。以下のコードを使用すると、$sourceからファイルを $destination にダウンロードできます。それぞれのコード行の上にあるコメントを参照して、それぞれのコード行が何を行っているかを確認してください。

以下のコードはライブであり、PowerShellセッションで実行してテストすることができます。

# ソースと宛先を設定する
$source = 'http://speedtest.tele2.net/10MB.zip'
$destination = 'c:\dload\10MB.zip'
 
# HTTPクライアントのダウンロードリクエストを作成する
$httpClient = New-Object System.Net.Http.HttpClient
$response = $httpClient.GetAsync($source)
$response.Wait()
 
# 出力ファイルの宛先を指すファイルストリームを作成する
$outputFileStream = [System.IO.FileStream]::new($destination, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write)
 
# ダウンロードを宛先のファイルストリームにストリームする
$downloadTask = $response.Result.Content.CopyToAsync($outputFileStream)
$downloadTask.Wait()
 
# ファイルストリームを閉じる
$outputFileStream.Close()

ファイルのダウンロードに認証が必要な場合、HttpClientオブジェクトに資格情報を追加する必要があります。ファイルダウンロードリクエストに資格情報を含めるには、新しいSystem.Net.Http.HttpClientHandlerオブジェクトを作成して資格情報を格納します。

以下のコードをコピーしてPowerShellで実行してテストするか、PowerShellスクリプトとして実行することもできます。この例では、コードはdownload-file.ps1という名前で保存されています。

# ソースと宛先を設定する
$source = 'http://speedtest.tele2.net/10MB.zip'
$destination = 'c:\dload\10MB.zip'
 
# 資格情報を入力する
$credentials = Get-Credential

# 資格情報を含めたHTTPクライアントのダウンロードリクエストを作成する
$handler = New-Object System.Net.Http.HttpClientHandler
$handler.Credentials = $credentials
$httpClient = New-Object System.Net.Http.HttpClient($handler)
$response = $httpClient.GetAsync($source)
$response.Wait()
 
# 出力ファイルの宛先を指すファイルストリームを作成する
$outputFileStream = [System.IO.FileStream]::new($destination, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write)
 
# ダウンロードを宛先のファイルストリームにストリームする
$downloadTask = $response.Result.Content.CopyToAsync($outputFileStream)
$downloadTask.Wait()
 
# ファイルストリームを閉じる
$outputFileStream.Close()

以下のデモは、PowerShellスクリプトを実行してファイルをダウンロードするときの結果を示しています。

開始時点で、ディレクトリにはスクリプトファイルのみがあります。ユーザー名とパスワードの入力プロンプトが表示されます。その後、スクリプトがファイルのダウンロードを進めます。ファイルのダウンロードが完了すると、目的のディレクトリ内に新しいファイルが表示されます。

Downloading a file using the .NET HttpClient class

まとめ

Windows PowerShellとPowerShell Coreには、PowerShell wgetの代替としてファイルをダウンロードするための組み込み機能が備わっています!パスワードで保護されたソース、単一または複数のファイルをダウンロードする場合でも、PowerShellの方法が利用できます。

この記事でカバーされているファイルのダウンロード方法は、Windows PowerShellとPowerShell Coreの両方で動作します。つまり、これらの方法はWindowsおよび非Windowsシステムの両方に適用されますが、Start-BitsTransferを除きます。

そして、PowerShellは単なるコマンドプロンプト以上のものなので、学んだ内容をスクリプトに翻訳することができます。これにより、自動化の機会が生まれます。URLをコピーしたり、リンクをクリックしたり、ダウンロードの完了を待つ必要はもうありません。

Source:
https://adamtheautomator.com/powershell-download-file/