diff --git a/scripts/deploy-iis-remote-apply.ps1 b/scripts/deploy-iis-remote-apply.ps1 index db6d223..e6077df 100644 --- a/scripts/deploy-iis-remote-apply.ps1 +++ b/scripts/deploy-iis-remote-apply.ps1 @@ -53,23 +53,38 @@ function Wait-AppPoolFullyStopped { # Wipes are attempted a few times with a short pause - file handles (IIS or AV scanning # the just-stopped worker process's files) can take a moment to release even after the # worker process itself is confirmed gone. +# +# Remove-Item returning without an error is not proof the directory is actually empty yet - +# NTFS can finish a large recursive delete asynchronously, so a Get-ChildItem right after can +# still show remnants. If Expand-Archive -Force then runs against those remnants, it queues +# them for removal itself and can lose the race against our own delete finishing, failing with +# "Cannot find path ... because it does not exist". So after Remove-Item reports success, poll +# until the directory is verifiably empty before trusting the wipe is done. function Remove-DirectoryContentsWithRetry { - param([string]$Path, [int]$MaxAttempts = 5, [int]$DelayMs = 2000) + param([string]$DirPath, [int]$MaxAttempts = 5, [int]$DelayMs = 2000) for($attempt = 1; $attempt -le $MaxAttempts; $attempt++){ - $failure = $null + $problem = $null try { - Remove-Item -Recurse -Force $Path -ErrorAction Stop - return + Remove-Item -Recurse -Force (Join-Path $DirPath '*') -ErrorAction Stop } catch { - $failure = $_ - if($attempt -lt $MaxAttempts){ - Write-Host "Wipe attempt $attempt failed (files still locked?) - retrying in $($DelayMs)ms" - Start-Sleep -Milliseconds $DelayMs + $problem = "delete failed: $($_.Exception.Message)" + } + + if(!$problem){ + if(!(Get-ChildItem -Force -LiteralPath $DirPath -ErrorAction SilentlyContinue)){ + return } + $problem = 'residual files still present after delete (async NTFS delete still finishing?)' + } + + if($attempt -lt $MaxAttempts){ + Write-Host "Wipe attempt $attempt failed ($problem) - retrying in $($DelayMs)ms" + Start-Sleep -Milliseconds $DelayMs + } else { + throw "Wipe of $DirPath did not complete after $MaxAttempts attempts - $problem" } } - throw $failure } if(!(Get-Website -Name $SiteName -ErrorAction SilentlyContinue)){ @@ -106,7 +121,7 @@ if(![string]::IsNullOrWhiteSpace($AdminSiteName) -and (Get-Website -Name $AdminS if(Test-Path $RemoteDir){ Write-Host "Wiping $RemoteDir" - Remove-DirectoryContentsWithRetry -Path (Join-Path $RemoteDir '*') + Remove-DirectoryContentsWithRetry -DirPath $RemoteDir } else { New-Item -ItemType Directory -Force -Path $RemoteDir | Out-Null }