Stamping Retention Policy Tag on Items using EWS Managed API 1.1 from PowerShell(Exchange 2010)

This post deals with a scenario where we need to stamp Retention Policy on specific items. In this case we wanted to stamp a policy on items with a specific message class. In my previous post I had explained about Messaging records management and how to stamp the policy on a folder. Please do read my previous post if you have not yet done so.

The process of stamping Retention Policy on items is not much different, when applying the Retention Policy to an item, we need to stamp it with two important properties:

  • PR_POLICY_TAG – The data type for this property is binary . The value that it contains is the GUID of the retention tag that you create. Do a Get-RetentionPolicyTag YourTagName |fl and copy the value in the GUID property. This value will be uses in the script later on.
  • PR_RETENTION_PERIOD – The data type for this property is Integer. This is the same value that you specify for the AgeLimitForRetention while creating or updating the retention policy tag.

Before you begin:
You will need to download and install the EWS Managed API on the box you run this script on from the link below:
Exchange Web Services Managed API
https://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=c3342fb3-fbcc-4127-becf-872c746840e1

Read about setting up Impersonation in Exchange 2010 as the code below uses it.
Configuring Exchange Impersonation (Exchange Web Services)
https://msdn.microsoft.com/en-us/library/bb204095.aspx

Using Exchange Impersonation XML Request/Response
https://msdn.microsoft.com/en-us/library/bb204088.aspx

Using Impersonation in EWS Managed API
https://msdn.microsoft.com/en-us/library/dd633680(EXCHG.80).aspx

We will stamp the properties using Exchange Web Services Managed API 1.1 in PowerShell 2.0 and below is how it is done. Create a .PS1 file with the code below:

 # This script requires PowerShell 2.0
# Make sure the Import-Module command below matches the DLL location of the API.
# This path must match the install location of the EWS managed API. Change it if needed.[string]$info = "White"                # Color for informational messages
[string]$warning = "Yellow"            # Color for warning messages
[string]$error = "Red"                # Color for error messages
[string]$LogFile = "C:\Temp\Log.txt"        # Path of the Log Filefunction StampPolicyOnItems($MailboxName)
{
    Write-host "Stamping Policy on Items for Mailbox Name:" $MailboxName -foregroundcolor  $info
    Add-Content $LogFile ("Stamping Policy on Items for Mailbox Name:" + $MailboxName)    #Change the user to Impersonate. Comment the line below if impersonation is not needed
    $service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress,$MailboxName);    #Number of Items to Get
    $pageSize =50
    $Offset = 0
    $MoreItems =$true
    $ItemCount=0    while ($MoreItems)
     {
        #Setup the View to get a limited number of Items at one time
        $itemView = new-object Microsoft.Exchange.WebServices.Data.ItemView($pageSize,$Offset,[Microsoft.Exchange.WebServices.Data.OffsetBasePoint]::Beginning)
        $itemView.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Shallow
        $itemView.PropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet(
                            [Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly,
                            [Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::ItemClass,
                            [Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::Subject);        #Create the Search Filter and look for items with the message class IPM.My-ARCHIVE
        $oSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::ItemClass, "IPM.My-ARCHIVE")  #Look for items in the Inbox

  $oFindItems = $service.FindItems([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox,$oSearchFilter,$itemView)
        
        foreach ($Item in $oFindItems.Items)
        {
            $ItemCount++

            Write-host "Item Number:" $ItemCount
            Write-host "Message Class:" $Item.ItemClass
            Write-host "Subject:" $Item.Subject            #PR_POLICY_TAG 0x3019
            $PolicyTag = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x3019,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary)            #PR_RETENTION_PERIOD 0x301A
            $RetentionPeriod = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x301A,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Integer)            #Same as that on the policy
            $Item.SetExtendedProperty($RetentionPeriod, 1095)            #Change the GUID based on your policy tag
            $PolicyTagGUID = new-Object Guid("{92186ff7-7f4d-4efa-a09b-bbdc5aee3908}")            $Item.SetExtendedProperty($PolicyTag, $PolicyTagGUID.ToByteArray())

            $Item.Update([Microsoft.Exchange.WebServices.Data.ConflictResolutionMode]::AlwaysOverwrite)

            Write-host "Retention policy stamped on " $Item.ID  -foregroundcolor $info
            Add-Content $LogFile ("Retention policy stamped on " + $Item.ID)

        }
        

     if ($oFindItems.MoreAvailable -eq $false)
        {$MoreItems = $false}

         if ($MoreItems)
        {$Offset += $pageSize}
        
     }

    Write-host "Stamping Policy on Items for Mailbox Name:" $MailboxName "Done!" -foregroundcolor  $info
    Add-Content $LogFile ("Done!")
    Add-Content $LogFile ("-------------------------------------------------" )    #Comment the line below if impersonation is not needed   

    $service.ImpersonatedUserId = $null
}Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll"

$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)# Set the Credentials,Use the account that has been granted Impersonation rights
# If impersonation is not used, use the credentials required to access the mailbox
$service.Credentials = new-object Microsoft.Exchange.WebServices.Data.WebCredentials("serviceAccount","Password","domain")# Change the URL to point to your cas server
$service.Url= new-object Uri(“https://Your-CAS-Server/EWS/Exchange.asmx”)# Set $UseAutoDiscover to $true if you want to use AutoDiscover else it will use the URL set above
$UseAutoDiscover = $false#Read data from the UserAccounts.txt
import-csv UserAccounts.txt | foreach-object {
    $WindowsEmailAddress = $_.WindowsEmailAddress.ToString()

    if ($UseAutoDiscover -eq $true) {
        Write-host "Autodiscovering.." -foregroundcolor $info
        $UseAutoDiscover = $false
        $service.AutodiscoverUrl($WindowsEmailAddress)
        Write-host "Autodiscovering Done!" -foregroundcolor $info
        Write-host "EWS URL set to :" $service.Url -foregroundcolor $info

    }
    #To catch the Exceptions generated
    trap [System.Exception] 
    {
        Write-host ("Error: " + $_.Exception.Message) -foregroundcolor $error;
        Add-Content $LogFile ("Error: " + $_.Exception.Message);
        continue;
    }
    StampPolicyOnItems($WindowsEmailAddress)
}    

UserAccounts.txt contains the list of the users mailboxes in which the items needs to be stamped. This file should exist in the same directory as the .PS1 file.The First row denotes the Field Names. Format of the text file is as below:

 WindowsEmailAddress
akasha@contoso.com
akashb@contoso.com
akashc@contoso.com

To Run the script:

1)Open the Exchange Management Shell

2)Navigate to the location where the script file is.

3)Type in .\ScriptName.PS1 and hit enter to execute the script

Note: This script creates a log file in C:\Temp. Make sure that directory exists.

Enjoy!