Is there a way of manipulating zip file contents in memory with Powershell?

后端 未结 3 1701
时光说笑
时光说笑 2021-01-03 06:46

I\'m currently trying to write a powershell function which works with the output of the Lync powershell cmdlet \"Export-CsConfiguration -AsBytes\". When using implicit Power

相关标签:
3条回答
  • 2021-01-03 07:05

    Answering my own question here, in case it proves useful to others: (N.B. Requires .NET 4.5)

    It looks like using System.IO.Compression.ZipArchive in combination with System.IO.Memorystream is the way forward. I've got this now:

    Function Load-CsConfig{
      [System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression') | Out-Null
    
      $ZipBytes = Export-CsConfiguration -AsBytes
      $ZipStream = New-Object System.IO.Memorystream
      $ZipStream.Write($ZipBytes,0,$ZipBytes.Length)
      $ZipArchive = New-Object System.IO.Compression.ZipArchive($ZipStream)
      $ZipEntry = $ZipArchive.GetEntry('DocItemSet.xml')
      $EntryReader = New-Object System.IO.StreamReader($ZipEntry.Open())
      $DocItemSet = $EntryReader.ReadToEnd()
      return $DocItemSet
    }
    

    Which does exactly what I need.

    Thanks all :)

    0 讨论(0)
  • 2021-01-03 07:13

    Making the "Made up Powershell function" a reality:

    #
    #   .SYNOPSIS
    #       Extract a file from a byte[] zip file
    #   
    #   .DESCRIPTION
    #       Extracts a file from a byte[] zip file as byte[]
    #   
    #   .PARAMETER ByteArray
    #       Byte array containing zip file
    #   
    #   .PARAMETER FileInsideZipIWant
    #       The file inside zip I want
    #   
    #   .PARAMETER utf8
    #       If the file is UTF-8 encoded, use this switch to get a string
    #   
    #   .EXAMPLE
    #       PS C:\> $utf8str = Extract-FileFromInMemoryZip -ByteArray $ZipFileBytes -FileInsideZipIWant "DocItemSet.xml" -utf8
    #       PS C:\> $utf8str = Extract-FileFromInMemoryZip $ZipFileBytes "DocItemSet.xml" -utf8
    #       PS C:\> $bs = Extract-FileFromInMemoryZip $ZipFileBytes "DocItemSet.xml"        
    #   
    #   .OUTPUTS
    #       string, byte[]
    #   
    #   .NOTES
    #       Exactly as desired. You may want to change the name of the "FileInsideZipIWant" parameter.
    #       Don't plan on extracting files larger than 2GB.
    #
    function Extract-FileFromInMemoryZip
    {
        [CmdletBinding(DefaultParameterSetName = 'raw')]
        [OutputType([string], ParameterSetName = 'utf8')]
        [OutputType([byte[]], ParameterSetName = 'raw')]
        param
        (
            [Parameter(Mandatory, ValueFromPipelineByPropertyName, Position = 0,
                       HelpMessage = 'Byte array containing zip file')]
            [byte[]]$ByteArray,
            [Parameter(Mandatory, ValueFromPipelineByPropertyName, Position = 1,
                       HelpMessage = 'Single file to extract')]
            [string]$FileInsideZipIWant,
            [Parameter(ParameterSetName = 'utf8')]
            [switch]$utf8
        )
    
        BEGIN { Add-Type -AN System.IO.Compression -ea:Stop } # Stop on error
    
        PROCESS {
            $entry = (
                New-Object System.IO.Compression.ZipArchive(
                    New-Object System.IO.MemoryStream ( ,$ByteArray)
                )
            ).GetEntry($FileInsideZipIWant)
    
            # Note ZipArchiveEntry.Length returns a long (rather than int),
            # but we can't conveniently construct arrays longer than System.Int32.MaxValue
            $b = [byte[]]::new($entry.Length)
    
            # Avoid StreamReader to (dramatically) improve performance
            # ...but it may be useful if the extracted file has a BOM header
            $entry.Open().Read($b, 0, $b.Length)
    
            write $(
                if ($utf8) { [System.Text.Encoding]::UTF8.GetString($b) }
                else { $b }
            )
        }
    }
    
    0 讨论(0)
  • 2021-01-03 07:23

    DotNetZip is your friend. This SO post reads from a stream, but it's C# code.

    The code below is PowerShell, but is untested. However, it should hopefully be a good starting point for you. You should get intellisense on the DotNetZip objects and there is tons of help and example code on their website.

    #load the DotNetZip assembly from disk and create a new zip object
    [System.Reflection.Assembly]::LoadFrom("C:\Path\To\Ionic.Zip.dll")
    $zipfile = New-Object Ionic.Zip.ZipFile
    
    #your stream
    $ZipFileBytes = Export-CsConfiguration -AsBytes
    
    #your filename
    $filename = "DocItemSet.xml"
    
    $zipfile.Read($ZipFileBytes)
    $file = $zipfile[$filename]
    
    $stream = $file.OpenReader()
    
    $buffer = New-Object Byte[] 4096
    [int]$n
    
    [string]$xmlFile = ""
    
    cls
    do {
      $n = $stream.Read($buffer,0, $buffer.Length);
      $totalBytesRead+=$n;
      $xmlFile += [System.Text.Encoding]::ASCII.GetString($buffer)
    } while ($n -gt 0);
    
    $stream.Close()
    $stream.Dispose()
    $zipfile.Dispose()
    
    0 讨论(0)
提交回复
热议问题