如何使用 PowerShell 和 EWS 将邮件消息导出到 EML 或 MSG 文件第 2 部分
How to export mail message to EML or MSG file with PowerShell and EWS part 2
我正在尝试导出 Exchange 2010 中特定帐户收件箱中的所有邮件。我在另一个 post 中找到了这个解决方案,它看起来很有前途,但我遇到了错误运行 脚本。我是使用 EWS 的新手,我有点迷茫。
这是我目前使用的代码的副本:
add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010
$strMailboxName = "Mailbox@domain.com"
$strSaveLocation = "\server\share"
$dllpath = "C:\Program Files\Microsoft\Exchange\Web Services.2\Microsoft.Exchange.WebServices.dll"
[void][Reflection.Assembly]::LoadFile($dllpath)
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
$windowsIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$sidbind = "LDAP://<SID=" + $windowsIdentity.user.Value.ToString() + ">"
$aceuser = [ADSI]$sidbind
$service.AutodiscoverUrl($aceuser.mail.ToString())
$MailboxName = get-mailbox -Identity $strMailboxName
$folderidcnt = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$MailboxName.PrimarySmtpAddress.ToString())
$rootfolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service, $folderidcnt)
$offset = 0;
$view = new-object Microsoft.Exchange.WebServices.Data.ItemView(10000, $offset)
$response = $service.LoadPropertiesForItems($results, [Microsoft.Exchange.WebServices.Data.PropertySet]::FirstClassProperties)
foreach ($mail in $results){
if ($mail.ToString() -eq "Microsoft.Exchange.WebServices.Data.EmailMessage") {
$mailSubject = $mail.Subject
$mailProps = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.ItemSchema]::MimeContent)
$mail.Load($mailProps)
#TODO: clean up $mailSubject so it's filesystem friendly
$fStream = New-Object System.IO.FileStream("$strSaveLocatoin$mailSubject.eml", [System.IO.FileMode]::Create)
$fStream.Write($mail.MimeContent.Content, 0, $mail.MimeContent.Content.Length)
$fStream.Close()
}
}
我收到以下错误:
Exception calling "LoadPropertiesForItems" with "2" argument(s): "Value cannot be null.
Parameter name: items"
At C:\PowershellScripts\Exchange-SaveEMailAsFile.ps1:23 char:44
+ $response = $service.LoadPropertiesForItems <<<< ($results, [Microsoft.Exchange.WebServices.Data.PropertySet]::FirstC
lassProperties)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
You cannot call a method on a null-valued expression.
At C:\PowershellScripts\Exchange-SaveEMailAsFile.ps1:27 char:19
+ if ($mail.ToString <<<< () -eq "Microsoft.Exchange.WebServices.Data.EmailMessage") {
+ CategoryInfo : InvalidOperation: (ToString:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
我在脚本的开头匿名化了 2 个 $str 变量,但除此之外,代码与我 posted.
我本来想给原帖加个评论post,但是我还没有足够的声望。
如有任何帮助,我们将不胜感激。谢谢。
LoadPropertiesForItems
expects that the first variable passed contains that items object and $result
is not populated in that code so that is why you are getting the errors. You can see an example of this from the MSDN blog.
我测试了以下哪些方法可以从连接到名为 $exchangeService
的 Exchange 服务的邮箱的收件箱中获取每封邮件。您将需要更改此代码中的几个变量以匹配您的变量。这是故意的,以便您可以看到事情是如何运作的。
这段代码可能会更好,因为我对此的经验也很有限。因为这并不难,而且需要完成才能进行良好的测试,所以我用一些正则表达式解决了这个评论:#TODO: clean up $mailSubject so it's filesystem friendly。 没有 这里做的一件事是逻辑来解释包含空白主题的文件。目前他们会互相覆盖,你最终会得到一个像处理过的最后一个“.eml”文件。
# Folder that will contain the eml files.
$destinationFolder = "E:\temp\test"
# Create the view. Set for 1000 paged items
$pageSize = 1000
$itemView = [Microsoft.Exchange.WebServices.Data.ItemView]::New($pageSize)
$itemView.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$mimeView = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.ItemSchema]::MimeContent)
# Bind to the root folder
$rootFolderID = New-Object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox)
$boundRootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($exchangeService,$rootFolderID)
# regex to remove illegal characters in the subject that are not allowed in the ntfs file system
$regex = ([char[]]'<>:"/\|?*' | ForEach-Object{[regex]::Escape($_)})-join"|"
# Loop through paging results
do{
# Get the next batch of results
$filterResults = $boundRootFolder.FindItems($itemView)
# We need to process each mail in this set of results
$filterResults.Items | ForEach-Object{
# Get the subject before we change the view
$mailSubject = $_.Subject -replace $regex
# Load the properties for the view create earlier
$_.Load($mimeView)
# Using a file stream to export this single messages mime content
write-host "$destinationFolder$mailSubject.eml" -ForegroundColor Green
$stream = New-Object System.IO.FileStream("$destinationFolder$mailSubject.eml", [System.IO.FileMode]::Create)
$stream.Write($_.MimeContent.Content, 0, $_.MimeContent.Content.Length)
$stream.Close()
}
# Loop if there are still more results in the filter. Adjust the filter offset.
$itemView.Offset += $filterResults.Items.Count
} while($filterResults.MoreAvailable)
我的第一个问题是我应该能够同时加载所需的属性,但我不知道该怎么做,因此技术上有两个加载操作。首先在初始查找期间再次循环以获取 mime 内容。这可能是必须完成的方式,因为如果您尝试一次完成所有操作,您会收到错误
The property MimeContent can't be used in FindItem requests.
我会好好看看 Glen's blog on the EWS API。很多好的信息和例子。当我苦苦挣扎时,这让我对 EWS API 的工作方式有了坚实的基础。他也是我经常看到的这里的用户
我正在尝试导出 Exchange 2010 中特定帐户收件箱中的所有邮件。我在另一个 post
这是我目前使用的代码的副本:
add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010
$strMailboxName = "Mailbox@domain.com"
$strSaveLocation = "\server\share"
$dllpath = "C:\Program Files\Microsoft\Exchange\Web Services.2\Microsoft.Exchange.WebServices.dll"
[void][Reflection.Assembly]::LoadFile($dllpath)
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)
$windowsIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$sidbind = "LDAP://<SID=" + $windowsIdentity.user.Value.ToString() + ">"
$aceuser = [ADSI]$sidbind
$service.AutodiscoverUrl($aceuser.mail.ToString())
$MailboxName = get-mailbox -Identity $strMailboxName
$folderidcnt = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$MailboxName.PrimarySmtpAddress.ToString())
$rootfolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service, $folderidcnt)
$offset = 0;
$view = new-object Microsoft.Exchange.WebServices.Data.ItemView(10000, $offset)
$response = $service.LoadPropertiesForItems($results, [Microsoft.Exchange.WebServices.Data.PropertySet]::FirstClassProperties)
foreach ($mail in $results){
if ($mail.ToString() -eq "Microsoft.Exchange.WebServices.Data.EmailMessage") {
$mailSubject = $mail.Subject
$mailProps = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.ItemSchema]::MimeContent)
$mail.Load($mailProps)
#TODO: clean up $mailSubject so it's filesystem friendly
$fStream = New-Object System.IO.FileStream("$strSaveLocatoin$mailSubject.eml", [System.IO.FileMode]::Create)
$fStream.Write($mail.MimeContent.Content, 0, $mail.MimeContent.Content.Length)
$fStream.Close()
}
}
我收到以下错误:
Exception calling "LoadPropertiesForItems" with "2" argument(s): "Value cannot be null.
Parameter name: items"
At C:\PowershellScripts\Exchange-SaveEMailAsFile.ps1:23 char:44
+ $response = $service.LoadPropertiesForItems <<<< ($results, [Microsoft.Exchange.WebServices.Data.PropertySet]::FirstC
lassProperties)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
You cannot call a method on a null-valued expression.
At C:\PowershellScripts\Exchange-SaveEMailAsFile.ps1:27 char:19
+ if ($mail.ToString <<<< () -eq "Microsoft.Exchange.WebServices.Data.EmailMessage") {
+ CategoryInfo : InvalidOperation: (ToString:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
我在脚本的开头匿名化了 2 个 $str 变量,但除此之外,代码与我 posted.
我本来想给原帖加个评论post,但是我还没有足够的声望。
如有任何帮助,我们将不胜感激。谢谢。
LoadPropertiesForItems
expects that the first variable passed contains that items object and $result
is not populated in that code so that is why you are getting the errors. You can see an example of this from the MSDN blog.
我测试了以下哪些方法可以从连接到名为 $exchangeService
的 Exchange 服务的邮箱的收件箱中获取每封邮件。您将需要更改此代码中的几个变量以匹配您的变量。这是故意的,以便您可以看到事情是如何运作的。
这段代码可能会更好,因为我对此的经验也很有限。因为这并不难,而且需要完成才能进行良好的测试,所以我用一些正则表达式解决了这个评论:#TODO: clean up $mailSubject so it's filesystem friendly。 没有 这里做的一件事是逻辑来解释包含空白主题的文件。目前他们会互相覆盖,你最终会得到一个像处理过的最后一个“.eml”文件。
# Folder that will contain the eml files.
$destinationFolder = "E:\temp\test"
# Create the view. Set for 1000 paged items
$pageSize = 1000
$itemView = [Microsoft.Exchange.WebServices.Data.ItemView]::New($pageSize)
$itemView.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$mimeView = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.ItemSchema]::MimeContent)
# Bind to the root folder
$rootFolderID = New-Object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox)
$boundRootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($exchangeService,$rootFolderID)
# regex to remove illegal characters in the subject that are not allowed in the ntfs file system
$regex = ([char[]]'<>:"/\|?*' | ForEach-Object{[regex]::Escape($_)})-join"|"
# Loop through paging results
do{
# Get the next batch of results
$filterResults = $boundRootFolder.FindItems($itemView)
# We need to process each mail in this set of results
$filterResults.Items | ForEach-Object{
# Get the subject before we change the view
$mailSubject = $_.Subject -replace $regex
# Load the properties for the view create earlier
$_.Load($mimeView)
# Using a file stream to export this single messages mime content
write-host "$destinationFolder$mailSubject.eml" -ForegroundColor Green
$stream = New-Object System.IO.FileStream("$destinationFolder$mailSubject.eml", [System.IO.FileMode]::Create)
$stream.Write($_.MimeContent.Content, 0, $_.MimeContent.Content.Length)
$stream.Close()
}
# Loop if there are still more results in the filter. Adjust the filter offset.
$itemView.Offset += $filterResults.Items.Count
} while($filterResults.MoreAvailable)
我的第一个问题是我应该能够同时加载所需的属性,但我不知道该怎么做,因此技术上有两个加载操作。首先在初始查找期间再次循环以获取 mime 内容。这可能是必须完成的方式,因为如果您尝试一次完成所有操作,您会收到错误
The property MimeContent can't be used in FindItem requests.
我会好好看看 Glen's blog on the EWS API。很多好的信息和例子。当我苦苦挣扎时,这让我对 EWS API 的工作方式有了坚实的基础。他也是我经常看到的这里的用户