diff --git a/src/cmd/purge/scripts/exchangePurge.ps1 b/src/cmd/purge/scripts/exchangePurge.ps1 index 90c905911..7ba036522 100644 --- a/src/cmd/purge/scripts/exchangePurge.ps1 +++ b/src/cmd/purge/scripts/exchangePurge.ps1 @@ -129,7 +129,7 @@ function Get-TimestampFromName { try { # Assumes that the timestamp is at the end and starts with yyyy-mm-ddT and is ISO8601 - if ($name -imatch "(\d{4}}-\d{2}-\d{2}T.*)") { + if ($name -imatch "(\d{4}-\d{2}-\d{2}T[\S]*)") { $timestamp = [System.Convert]::ToDatetime($Matches.0) } @@ -226,21 +226,31 @@ function Get-FoldersToPurge { | Select-Object -ExpandProperty Value | Get-Date - $IsNameMatchParams = @{ - 'FolderName' = $folderName; - 'FolderNamePurgeList' = $FolderNamePurgeList - } + if ($FolderNamePurgeList.count -gt 0) { + $IsNameMatchParams = @{ + 'FolderName' = $folderName; + 'FolderNamePurgeList' = $FolderNamePurgeList + } - $IsPrefixAndAgeMatchParams = @{ - 'FolderName' = $folderName; - 'FolderCreateTime' = $folderCreateTime; - 'FolderPrefixPurgeList' = $FolderPrefixPurgeList; - 'PurgeBeforeTimestamp' = $PurgeBeforeTimestamp; + if ((IsNameMatch @IsNameMatchParams)) { + Write-Host "• Found name match: $folderName ($folderCreateTime)" + $foldersToDelete += $folder + continue + } } - if ((IsNameMatch @IsNameMatchParams) -or (IsPrefixAndAgeMatch @IsPrefixAndAgeMatchParams)) { - Write-Host "• Found: $folderName ($folderCreateTime)" - $foldersToDelete += $folder + if ($FolderPrefixPurgeList.count -gt 0) { + $IsPrefixAndAgeMatchParams = @{ + 'FolderName' = $folderName; + 'FolderCreateTime' = $folderCreateTime; + 'FolderPrefixPurgeList' = $FolderPrefixPurgeList; + 'PurgeBeforeTimestamp' = $PurgeBeforeTimestamp; + } + + if ((IsPrefixAndAgeMatch @IsPrefixAndAgeMatchParams)) { + Write-Host "• Found prefix match: $folderName ($folderCreateTime)" + $foldersToDelete += $folder + } } } @@ -399,6 +409,8 @@ function Purge-Folders { } function Create-Contact { + [CmdletBinding(SupportsShouldProcess)] + $now = (Get-Date (Get-Date).ToUniversalTime() -Format "o") #used to create a recent seed contact that will be shielded from cleanup. CI tests rely on this $body = @" @@ -419,14 +431,16 @@ function Create-Contact { 2000-01-01T11:59:00Z Tester - Plate "@ - $createContactMsg = Initialize-SOAPMessage -User $User -Body $body - $response = Invoke-SOAPRequest -Token $Token -Message $createContactMsg + if ($PSCmdlet.ShouldProcess("Creating seed contact...", "", "Create contact")) { + Write-Host "`nCreating seed contact..." + $createContactMsg = Initialize-SOAPMessage -User $User -Body $body + $response = Invoke-SOAPRequest -Token $Token -Message $createContactMsg + } } function Get-ItemsToPurge { @@ -434,11 +448,33 @@ function Get-ItemsToPurge { [Parameter(Mandatory = $True, HelpMessage = "Folder under which to look for items matching removal criteria")] [String]$WellKnownRoot, + [Parameter(Mandatory = $False, HelpMessage = "Immediate subfolder within well known folder")] + [String]$SubFolderName = $null, + [Parameter(Mandatory = $True, HelpMessage = "Purge items before this date time (UTC)")] [datetime]$PurgeBeforeTimestamp ) $itemsToDelete = @() + $foldersToSearchBody = "" + + if (![String]::IsNullOrEmpty($SubFolderName)) { + $subFolders, $moreToList = Get-FoldersToPurge -WellKnownRoot $WellKnownRoot -FolderNamePurgeList $SubFolderName -PurgeBeforeTimestamp $PurgeBeforeTimestamp + + if ($subFolders.count -gt 0 ) { + $foldersToSearchBody = "" + foreach ($sub in $subFolders) { + $subName = $sub.DisplayName + $subId = $sub.FolderId.Id + Write-Host "Found subfolder from which to purge items: $subName" + $foldersToSearchBody = "`n" + } + } + else { + Write-Host "Requested subfolder $SubFolderName in folder $WellKnownRoot was not found" + return + } + } # SOAP message for getting the folder id $body = @" @@ -450,12 +486,12 @@ function Get-ItemsToPurge { - + $FoldersToSearchBody "@ - Write-Host "`nLooking for items under well-known folder: $WellKnownRoot older than $PurgeBeforeTimestamp for user: $User" + Write-Host "`nLooking for items under well-known folder: $WellKnownRoot($SubFolderName) older than $PurgeBeforeTimestamp for user: $User" $getItemsMsg = Initialize-SOAPMessage -User $User -Body $body $response = Invoke-SOAPRequest -Token $Token -Message $getItemsMsg @@ -468,15 +504,24 @@ function Get-ItemsToPurge { Select-Object -ExpandProperty Node $moreToList = ![System.Convert]::ToBoolean($rootFolder.IncludesLastItemInRange) + Write-Host "Total items under $WellKnownRoot/$SubFolderName"$rootFolder.TotalItemsInView + foreach ($item in $items) { $itemId = $item.ItemId.Id $changeKey = $item.ItemId.Changekey - $itemName = $item.DisplayName + $itemName = "" $itemCreateTime = $item.ExtendedProperty | Where-Object { $_.ExtendedFieldURI.PropertyTag -eq "0x3007" } | Select-Object -ExpandProperty Value | Get-Date + # can be improved to pass the field to use as a name as a parameter but this is good for now + switch -casesensitive ($WellKnownRoot) { + "calendar" { $itemName = $item.Subject } + "contacts" { $itemName = $item.DisplayName } + Default { $itemName = $item.DisplayName } + } + if ([String]::IsNullOrEmpty($itemId) -or [String]::IsNullOrEmpty($changeKey)) { continue } @@ -491,33 +536,51 @@ function Get-ItemsToPurge { $itemsToDelete += $item } + if ($WhatIfPreference) { + # not actually deleting items so only do a single iteration + $moreToList = $false + } + return $itemsToDelete, $moreToList } -function Purge-Contacts { +function Purge-Items { [CmdletBinding(SupportsShouldProcess)] Param( [Parameter(Mandatory = $True, HelpMessage = "Purge items before this date time (UTC)")] - [datetime]$PurgeBeforeTimestamp + [datetime]$PurgeBeforeTimestamp, + + [Parameter(Mandatory = $True, HelpMessage = "Items folder")] + [string]$ItemsFolder, + + [Parameter(Mandatory = $False, HelpMessage = "Items sub-folder")] + [string]$ItemsSubFolder = $null + ) - Write-Host "`nCleaning up contacts older than $PurgeBeforeTimestamp" - Write-Host "-------------------------------------------------------" + $additionalAttributes = "SendMeetingCancellations='SendToNone'" - # Create one seed contact which will have recent create date and will not be swept - # This is needed since tests rely on some contact data being present - Write-Host "`nCreating seed contact" - Create-Contact + Write-Host "`nCleaning up items from folder $ItemsFolder($ItemsSubFolder) older than $PurgeBeforeTimestamp" + Write-Host "-----------------------------------------------------------------------------" + + if ($ItemsFolder -eq "contacts") { + $ItemsSubFolder = $null + $additionalAttributes = "" + + # Create one seed contact which will have recent create date and will not be sweapt + # This is needed since tests rely on some contact data being present + Create-Contact + } $moreToList = $True # only get max of 1000 results so we may need to iterate over eligible contacts while ($moreToList) { - $itemsToDelete, $moreToList = Get-ItemsToPurge -WellKnownRoot "contacts" -PurgeBeforeTimestamp $PurgeBeforeTimestamp + $itemsToDelete, $moreToList = Get-ItemsToPurge -WellKnownRoot $ItemsFolder -SubFolderName $ItemsSubFolder -PurgeBeforeTimestamp $PurgeBeforeTimestamp $itemsToDeleteCount = $itemsToDelete.count $itemsToDeleteBody = "" if ($itemsToDeleteCount -eq 0) { - Write-Host "`nNo more contacts to delete matching criteria" + Write-Host "`nNo more items to delete matching criteria" break } @@ -531,21 +594,23 @@ function Purge-Contacts { # Do the actual deletion in a batch request # DeleteType = HardDelete, MoveToDeletedItems, or SoftDelete $body = @" - + $itemsToDeleteBody "@ - + if ($PSCmdlet.ShouldProcess("Deleting $itemsToDeleteCount items...", "$itemsToDeleteCount items", "Delete items")) { Write-Host "`nDeleting $itemsToDeleteCount items..." $emptyFolderMsg = Initialize-SOAPMessage -User $User -Body $body $response = Invoke-SOAPRequest -Token $Token -Message $emptyFolderMsg + + Write-Verbose "Delete response:`n" + Write-Verbose $response.OuterXml Write-Host "`nDeleted $itemsToDeleteCount items..." - } } } @@ -564,7 +629,10 @@ $purgeFolderParams = @{ Purge-Folders @purgeFolderParams #purge older contacts -Purge-Contacts -PurgeBeforeTimestamp $PurgeBeforeTimestamp +Purge-Items -ItemsFolder "contacts" -PurgeBeforeTimestamp $PurgeBeforeTimestamp + +#purge older contact birthday events +Purge-Items -ItemsFolder "calendar" -ItemsSubFolder "Birthdays" -PurgeBeforeTimestamp $PurgeBeforeTimestamp # Empty Deleted Items and then purge all recoverable items. Deletes the following # -/Recoverable Items/Audits