Windows10でPowerShellを使ってgzipファイルを解凍する

Windows11では標準でtarファイルやgzipファイル(gzファイル)を解凍(展開)できるようですが、Windows10ではできません。

PowerShellを使ってgzipファイルを展開できると知ったのでここで紹介しておきます。 この記事で紹介している方法は下のMicrosoftの記事に書かれていたものです。

Unzip GZ files using Powershell | Microsoft Learn

この記事での環境情報を先に示しておきます。

問題

Windowsでは圧縮ファイルといえばzipファイルが主流ですが、Linuxではtarファイルやtar.gzファイル、gzipファイルを使います。 Windows10の標準機能ではzipファイルを展開できるものの、それ以外の形式のファイルはできません。 (Lhaplusや7-zipなどをインストールすることで展開することはできます。)

ただし、PowerShellではtarコマンドを利用できるため、 tarファイルはtar -xvf sample.tar、tar.gzファイルはtar -xvzf sample.tar.gzのようにすれば展開可能です。

しかしながら、gzipファイルはtarコマンドでは展開できません。 gzipファイルはgzipコマンドまたはgunzipコマンドで展開できますが、PowerShellには入っていませんでした。

解決方法

Lhaplusや7-zipなどのフリーソフトをインストールすることなく、PowerShellでコードを書くことでgzipファイルを展開できます。 コードは最初に紹介したMicrosoftのページから持ってきました。

Unzip GZ files using Powershell | Microsoft Learn

手順は以下のとおりです。

  1. PowerShellを起動する
  2. 以下のコマンドをPowerShellコマンドシェルに貼り付ける
  Function DeGZip-File {
    Param(
        $infile,
        $outfile = ($infile -replace '\.gz$','')
        )

    $input = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read)
    $output = New-Object System.IO.FileStream $outFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None)
    $gzipStream = New-Object System.IO.Compression.GzipStream $input, ([IO.Compression.CompressionMode]::Decompress)

    $buffer = New-Object byte[](1024)
    while($true){
        $read = $gzipstream.Read($buffer, 0, 1024)
        if ($read -le 0){break}
        $output.Write($buffer, 0, $read)
        }

    $gzipStream.Close()
    $output.Close()
    $input.Close()
  }
  1. 手順2で作成したファンクションを使ってgzipファイルを展開する
  2. 実行例:DeGzip-File ".\mytestfile.txt.gz" ".\mytestfile.txt"
  3. .\mytestfile.txt.gzファイルを.\mytestfile.txtとして展開するということになります

ps1ファイルとbatファイルを作って使いやすくする

先ほどのコードを毎回PowerShellにコピペするのは面倒くさいのでps1ファイルに保存し、batファイルから呼び出せるようにしておきます。

用意するファイルは2つです。

  • DeGZip-File.ps1: 先述のコードを外部から呼び出せるようにしたPowerShellスクリプトファイル
  • expand-gzip.bat: DeGZip-File.ps1を呼び出すためのbatファイル

DeGZip-File.ps1ファイルの内容は以下のようにします。

Param($Arg1, $Arg2)

Function DeGZip-File {
  Param(
      $infile,
      $outfile = ($infile -replace '\.gz$','')
      )

  $input = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read)
  $output = New-Object System.IO.FileStream $outFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None)
  $gzipStream = New-Object System.IO.Compression.GzipStream $input, ([IO.Compression.CompressionMode]::Decompress)

  $buffer = New-Object byte[](1024)
  while($true){
      $read = $gzipstream.Read($buffer, 0, 1024)
      if ($read -le 0){break}
      $output.Write($buffer, 0, $read)
      }

  $gzipStream.Close()
  $output.Close()
  $input.Close()
}

DeGZip-File $Arg1 $Arg2

expand-gzip.batファイルの内容は以下のようにします(文字コードはS-JISです)。

@ECHO OFF

ECHO 入力されたパスのGzipファイルを展開します

:INPUT_GZIP_PATH
SET GZIP_PATH=
SET /P GZIP_PATH="Gzipファイルパスを入力してください。:"
IF "%GZIP_PATH%"=="" GOTO :INPUT_GZIP_PATH
SET EXPAND_PATH=
SET /P EXPAND_PATH="展開先パスを入力してください。(省略可、省略した場合にはGzipファイルパスの末尾 .gz を削除したものをパスとします):"

ECHO GZipファイルパス:[%GZIP_PATH%] 展開先パス:[%EXPAND_PATH%]

powershell -NoProfile -ExecutionPolicy Unrestricted -file .\DeGZip-File.ps1 "%GZIP_PATH%" "%EXPAND_PATH%"
PAUSE
EXIT

使い方としてはexpand-gzip.batファイルをダブルクリックし、指示のとおりgzipファイルのパスと展開先のパスを入力します。 実際に実行し、処理が完了したときのコマンドプロンプトの様子のスクリーンショットを貼っておきます(ちょっとブサイクですが、、、)。指定した展開先パスにファイルが展開されていることを確認してください。

おわりに

gzipファイルをPowerShellだけで展開(解凍)する方法とそれをps1ファイルに保存し、batファイルを介して簡単に呼び出せるようにしました。

batファイルでps1ファイルでのgzipファイルの展開処理の待機ができればもっといい感じのbatファイルになったのですが、やり方がわからなかったのでとりあえずこんな感じになりました。

参考