Powershell Send-MailMessage在发送失败后不会处理附件

时间:2013-08-22 12:07:56

标签: email powershell dispose

我的自动化Powershell Hyper-V备份脚本遇到了一些麻烦。该脚本运行完美,但我的问题是,当我尝试发送带有日志文件作为附件的电子邮件时,它在FAILS发送后不会解锁文件。 (当我成功发送邮件时,我无法检查它的行为方式,但说实话,它也应该处理它,即使它无法发送。)

我在整个网络上搜索过所有我能找到的,是:

  1. Send-MailMessage在发送后自动处理附件 邮件。
  2. 使用Powershell v1中的方法和new-object system.net.mail.mailmessage和new-object system.net.mail.attachment。
  3. 继承我的代码部分(我已将其缩短为只需要代码的基本要素):

    [String]$ComputerName = Get-Content Env:ComputerName
    [String]$LogFile = "Hyper-V Backup Logs\$ComputerName.Hyper-V Backup." + (Get-Date).Day + "-" +(Get-Date).Month + "-" +(Get-Date).Year + "-" +(Get-Date).Hour + "." +(Get-Date).Minute + "." +(Get-Date).Second + ".log"
    
    "# $(Get-Date) :: Attempting to send log file to 'Support@example.dk'..." | Out-File $LogFile -Append
    Try
    {
        $EmailTo = "Support@example.dk"
        $EmailFrom = "Service@example.dk"
        $EmailServer = "server.example.dk"
        $EmailSubject = "An error occurred during Hyper-V Backup on $ComputerName!"
        $EmailBody = "Hello,
    
        An error occured during Hyper-V Backup on $ComputerName.
    
        I have attached the log file, $LogFile, to this mail.
    
        Kind Regards,<br></p>
        Hyper-V Backup.
        "
    
        Send-MailMessage -From $EmailFrom -To $EmailTo -Subject $EmailSubject -Body $EmailBody -Attachments $LogFile -SmtpServer $EmailServer
        "# $(Get-Date) :: Successfully send log file to 'Support@example.dk" | Out-File $LogFile -Append
    
    }
    Catch
    {
        "# $(Get-Date) :: Failed to send log file to 'Support@example.dk" | Out-File $LogFile -Append
        "                      :: Error Command: Send-MailMessage -From $EmailFrom -To $EmailTo -Subject $EmailSubject -Body $EmailBody -Attachments $LogFile -SmtpServer $EmailServer" | Out-File $LogFile -Append
        "                      :: Error Message: $($_.Exception.Message)" | Out-File $LogFile -Append
    }
    

    会引发以下错误:

    Out-File : The process cannot access the file 'C:\Hyper-V Backup\Hyper-V Backup
    Logs\example.Hyper-V Backup.22-8-2013-13.48.16.log' because it is being used by
    another process.
    At C:\Hyper-V Backup\Hyper-V Backup.ps1:310 char:163
    + ... port@example.dk" | Out-File $LogFile -Append
    +                    ~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : OpenError: (:) [Out-File], IOException
        + FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand
    

    所以我的问题是,如果发送电子邮件失败后如何让Send-MailMessage处理附件,那么我的脚本可以继续写入日志文件?

    PS。当邮件成功发送时,上面的脚本可以正常工作,不会丢失任何错误,也不会锁定文件。

    亲切的问候,

    Thomas Schmidt

    修改

    我选择了旧的Powershell v1方式:

    Try
    {
        $SMTPServer = "exchange.example.dk"
        $SMTP = new-object Net.Mail.SmtpClient($SMTPServer)
    
        $EmailAttachment = new-object Net.Mail.Attachment($Logfile)
        $EmailMessage = new-object Net.Mail.MailMessage
    
        $EmailMessage.Attachments.Add($EmailAttachment)
        $EmailMessage.From = "service@example.dk"
        $EmailMessage.To.Add("spport@example.dk")
        $EmailMessage.Subject = "Notification from email server"
        $EmailMessage.Body = "Hello,
    An error occurred during A/S Hyper-V Backup on $ComputerName.
    
    I have attached the log file, $LogFile, to this mail.
    
    Kind Regards,
    Hyper-V Backup.
    "
        $SMTP.Send($EmailMessage)
        $EmailAttachment.Dispose()
        Write-Host "# $(Get-Date) :: Successfully send log file to 'Support@example.dk" -foregroundcolor green; "# $(Get-Date) :: Successfully send log file to 'Support@example.dk" | Out-File $LogFile -Append
    }
    Catch
    {
        $EmailAttachment.Dispose()
        Write-Host "# $(Get-Date) :: Failed to send log file to 'Support@example.dk" -foregroundcolor red; "# $(Get-Date) :: Failed to send log file to 'Support@example.dk" | Out-File $LogFile -Append
        "                      :: Error Command: SMTP.Send(EmailMessage)" | Out-File $LogFile -Append
        "                      :: Error Message: $($_.Exception.Message)" | Out-File $LogFile -Append
    }
    

    但如果有人能提供上述答案,我很乐意使用该解决方案!

    亲切的问候,

    Thomas Schmidt

2 个答案:

答案 0 :(得分:1)

这就是我处理它的方式,它似乎对我有用:

 try {
    $ErrorActionPreference = 'Stop'
    $SmtpSettings = @{
        To = $Recipients.Split(',')
        From = $Sender
        SmtpServer = $SmtpServer
        Subject = "Email test"
        Body = "Please check attached file"
        Attachment = $Attachment
    }
    Send-MailMessage @SmtpSettings -BodyAsHtml
 } catch {
    $ErrorActionPreference = 'Continue'
    [gc]::collect()
    $CustomError = ($_ -replace "`r`n","")
    $ScriptLine = "$($_.InvocationInfo.ScriptLineNumber)" +','+ "$($_.InvocationInfo.OffsetInLine)"
    Write-Verbose "Error sending email: $CustomError (script line $ScriptLine)"
}

我基本上使用垃圾收集器 - [gc] :: collect(),尽管发送电子邮件时出错,但它解锁了附件文件。 我还在尝试中设置 $ ErrorActionPreference ='停止',这样就可以正确捕获错误并且 $ ErrorActionPreference ='继续' 捕获,因此脚本不会完全停止。

答案 1 :(得分:0)

尝试这种旧式。对我来说很好。

#Send Email
$smtpServer = "10.10.10.10"
$file = "C:\Temp\TEST.zip"
$att = new-object Net.Mail.Attachment($file)
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = "MYNAME@DOMAIN.com"
$msg.To.Add("yourname@domian.com")
$msg.CC.Add("yourname2@domain.com")
$msg.Subject = "Subject here"
$msg.Body = "Body here"
$msg.Attachments.Add($att)
$smtp.Send($msg)
$att.Dispose()