Public/Remediate/Optimize-SPCFileVersion.ps1
|
function Optimize-SPCFileVersion { <# .SYNOPSIS Optimizes document library storage by safely trimming redundant historical file versions. .DESCRIPTION Optimize-SPCFileVersion trims old historical file versions across document libraries within a SharePoint Online site collection based on configurable version count (-KeepVersions) and age (-OlderThanDays) criteria. Key Capabilities: - Version Trimming: Identifies and deletes excessive intermediate versions while preserving the latest major versions. - Library Policy Adjustment: Optionally updates document library settings (-ApplyPolicyToLibrary) to enforce MajorVersionLimit going forward, preventing future version sprawl. - Simulation & Safety: Fully supports -DryRun and -WhatIf modes to preview potential storage reclamation before taking action. - Immutable Audit Logging: Detailed logs recording every file processed, versions removed, and bytes freed are saved to CSV. .PARAMETER SiteUrl The full URL of the SharePoint Online site collection to optimize. Supports pipeline input by value and property name. .PARAMETER LibraryTitle Optional list of document library titles to optimize. When omitted, all visible, non-system document libraries in the site collection are processed. .PARAMETER KeepVersions The number of recent major historical versions to retain for each file. Default is 50. Range: 1 to 50,000. .PARAMETER OlderThanDays The minimum age (in days) that a version must have to be eligible for trimming. Default is 90 days. Range: 0 to 3,650. .PARAMETER ApplyPolicyToLibrary When specified, updates the document library configuration's MajorVersionLimit to match -KeepVersions. .PARAMETER DryRun Executes in simulation mode. No versions are removed and no policies are changed, but storage savings are calculated. .PARAMETER AuditLogPath Custom file path for the append-only CSV audit log. If omitted, a timestamped CSV file is created in the current directory. .PARAMETER Force Suppresses interactive confirmation prompts during execution. .INPUTS System.String Accepts site collection URLs from the pipeline. .OUTPUTS SPC.FileVersionOptimizeResult Returns custom objects containing site URL, count of libraries processed, files optimized, versions removed, storage freed in MB, monthly/annual cost savings in USD, policy update status, simulation flag, and audit log path. .EXAMPLE Optimize-SPCFileVersion -SiteUrl 'https://contoso.sharepoint.com/sites/Engineering' -KeepVersions 30 -OlderThanDays 60 -DryRun Simulates trimming file versions older than 60 days while retaining 30 versions on the Engineering site. .EXAMPLE Optimize-SPCFileVersion -SiteUrl 'https://contoso.sharepoint.com/sites/Marketing' -LibraryTitle 'Brand Assets' -KeepVersions 20 -ApplyPolicyToLibrary -Force Trims redundant versions in the 'Brand Assets' library and configures the library to retain a maximum of 20 major versions. .EXAMPLE Get-SPCVersionWaste -SiteUrl 'https://contoso.sharepoint.com/sites/Finance' | Where-Object BloatRatio -gt 2.0 | ForEach-Object { Optimize-SPCFileVersion -SiteUrl $_.SiteUrl -LibraryTitle $_.LibraryTitle -KeepVersions 50 -OlderThanDays 90 } Identifies bloated document libraries using Get-SPCVersionWaste and immediately optimizes them. .NOTES Requires an active SPClean connection initialized via Connect-SPCTenant. Live execution requires a Pro or Consultant tier license. .LINK Get-SPCVersionWaste Get-SPCStorageWaste Export-SPCStorageReport #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] [OutputType('SPC.FileVersionOptimizeResult')] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [string]$SiteUrl, [Parameter()] [string[]]$LibraryTitle, [Parameter()] [ValidateRange(1, 50000)] [int]$KeepVersions = 50, [Parameter()] [ValidateRange(0, 3650)] [int]$OlderThanDays = 90, [Parameter()] [switch]$ApplyPolicyToLibrary, [Parameter()] [switch]$DryRun, [Parameter()] [string]$AuditLogPath, [Parameter()] [switch]$Force ) begin { Test-SPCConnection $isSimulation = $DryRun.IsPresent -or $WhatIfPreference if (-not $isSimulation) { Assert-SPCProLicense -Feature 'Optimize-SPCFileVersion' } if ([string]::IsNullOrWhiteSpace($AuditLogPath)) { $timestamp = (Get-Date).ToString("yyyyMMdd_HHmmss") $AuditLogPath = Join-Path (Get-Location) "SPClean_VersionTrim_Audit_$timestamp.csv" } } process { if (-not $Force -and -not $isSimulation) { if (-not $PSCmdlet.ShouldProcess("Site: $SiteUrl [KeepVersions: $KeepVersions, OlderThan: $OlderThanDays days]", "Trim File Versions")) { return } } $trimResult = Invoke-SPCVersionTrimmingInternal ` -SiteUrl $SiteUrl ` -LibraryTitle $LibraryTitle ` -KeepVersions $KeepVersions ` -OlderThanDays $OlderThanDays ` -ApplyPolicy $ApplyPolicyToLibrary.IsPresent ` -DryRun $isSimulation ` -AuditLogPath $AuditLogPath $freedMB = if ($null -ne $trimResult -and $null -ne $trimResult.StorageFreedMB) { $trimResult.StorageFreedMB } else { 0.0 } $monthlySaved = [Math]::Round((($freedMB / 1024) * 0.20), 2) $annualSaved = [Math]::Round(($monthlySaved * 12), 2) $libProcessed = if ($null -ne $trimResult -and $null -ne $trimResult.LibrariesProcessed) { $trimResult.LibrariesProcessed } else { 0 } $filesOptimized = if ($null -ne $trimResult -and $null -ne $trimResult.FilesOptimizedCount) { $trimResult.FilesOptimizedCount } else { 0 } $verRemoved = if ($null -ne $trimResult -and $null -ne $trimResult.VersionsRemovedCount) { $trimResult.VersionsRemovedCount } else { 0 } [PSCustomObject][ordered]@{ PSTypeName = 'SPC.FileVersionOptimizeResult' SiteUrl = $SiteUrl LibrariesProcessed = $libProcessed FilesOptimizedCount = $filesOptimized VersionsRemovedCount = $verRemoved StorageFreedMB = $freedMB MonthlyCostSavedUSD = $monthlySaved AnnualCostSavedUSD = $annualSaved PolicyUpdated = $ApplyPolicyToLibrary.IsPresent IsDryRun = $isSimulation AuditLogFilePath = $AuditLogPath ExecutedAt = (Get-Date).ToUniversalTime() } } } |