I want to move an email from one folder to another. I know I need to find the folder ID. That's where my issue is. I see there is a FindFolders
method for the inbox, but I just need to find the ID of the folder in the inbox.
[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)
}
I also looked up the FolderID
using VB in Outlook. But this didn't work either. I think I need to find the ID through PowerShell?
$TargetFolder = '00000000DBDD150E618BD0489CDE09859DC24F7A0100949BEDD21F6B4245BEEA6999720A0B090013516500830000'
$item.Move($TargetFolder)
I added the using namespace
and converted the to Data.FolderID
. However, I get an error that it wants it to be a well known folder. I created a customer main folder.
$TargetFolder = '00000000DBDD150E618BD0489CDE09859DC24F7A0100949BEDD21F6B4245BEEA6999720A0B090013516500830000'
$id = [Data.FolderId]::new($TargetFolder)
$item.Move($id.UniqueId)
I get these errors:
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
When I try your code with my login way I still error out.
Using namespace "Microsoft.Exchange.WebServices"
[CmdletBinding()]
param(
[parameter(Mandatory=$true)]
[string]$MailAddress
)
# need to download this!!!!!!!!!!!!
[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($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)
I get this error for the FindFolders
method:
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
I can connecting for $objExchange
and I get these values and more:
Id : AAMkADk5ZDNmODk2LTk0NzAtNDZkNi05Mjk1LTNhMjNlYmYzNzg1ZAAuAAAAAADb3RUOYYvQSJzeCYWdwk96AQD+Gq9HeAtSSLFM1nhOxNIuAAAAMAqcAAA=
ParentFolderId : AAMkADk5ZDNmODk2LTk0NzAtNDZkNi05Mjk1LTNhMjNlYmYzNzg1ZAAuAAAAAADb3RUOYYvQSJzeCYWdwk96AQD+Gq9HeAtSSLFM1nhOxNIuAAAAMAqbAAA=
ChildFolderCount: 20
There is going to be a little more information here than required but I want to show how I get this information in my cmdlets that I made for interacting with my mailbox.
If you look at the overloads for FindFolders()
they want more than just a string to get the results you are looking for. My example below uses the last overload
FindFolders(WellKnownFolderName, SearchFilter, FolderView)
Searches a well-known folder by using a specified search filter and a specified folder view.
This is a function I have to get me all folders in a mailbox.
[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
is just a function that does more or less what your first few lines are doing. Using FindFolders()
I search from the root folder and return all folders with some custom properties into $filterResult
. $filterResult
now contains information about each folder. Specifically their ID's.
So down the line if I wanted to move a mail item to another folder I could do something like this.
$targetFolderID = ($folders | Where-Object{$_.Displayname -eq $sourceFolder}).ID.UniqueID
$item.Move($targetFolderID)
Plenty of the EWS parameters want a typedID, not just a string. In you last example I think that should have triggered an error stating something similar. Either way if you have a string cast it like this to get something EWS will work with
$id = [Data.FolderId]::new($targetFolderID)
You might notice that the type names here are shorter. I have Using namespace "Microsoft.Exchange.WebServices"
in my script to keep my line length down.
I had a tough time getting my head wrapped around EWS. This blog helped immensely with many example showing how its done. The author is also a member here that frequently answers EWS questions.