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

Yes, this is similar to the script in my previous post but is also different in the following ways:

  • This script searches the entire mailbox and looks for items in folders that contain mail items or in other words where the folders class is IPF.Note
  • This scripts also shows how to use the Not, Exists the AND logical operator to build up a Search Filter collection

I would suggest you read my previous post as it covers some fundamental used in this post.

To summarize what the script below does:

  • We start of by passing the SMTP address of the mailbox we want to search. We then do a deep folder traversal to get a list of all the folder where the FolderClass = “IPF.Note”.
  • We then pass to folder id to the StampPolicyOnItems function which then looks for Items which have a specific message class AND  does not have the PR_POLICY_TAG property stamped on the item. This is done using Search Filter Collection.
  • Finally we loop through all the items that meet the criteria above and stamp the PR_POLICY_TAG and the PR_RETENTION_PERIOD properties on the item and update it.

Straight to code now. Create a .PS1 file with the code below:

 # The script requires the EWS managed API, which can be downloaded here:
# https://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=c3342fb3-fbcc-4127-becf-872c746840e1
# This also 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 SearchFolders($MailboxName)
{
    Write-host "Searching folders in Mailbox Name:" $MailboxName -foregroundcolor  $info
    Add-Content $LogFile ("Searching folders in Mailbox Name:" + $MailboxName)    #Change the user to Impersonate
    $service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress,$MailboxName);    #Number of Items to Get
    $FpageSize =50
    $FOffset = 0
    $MoreFolders =$true

    while ($MoreFolders)
     {

         #Setup the View to get a limited number of Items at one time
        $folderView = new-object Microsoft.Exchange.WebServices.Data.FolderView($FpageSize,$FOffset,[Microsoft.Exchange.WebServices.Data.OffsetBasePoint]::Beginning)
        $folderView.Traversal = [Microsoft.Exchange.WebServices.Data.FolderTraversal]::Deep
        $folderView.PropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet(
                            [Microsoft.Exchange.WebServices.Data.BasePropertySet]::IdOnly,
                            [Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,
                            [Microsoft.Exchange.WebServices.Data.FolderSchema]::FolderClass);        #Create the Search Filter.
        $FoSearchFilter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.FolderSchema]::FolderClass, "IPF.Note")

        $oFindFolders = $service.FindFolders([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$FoSearchFilter,$folderView)
        
        foreach ($folder in $oFindFolders.Folders)
        {

            Write-host "Begining to stamp policy on Items in folder:" $folder.DisplayName  -foregroundcolor $info;
            Add-Content $LogFile ("Begining to stamp policy on Items in folder:" + $folder.DisplayName);

            &{

              StampPolicyOnItems($folder.Id.UniqueId)              Write-host "Retention policy stamped on  Items in folder:" $folder.DisplayName  -foregroundcolor $info
              Add-Content $LogFile ("Retention policy stamped on  Items in folder:" + $folder.DisplayName)

            }
            trap [System.Exception] 
            {
                $IsFailure = $true;
                Write-host ("Error in StampPolicyOnItems: " + $_.Exception.Message) -foregroundcolor $error;
                Add-Content $LogFile ("Error in StampPolicyOnItems: " + $_.Exception.Message);
                Write-host "Failure in stamping Retention policy on  Items in folder:" $folder.DisplayName  -foregroundcolor $info
                Add-Content $LogFile ("Failure in stamping Retention policy on  Items in folder:" + $folder.DisplayName)

                continue;
            }

        }
        

         if ($oFindFolders.MoreAvailable -eq $false)
            {$MoreFolders = $false}

             if ($MoreFolders)
            {$FOffset += $FpageSize}
     
     }    Write-host "Finished with Mailbox Name:" $MailboxName "Done!" -foregroundcolor  $info
    Write-host "-------------------------------------------------" -foregroundcolor  $info

    Add-Content $LogFile ("Done!")
    Add-Content $LogFile ("-------------------------------------------------" )    

    $service.ImpersonatedUserId = $null
}



function StampPolicyOnItems($fId)
{
    #Number of Items to Get
    $pageSize =100
    $Offset = 0
    $MoreItems =$true
    $ItemCount=0    #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);    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.
        $oSearchFilters = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection(
                    [Microsoft.Exchange.WebServices.Data.LogicalOperator]::And)


        $oSearchFilterEA1 = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::ItemClass, "IPM.My-ARCHIVE")
        $oSearchFilterEA2 = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+Not(New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+Exists($PolicyTag))        $oSearchFilters.add($oSearchFilterEA1)
        $oSearchFilters.add($oSearchFilterEA2)

        
        $uniqueId = new-object Microsoft.Exchange.WebServices.Data.FolderId($fId);

        $oFindItems = $service.FindItems($uniqueId,$oSearchFilters,$itemView)
        

        foreach ($Item in $oFindItems.Items)
        {
            $ItemCount++

            Write-host "Item Number:" $ItemCount
            Write-host "Message Class:" $Item.ItemClass
            Write-host "Subject:" $Item.Subject

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

}

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
$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/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;
    }
    SearchFolders($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!