powershell - 在 Powershell 中,仅使用内存(没有可用的磁盘存储),如何创建大型文本文件的 zip 存档并将其附加到电子邮件中?

标签 powershell email zip memorystream system.io.compression

在 Powershell 中,我试图从一个大文本字符串创建一个 zip 文件,将其附加到电子邮件中,然后一起发送。诀窍是我需要在不使用本地存储或磁盘资源的情况下在内存中创建结构。

我有两 block 卡住了。

  1. 我在下面执行的步骤不会将任何内容写入 zip 变量或其条目。
  2. 完成后如何将 zip 附加到电子邮件?

因为我无法通过创建 zip 的第一个问题,所以我无法尝试将 zip 附加到电子邮件中。

$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)

条目的第 3 步中的流式处理不会填充变量。此外,一旦成功填充,我不确定如何关闭流并保持内容可用于电子邮件附件。最后,我认为第 5 步中 Net.Mail.AttachmentAdd 应该可以成功地将 zip 复制到邮件中,但也欢迎任何指点。

最佳答案

为了至少对第一项提供正确的指导,如何在没有文件的情况下在内存中创建 Zip。你已经很接近了,这就是它的完成方式,旧版本的 Compress-Archive使用与 MemoryStream 类似的逻辑值得注意的是,它有 2Gb 的限制,请参阅 this answer了解更多详情。

using namespace System.Text
using namespace System.IO
using namespace System.IO.Compression
using namespace System.Net.Mail
using namespace System.Net.Mime

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

$memStream     = [MemoryStream]::new()
$zipArchive    = [ZipArchive]::new($memStream, [ZipArchiveMode]::Create, $true)
$entry         = $zipArchive.CreateEntry('log.html', [CompressionLevel]::Optimal)
$wrappedStream = $entry.Open()
$writer = [StreamWriter] $wrappedStream
$writer.AutoFlush = $true
$writer.Write(@'
<html>
  <head>
    <title>Log report</title>
  </head>
  <body>
    <p>Paragraph</p>
    <ul>
      <li>first</li>
      <li>second</li>
    </ul>
  </body>
</html>
'@)

$writer, $wrappedStream, $zipArchive | ForEach-Object Dispose

到此为止,第一个问题已经得到解答,现在 $memStream 将您的 Zip 文件保存在内存中,如果我们要测试这是否属实(显然我们需要一个文件,因为我没有可用于进一步测试的 smtp 服务器):

$file = (New-Item 'test.zip' -ItemType File -Force).OpenWrite()
$memStream.Flush()
$memStream.WriteTo($file)
# We dispose here for demonstration purposes
# in the actual code you should Dispose as last step (I think, untested)
$file, $memStream | ForEach-Object Dispose

生成的 Zip 文件将变为:

demo

现在尝试回答第二个问题,这是基于直觉,我认为你的逻辑已经很合理了,Attachment 类有一个支持流的 .ctor Attachment(Stream, ContentType)所以我觉得这应该可以正常工作,尽管我不能亲自测试它:

$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

关于powershell - 在 Powershell 中,仅使用内存(没有可用的磁盘存储),如何创建大型文本文件的 zip 存档并将其附加到电子邮件中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74325724/

相关文章:

javascript - 使用 html5 和 javascript 创建带有动态生成正文的电子邮件链接

html - EDM 模板中的顶部对齐 <td>

javascript - 如何通过 Gmail API 在 JavaScript 中发送带有附件的邮件

php - 为 PHP 启用 zip 扩展

zip - 解压缩 Zip 压缩的二进制字符串

powershell - 在 PowerShell 中从 2 个变量创建一个递增变量

作为提升用户的 Python 子进程脚本

c++ - 应用程序/zip winsock C++

r - 连接断开时如何在PowerShell中对R脚本自动重试

powershell - 如何在 vNext 版本模板的部署日志中获取 powershell 脚本输出?