powershellzip

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


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 Powershell remoting with the Lync Cmdlets, the -AsBytes flag is the only way to work the Export-CsConfiguration cmdlet, and it returns a Byte array, which, if you write it to disk with "Set-Content -Encoding Byte", results in a zip file.

I'm wondering if there's a way to expand the content of the byte array into the two files which are contained in that zip, but only do it in memory. I'm not really interested in keeping the zip file around for long, as it changes frequently, and something about writing the file contents out to disk only to read them straight back in again so I can do something with the uncompressed content seems horribly wrong to me.

So is there someway of doing something like this which avoids writes to disk:

$ZipFileBytes = Export-CsConfiguration -AsBytes
# Made up Powershell function follows:
[xml]DocItemSet = Extract-FileFromInMemoryZip -ByteArray $ZipFileBytes -FileInsideZipIWant "DocItemSet.xml"
# Do stuff with XML here

Instead of doing:

$ZipFileBytes = Export-CsConfiguration -AsBytes | Set-Content -Encoding Byte "CsConfig.zip"
[System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')
[System.IO.Compression.ZipFile]::ExtractToDirectory("CsConfig.zip", "C:\Temp")
[xml]$DocItemSet = New-Object Xml.XmlDocument
$DocItemSet.Load("C:\Temp\DocItemSet.xml")
# Do stuff with XML here

Or am I SOL?


Solution

  • 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 :)