Home > OS >  In Powershell, using only memory (no disk storage available), how can I create a zip archive of a la
In Powershell, using only memory (no disk storage available), how can I create a zip archive of a la

Time:11-08

In Powershell, I'm trying to create a zip file from a large text string, attach it to an email message, and send it along. The trick is that I need to do it without using local storage or disk resources, creating the constructs in memory.

I have two pieces where I'm stuck.

  1. The steps I'm taking below don't write any content to the zip variable or its entry.
  2. How do I attach the zip, once it's complete, to the email?

Because I can't get past the first issue of creating the zip, I haven't been able to attempt to attach the zip to the email.

$strTextToZip = '<html><head><title>Log report</title></head><body><p>Paragraph</p><ul><li>first</li><li>second</li></ul></body></html>'

Add-Type -Assembly 'System.IO.Compression'
Add-Type -Assembly 'System.IO.Compression.FileSystem'

# step 1 - create the memorystream for the zip archive
   $memoryStream = New-Object System.IO.Memorystream
   $zipArchive = New-Object System.IO.Compression.ZipArchive($memoryStream, [System.IO.Compression.ZipArchiveMode]::Create, $true)

# step 2 - create the zip archive's entry for the log file and open it for writing
   $htmlFile = $zipArchive.CreateEntry("log.html", 0)
   $entryStream = $htmlFile.Open()

# step 3 - write the HTML file to the zip archive entry
   $fileStream = [System.IO.StreamWriter]::new( $entryStream )
   $fileStream.Write( $strTextToZip )
   $fileStream.close()

# step 4 - create mail message
   $msg = New-Object Net.Mail.MailMessage($smtp['from'], $smtp['to'], $smtp['subject'], $smtp['body'])
   $msg.IsBodyHTML = $true

# step 5 - add attachment
   $attachment = New-Object Net.Mail.Attachment $memoryStream, "application/zip"
   $msg.Attachments.Add($attachment)

# step 6 - send email
   $smtpClient = New-Object Net.Mail.SmtpClient($smtp['server'])
   $smtpClient.Send($msg)

The streaming in step 3 for the entry doesn't populate the variable. Also, once populated successfully, I'm not sure how to close the streams and keep the content available for the email attachment. Lastly, I think the Add for the Net.Mail.Attachment in step 5 should successfully copy the zip to the message, but any pointers here would be welcome as well.

CodePudding user response:

For the sake of at least giving a proper guidance on the first item, how to create a Zip in Memory without a file. You're pretty close, this is how it's done, older version of demo

Now trying to answer the 2nd question, this is based on a hunch and I think your logic is sound already, Attachment class has a .ctor that supports a stream Attachment(Stream, ContentType) so I feel this should work properly though I can't personally test it:

$msg = [MailMessage]::new($smtp['from'], $smtp['to'], $smtp['subject'], $smtp['body'])
$msg.IsBodyHTML = $true

# EDIT:
# Based on OP's comments, this is the correct order to follow
# first Flush()
$memStream.Flush()
# then
$memStream.Position = 0
# now we can attach the memstream

# Use `Attachment(Stream, String, String)` ctor instead
# so you can give it a name
$msg.Attachments.Add([Attachment]::new(
    $memStream,
    'nameyourziphere.zip',
    [ContentType]::new('application/zip')
))
$memStream.Close() # I think you can close here then send
$smtpClient = [SmtpClient]::new($smtp['server'])
$smtpClient.EnableSsl = $true
$smtpClient.Send($msg)
$msg, $smtpClient | ForEach-Object Dispose
  • Related