使用EWS

时间:2017-08-23 13:58:10

标签: powershell outlook exchangewebservices

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

[void] [Reflection.Assembly]::LoadFile("C:\Program Files (x86)\Microsoft\Exchange\Web Services\2.1\Microsoft.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命名空间并将其转换为Data.FolderID。但是,我得到一个错误,它希望它是一个众所周知的文件夹。我创建了一个客户主文件夹。

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

       $item.Move( $id.UniqueId)

我得到了这些错误:

Cannot convert argument "destinationFolderName", with value: "00000000DBDD150E618BD0489CDE09859DC24F7A0100949BEDD21F6B4245BEEA6999720A0B090013516500830000", for "Move" to type 
    "Microsoft.Exchange.WebServices.Data.WellKnownFolderName": "Cannot convert value"00000000DBDD150E618BD0489CDE09859DC24F7A0100949BEDD21F6B4245BEEA6999720A0B090013516500830000" 
to type "Microsoft.Exchange.WebServices.Data.WellKnownFolderName". Error: "Unable to match the identifier name 
00000000DBDD150E618BD0489CDE09859DC24F7A0100949BEDD21F6B4245BEEA6999720A0B090013516500830000 to a valid enumerator name. Specify one of the following enumerator names and try 
again:
Calendar, Contacts, DeletedItems, Drafts, Inbox, Journal, Notes, Outbox, SentItems, Tasks, MsgFolderRoot, PublicFoldersRoot, Root, JunkEmail, SearchFolders, VoiceMail, 
RecoverableItemsRoot, RecoverableItemsDeletions, RecoverableItemsVersions, RecoverableItemsPurges, ArchiveRoot, ArchiveMsgFolderRoot, ArchiveDeletedItems, 
ArchiveRecoverableItemsRoot, ArchiveRecoverableItemsDeletions, ArchiveRecoverableItemsVersions, ArchiveRecoverableItemsPurges, SyncIssues, Conflicts, LocalFailures, 
ServerFailures, RecipientCache, QuickContacts, ConversationHistory, ToDoSearch""
At C:\Users\jpb\Desktop\literatum\literatum.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
)


[void] [Reflection.Assembly]::LoadFile("C:\Program Files (x86)\Microsoft\Exchange\Web Services\2.1\Microsoft.Exchange.WebServices.dll") # need to download this!!!!!!!!!!!!
$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方法中遇到此错误。

Cannot find an overload for "FindFolders" and the argument count: "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

2 个答案:

答案 0 :(得分:1)

这里的信息比需要的要多一些,但我想说明如何在我的cmdlet中获取此信息,以便与我的邮箱进行交互。

如果你看overloads for 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参数需要typedID,而不仅仅是字符串。在上一个例子中,我认为应该触发一个类似的错误。无论哪种方式,如果你有一个像这样的字符串,以获得EWS将使用的东西

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

您可能会注意到此处的类型名称较短。我的脚本中有Using namespace "Microsoft.Exchange.WebServices"来保持我的线路长度。

额外阅读

我很难将头部缠绕在EWS上。 This blog通过许多例子展示了它是如何完成的。作者也是这里经常回答EWS问题的成员。

答案 1 :(得分:0)

好。所以我尝试了一种新的Travel Deep方式,用于从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

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

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

}