Move 150+ scripts from root and scripts/ into client/project directories: - clients/dataforth/scripts/ (110 files: AD2, sync, SSH, DB, DOS scripts) - clients/bg-builders/scripts/ (14 files: Lesley mgmt, Exchange, termination) - clients/internal-infrastructure/scripts/ (10 files: GDAP, Gitea, backups) - projects/msp-tools/scripts/ (9 files: CIPP, MSP onboarding, Datto) - projects/gururmm-agent/scripts/ (3 files: API test, JWT, record counts) - clients/glaztech/scripts/ (1 file: CentraStage removal) Also reorganized: - VPN scripts → infrastructure/vpn-configs/ - Retrieved API/JS files → api/ - Forum posts → projects/community-forum/forum-posts/ - SSH docs → clients/internal-infrastructure/docs/ - NWTOC/CTONW docs → projects/wrightstown-smarthome/docs/ - ACG website files → projects/internal/acg-website-2025/ - Dataforth docs → clients/dataforth/docs/ - schema-retrieved.sql → docs/database/ Deleted 24 tmp_*.ps1 one-off debug scripts (preserved in git history). Root reduced from 220+ files to 62 items (docs + directories only). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
194 lines
9.1 KiB
PowerShell
194 lines
9.1 KiB
PowerShell
#Requires -Modules ExchangeOnlineManagement
|
|
<#
|
|
.SYNOPSIS
|
|
BG Builders - Lesley Roth: Recover deleted items (last 10 days) and review inbox rules
|
|
.DESCRIPTION
|
|
1. Connects to Exchange Online as sysadmin@bgbuildersllc.com
|
|
2. Recovers all soft-deleted items from Lesley's mailbox (last 10 days)
|
|
3. Lists all inbox rules on the account
|
|
.NOTES
|
|
Run in PowerShell 7 (pwsh) for best compatibility
|
|
Tenant: bgbuildersllc.com / sonorangreenllc.onmicrosoft.com
|
|
Target: lesley@bgbuildersllc.com
|
|
#>
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$targetUser = 'lesley@bgbuildersllc.com'
|
|
|
|
# ── Connect to Exchange Online ──────────────────────────────────────
|
|
Write-Host "`n=== Connecting to Exchange Online ===" -ForegroundColor Cyan
|
|
try {
|
|
$session = Get-ConnectionInformation -ErrorAction SilentlyContinue
|
|
if (-not $session -or $session.State -ne 'Connected') {
|
|
Connect-ExchangeOnline -UserPrincipalName sysadmin@bgbuildersllc.com -ShowBanner:$false
|
|
} else {
|
|
Write-Host "Already connected to Exchange Online" -ForegroundColor Green
|
|
}
|
|
} catch {
|
|
Write-Host "Connecting fresh..." -ForegroundColor Yellow
|
|
Connect-ExchangeOnline -UserPrincipalName sysadmin@bgbuildersllc.com -ShowBanner:$false
|
|
}
|
|
|
|
# ── Part 1: Review Inbox Rules ──────────────────────────────────────
|
|
Write-Host "`n=== INBOX RULES for $targetUser ===" -ForegroundColor Cyan
|
|
|
|
try {
|
|
$rules = Get-InboxRule -Mailbox $targetUser -IncludeHidden
|
|
if ($rules) {
|
|
Write-Host "`nFound $($rules.Count) rule(s):" -ForegroundColor Yellow
|
|
foreach ($rule in $rules) {
|
|
Write-Host "`n--- Rule: $($rule.Name) ---" -ForegroundColor White
|
|
Write-Host " Enabled: $($rule.Enabled)"
|
|
Write-Host " Priority: $($rule.Priority)"
|
|
Write-Host " Description: $($rule.Description)"
|
|
|
|
if ($rule.ForwardTo) {
|
|
Write-Host " ** FORWARD TO: $($rule.ForwardTo)" -ForegroundColor Red
|
|
}
|
|
if ($rule.ForwardAsAttachmentTo) {
|
|
Write-Host " ** FWD ATTACH: $($rule.ForwardAsAttachmentTo)" -ForegroundColor Red
|
|
}
|
|
if ($rule.RedirectTo) {
|
|
Write-Host " ** REDIRECT TO: $($rule.RedirectTo)" -ForegroundColor Red
|
|
}
|
|
if ($rule.DeleteMessage) {
|
|
Write-Host " ** DELETE MSG: True" -ForegroundColor Red
|
|
}
|
|
if ($rule.MoveToFolder) {
|
|
Write-Host " Move To: $($rule.MoveToFolder)"
|
|
}
|
|
if ($rule.From) {
|
|
Write-Host " From: $($rule.From)"
|
|
}
|
|
if ($rule.SubjectContainsWords) {
|
|
Write-Host " Subject Words: $($rule.SubjectContainsWords -join ', ')"
|
|
}
|
|
if ($rule.BodyContainsWords) {
|
|
Write-Host " Body Words: $($rule.BodyContainsWords -join ', ')"
|
|
}
|
|
}
|
|
} else {
|
|
Write-Host "No inbox rules found." -ForegroundColor Green
|
|
}
|
|
} catch {
|
|
Write-Host "Error getting inbox rules: $_" -ForegroundColor Red
|
|
}
|
|
|
|
# ── Check forwarding configuration ──────────────────────────────────
|
|
Write-Host "`n=== FORWARDING CONFIG for $targetUser ===" -ForegroundColor Cyan
|
|
|
|
try {
|
|
$mbx = Get-Mailbox -Identity $targetUser
|
|
if ($mbx.ForwardingAddress) {
|
|
Write-Host " ForwardingAddress: $($mbx.ForwardingAddress)" -ForegroundColor Red
|
|
} else {
|
|
Write-Host " ForwardingAddress: (none)" -ForegroundColor Green
|
|
}
|
|
if ($mbx.ForwardingSmtpAddress) {
|
|
Write-Host " ForwardingSmtpAddress: $($mbx.ForwardingSmtpAddress)" -ForegroundColor Red
|
|
} else {
|
|
Write-Host " ForwardingSmtpAddress: (none)" -ForegroundColor Green
|
|
}
|
|
Write-Host " DeliverToMailboxAndForward: $($mbx.DeliverToMailboxAndForward)"
|
|
} catch {
|
|
Write-Host "Error getting forwarding config: $_" -ForegroundColor Red
|
|
}
|
|
|
|
# ── Part 2: Recover Deleted Items (last 10 days) ───────────────────
|
|
Write-Host "`n=== RECOVERING DELETED ITEMS (last 10 days) ===" -ForegroundColor Cyan
|
|
Write-Host "Target: $targetUser" -ForegroundColor White
|
|
|
|
$startDate = (Get-Date).AddDays(-10)
|
|
$endDate = Get-Date
|
|
$dateRange = "$($startDate.ToString('yyyy-MM-dd'))..$($endDate.ToString('yyyy-MM-dd'))"
|
|
|
|
# Step 1: Try Get-RecoverableItems (requires Mailbox Import Export role)
|
|
Write-Host "`n--- Method 1: Get-RecoverableItems ---" -ForegroundColor White
|
|
try {
|
|
Write-Host "Scanning recoverable items from $dateRange..."
|
|
$preview = Get-RecoverableItems -Identity $targetUser -FilterStartTime $startDate -FilterEndTime $endDate -FilterItemType All
|
|
|
|
if ($preview) {
|
|
Write-Host "Found $($preview.Count) recoverable item(s):" -ForegroundColor Yellow
|
|
$preview | Group-Object ItemClass | ForEach-Object { Write-Host " $($_.Name): $($_.Count) items" }
|
|
$preview | Select-Object -First 20 | ForEach-Object {
|
|
$subj = if ($_.Subject) { $_.Subject } else { "(no subject)" }
|
|
Write-Host " [$($_.LastModifiedTime.ToString('MM/dd HH:mm'))] $subj"
|
|
}
|
|
Write-Host "`nRestoring all $($preview.Count) items..." -ForegroundColor Yellow
|
|
Restore-RecoverableItems -Identity $targetUser -FilterStartTime $startDate -FilterEndTime $endDate -FilterItemType All -Confirm:$false
|
|
Write-Host "Recovery complete!" -ForegroundColor Green
|
|
} else {
|
|
Write-Host "No recoverable items found." -ForegroundColor Green
|
|
}
|
|
} catch {
|
|
Write-Host "Get-RecoverableItems not available (needs Mailbox Import Export role)." -ForegroundColor Yellow
|
|
Write-Host "Falling back to Compliance Search..." -ForegroundColor Yellow
|
|
|
|
# Step 2: Connect to Security & Compliance and run a content search
|
|
Write-Host "`n--- Method 2: Compliance Search (eDiscovery) ---" -ForegroundColor White
|
|
try {
|
|
Connect-IPPSSession -UserPrincipalName sysadmin@bgbuildersllc.com -ShowBanner:$false
|
|
Write-Host "Connected to Security & Compliance Center." -ForegroundColor Green
|
|
|
|
$searchName = "LesleyRecovery_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
|
$kql = "received>=$($startDate.ToString('yyyy-MM-dd')) AND received<=$($endDate.ToString('yyyy-MM-dd'))"
|
|
|
|
Write-Host "Creating compliance search: $searchName"
|
|
Write-Host " KQL: $kql"
|
|
Write-Host " Mailbox: $targetUser"
|
|
|
|
New-ComplianceSearch -Name $searchName `
|
|
-ExchangeLocation $targetUser `
|
|
-ContentMatchQuery $kql `
|
|
-Description "Recover deleted items for Lesley Roth - last 10 days" |
|
|
Out-Null
|
|
|
|
Write-Host "Starting search..." -ForegroundColor Yellow
|
|
Start-ComplianceSearch -Identity $searchName
|
|
|
|
# Poll for completion (max 5 minutes)
|
|
$maxWait = 300
|
|
$elapsed = 0
|
|
do {
|
|
Start-Sleep -Seconds 10
|
|
$elapsed += 10
|
|
$status = (Get-ComplianceSearch -Identity $searchName).Status
|
|
Write-Host " Status: $status ($elapsed sec)"
|
|
} while ($status -ne 'Completed' -and $elapsed -lt $maxWait)
|
|
|
|
$result = Get-ComplianceSearch -Identity $searchName
|
|
Write-Host "`nSearch Results:" -ForegroundColor Cyan
|
|
Write-Host " Status: $($result.Status)"
|
|
Write-Host " Items Found: $($result.Items)"
|
|
Write-Host " Size: $($result.Size)"
|
|
Write-Host " Success Results: $($result.SuccessResults)"
|
|
|
|
if ($result.Items -gt 0) {
|
|
Write-Host "`nItems found! To restore them:" -ForegroundColor Yellow
|
|
Write-Host " Option A: Use the Microsoft Purview portal > Content Search > '$searchName' > Export/Restore"
|
|
Write-Host " Option B: Run New-ComplianceSearchAction -SearchName '$searchName' -Purge -PurgeType SoftDelete"
|
|
Write-Host " (This moves items - for restore, use the Purview portal export instead)"
|
|
Write-Host "`n Purview URL: https://compliance.microsoft.com/contentsearchv2" -ForegroundColor Cyan
|
|
} else {
|
|
Write-Host "`nNo deleted items found in date range." -ForegroundColor Green
|
|
Write-Host "(Litigation hold preserves items in-place - they may still be in the mailbox)"
|
|
}
|
|
} catch {
|
|
Write-Host "Compliance search also failed: $_" -ForegroundColor Red
|
|
Write-Host "`nManual recovery options:" -ForegroundColor Yellow
|
|
Write-Host " 1. Outlook > Deleted Items > 'Recover items recently removed from this folder'"
|
|
Write-Host " (Log in as Barry/Shelly who have FullAccess)"
|
|
Write-Host " 2. CIPP > Mailbox Restore"
|
|
Write-Host " 3. Microsoft Purview portal > eDiscovery > Content Search"
|
|
Write-Host " URL: https://compliance.microsoft.com/contentsearchv2"
|
|
}
|
|
}
|
|
|
|
Write-Host "`n=== DONE ===" -ForegroundColor Cyan
|
|
Write-Host "Summary:"
|
|
Write-Host " - Inbox rules reviewed"
|
|
Write-Host " - Forwarding config checked"
|
|
Write-Host " - Deleted item recovery attempted"
|
|
Write-Host ""
|