Adding a Retention Tag / Custom Folder / Exchange


At the company I work for we have begun the task of moving users to Exchange online.  As such we discovered we needed to add a policy that sets the retention policy on a folder to some value specified by the online exchange administrator.  This Post is about how I was able to piece together some scripts  from this post and come up with something where I could apply this policy on any folder I found with a specific name. I by no means am an Exchange expert so bear with me as I do my best to explain.

To start with if we browse to my Exchange and look at compliance management then retention policy’s I’ve set a test retention policy as I want the contents of a folder to be held for X time period.

This is my Retention tag and what I called it TestRetention

2017-02-08 15_12_13-retention tags - Microsoft Exchange.png

Here I’ve associated my tag with my Policy:

2017-02-08-14_56_43-retention-policies-microsoft-exchange

Here I’m showing that my user has the retention policy set that has my tag in it.

2017-02-08 15_11_04-mailboxes - Microsoft Exchange.png

Now onto the scripts that I started Stamping Retention Policy Tag and Script to recreate “managed folders”.

In the example they show you how to connect to the on premise exchange server.  To connect to an exchange online instance just had to modify the code to this:

$ImpersonationCreds = Get-Credential -Message "Enter Credentials for Account with Impersonation Role..."
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $connectionUri -Authentication Basic -Credential $ImpersonationCreds
Import-PSSession $Session

Where the connection uri is to exchange online: ‘https://outlook.office365.com/powershell-liveid/’

This session brings in all the cmdlets that I’ll need to use for configuring using what is called PowerShell Implicit remoting. Now since I have the cmdlets for Exchange online I can now work on the mailbox I need to make this change on.

$mailboxes = get-content $TargetMailboxes
   $Version = "Exchange2013_SP1"
    $returnStatus =@()
    Add-Type -Path $ApiPath
    $ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::$Version
    $Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
    $Creds = New-Object System.Net.NetworkCredential($ImpersonationCreds.UserName, $ImpersonationCreds.Password)
    $RetentionPeriod = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x301A,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Integer)
    $RetentionFlags = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x301D,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Integer)
    $PolicyTag = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x3019,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary) 

The $ExchangeVersion sets my version that I’m going to use.   In order to get to the Retention flag and policy I need to declare objects that contain those items shown in the pictures above.  Another good post on how we are connecting and looking to accomplish is posted here. Now onto the meat of the post.  The function I wrote to search for folders in TargetMailbox.

I chose to call this function Get-Mailbox folders. The function expects a Exchange service object, a Valid SMTP Mail box, and a Folder2Find.

The assumption is that whomever is running this script has the proper credentials to get to this mailbox.   To be able to find objects in the mailbox we must get an object that allows us to see the Folderviews and set a value for how many we wish to find. In addition we need to tell the Exchange dll how far to traverse the mailbox this is done by setting an enum value on the FolderView object. Now that we have told the dll that we want a folder vview and we want to traverse the folder view a 1000 deep.  We need to tell the Dll what the folder we want to start with. This is done by creating the folder ID object with the folder root, again using an enum value, this enum value we’ve chosen is the Root folder.

$fvFolderView = new-object Microsoft.Exchange.WebServices.Data.FolderView(1000)
  $fvFolderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep
  $folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$targetMailbox)

Now that we have the object created we need to bind to the folder that was created. This is so that we can call the search method for that folder. This is done by calling the class [Microsoft.Exchange.WebServices.Data.Folder] and the corresponding method Bind.

 $tfTargetFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid) 

This binding allows us to call the method to find the folders that we wish to find. The find folders method expects an object that specifies the folder view which we defined earlier.

 $findFolderResults = $tfTargetFolder.FindFolders($fvFolderView) 

Now all we need to do is go thru each one of the folders  with the $findFolderResults. I chose to retrieve the parent folder and the folder id and the type for the folder of ‘IPF.Note’.

function Get-MailBoxfolders
{
  [CmdletBinding()]
  param
  (
    [Parameter(Mandatory=$true, Position=0, HelpMessage='A service that points to exchange instance you wish to query')]
    [Microsoft.Exchange.WebServices.Data.ExchangeService]$Service,
    [Parameter(Mandatory=$true, Position=1, HelpMessage='A mailbox (smtp) that the service has access to')]
    [string]$targetMailbox,
    [string]$Folder2Find
  )
Write-Verbose -Message "create an object that gets the root folder for the mailbox"
  $fvFolderView = new-object Microsoft.Exchange.WebServices.Data.FolderView(1000)
  $fvFolderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep
  $folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$targetMailbox) 

  $tfTargetFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,$folderid)

  $findFolderResults = $tfTargetFolder.FindFolders($fvFolderView)

  foreach($folder in $findFolderResults.Folders){
    if($folder.FolderClass -eq 'IPF.Note')
    {
      $parentfolder = ($findFolderResults.Folders |?{$_.id.uniqueid -eq $folder.ParentFolderId.UniqueId}).displayname
      if(-not $parentfolder)
      {$parentfolder = 'Root'}
      if($Folder2Find)
      {
        if($folder.DisplayName -eq $folder2find)
        {
              [pscustomobject] @{
            'name'= $folder.DisplayName
            'folderid' = $folder.Id.UniqueId
            'ParentFolderName' = $parentfolder
            'ParentFolderId' = $folder.ParentFolderId.UniqueId
            'folderclass' = $folder.FolderClass
          }
        }

      }
      else
      {
        [pscustomobject] @{
          'name'= $folder.DisplayName
          'folderid' = $folder.Id.UniqueId
          'ParentFolderName' = $parentfolder
          'ParentFolderId' = $folder.ParentFolderId.UniqueId
          'folderclass' = $folder.FolderClass
        }
    }
  }
  }
  } 

For the full script source see this Gist 

At the end of the script run this is how my folders look in Outlook based on my tagging.

2017-02-09-09_52_52-unread-mail-outlook

I Hope this helps someone.

Until then

Keep Scripting

thom

3 thoughts on “Adding a Retention Tag / Custom Folder / Exchange

  1. JD

    Thanks for the script, I’m able to run it but it looks like it stops after pulling the mailbox name, in the log file it generates I see the following and nothing else, no errors in powershell

    MailboxName: xxxx@example.com
    GUID: No Guid
    folders:
    folderGUID:
    ParentFolder:
    Status:

    I’m guessing it can’t resolve the GUID of the retention tag? Any ideas?

    Thanks.

    Like

  2. Jo

    The same goes to me. It stops there without identifying the guid and then do nothing and won’t provide errors.

    Is there anyone who successfully used this script?

    Like

Leave a comment