Cleanup birthday events for old contacts (#3019)

Purge events birthdays corresponding to old contacts
---

#### Does this PR need a docs update or release note?

- [ ]  Yes, it's included
- [ ] 🕐 Yes, but in a later PR
- [x]  No

#### Type of change

<!--- Please check the type of change your PR introduces: --->
- [ ] 🌻 Feature
- [x] 🐛 Bugfix
- [ ] 🗺️ Documentation
- [ ] 🤖 Supportability/Tests
- [x] 💻 CI/Deployment
- [ ] 🧹 Tech Debt/Cleanup

#### Issue(s)

<!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. -->
* #<issue>

#### Test Plan

<!-- How will this be tested prior to merging.-->
- [x] 💪 Manual
- [ ]  Unit test
- [ ] 💚 E2E
This commit is contained in:
Georgi Matev 2023-04-04 04:53:28 -07:00 committed by GitHub
parent c696e7b7ff
commit ce755ecf3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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,11 +226,20 @@ function Get-FoldersToPurge {
| Select-Object -ExpandProperty Value
| Get-Date
if ($FolderNamePurgeList.count -gt 0) {
$IsNameMatchParams = @{
'FolderName' = $folderName;
'FolderNamePurgeList' = $FolderNamePurgeList
}
if ((IsNameMatch @IsNameMatchParams)) {
Write-Host "• Found name match: $folderName ($folderCreateTime)"
$foldersToDelete += $folder
continue
}
}
if ($FolderPrefixPurgeList.count -gt 0) {
$IsPrefixAndAgeMatchParams = @{
'FolderName' = $folderName;
'FolderCreateTime' = $folderCreateTime;
@ -238,11 +247,12 @@ function Get-FoldersToPurge {
'PurgeBeforeTimestamp' = $PurgeBeforeTimestamp;
}
if ((IsNameMatch @IsNameMatchParams) -or (IsPrefixAndAgeMatch @IsPrefixAndAgeMatchParams)) {
Write-Host "• Found: $folderName ($folderCreateTime)"
if ((IsPrefixAndAgeMatch @IsPrefixAndAgeMatchParams)) {
Write-Host "• Found prefix match: $folderName ($folderCreateTime)"
$foldersToDelete += $folder
}
}
}
# powershel does not do well when returning empty arrays
return $foldersToDelete, $moreToList
@ -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 {
</t:PhoneNumbers>
<t:Birthday>2000-01-01T11:59:00Z</t:Birthday>
<t:JobTitle>Tester</t:JobTitle>
<t:Surname>Plate</t:Surname>
</t:Contact>
</Items>
</CreateItem>
"@
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 = "<t:DistinguishedFolderId Id='$WellKnownRoot'/>"
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 = "<t:FolderId Id='$subId'/>`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 {
</t:AdditionalProperties>
</ItemShape>
<ParentFolderIds>
<t:DistinguishedFolderId Id="$WellKnownRoot"/>
$FoldersToSearchBody
</ParentFolderIds>
</FindItem>
"@
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
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
Write-Host "`nCreating seed contact"
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,7 +594,7 @@ function Purge-Contacts {
# Do the actual deletion in a batch request
# DeleteType = HardDelete, MoveToDeletedItems, or SoftDelete
$body = @"
<m:DeleteItem DeleteType="HardDelete">
<m:DeleteItem DeleteType="HardDelete" $additionalAttributes>
<m:ItemIds>
$itemsToDeleteBody
</m:ItemIds>
@ -544,8 +607,10 @@ function Purge-Contacts {
$emptyFolderMsg = Initialize-SOAPMessage -User $User -Body $body
$response = Invoke-SOAPRequest -Token $Token -Message $emptyFolderMsg
Write-Host "`nDeleted $itemsToDeleteCount items..."
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