web-dev-qa-db-ja.com

PowerShellを使用してアーカイブをダウンロードおよび抽出する

PowerShell 5.1を使用して、tar.xzアーカイブをダウンロードし、最初にディスクに書き込まずに抽出するにはどうすればよいですか?

これらすべての試み:

Invoke-WebRequest https://www.examle.com/archive.tar.xz -UseBasicParsing | 7z x -si
(Invoke-WebRequest https://www.examle.com/archive.tar.xz -UseBasicParsing).ToString() | 7z x -si
(Invoke-WebRequest https://www.examle.com/archive.tar.xz -UseBasicParsing).Content | 7z x -si
(Invoke-WebRequest https://www.examle.com/archive.tar.xz -UseBasicParsing).RawContent | 7z x -si

このエラーが発生します:

7-Zip 19.00 (x64) : Copyright (c) 1999-2018 Igor Pavlov : 2019-02-21

Extracting archive:
ERROR:
Can not open encrypted archive. Wrong password?

Not implemented

Can't open as archive: 1
Files: 0
Size:       0
Compressed: 0

これは機能します:

Invoke-WebRequest https://www.examle.com/archive.tar.xz -UseBasicParsing -OutFile temp.tar.xz
7z x temp.tar.xz
3
Magnar Myrtveit

課題:PowerShellでxzアーカイブをダウンロードして抽出する

ディスクに何も書き込まずに

実際の例があるので、ダウンロードして、mingw32-dev.tar.xz XZアーカイブを MinGW --Minimalist GNU for Windows )から抽出するとします。

次のように、ディスクに書き込まずにダウンロードできます。

$r=Invoke-WebRequest -Uri 'https://mirrors.gigenet.com/OSDN//mingw/70554/mingwrt-5.2.1-mingw32-dev.tar.xz'

これで、ターゲットアーカイブをr.Contentのバイト配列としてシェルで使用できるようになりました。抽出する方法は?

これは、 SevenZipExtractor 7ZipのC#ラッパーを使用して可能です。

#Download and install from nuget.org (needs admin privileges)
Install-Package SevenZipExtractor

#Add the SevenZip Assembly to our current PowerShell session
(Get-Item (Join-Path (Split-Path (Get-Package SevenZipExtractor).Source) lib/netstandard*) | 
  Sort-Object { [version] ($_.Name -replace '^netstandard') })[-1] |
    Get-ChildItem -Filter *.dll -Recurse |
      ForEach-Object { Write-Host "Adding ``$($_.Name)``"; Add-Type -LiteralPath $_.FullName }

SevenZipExtractorクラスには、次のオーバーロードされたコンストラクター署名が含まれています(無視している他の署名もあります)。

public SevenZipExtractor(Stream archiveStream);
public SevenZipExtractor(Stream archiveStream, string password);
public SevenZipExtractor(Stream archiveStream, InArchiveFormat format);
public SevenZipExtractor(Stream archiveStream, string password, InArchiveFormat format);

ここで、StreamはタイプSystem.IO.Streamを意味し、InArchiveFormatはタイプSevenZip.InArchiveFormatを意味します。したがって、SevenZipExtractorクラスを次のように使用できます。

$sevenZipStream = [System.IO.MemoryStream]::new()
$sevenZipStream.Write($r.Content,0,$r.Content.Length)
New-Object -TypeName SevenZipExtractor -ArgumentList @($sevenZipStream,[SevenZip.InArchiveFormat]::XZ)

一時ファイルからディスクへの書き込み

ファイルをディスクに書き込んでいる場合、これは 7Zip4Powershellモジュール を使用して実現する方が簡単です。

Install-Module -Name 7Zip4Powershell
Import-Module -Name 7Zip4Powershell -Global

ただし、7Zip4PowerShellは、SevenZipExtractorのオーバーロードされたメソッドシグネチャのすべてを実装しているわけではありません Windows 10プレビュービルド17063以降 、bsdtarはPowerShellに含まれています。 tar.xzファイルを抽出するには、--extract-x)オプションを指定してtarコマンドを呼び出し、-fオプションの後にアーカイブファイル名を指定します。

tar -xf .\whatever.xz

tarは圧縮タイプを自動検出し、アーカイブを抽出します。より詳細な出力を得るには、-vオプションを使用します。このオプションは、端末で抽出されるファイルの名前を表示するようにtarに指示します。

メモリ内の通常のZipファイル

これは、ffmpegソースコードのZipアーカイブ内でaes.hを見つけた例です。

    [System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression')
    $IWRresult = Invoke-WebRequest -Uri "https://ffmpeg.zeranoe.com/builds/win64/dev/ffmpeg-latest-win64-dev.Zip"  -SslProtocol Tls12 -Method Get
    $zipStream = New-Object System.IO.Memorystream
    $zipStream.Write($IWRresult.Content,0,$IWRresult.Content.Length)
    $zipFile = [System.IO.Compression.ZipArchive]::new($zipStream)
    #OK, what's in the archive I just downloaded?
    #Write the archive contents to the Shell output
    $zipFile.Entries | Select-Object -ExcludeProperty @('Archive','ExternalAttributes') | Format-Table #I don't care about 'Archive' or 'ExternalAttributes', so I instruct suppress those
    #oh, there's my `aes.h` inside `ffmpeg-latest-win64-dev/include/libavutil/`
    $entry =  $zipFile.GetEntry('ffmpeg-latest-win64-dev/include/libavutil/aes.h')
    #now we have a streamreader, we can do all the things
    #for example, let's output the content to the screen
    $reader = [System.IO.StreamReader]::new($entry.Open())
    Write-Host $reader.ReadToEnd()

アーカイブをダウンロードすることを目的とした別の例では、すべてメモリ内のそのアーカイブからEXEを実行します。

    [System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression')
    $IWRresult=Invoke-WebRequest -Uri 'https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20200424-a501947-win64-static.Zip' -Method Get -SslProtocol Tls12
    $zipStream = New-Object System.IO.Memorystream
    $zipStream.Write($IWRresult.Content,0,$IWRresult.Content.Length)
    $zipFile = [System.IO.Compression.ZipArchive]::new($zipStream)
    #OK, what did I just download?
    #Write the contents to the Shell output
    $zipFile.Entries | Select-Object -ExcludeProperty @('Archive','ExternalAttributes') | Format-Table #I don't care about 'Archive' or 'ExternalAttributes', so I instruct suppress those
    #I see there is 'ffmpeg-20200424-a501947-win64-static/bin/ffmpeg.exe' entry
    $zipEntry = $zipFile.GetEntry('ffmpeg-20200424-a501947-win64-static/bin/ffmpeg.exe')
    $binReader = [System.IO.BinaryReader]::new($ffmpeg.Open())
    #need external modules `PowerShellMafia/PowerSploit` to be able to run exe from memory (without writing to disk); see comments below this code block
    Invoke-ReflectivePEInjection -PEBytes $binReader.ReadBytes() -ExeArgs "Arg1 Arg2 Arg3 Arg4"

メモリからEXEを実行する方法の詳細については、 PowerShellMafia/PowerSploit を参照してください。ここで例を見つけてください: GitHubの例

1
Mavaddat Javid