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.
- The steps I'm taking below don't write any content to the zip variable or its entry.
- 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
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