<# .SYNOPSIS SharePoint Production Toolkit - Script Write-Host $lineSharePoint Production Toolkit - Script 07 - Lists and Libraries Inventory Report } function Add-Error($scope, $msg) { $errors += [pscustomobject]@{ Timestamp = Get-Date Scope = $scope Message = $msg } } if (-not $NoPrompt) { Write-Host "Scanning lists and libraries. No changes will be made." -ForegroundColor Yellow if ((Read-Host "Type YES to continue") -ne "YES") { return } } # ------------------------------------------------------------ # Resolve sites # ------------------------------------------------------------ function Get-Sites { if ($SiteCollectionUrl) { return @(Get-SPSite $SiteCollectionUrl) } return @(Get-SPSite -WebApplication $WebAppUrl -Limit All) } # ------------------------------------------------------------ # Risk logic # ------------------------------------------------------------ function Get-RiskLevel { param($ItemCount, $HasUniquePermissions, $IsHidden) if ($ItemCount -gt 5000) { return "High" } # list threshold risk if ($HasUniquePermissions -eq $true) { return "Medium" } if ($IsHidden -eq $true) { return "Low" } return "Low" } function Get-Score { param($risk) switch ($risk) { "High" { return 30 } "Medium" { return 60 } "Low" { return 90 } } } function Get-Recommendation { param($risk, $ItemCount, $HasUniquePermissions) if ($ItemCount -gt 5000) { return "Large list. Review indexing, structure, or split before migration." } if ($HasUniquePermissions) { return "Validate permissions model before migration." } return "Standard migration candidate." } # ------------------------------------------------------------ # Main scan # ------------------------------------------------------------ $results = @() try { $sites = Get-Sites Log "Scanning $($sites.Count) site collections..." } catch { Add-Error $WebAppUrl $_.Exception.Message throw } foreach ($site in $sites) { foreach ($web in $site.AllWebs) { try { Log "Scanning Web: $($web.Url)" foreach ($list in $web.Lists) { try { $itemCount = 0 try { $itemCount = $list.ItemCount } catch {} $isLibrary = $false try { if ($list.BaseType -eq "DocumentLibrary") { $isLibrary = $true } } catch {} $hasUniquePermissions = $false try { $hasUniquePermissions = $list.HasUniqueRoleAssignments } catch {} $risk = Get-RiskLevel $itemCount $hasUniquePermissions $list.Hidden $results += [pscustomobject]@{ SiteCollectionUrl = $site.Url WebUrl = $web.Url ListTitle = $list.Title ListUrl = $web.Url + "/" + $list.RootFolder.Url BaseType = $list.BaseType IsLibrary = $isLibrary ItemCount = $itemCount IsHidden = $list.Hidden HasUniquePermissions = $hasUniquePermissions EnableVersioning = $list.EnableVersioning RiskLevel = $risk Score = Get-Score $risk Category = "ListInventory" ActionRecommendation = Get-Recommendation $risk $itemCount $hasUniquePermissions } } catch { Add-Error $web.Url $_.Exception.Message } } } finally { $web.Dispose() } } $site.Dispose() } # ------------------------------------------------------------ # Export results # ------------------------------------------------------------ $results | Export-Csv -Path $OutputCsv -NoTypeInformation -Encoding UTF8 $results | Group-Object RiskLevel | ForEach-Object { [pscustomobject]@{ RiskLevel = $_.Name Count = $_.Count } } | Export-Csv -Path $summaryPath -NoTypeInformation -Encoding UTF8 $log | Set-Content $logPath if ($errors.Count -gt 0) { $errors | Export-Csv -Path $errorPath -NoTypeInformation -Encoding UTF8 Write-Host "ERROR REPORT: $errorPath" -ForegroundColor Yellow } Write-Host "" Write-Host "DETAIL REPORT: $OutputCsv" -ForegroundColor Green Write-Host "SUMMARY REPORT: $summaryPath" -ForegroundColor Green Write-Host "RUN LOG: $logPath" -ForegroundColor Green Write-Host "Complete." -ForegroundColor Green .DESCRIPTION READ-ONLY. Scans SharePoint lists and libraries for: - Migration planning - Large list detection - Governance review .PARAMETER WebAppUrl Target SharePoint Web Application URL. .PARAMETER OutputCsv Full path to output CSV. .PARAMETER SiteCollectionUrl Optional. Limit scan to a single site collection. .PARAMETER NoPrompt Optional. Skips confirmation prompt. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$WebAppUrl, [Parameter(Mandatory = $true)] [string]$OutputCsv, [string]$SiteCollectionUrl, [switch]$NoPrompt ) Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" Write-Host "" Write-Host "SCRIPT 07 - LISTS AND LIBRARIES INVENTORY" -ForegroundColor Cyan Write-Host "READ-ONLY. NO CHANGES ARE MADE." -ForegroundColor Green Write-Host "" # ------------------------------------------------------------ # Load SharePoint snap-in # ------------------------------------------------------------ if (-not (Get-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue)) { Add-PSSnapin Microsoft.SharePoint.PowerShell } # ------------------------------------------------------------ # Output setup # ------------------------------------------------------------ $outDir = Split-Path $OutputCsv -Parent if (-not (Test-Path $outDir)) { New-Item -Path $outDir -ItemType Directory -Force | Out-Null } $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $baseName = [System.IO.Path]::GetFileNameWithoutExtension($OutputCsv) $summaryPath = Join-Path $outDir "$baseName`_${timestamp}_Summary_ByRisk.csv" $logPath = Join-Path $outDir "$baseName`_${timestamp}_RunLog.txt" $errorPath = Join-Path $outDir "$baseName`_${timestamp}_Errors.csv" # ------------------------------------------------------------ # Logging # ------------------------------------------------------------ $log = @() $errors = @() function Log($msg) { $line = "[{0}] {1}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $msg $log += $line