param (
[string]$Username = ""
)
$StorageAccountName = "XXXXXXX"
$SharesToCheck = @("fslogix-profiles", "fslogix-o365")
Write-Host "=== FSLogix Stuck Handle Cleanup Tool ===`n" -ForegroundColor Cyan
if (-not $Username) {
$Username = Read-Host "Enter username (e.g. nwaiki)"
}
$UserPattern = "*$Username*"
Write-Host "Searching for handles for user: $Username" -ForegroundColor Yellow
# Get Storage Key
$StorageAccountKey = Read-Host "Enter Storage Account Key" -AsSecureString
$KeyPlain = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($StorageAccountKey))
$Context = New-AzStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $KeyPlain
$TotalClosed = 0
foreach ($ShareName in $SharesToCheck) {
Write-Host "`nChecking share: $ShareName ..." -ForegroundColor Yellow
$Handles = Get-AzStorageFileHandle -ShareName $ShareName -Recursive -Context $Context |
Where-Object { $_.Path -like $UserPattern }
if ($Handles.Count -gt 0) {
Write-Host "Found $($Handles.Count) handle(s)" -ForegroundColor Red
$Handles | Format-Table ClientIP, OpenTime, Path, HandleId -AutoSize
$Confirm = Read-Host "Close ALL handles for $Username in $ShareName? (YES)"
if ($Confirm -eq "YES") {
foreach ($h in $Handles) {
Write-Host "Closing: $($h.Path)" -ForegroundColor Yellow
Close-AzStorageFileHandle -ShareName $ShareName -Path $h.Path -CloseAll -Context $Context -Verbose
$TotalClosed++
}
Write-Host "Handles closed in $ShareName" -ForegroundColor Green
}
} else {
Write-Host "No handles found in $ShareName" -ForegroundColor Green
}
}
Write-Host "`n=== Finished! Total handles closed: $TotalClosed ===" -ForegroundColor Cyan