0

I hope you can help as this is driving me wild and I think I must be the only person on planet earth wanting to do this....

I want to delete emails, from a specific folder...

Errors

"The search is completed 0 item(s) (0.00 B) 3,120 unindexed items, 3.61 GB 4 mailbox(es) 2 errors"

and

"The search on the following locations failed: [mailbox]:Transient error occurred while trying to search the mailbox. Please make sure the mailboxes you're searching still exist and then run the search again. (CS007)"

The code I am using;

Get-PSSession | Remove-PSSession 
Disconnect-ExchangeOnline -Confirm:$false
cls

$user= Get-Content "user.txt"
$passplain= Get-Content "O365Pass.txt"
$pass = ConvertTo-SecureString -String $passplain -AsPlainText -Force

$cred=New-Object System.Management.Automation.PSCredential ($user, $pass)

#$user = "mysupersecretemailadminaddress"      
#pass = 'my super secret super admin password'
[Security.Principal.WindowsIdentity]::GetCurrent()

write-host $user
write-host $pass

#  The section below creates a remote PowerShell connection to Office 365 
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;

Function GetFolderID {

    Param (
        [parameter(Mandatory = $true)]
                [String]
                $Mailbox,
        [parameter(Mandatory = $true)]
                [String]
                $FolderName
        )


    $TargetMailFolders = Get-MailboxFolderStatistics -Identity $Mailbox | Select FolderID, Name

    Try {

        foreach ($TargetMailFolder in $TargetMailFolders) {
    
            $TargetMailFolderID = $TargetMailFolder.FolderID
            $TargetMailFolderName = $TargetMailFolder.Name

            Write-Host "TargetEmailFolderID is $($TargetMailFolderID)"

            If ($TargetMailFolderID) 
                {
                    if ($TargetMailFolderName -eq $FolderName)
                        
                        {
                      
                           Write-Host "TargetEmailFolderID is $($TargetMailFolderID)"
                           Write-Host "TargetEmailFolderID is $($TargetMailFolderName)"
                           Return $TargetMailFolderID
                        }
                }
            Else
                {
                    Write-Host "Target Email Folder does not exist"
                }
        }
    }
    catch {
        throw "There was an error getting email folders"
        break
        }
}

function CleanupMailbox {

    Param(
        [parameter(Mandatory = $true)]
        [String]
        $Mailbox,
        #$mailboxes = @("mailbox1@example.net", "mailbox2@example.net")
        [parameter(Mandatory = $true)]
        [String]
        $DaysToKeep,
        #$DaysToKeep = 3
        [parameter(Mandatory = $true)]
        [String]
        $SearchName,
        [parameter(Mandatory = $true)]
        [String]
        $SearchQuery

    )

    # Clean-up any old searches from failed runs of this script
    if (Get-ComplianceSearch -Identity $searchName) {
        Write-Host "Cleaning up any old searches from failed runs of this script"

        try {
            Remove-ComplianceSearch -Identity $searchName -Confirm:$false | Out-Null
            }
        catch {
            Write-Host "Clean-up of old script runs failed!" -ForegroundColor Red
            break
            }
        }

    Write-Host "Creating new search for emails older than $($DateSearch)"

    
                       
                            New-ComplianceSearch -Name $searchName -ExchangeLocation $Mailbox -ContentMatchQuery $SearchQuery -AllowNotFoundExchangeLocationsEnabled $true | Out-Null
                            
                                                                            
                            Start-ComplianceSearch -Identity $searchName | Out-Null

                            Write-Host "Searching..." -NoNewline

                            while ((Get-ComplianceSearch -Identity $searchName).Status -ne "Completed") {
                                Write-Host "." -NoNewline
                                Start-Sleep -Seconds 2
                            }

                            $items = (Get-ComplianceSearch -Identity $searchName).Items

                            if ($items -gt 0) {
                                $searchStatistics = Get-ComplianceSearch -Identity $searchName | Select-Object -Expand SearchStatistics | Convertfrom-JSON

                                $sources = $searchStatistics.ExchangeBinding.Sources | Where-Object { $_.ContentItems -gt 0 }

                                Write-Host ""
                                Write-Host "Total Items found matching query:" $items 
                                Write-Host ""
                                Write-Host "Items found in the following mailboxes"
                                Write-Host "--------------------------------------"

                                foreach ($source in $sources) {
                                    Write-Host $source.Name "has" $source.ContentItems "items of size" $source.ContentSize
                                }

                                Write-Host ""

                                $iterations = 0;
    
                                $itemsProcessed = 0
    
                                while ($itemsProcessed -lt $items) {
                                    $iterations++

                                    Write-Host "Deleting items iteration $($iterations)"

                                    #########################the below line does the delete
                                    New-ComplianceSearchAction -SearchName $searchName -Purge -PurgeType SoftDelete -Confirm:$false | Out-Null

                                    while ((Get-ComplianceSearchAction -Identity "$($searchName)_Purge").Status -ne "Completed") { 
                                        Start-Sleep -Seconds 2
                                    }

                                    $itemsProcessed = $itemsProcessed + 10
        
                                    # Remove the search action so we can recreate it
                                    Remove-ComplianceSearchAction -Identity "$($searchName)_Purge" -Confirm:$false  
                                }
                            } else {
                                Write-Host "No items found"
                            }

                            Write-Host ""
                            Write-Host "COMPLETED!"

                        }
 


Import-Module ExchangeOnlineManagement     
Connect-ExchangeOnline -Credential $cred
Connect-IPPSSession -Credential $cred

Write-Host "$(Get-Date -Format u) Cleanup $($Mailbox) Started"

$Mailbox = "emailaddresshere"
$FolderName = "foldernamehere"

$FolderID=GetFolderID -Mailbox $Mailbox -FolderName $FolderName
write-host "Returned Folder ID is: $($FolderID)"

$SearchName  = "Cleanup$($Mailbox)$($Foldername)"
$DaysToKeep  = 90
$DateSearch=(Get-Date).AddDays(-$($DaysToKeep)).ToString("yyyy-MM-dd") #ToString("MM/dd/yyyy")
write-host "$(Get-Date -Format u) DateSearch is $DateSearch"

$SearchQuery = "(subject:'subjectstringhere') AND (folderid:$($FolderID))"

write-host "Search query is <$($SearchQuery)>"

CleanupMailbox -Mailbox $Mailbox -DaysToKeep $DaysToKeep -SearchName $SearchName -SearchQuery $SearchQuery

Write-Host "$(Get-Date -Format u) Cleanup $($Mailbox) Finished"

Get-PSSession | Remove-PSSession 
Write-Host "Cleanup complete"

So my script gets the folderid of the folder (it's correct) and runs.

I then get nothing happening.

When I check compliance on the web portal, my search is sitting there with the errors above.

I am only working on one single mailbox.... not 4.

If I edit and run the search without the folderid, it works.

If I construct the search using the query builder it doesn't offer me "folderid" from the dropdown despite the documentation but does "errorcheck" folderid properly.

It doesn't matter which inbox I use, which folder I use.

If I omit the folderid, it runs, if I include it fails with the messages below regardless of mailbox or folder.

I have tried every combo of " or ', = or :.

So is the documentation rubbish or am I missing something obvious?

Am I using the wrong cmdlet?

Neil
  • 1
  • 1

1 Answers1

0

The folderid from Get-MailboxFolderStatistics needs to be reformatted to be used with Keyword Query Language (KQL).

This code will do that:

$folderStatistics = Get-MailboxFolderStatistics $Mailbox
$folderQueries = foreach ($folderStatistic in $folderStatistics) {
    $folderId = $folderStatistic.FolderId
    $folderPath = $folderStatistic.FolderPath
    $encoding = [System.Text.Encoding]::GetEncoding("us-ascii")
    $nibbler = $encoding.GetBytes("0123456789ABCDEF")
    $folderIdBytes = [Convert]::FromBase64String($folderId)
    $indexIdBytes = New-Object byte[] 48
    $indexIdIdx = 0
    $folderIdBytes | Select-Object -Skip 23 -First 24 | ForEach-Object { $indexIdBytes[$indexIdIdx++] = $nibbler[$_ -shr 4]; $indexIdBytes[$indexIdIdx++] = $nibbler[$_ -band 0xF] }
    $folderQuery = "folderid:$($encoding.GetString($indexIdBytes))"
    $folderStat = New-Object PSObject
    Add-Member -InputObject $folderStat -MemberType NoteProperty -Name FolderPath -Value $folderPath
    Add-Member -InputObject $folderStat -MemberType NoteProperty -Name FolderQuery -Value $folderQuery -PassThru
}
$folderQueries | Sort-Object -Property FolderPath
jfrmilner
  • 1,458
  • 10
  • 11