Pre-Diagnostic Preparation
Essential Information Gathering
- Problem Statement: Clear description of the issue, when it started, and affected users
- Environment Details: Tenant ID, site URLs, user accounts, and browser information
- Reproduction Steps: Exact steps to reproduce the issue consistently
- Error Messages: Complete error text, screenshots, and correlation IDs
- Recent Changes: Any configuration changes, updates, or migrations in the past 30 days
Systematic Diagnostic Checklist
1. Service Health Verification
Microsoft 365 Service Health Check
- Access Admin Center: Navigate to Microsoft 365 Admin Center > Health > Service Health
- Check SharePoint Status: Look for any active incidents or advisories
- Review Recent Issues: Check for resolved issues that might have ongoing effects
- Message Center Review: Check for planned maintenance or feature changes
# PowerShell Service Health Check
Connect-MgGraph -Scopes "ServiceHealth.Read.All"
# Get current service health status
Get-MgServiceAnnouncementHealthOverview | Where-Object {$_.Service -eq "SharePoint"}
# Get recent service issues
Get-MgServiceAnnouncementIssue | Where-Object {$_.Service -eq "SharePoint" -and $_.EndDateTime -gt (Get-Date).AddDays(-7)}
Tenant Status Validation
- Billing Status: Verify tenant is in good standing with no payment issues
- License Assignments: Confirm affected users have proper SharePoint licenses
- Feature Availability: Check if the problematic feature is included in current licenses
- Maintenance Mode: Verify tenant isn't in maintenance or migration state
2. User Account and Authentication Analysis
User Account Verification
# Connect to SharePoint Online Admin Center
Connect-SPOService -Url https://[tenant]-admin.sharepoint.com
# Verify user exists and has proper access
Get-SPOUser -Site https://[tenant].sharepoint.com/sites/[site] -LoginName user@domain.com
# Check user's license assignments
Connect-MgGraph -Scopes "User.Read.All"
Get-MgUserLicenseDetail -UserId "user@domain.com"
# Verify site collection administrators
Get-SPOSite -Identity https://[tenant].sharepoint.com/sites/[site] | Select Url, Owner, @{Name="Admins";Expression={$_.Administrators}}
Authentication and Access Testing
- Multiple Browser Test: Test in Edge, Chrome, and Firefox
- Incognito/Private Mode: Test in private browsing to eliminate cache issues
- Different Networks: Test from different network connections (corporate, home, mobile)
- Different Devices: Test on desktop, mobile, and tablet devices
- Different Users: Test with multiple user accounts to isolate user-specific issues
Permission and Group Membership Analysis
# Check external sharing settings at tenant and site level
Get-SPOTenant | Select SharingCapability, RequireAcceptingAccountMatchInvitedAccount
Get-SPOSite -Identity https://[tenant].sharepoint.com/sites/[site] | Select SharingCapability
# Analyze user group memberships
Connect-PnPOnline -Url https://[tenant].sharepoint.com/sites/[site] -Interactive
$user = Get-PnPUser -Identity "user@domain.com"
Get-PnPGroupMember -Group "Site Members" | Where-Object {$_.Email -eq $user.Email}
# Check effective permissions
$web = Get-PnPWeb
$permissions = $web.GetUserEffectivePermissions($user.LoginName)
3. Search and Indexing Diagnostics
Search Functionality Testing
# Test search service availability
$searchResults = Search-PnPContent -Query "ContentClass:STS_ListItem_DocumentLibrary"
Write-Host "Search returned $($searchResults.Count) results"
# Check recent content indexing
$recentQuery = "LastModifiedTime>=$(Get-Date -Format 'yyyy-MM-dd')"
$recentResults = Search-PnPContent -Query $recentQuery
Write-Host "Recent content found: $($recentResults.Count) items"
# Test site-specific search
$siteQuery = "Path:https://[tenant].sharepoint.com/sites/[site]*"
$siteResults = Search-PnPContent -Query $siteQuery
Force Reindexing Procedures
# Force site reindexing
Connect-SPOService -Url https://[tenant]-admin.sharepoint.com
Request-SPOReIndexWeb -Identity https://[tenant].sharepoint.com/sites/[site]
# Force list reindexing
Request-SPOReIndexList -Identity https://[tenant].sharepoint.com/sites/[site]/lists/documents
# Check indexing status and last crawl time
$site = Get-SPOSite -Identity https://[tenant].sharepoint.com/sites/[site] -Detailed
Write-Host "Last content modified: $($site.LastContentModifiedDate)"
Write-Host "Site creation time: $($site.Created)"
Search Configuration Validation
- Managed Properties: Verify custom managed properties are configured correctly
- Result Sources: Check result source configurations and scoping
- Query Rules: Review query rules that might affect search results
- Search Schema: Validate search schema modifications and mappings
4. Storage and Performance Analysis
Site Storage Diagnostics
# Comprehensive site storage analysis
$sites = Get-SPOSite -Limit All
$storageReport = @()
foreach ($site in $sites) {
$siteDetails = Get-SPOSite -Identity $site.Url -Detailed
$storagePercent = if ($siteDetails.StorageQuota -gt 0) {
[math]::Round(($siteDetails.StorageUsageCurrent / $siteDetails.StorageQuota) * 100, 2)
} else { 0 }
$storageReport += [PSCustomObject]@{
SiteUrl = $site.Url
Title = $site.Title
StorageUsedMB = $siteDetails.StorageUsageCurrent
StorageQuotaMB = $siteDetails.StorageQuota
PercentageUsed = $storagePercent
Status = if ($storagePercent -gt 90) { "Critical" }
elseif ($storagePercent -gt 80) { "Warning" }
else { "Normal" }
LastModified = $siteDetails.LastContentModifiedDate
}
}
# Display sites with storage issues
$storageReport | Where-Object {$_.Status -ne "Normal"} | Format-Table -AutoSize
# Export for detailed analysis
$storageReport | Export-Csv -Path "C:\Reports\SiteStorageAnalysis.csv" -NoTypeInformation
List and Library Performance Check
# Check for large lists that might impact performance
Connect-PnPOnline -Url https://[tenant].sharepoint.com/sites/[site] -Interactive
$lists = Get-PnPList
$largeListsReport = @()
foreach ($list in $lists) {
if ($list.ItemCount -gt 2000) {
$largeListsReport += [PSCustomObject]@{
ListTitle = $list.Title
ItemCount = $list.ItemCount
BaseType = $list.BaseType
Created = $list.Created
LastModified = $list.LastItemModifiedDate
HasThresholdIssues = $list.ItemCount -gt 5000
}
}
}
$largeListsReport | Format-Table -AutoSize
Version History and Cleanup
# Check version history settings and storage impact
$libraries = Get-PnPList | Where-Object {$_.BaseType -eq "DocumentLibrary"}
foreach ($library in $libraries) {
$versionSettings = Get-PnPList -Identity $library.Title
Write-Host "Library: $($library.Title)"
Write-Host " Major Versions: $($versionSettings.MajorVersionLimit)"
Write-Host " Minor Versions: $($versionSettings.MajorWithMinorVersionsLimit)"
Write-Host " Versioning Enabled: $($versionSettings.EnableVersioning)"
Write-Host " Item Count: $($versionSettings.ItemCount)"
}
5. Network and Connectivity Diagnostics
Network Connectivity Testing
# Test connectivity to key SharePoint Online endpoints
$endpoints = @(
"login.microsoftonline.com",
"[tenant].sharepoint.com",
"[tenant]-admin.sharepoint.com",
"outlook.office365.com",
"graph.microsoft.com"
)
foreach ($endpoint in $endpoints) {
$result = Test-NetConnection -ComputerName $endpoint -Port 443 -InformationLevel Quiet
Write-Host "$endpoint`: $($result)" -ForegroundColor $(if ($result) { "Green" } else { "Red" })
}
# Test DNS resolution
foreach ($endpoint in $endpoints) {
$dnsResult = Resolve-DnsName -Name $endpoint -ErrorAction SilentlyContinue
if ($dnsResult) {
Write-Host "DNS Resolution for $endpoint`: Success" -ForegroundColor Green
} else {
Write-Host "DNS Resolution for $endpoint`: Failed" -ForegroundColor Red
}
}
Browser and Client Diagnostics
- Clear Browser Cache: Clear cache, cookies, and stored data
- Disable Extensions: Test with browser extensions disabled
- Reset Browser Settings: Test with default browser settings
- Update Browser: Ensure browser is updated to latest version
- Test Alternative Browsers: Compare behavior across different browsers
Common Issue Quick Fixes
Site User ID Mismatch Resolution
This addresses issues where user permissions appear correct but access is denied (similar to the Microsoft Learn article referenced above).
# Step 1: Document current user permissions
$userLogin = "user@domain.com"
$siteUrl = "https://[tenant].sharepoint.com/sites/[site]"
Connect-PnPOnline -Url $siteUrl -Interactive
$userBefore = Get-PnPUser -Identity $userLogin -ErrorAction SilentlyContinue
if ($userBefore) {
Write-Host "User found - Groups: $($userBefore.Groups -join ', ')"
# Step 2: Remove user from site (this clears cached permissions)
Remove-PnPUser -Identity $userLogin -Force
Write-Host "User removed from site"
# Step 3: Wait for replication
Start-Sleep -Seconds 30
# Step 4: Re-add user with proper permissions
Add-PnPUser -LoginName $userLogin -Group "Members"
Write-Host "User re-added to Members group"
# Step 5: Verify fix
$userAfter = Get-PnPUser -Identity $userLogin
Write-Host "Fix applied - New groups: $($userAfter.Groups -join ', ')"
} else {
Write-Host "User not found in site - adding fresh"
Add-PnPUser -LoginName $userLogin -Group "Members"
}
Search Index Refresh
# Comprehensive search reindexing procedure
Connect-SPOService -Url https://[tenant]-admin.sharepoint.com
# Option 1: Full site reindexing
Request-SPOReIndexWeb -Identity $siteUrl
Write-Host "Site reindexing requested"
# Option 2: Specific list reindexing
$listUrl = "$siteUrl/lists/Documents"
Request-SPOReIndexList -Identity $listUrl
Write-Host "List reindexing requested"
# Option 3: Force crawl through site settings (PowerShell method)
Connect-PnPOnline -Url $siteUrl -Interactive
$web = Get-PnPWeb
$web.ReindexWeb()
Invoke-PnPQuery
Write-Host "Web reindex executed"
External Sharing Configuration Fix
# Fix external sharing issues
$siteUrl = "https://[tenant].sharepoint.com/sites/[site]"
# Check current sharing settings
$tenant = Get-SPOTenant
$site = Get-SPOSite -Identity $siteUrl
Write-Host "Tenant sharing capability: $($tenant.SharingCapability)"
Write-Host "Site sharing capability: $($site.SharingCapability)"
# Fix: Align site sharing with tenant policy
if ($site.SharingCapability -ne $tenant.SharingCapability) {
Set-SPOSite -Identity $siteUrl -SharingCapability $tenant.SharingCapability
Write-Host "Site sharing capability updated to match tenant settings"
}
# Fix: Enable external user sharing if needed
Set-SPOSite -Identity $siteUrl -SharingCapability ExternalUserSharingOnly
Write-Host "External user sharing enabled"
# Fix: Remove invitation acceptance requirement if blocking access
Set-SPOTenant -RequireAcceptingAccountMatchInvitedAccount $false
Write-Host "Invitation acceptance requirement removed"
OneDrive Sync Issues
# OneDrive sync diagnostics and fixes
# Step 1: Check OneDrive service health
Get-Service -Name "OneDrive*" | Format-Table Name, Status, StartType
# Step 2: Reset OneDrive sync client
Stop-Process -Name "OneDrive" -Force -ErrorAction SilentlyContinue
Start-Sleep -Seconds 5
# Step 3: Clear OneDrive cache
$oneDriveCache = "$env:LOCALAPPDATA\Microsoft\OneDrive\settings"
if (Test-Path $oneDriveCache) {
Remove-Item "$oneDriveCache\*" -Recurse -Force
Write-Host "OneDrive cache cleared"
}
# Step 4: Restart OneDrive
Start-Process "OneDrive.exe"
Write-Host "OneDrive restarted"
# Step 5: Verify library sync settings
Connect-PnPOnline -Url $siteUrl -Interactive
$library = Get-PnPList -Identity "Documents"
$syncEnabled = $library.DisableCommenting -eq $false
Write-Host "Library sync enabled: $syncEnabled"
Advanced Diagnostic Procedures
PowerShell Health Check Script
# Comprehensive SharePoint Online health check script
param(
[Parameter(Mandatory=$true)]
[string]$SiteUrl,
[Parameter(Mandatory=$false)]
[string]$OutputPath = "C:\Reports\SPOHealthCheck.html"
)
# Initialize report
$healthReport = @{
SiteUrl = $SiteUrl
CheckTime = Get-Date
Issues = @()
Recommendations = @()
}
try {
# Connect to site
Connect-PnPOnline -Url $SiteUrl -Interactive
$web = Get-PnPWeb
Write-Host "✓ Connection successful" -ForegroundColor Green
$healthReport.ConnectionStatus = "Success"
# Check 1: Site storage
$site = Get-PnPTenantSite -Url $SiteUrl
$storagePercent = ($site.StorageUsageCurrent / $site.StorageQuota) * 100
if ($storagePercent -gt 90) {
$healthReport.Issues += "Critical: Storage usage at $([math]::Round($storagePercent,2))%"
$healthReport.Recommendations += "Increase storage quota or archive old content"
}
# Check 2: Large lists
$lists = Get-PnPList
$largeLists = $lists | Where-Object {$_.ItemCount -gt 5000}
if ($largeLists.Count -gt 0) {
$healthReport.Issues += "Warning: $($largeLists.Count) lists exceed 5000 items"
$healthReport.Recommendations += "Implement list archiving or folder structure"
}
# Check 3: External sharing
if ($site.SharingCapability -eq "Disabled") {
$healthReport.Issues += "Info: External sharing is disabled"
}
# Check 4: Search functionality
$searchResults = Search-PnPContent -Query "ContentClass:STS_ListItem_DocumentLibrary" -MaxResults 1
if ($searchResults.Count -eq 0) {
$healthReport.Issues += "Warning: Search returned no document library results"
$healthReport.Recommendations += "Request site reindexing"
}
# Generate HTML report
$htmlReport = @"
SharePoint Online Health Check
SharePoint Online Health Check Report
Site: $($healthReport.SiteUrl)
Check Time: $($healthReport.CheckTime)
Issues Found:
$(($healthReport.Issues | ForEach-Object {"- $_
"}) -join "`n")
Recommendations:
$(($healthReport.Recommendations | ForEach-Object {"- $_
"}) -join "`n")
"@
$htmlReport | Out-File -FilePath $OutputPath -Encoding UTF8
Write-Host "Health check report saved to: $OutputPath" -ForegroundColor Green
}
catch {
Write-Host "✗ Health check failed: $($_.Exception.Message)" -ForegroundColor Red
$healthReport.ConnectionStatus = "Failed"
$healthReport.Issues += "Critical: $($_.Exception.Message)"
}
Documentation for Microsoft Support
If self-diagnostics don't resolve the issue, gather this information before contacting support:
Essential Information Package
- Correlation ID: From error messages or HTTP headers (SPRequestGuid, request-id)
- Exact Error Messages: Complete text and screenshots of all error messages
- Reproduction Steps: Detailed step-by-step process to reproduce the issue
- User Impact Assessment: Number of affected users, business impact, and urgency level
- Environment Details: Browser versions, device types, network configuration
- Recent Changes Log: Any configuration changes, migrations, or updates in past 30 days
- Diagnostic Results: Results from all self-diagnostic procedures performed
# Template for support information gathering
$supportPackage = @{
TenantID = (Get-PnPTenantId)
SiteURL = $siteUrl
AffectedUsers = @("user1@domain.com", "user2@domain.com")
ErrorMessage = "Detailed error message here"
CorrelationID = "12345678-1234-1234-1234-123456789012"
BrowserInfo = "Chrome 118.0.5993.88 on Windows 11"
NetworkInfo = "Corporate network, no proxy"
ReproductionSteps = @(
"1. Navigate to site",
"2. Click on Documents library",
"3. Attempt to upload file",
"4. Error occurs"
)
DiagnosticsPerformed = @(
"Service health check - No issues found",
"User permissions verified - User has Contribute access",
"Storage check - 45% utilized",
"Browser cache cleared - Issue persists"
)
BusinessImpact = "High - Blocking document uploads for 25 users"
Timeline = "Issue started 2025-09-15 at 10:30 AM UTC"
}
# Export support package
$supportPackage | ConvertTo-Json -Depth 3 | Out-File "C:\Reports\SupportPackage.json"
Proactive Monitoring and Prevention
Automated Health Monitoring
# Schedule this script to run daily for proactive monitoring
# Create scheduled task or Azure Function for automated execution
$monitoringResults = @()
$alertThresholds = @{
StorageWarning = 80
StorageCritical = 90
LargeListThreshold = 5000
SearchLatencyWarning = 5000 # milliseconds
}
# Monitor all site collections
$sites = Get-SPOSite -Limit All
foreach ($site in $sites) {
$siteHealth = @{
SiteUrl = $site.Url
Title = $site.Title
CheckTime = Get-Date
Alerts = @()
}
# Storage monitoring
$storagePercent = ($site.StorageUsageCurrent / $site.StorageQuota) * 100
if ($storagePercent -gt $alertThresholds.StorageCritical) {
$siteHealth.Alerts += "CRITICAL: Storage at $([math]::Round($storagePercent,2))%"
} elseif ($storagePercent -gt $alertThresholds.StorageWarning) {
$siteHealth.Alerts += "WARNING: Storage at $([math]::Round($storagePercent,2))%"
}
# Performance monitoring
$searchStart = Get-Date
$searchTest = Search-PnPContent -Query "Path:$($site.Url)*" -MaxResults 1
$searchDuration = (Get-Date) - $searchStart
if ($searchDuration.TotalMilliseconds -gt $alertThresholds.SearchLatencyWarning) {
$siteHealth.Alerts += "WARNING: Search latency $([math]::Round($searchDuration.TotalMilliseconds,0))ms"
}
$monitoringResults += $siteHealth
}
# Generate alerts for sites with issues
$sitesWithAlerts = $monitoringResults | Where-Object {$_.Alerts.Count -gt 0}
if ($sitesWithAlerts.Count -gt 0) {
# Send email alert, write to log, or trigger notification
$alertMessage = "SharePoint Online Health Alert: $($sitesWithAlerts.Count) sites require attention"
Write-Host $alertMessage -ForegroundColor Yellow
# Log details
$sitesWithAlerts | Format-Table SiteUrl, @{Name="Alerts";Expression={$_.Alerts -join "; "}} -AutoSize
}
About the Author: Nagendra Jayaram is a Microsoft Sr Technical Advisor who has resolved over 480 SharePoint escalations annually, achieving 98% customer satisfaction through systematic self-diagnostic procedures and proactive monitoring strategies.