使用 EWS 查找文件夹 ID



我想将电子邮件从一个文件夹移动到另一个文件夹。我知道我需要找到文件夹 ID。这就是我的问题所在。我看到收件箱有一个FindFolders方法,但我只需要在收件箱中找到文件夹的 ID。

[void] [Reflection.Assembly]::LoadFile("C:Program Files (x86)MicrosoftExchangeWeb Services2.1Microsoft.Exchange.WebServices.dll")
$s = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)
$s.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
$s.AutodiscoverUrl($email)
$inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($s,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox)
$psPropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$psPropertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text;
$items = $inbox.FindItems($inbox.TotalCount)
# this doesn't work
$TargetFolder = $inbox.FindFolders('MyFolder')
foreach ($item in $items.Items) {
$item.Move($TargetFolder)
}

我还在Outlook中使用VB查找了FolderID。但这也没有用。我想我需要通过PowerShell找到ID?

$TargetFolder = '00000000DBDD150E618BD0489CDE09859DC24F7A0100949BEDD21F6B4245BEEA6999720A0B090013516500830000'
$item.Move($TargetFolder)

我添加了using namespace并将其转换为Data.FolderID.但是,我收到一个错误,它希望它是一个众所周知的文件夹。我创建了一个客户主文件夹。

$TargetFolder = '00000000DBDD150E618BD0489CDE09859DC24F7A0100949BEDD21F6B4245BEEA6999720A0B090013516500830000'
$id = [Data.FolderId]::new($TargetFolder)
$item.Move($id.UniqueId)

我收到这些错误:

无法将参数"destinationFolderName"转换为",值为:"00000000DBDD150E618BD0489CDE09859DC24F7A0100949BEDD21F6B4245BEEA6999720A0B090013516500830000",对于"Move"键入"Microsoft.Exchange.WebServices.Data.WellKnownFolderName":

无法将值"00000000DBDD150E618BD0489CDE09859DC24F7A0100949BEDD21F6B4245BEEA6999720A0B090013516500830000"转换为类型"Microsoft.Exchange.WebServices.Data.WellKnownFolderName"。

错误:"无法将标识符名称00000000DBDD150E618BD0489CDE09859DC24F7A0100949BEDD21F6B4245BEEA6999720A0B090013516500830000与有效的枚举器名称匹配。指定以下枚举器名称之一,然后重试:

日历, 联系人, 已删除的项目, 草稿, 收件箱, 日记, 便笺, 发件箱, 已发送邮件, 任务, 消息文件夹根, 公用文件夹根, 根, 垃圾邮件, 搜索文件夹, 语音邮件, 可恢复项目根, 可恢复项目删除, 可恢复项目版本, 可恢复项目清除, 存档根, 存档Msg文件夹根, 存档已删除项目, 存档可恢复项目根目录, 存档可恢复项目删除, 存档可恢复项目版本, 存档可恢复项目清除, 同步问题, 冲突, 本地故障, ServerFailures, RecipientCache, QuickContacts, ConversationHistory, ToDoSearch">

At C:UsersjpbDesktopliteratumliteratum.ps1:261 char:1
+ $item.Move($id.UniqueId)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

当我用登录方式尝试您的代码时,我仍然出错。

Using namespace "Microsoft.Exchange.WebServices"
[CmdletBinding()]
param(
[parameter(Mandatory=$true)]
[string]$MailAddress
)
# need to download this!!!!!!!!!!!!
[void] [Reflection.Assembly]::LoadFile("C:Program Files (x86)MicrosoftExchangeWeb Services2.1Microsoft.Exchange.WebServices.dll")
$s = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)
$s.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
$s.AutodiscoverUrl($MailAddress)
$objExchange = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($s,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::msgFolderRoot)  ###Inbox
<#
Define Extended properties
PR_FOLDER_TYPE: Contains a constant that indicates the folder type.
https://msdn.microsoft.com/en-us/library/office/cc815373.asp
PR_MESSAGE_SIZE_EXTENDED: Contains the sum, in bytes, of the sizes of all properties on a message object.
int64 version of PR_MESSAGE_SIZE
https://msdn.microsoft.com/en-us/library/office/cc839933.aspx
PR_DELETED_MESSAGE_SIZE_EXTENDED: Could not find official reference.
PR_FOLDER_PATH: Could not find official reference.
#>
$PR_FOLDER_TYPE = [Data.ExtendedPropertyDefinition]::new(13825,[Data.MapiPropertyType]::Integer)
$PR_MESSAGE_SIZE_EXTENDED = New-Object Data.ExtendedPropertyDefinition(3592,[Data.MapiPropertyType]::Long);
$PR_DELETED_MESSAGE_SIZE_EXTENDED = New-Object Data.ExtendedPropertyDefinition(26267,[Data.MapiPropertyType]::Long);
$PR_FOLDER_PATH = New-Object Data.ExtendedPropertyDefinition(26293, [Data.MapiPropertyType]::String);
$folderIDCount = [Data.FolderId]::new([Data.WellKnownFolderName]::MsgFolderRoot,$MailAddress)
# Define the FolderView used for Export. Should not be any larger then 1000 folders due to throttling
$folderView = [Data.FolderView]::new(1000)
# Deep Traversal will ensure all folders in the search path are returned
$folderView.Traversal = [Data.FolderTraversal]::Deep;
$ewsPropertySet = [Data.PropertySet]::new([Data.BasePropertySet]::FirstClassProperties)
# Add Properties to the  Property Set
$ewsPropertySet.Add($PR_MESSAGE_SIZE_EXTENDED);
$ewsPropertySet.Add($PR_FOLDER_PATH);
$folderView.PropertySet = $ewsPropertySet;
# Exclude any Search Folders in the filter
$searchFilter = [Data.SearchFilter+IsEqualTo]::new($PR_FOLDER_TYPE,"1")
# The Do loop will handle any paging that is required if there are more the 1000 folders in a mailbox
do {
$filterResult = $objExchange.FindFolders($folderIDCount, $searchFilter, $folderView)
foreach ($singleFolder in $filterResult.Folders) {
# Try to get the FolderPath Value and then covert it to a usable String
$folderPathValue = $null
$singleFolder.TryGetProperty($PR_FOLDER_PATH, [ref]$folderPathValue) | Out-Null
# Output folder object to pipeline
$singleFolder | Select-Object Id,DisplayName,@{Name="FolderPath";Expression={$folderPathValue}},FolderClass,ParentFolderId
}
$folderView.Offset += $filterResult.Folders.Count
} while($filterResult.MoreAvailable)

我收到FindFolders方法的错误:

找不到 "FindFolders" 的重载,参数计数:"3"。

At line:50 char:9
+         $filterResult = $objExchange.FindFolders($folderIDCount, $sea ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest

我可以连接$objExchange,我得到这些值以及更多:

Id              : AAMkADk5ZDNmODk2LTk0NzAtNDZkNi05Mjk1LTNhMjNlYmYzNzg1ZAAuAAAAAADb3RUOYYvQSJzeCYWdwk96AQD+Gq9HeAtSSLFM1nhOxNIuAAAAMAqcAAA=
ParentFolderId  : AAMkADk5ZDNmODk2LTk0NzAtNDZkNi05Mjk1LTNhMjNlYmYzNzg1ZAAuAAAAAADb3RUOYYvQSJzeCYWdwk96AQD+Gq9HeAtSSLFM1nhOxNIuAAAAMAqbAAA=
ChildFolderCount: 20

这里的信息会比所需的多一点,但我想展示如何在我为与邮箱交互而创建的 cmdlet 中获取此信息。

如果您查看重载FindFolders()他们想要的不仅仅是一个字符串来获得您正在寻找的结果。我下面的示例使用最后一个重载

FindFolders(WellKnownFolderName, SearchFilter, FolderView)

使用指定的搜索筛选器和指定的文件夹视图搜索已知文件夹。

这是我必须获取邮箱中所有文件夹的功能。

[CmdletBinding()]
param(
[parameter(Mandatory=$true)]
[string]$MailAddress
)
# Create a reference to Exchange 2010 to match our current environment.
$objExchange = Connect-ExchangeService -MailAddress $MailAddress -DefaultCredentials
<#
Define Extended properties  
PR_FOLDER_TYPE: Contains a constant that indicates the folder type.
https://msdn.microsoft.com/en-us/library/office/cc815373.asp
PR_MESSAGE_SIZE_EXTENDED: Contains the sum, in bytes, of the sizes of all properties on a message object. int64 version of PR_MESSAGE_SIZE
https://msdn.microsoft.com/en-us/library/office/cc839933.aspx
PR_DELETED_MESSAGE_SIZE_EXTENDED: Could not find official reference.
PR_FOLDER_PATH: Could not find official reference.
#>
$PR_FOLDER_TYPE = [Data.ExtendedPropertyDefinition]::new(13825,[Data.MapiPropertyType]::Integer)
$PR_MESSAGE_SIZE_EXTENDED = New-Object Data.ExtendedPropertyDefinition(3592,[Data.MapiPropertyType]::Long);  
$PR_DELETED_MESSAGE_SIZE_EXTENDED = New-Object Data.ExtendedPropertyDefinition(26267,[Data.MapiPropertyType]::Long);  
$PR_FOLDER_PATH = New-Object Data.ExtendedPropertyDefinition(26293, [Data.MapiPropertyType]::String);  
$folderIDCount = [Data.FolderId]::new([Data.WellKnownFolderName]::MsgFolderRoot,$MailAddress)  
# Define the FolderView used for Export. Should not be any larger then 1000 folders due to throttling  
$folderView = [Data.FolderView]::new(1000)
# Deep Traversal will ensure all folders in the search path are returned  
$folderView.Traversal = [Data.FolderTraversal]::Deep;  
$ewsPropertySet = [Data.PropertySet]::new([Data.BasePropertySet]::FirstClassProperties)
# Add Properties to the  Property Set  
$ewsPropertySet.Add($PR_MESSAGE_SIZE_EXTENDED);  
$ewsPropertySet.Add($PR_FOLDER_PATH);  
$folderView.PropertySet = $ewsPropertySet;
# Exclude any Search Folders in the filter
$searchFilter = [Data.SearchFilter+IsEqualTo]::new($PR_FOLDER_TYPE,"1")  
#The Do loop will handle any paging that is required if there are more the 1000 folders in a mailbox  
do {  
$filterResult = $objExchange.FindFolders($folderIDCount, $searchFilter, $folderView)       
foreach($singleFolder in $filterResult.Folders){              
#Try to get the FolderPath Value and then covert it to a usable String
$folderPathValue = $null     
$singleFolder.TryGetProperty($PR_FOLDER_PATH, [ref]$folderPathValue) | Out-Null
# Output folder object to pipeline
$singleFolder | Select-Object Id,DisplayName,@{Name="FolderPath";Expression={$folderPathValue}},FolderClass,ParentFolderId
} 
$folderView.Offset += $filterResult.Folders.Count
}while($filterResult.MoreAvailable)

Connect-ExchangeService只是一个函数,它或多或少地执行了前几行正在做的事情。使用FindFolders()我从根文件夹搜索并将所有具有一些自定义属性的文件夹返回到$filterResult中。$filterResult现在包含有关每个文件夹的信息。特别是他们的身份证。

因此,如果我想将邮件项目移动到另一个文件夹,我可以做这样的事情。

$targetFolderID = ($folders | Where-Object{$_.Displayname -eq $sourceFolder}).ID.UniqueID
$item.Move($targetFolderID)

许多 EWS 参数都需要一个类型dID,而不仅仅是一个字符串。在上一个例子中,我认为这应该触发一个错误,说明类似的东西。无论哪种方式,如果你有一个像这样的字符串来获得 EWS 可以使用的东西

$id = [Data.FolderId]::new($targetFolderID)

您可能会注意到此处的类型名称较短。我的脚本中有Using namespace "Microsoft.Exchange.WebServices"来减少我的行长。

额外阅读

我很难让我的头被 EWS 包裹起来。这个博客对许多例子提供了极大的帮助,展示了它是如何完成的。作者也是这里经常回答EWS问题的成员。

好的。所以我尝试了一种深入旅行的新方法,以查找从msgFolderRoot开始的文件夹。

$s = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)
$s.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
$s.AutodiscoverUrl($MailAddress)
#$objExchange = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($s,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::msgFolderRoot)  ###Inbox
$objExchange = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($s,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::msgFolderRoot)  ###Inbox
$fv = [Microsoft.Exchange.WebServices.Data.FolderView]100
$fv.Traversal = 'Deep'
$objExchange.Load()
$folders = $objExchange.FindFolders($fv)|select DisplayName,ID
$folders = $objExchange.FindFolders($fv)
foreach ($folder in $folders) {
if ($folder.DisplayName -eq 'LiteratumLicenseInventoryReportArchive') {
$folderMoveTo = $folder;
}
}
$folderMoveTo

然后我通过搜索收件箱找到电子邮件,然后将文件夹转换为文件夹ID并移动该电子邮件。

$s = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)
$s.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
# discover the url from your email address
$s.AutodiscoverUrl($email)
$inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($s,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox) 
# create a property set (to let us access the body & other details not available from the FindItems call)
$psPropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
$psPropertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text;
$items = $inbox.FindItems($inbox.TotalCount)
foreach ($item in $items.Items) {
$item.load($psPropertySet)
if ($item.Subject.Contains('Subject Test')) {
$convertedFolder = [Data.FolderId]::new($folderMoveTo.Id)
$item.Move($convertedFolder)
break 
}
}

最新更新