- Authenticates using Microsoft Graph API with client credentials.
- Retrieves and analyzes mailbox folders to identify those exceeding 99,999 items.
- Splits large folders into smaller ones by creating new folders and moving emails in batches.
- Includes robust logging for all operations, including successes, errors, and retries.
- Implements retry logic to handle errors and ensure reliable execution.
- Requires user confirmation before proceeding with folder splitting.
# Install Microsoft Graph PowerShell module if not already installed
Install-Module Microsoft.Graph -Scope CurrentUser
# Step 1: Authenticate with Client Credentials
$tenantId = "YOUR_TENANT_ID"
$clientId = "YOUR_CLIENT_ID"
$clientSecret = "YOUR_CLIENT_SECRET"
# Authenticate and get an access token
$tokenRequest = @{
TenantId = $tenantId
ClientId = $clientId
ClientSecret = $clientSecret
Scope = "https://graph.microsoft.com/.default"
}
Connect-MgGraph -ClientId $clientId -TenantId $tenantId -ClientSecret $clientSecret -Scopes "Mail.ReadWrite", "Mail.Move", "MailFolders.ReadWrite"
# Confirm authentication
$me = Get-MgUser -UserId "me"
Write-Host "Authenticated as: $($me.DisplayName)"
# Step 2: Get UPN for the user mailbox we are targeting
$upn = Read-Host -Prompt "Enter the UPN of the mailbox to analyze"
# Define log file name based on UPN
$logFileName = "$upn`_splitfile_log.txt"
# Function to write log to the file
function Write-Log {
param (
[string]$message
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logMessage = "$timestamp - $message"
$logMessage | Out-File -FilePath $logFileName -Append
Write-Host $logMessage # Also output to console
}
# Step 3: Get all folders for the user
Write-Log "Fetching folders for $upn"
$folders = Get-MgUserMailFolder -UserId $upn -All
# Step 4: Analyze and summarize folders with more than 99,999 items
$largeFolders = $folders | Where-Object { $_.TotalItemCount -gt 99999 }
# Display summary of folders to be split
foreach ($folder in $largeFolders) {
$totalItems = $folder.TotalItemCount
$excessItems = $totalItems - 99999
$numNewFolders = [math]::Ceiling($excessItems / 99999)
Write-Log "Folder: $($folder.DisplayName) (ID: $($folder.Id))"
Write-Log "Total Items: $totalItems"
Write-Log "Items to be moved: $excessItems"
Write-Log "Proposed new folders: $numNewFolders"
}
# Step 5: Confirm before proceeding
$confirmation = Read-Host -Prompt "Do you want to proceed with splitting the folders? (yes/no)"
if ($confirmation -ne "yes") {
Write-Log "Operation canceled by user."
Write-Host "Operation canceled."
Exit
}
# Error handling function for retries with logging
function Retry-Operation {
param (
[scriptblock]$ScriptBlock,
[int]$MaxRetries = 3,
[int]$RetryDelay = 5 # Seconds to wait between retries
)
$attempt = 0
while ($attempt -lt $MaxRetries) {
try {
$attempt++
Write-Log "Attempt $attempt to execute operation."
& $ScriptBlock
Write-Log "Operation succeeded on attempt $attempt."
return # Success, exit the retry loop
} catch {
Write-Log "Attempt $attempt failed: $($_.Exception.Message)"
# Log the entire error details (stack trace, message, etc.)
Write-Log "Error Details: $($_ | Out-String)"
if ($attempt -eq $MaxRetries) {
$errorMsg = "Max retries reached. Operation failed."
Write-Log $errorMsg
throw $errorMsg
}
Write-Log "Retrying in $RetryDelay seconds..."
Start-Sleep -Seconds $RetryDelay
}
}
}
# Function to create a new folder with retry logic and logging
function Create-NewMailFolder {
param (
[string]$upn,
[string]$parentFolderId,
[string]$folderName
)
Retry-Operation -ScriptBlock {
$newFolder = New-MgUserMailFolder -UserId $upn -DisplayName $folderName -ParentFolderId $parentFolderId
Write-Log "Created new folder $folderName with ID $($newFolder.Id)"
return $newFolder.Id
}
}
# Function to move emails in batches with retry logic and logging
function Move-EmailsInBatches {
param (
[string]$upn,
[string]$sourceFolderId,
[string]$destinationFolderId,
[int]$batchSize = 99999
)
Retry-Operation -ScriptBlock {
# Get messages in the source folder
$messages = Get-MgUserMailFolderMessage -UserId $upn -MailFolderId $sourceFolderId -Top $batchSize
foreach ($message in $messages) {
$messageId = $message.Id
# Move the message
Retry-Operation -ScriptBlock {
Move-MgUserMessage -UserId $upn -MessageId $messageId -DestinationId $destinationFolderId
Write-Log "Moved message $messageId to folder $destinationFolderId"
}
}
Write-Log "Moved $batchSize messages from folder $sourceFolderId to folder $destinationFolderId"
}
}
# Process each large folder with error handling, retries, and logging
foreach ($folder in $largeFolders) {
$folderId = $folder.Id
$totalItems = $folder.TotalItemCount
$excessItems = $totalItems - 99999
if ($excessItems -gt 0) {
$numNewFolders = [math]::Ceiling($excessItems / 99999)
# Create the necessary number of new folders and move items
for ($i = 1; $i -le $numNewFolders; $i++) {
$newFolderName = "split_${folderId}_$i"
$newFolderId = Create-NewMailFolder -upn $upn -parentFolderId $folderId -folderName $newFolderName
# Move emails to the new folder
if ($i -lt $numNewFolders) {
# Move a full batch of 99,999 emails
Move-EmailsInBatches -upn $upn -sourceFolderId $folderId -destinationFolderId $newFolderId -batchSize 99999
} else {
# Move the remainder (less than 99,999 emails)
$remainder = $excessItems % 99999
Move-EmailsInBatches -upn $upn -sourceFolderId $folderId -destinationFolderId $newFolderId -batchSize $remainder
}
}
}
}
Write-Log "All folder splits and moves for $upn are completed!"
Write-Host "All folder splits and moves are completed!"
Sorry! The Author has not filled his profile.