使用 PowerShell 下载并解压存档

Mag*_*eit 5 powershell wget tar curl 7-zip

使用 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
Run Code Online (Sandbox Code Playgroud)

给出这个错误:

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
Run Code Online (Sandbox Code Playgroud)

这有效:

Invoke-WebRequest https://www.examle.com/archive.tar.xz -UseBasicParsing -OutFile temp.tar.xz
7z x temp.tar.xz
Run Code Online (Sandbox Code Playgroud)

Mav*_*vid 3

挑战:在 PowerShell 中下载并解压 xz 存档

我描述了实现该目标的两种方法。

不向磁盘写入任何内容

例如,假设我们要从MinGW - Minimalist GNU for Windowsmingw32-dev.tar.xz上提供的 XZ 存档中下载/提取文件。

我们可以在不写入磁盘的情况下下载,如下所示:

$r=Invoke-WebRequest -Uri 'https://mirrors.gigenet.com/OSDN//mingw/70554/mingwrt-5.2.1-mingw32-dev.tar.xz'
Run Code Online (Sandbox Code Playgroud)

我们的目标存档可作为字节数组进行 shell 处理$r.Content。如何提取?

使用SevenZipExtractor7Zip 的 C# 包装器,我们提取如下:

#Download and install from nuget.org
Install-Package SevenZipExtractor -Scope CurrentUser

#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 }

Run Code Online (Sandbox Code Playgroud)

该类SevenZipExtractor尤其包括以下重载构造函数签名:

public SevenZipExtractor(Stream archiveStream);
public SevenZipExtractor(Stream archiveStream, string password);
public SevenZipExtractor(Stream archiveStream, SevenZipFormat format);
public SevenZipExtractor(Stream archiveStream, string password, InArchiveFormat format);
Run Code Online (Sandbox Code Playgroud)

这里的Stream意思是 data-type System.IO.StreamSevenZipFormat意思是 type SevenZipExtractor.SevenZipFormat

所以我们可以使用 SevenZipExtractor 类

$sevenZipStream = [System.IO.MemoryStream]::new(($r.Content))
$szExtractor = New-Object -TypeName SevenZipExtractor.ArchiveFile -ArgumentList @($sevenZipStream)
$szExtractor.Extract("$env:TEMP",$False) # Instead of $env:TEMP, wherever you want the files to go
Run Code Online (Sandbox Code Playgroud)

是我编写的一个工作示例,它实现了上述下载和安装方法ffmpeg

将临时文件写入磁盘

如果我们将文件写入磁盘,则使用该7Zip4Powershell模块可以更简单地实现目标。

Install-Module -Name 7Zip4Powershell
Import-Module -Name 7Zip4Powershell -Global
Run Code Online (Sandbox Code Playgroud)

但是,并7Zip4PowerShell没有实现所有重载方法签名SevenZipExtractor

自 Windows 10 Preview Build 17063 起,bsdtar 包含在 PowerShell 中。要提取 tar.xz 文件,请使用( ) 选项调用tar命令并在选项后指定存档文件名:--extract-x-f

tar -xf .\whatever.xz
Run Code Online (Sandbox Code Playgroud)

tar自动检测压缩类型并提取存档。要获得更详细的输出,请使用该-v选项。此选项指示tar在终端上显示正在提取的文件的名称。

内存中的普通 zip 文件

作为额外奖励,让我们看看它如何与 ZIP 一起使用。这是我在ffmpeg 源代码aes.hzip 存档中找到的示例:

    [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()
Run Code Online (Sandbox Code Playgroud)

另一个例子,旨在下载存档,从内存中的存档中运行 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($zipEntry.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"
Run Code Online (Sandbox Code Playgroud)

有关如何从内存运行 EXE 的更多信息,请参阅PowerShellMafia/PowerSploit 。在这里查找示例:GitHub 示例