PowerShell中的.Net异步方法:Net.Mail.SmtpClient::Send()不总是同步的?(与计划任务不一致) 问题:
发送电子邮件的PowerShell脚本在从交互式会话调用时工作,但在通过计划任务调用时失败。这似乎是由于脚本退出时SMTP会话在传输过程中被中断造成的。当然,在交互式会话期间不会发生这种情况,因为脚本结束后会话将继续活动。但是,通过计划任务调用时,会话将在脚本末尾终止 脚本:PowerShell中的.Net异步方法:Net.Mail.SmtpClient::Send()不总是同步的?(与计划任务不一致) 问题:,.net,email,powershell,asynchronous,scheduled-tasks,.net,Email,Powershell,Asynchronous,Scheduled Tasks,发送电子邮件的PowerShell脚本在从交互式会话调用时工作,但在通过计划任务调用时失败。这似乎是由于脚本退出时SMTP会话在传输过程中被中断造成的。当然,在交互式会话期间不会发生这种情况,因为脚本结束后会话将继续活动。但是,通过计划任务调用时,会话将在脚本末尾终止 脚本: $msg = New-Object Net.Mail.MailMessage foreach( $To in $Recipients ) { $msg.To.Add($To) }
$msg = New-Object Net.Mail.MailMessage
foreach( $To in $Recipients ) {
$msg.To.Add($To)
}
$msg.From = $From
$msg.Subject = $Subject
$msg.Body = $Body
$ctype = New-Object Net.Mime.ContentType -Property @{
MediaType = [Net.Mime.MediaTypeNames+Application]::Octet
Name = $AttachmentName
}
$msg.Attachments.Add([Net.Mail.Attachment]::CreateAttachmentFromString($csv, $ctype))
$client = new-object System.Net.Mail.SmtpClient($SMTPServer)
$client.Send($msg)
问题:
System.Net.Mail.SmtpClient::Send()应该是同步的,但实际上并不是这样。我知道我可以通过在脚本结束时让脚本短时间睡眠来缓解这种情况。坦率地说,这是一项非常草率的工作,我拒绝这样做。最好的解决办法是什么
注意:Send MailMessage
不合适,因为我宁愿避免创建文件来制作附件。我不确定它是否也有同样的问题。解决方案:sendsync()
不幸的是,Send()
并不像文档所说的那样同步。我发现使用异步变量sendascync()
并使用sendpleted
事件来提供同步性是最有益的。请参阅我为解决这个问题而编写的以下通用函数(尽管它可以用于各种异步调用):
<#
.SYNOPSIS
Calls a script block and waits for the specified event.
.DESCRIPTION
Provides a convenient way to call an asynchronous method with synchronous semantics.
This is achieved by registering to receive an event before calling the block that is
expected to signal its completion via a .NET event. The given script block need not
necessarily cause the event to be signaled, but that is the most obvious use case.
.PARAMETER EventSource
The object expected to raise the event.
.PARAMETER EventName
The name of the expected event.
.PARAMETER ScriptBlock
This block will be executed after registering the event and before waiting for the event.
.PARAMETER Timeout
Maximum duration in seconds to wait for the expected event. Default value of -1 means
to wait indefinitely. No error is raised when this timeout is reached.
.NOTES
Author: Erik Elmore <erik@ironsavior.net>
#>
function Wait-AsyncCall {
Param(
[Parameter(Mandatory = $True, Position = 0)]
$EventSource,
[Parameter(Mandatory = $True, Position = 1)]
[string]$EventName,
[Parameter(Mandatory = $True, Position = 2)]
[ScriptBlock]$ScriptBlock,
[int]$Timeout = -1
)
$id = "Wait-AsyncCall:$($EventName):$([guid]::NewGuid().ToString())"
Register-ObjectEvent $EventSource $EventName -SourceIdentifier $id -EA Stop
try {
$output = &$ScriptBlock
Wait-Event -SourceIdentifier $id -Timeout $Timeout -EA SilentlyContinue |Remove-Event -EA SilentlyContinue
}
finally {
Unregister-Event -SourceIdentifier $id -EA SilentlyContinue
}
$output
}
$msg = New-Object Net.Mail.MailMessage
foreach( $To in $Recipients ) {
$msg.To.Add($To)
}
$msg.From = $From
$msg.Subject = $Subject
$msg.Body = $Body
$ctype = New-Object Net.Mime.ContentType -Property @{
MediaType = [Net.Mime.MediaTypeNames+Application]::Octet
Name = $AttachmentName
}
$msg.Attachments.Add([Net.Mail.Attachment]::CreateAttachmentFromString($csv, $ctype))
$client = new-object System.Net.Mail.SmtpClient($SMTPServer)
Wait-AsyncCall $client "SendCompleted" { $client.SendAsync($msg, $Null) }