Skip to content

Instantly share code, notes, and snippets.

@silverl
Created March 21, 2023 22:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save silverl/3fcc7c193aba504d2f2c79685861efdc to your computer and use it in GitHub Desktop.
Save silverl/3fcc7c193aba504d2f2c79685861efdc to your computer and use it in GitHub Desktop.
PowerShell Core script to remove old files recursively, and in parallel, from a local file system or remote share, like Azure Storage File Share
param (
$StartPath = "\\your_storage_account_name.file.core.windows.net\your_share_name\whatever"
)
Set-StrictMode -Version Latest
# Write a transcript to file.
$path = Get-Location
$scriptName = $MyInvocation.MyCommand.Name
$scriptLog = "$path\$scriptName.log"
Start-Transcript -Path $scriptLog -Force
$stopWatch = [System.Diagnostics.Stopwatch]::StartNew()
Write-Output "Started at $(Get-Date)"
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
$foldersToPurge = @(
[pscustomobject]@{Name = 'Folder1'; RetentionInDays = 180 }
[pscustomobject]@{Name = 'Folder2'; RetentionInDays = 365 }
[pscustomobject]@{Name = 'Folder3'; RetentionInDays = 30 }
)
# Thanks to https://stackoverflow.com/a/45472343/7752
function Retry-Command {
[CmdletBinding()]
Param(
[Parameter(Position = 0, Mandatory = $true)]
[scriptblock]$ScriptBlock,
[Parameter(Position = 1, Mandatory = $false)]
[int]$Maximum = 5,
[Parameter(Position = 2, Mandatory = $false)]
[int]$Delay = 100
)
Begin {
$cnt = 0
}
Process {
do {
$cnt++
try {
$ScriptBlock.Invoke()
return
}
catch {
Write-Error $_.Exception.InnerException.Message -ErrorAction Continue
Start-Sleep -Milliseconds $Delay
}
} while ($cnt -lt $Maximum)
# Throw an error after $Maximum unsuccessful invocations. Doesn't need
# a condition, since the function returns upon successful invocation.
throw 'Execution failed.'
}
}
$funcDef = ${function:Retry-Command}.ToString()
# Define a recursive function
function Remove-Files ($Path, $Days) {
Write-Output "Processing folder $($Path)"
# Get current date
$CurrentDate = Get-Date
# Calculate date to delete
$DateToDelete = $CurrentDate.AddDays(-$Days)
if (! ( Test-Path -Path $Path) ) {
continue
}
# Delete files in parallel older than date
Get-ChildItem -Path $Path -File | Where-Object { $_.LastWriteTime -lt $DateToDelete } | ForEach-Object -ThrottleLimit 10 -Parallel {
$File = $_
# Bring in out-of-scope function.
${function:Retry-Command} = $using:funcDef
Write-Output "Removing $($File.FullName)"
Retry-Command -Delay 1000 -ScriptBlock { Remove-Item -Path $File.FullName } -Maximum 5
}
# Get folders in current path
$Folders = Get-ChildItem -Path $Path -Directory -ErrorAction SilentlyContinue
# Call function for each subfolder
$Folders | ForEach-Object {
$Folder = $_
Remove-Files -Path $Folder.FullName -Days $Days
# Delete empty folder
if ($null -eq (Get-ChildItem -Path $Folder.FullName)) {
Write-Output "Removing empty folder $($Folder.FullName)"
Remove-Item -Path $Folder.FullName
}
}
}
$folders = Get-ChildItem -Directory -Path $StartPath
foreach ($clientFolder in $folders) {
foreach ($folder in $foldersToPurge) {
$fullpath = $clientFolder.FullName + "\$($folder.Name)"
Remove-Files -Path $fullpath -Days $folder.RetentionInDays
}
}
$stopWatch.Stop()
$stopWatch.Elapsed.ToString()
Write-Output "Ended at $(Get-Date)"
# Stop Logging
Stop-Transcript
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment