Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 47 additions & 6 deletions eng/common/scripts/Helpers/Resource-Helpers.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -434,11 +434,17 @@ function RemoveStorageAccount($Account) {

try {
foreach ($container in $containers) {
$blobs = $container | Get-AzStorageBlob
foreach ($blob in $blobs) {
$shouldDelete = EnableBlobDeletion -Blob $blob -Container $container -StorageAccountName $Account.StorageAccountName -ResourceGroupName $Account.ResourceGroupName
if ($shouldDelete) {
$deleteNow += $blob
# VLW containers need version-aware cleanup: soft-delete causes deleted blobs to linger
# as non-current versions that block container deletion. See Remove-VlwContainerBlobs.
if (($container | Get-Member 'BlobContainerProperties') -and $container.BlobContainerProperties.HasImmutableStorageWithVersioning) {
Remove-VlwContainerBlobs -Container $container -StorageAccountName $Account.StorageAccountName -ResourceGroupName $Account.ResourceGroupName
} else {
$blobs = $container | Get-AzStorageBlob
foreach ($blob in $blobs) {
$shouldDelete = EnableBlobDeletion -Blob $blob -Container $container -StorageAccountName $Account.StorageAccountName -ResourceGroupName $Account.ResourceGroupName
if ($shouldDelete) {
$deleteNow += $blob
}
}
}
}
Expand Down Expand Up @@ -524,6 +530,41 @@ function EnableBlobDeletion($Blob, $Container, $StorageAccountName, $ResourceGro
return $forceBlobDeletion
}

# In VLW (Versioned-Level WORM) containers with soft-delete enabled, deleting a blob creates a
# non-current version instead of truly removing it. A standard Get-AzStorageBlob listing can't
# see these leftovers, but they still block container deletion (409 Conflict on the management
# plane DELETE). Listing with -IncludeVersion -IncludeDeleted makes them visible so we can clear
# immutability policies / legal holds and delete each version individually. Multiple passes handle
# new non-current versions that surface after each round of deletions.
function Remove-VlwContainerBlobs($Container, $StorageAccountName, $ResourceGroupName) {
Write-Host "Cleaning VLW container '$($Container.Name)' versions and soft-deleted blobs in account '$StorageAccountName', group: $ResourceGroupName"

for ($round = 0; $round -lt 5; $round++) {
$found = $false
$blobs = @($Container | Get-AzStorageBlob -IncludeVersion -IncludeDeleted -ErrorAction SilentlyContinue)

foreach ($blob in $blobs) {
$found = $true

# Unconditionally clear legal holds and immutability policies. Errors are expected for
# soft-deleted blobs or blobs that don't have these set.
try { $blob | Set-AzStorageBlobLegalHold -DisableLegalHold | Out-Null } catch { }
try { $blob | Remove-AzStorageBlobImmutabilityPolicy | Out-Null } catch { }
try {
$blob | Remove-AzStorageBlob -Force
} catch {
# Deleting the current version by version ID returns 403
# (OperationNotAllowedOnRootBlob); fall back to base blob deletion.
try {
Remove-AzStorageBlob -Container $Container.Name -Blob $blob.Name -Context $Container.Context -Force
} catch { }
}
}

if (-not $found) { break }
}
}

function DoesSubnetOverlap([string]$ipOrCidr, [string]$overlapIp) {
[System.Net.IPAddress]$overlapIpAddress = $overlapIp
$parsed = $ipOrCidr -split '/'
Expand All @@ -543,4 +584,4 @@ function DoesSubnetOverlap([string]$ipOrCidr, [string]$overlapIp) {
}

return $baseIp.Address -eq ($overlapIpAddress.Address -band ([System.Net.IPAddress]$mask).Address)
}
}