@@ -232,104 +232,10 @@ function Remove-WormStorageAccounts() {
232232 foreach ($group in $groups ) {
233233 Write-Host " ========================================="
234234 $accounts = Get-AzStorageAccount - ResourceGroupName $group.ResourceGroupName
235- if ($accounts ) {
236- foreach ($account in $accounts ) {
237- if ($WhatIfPreference ) {
238- Write-Host " What if: Removing $ ( $account.StorageAccountName ) in $ ( $account.ResourceGroupName ) "
239- }
240- else {
241- Write-Host " Removing $ ( $account.StorageAccountName ) in $ ( $account.ResourceGroupName ) "
242- }
243-
244- $hasContainers = ($account.Kind -ne " FileStorage" )
245-
246- # If it doesn't have containers then we can skip the explicit clean-up of this storage account
247- if (! $hasContainers ) { continue }
248-
249- $ctx = New-AzStorageContext - StorageAccountName $account.StorageAccountName
250- $containers = $ctx | Get-AzStorageContainer
251- $blobs = $containers | Get-AzStorageBlob
252-
253- $immutableBlobs = $containers `
254- | Where-Object { $_.BlobContainerProperties.HasImmutableStorageWithVersioning } `
255- | Get-AzStorageBlob
256- try {
257- foreach ($blob in $immutableBlobs ) {
258- # We can't edit blobs with customer encryption without using that key
259- # so just try to delete them fully instead. It is unlikely they
260- # will also have a legal hold enabled.
261- if (($blob | Get-Member ' ListBlobProperties' ) `
262- -and $blob.ListBlobProperties.Properties.CustomerProvidedKeySha256 ) {
263- Write-Host " Removing customer encrypted blob: $ ( $blob.Name ) , account: $ ( $account.StorageAccountName ) , group: $ ( $group.ResourceGroupName ) "
264- $blob | Remove-AzStorageBlob - Force
265- continue
266- }
267-
268- if (! ($blob | Get-Member ' BlobProperties' )) {
269- continue
270- }
271-
272- if ($blob.BlobProperties.LeaseState -eq ' Leased' ) {
273- Write-Host " Breaking blob lease: $ ( $blob.Name ) , account: $ ( $account.StorageAccountName ) , group: $ ( $group.ResourceGroupName ) "
274- $blob.ICloudBlob.BreakLease ()
275- }
235+ if (! $accounts ) { break }
276236
277- if ($blob.BlobProperties.HasLegalHold ) {
278- Write-Host " Removing legal hold - blob: $ ( $blob.Name ) , account: $ ( $account.StorageAccountName ) , group: $ ( $group.ResourceGroupName ) "
279- $blob | Set-AzStorageBlobLegalHold - DisableLegalHold | Out-Null
280- }
281- }
282- } catch {
283- Write-Warning " Ensure user has 'Storage Blob Data Owner' RBAC permission on subscription or resource group"
284- Write-Error $_
285- throw
286- }
287- # Sometimes we get a 404 blob not found but can still delete containers,
288- # and sometimes we must delete the blob if there's a legal hold.
289- # Try to remove the blob, but keep running regardless.
290- $succeeded = $false
291- for ($attempt = 0 ; $attempt -lt 2 ; $attempt ++ ) {
292- if ($succeeded ) {
293- break
294- }
295-
296- try {
297- foreach ($blob in $blobs ) {
298- if ($blob.BlobProperties.ImmutabilityPolicy.PolicyMode ) {
299- Write-Host " Removing immutability policy - blob: $ ( $blob.Name ) , account: $ ( $ctx.StorageAccountName ) , group: $ ( $group.ResourceGroupName ) "
300- $null = $blob | Remove-AzStorageBlobImmutabilityPolicy
301- }
302- }
303- }
304- catch {}
305-
306- try {
307- foreach ($blob in $blobs ) {
308- $blob | Remove-AzStorageBlob - Force
309- }
310- $succeeded = $true
311- }
312- catch {
313- Write-Warning " Failed to remove blobs - account: $ ( $ctx.StorageAccountName ) , group: $ ( $group.ResourceGroupName ) "
314- Write-Warning $_
315- }
316- }
317-
318- try {
319- # Use AzRm cmdlet as deletion will only work through ARM with the immutability policies defined on the blobs
320- $containers | ForEach-Object { Remove-AzRmStorageContainer - Name $_.Name - StorageAccountName $ctx.StorageAccountName - ResourceGroupName $group.ResourceGroupName - Force }
321- } catch {
322- Write-Warning " Container removal failed. Ignoring the error and trying to delete the storage account."
323- Write-Warning $_
324- }
325- Remove-AzStorageAccount - StorageAccountName $account.StorageAccountName - ResourceGroupName $account.ResourceGroupName - Force
326- }
327- }
328- if ($WhatIfPreference ) {
329- Write-Host " What if: Removing resource group $ ( $group.ResourceGroupName ) "
330- }
331- else {
332- Remove-AzResourceGroup - ResourceGroupName $group.ResourceGroupName - Force - AsJob
237+ foreach ($account in $accounts ) {
238+ RemoveStorageAccount - Account $account
333239 }
334240 }
335241}
@@ -401,6 +307,96 @@ function SetStorageNetworkAccessRules([string]$ResourceGroupName, [array]$AllowI
401307 }
402308}
403309
310+ function RemoveStorageAccount ($Account ) {
311+ Write-Host ($WhatIfPreference ? ' What if: ' : ' ' ) + " Readying $ ( $Account.StorageAccountName ) in $ ( $Account.ResourceGroupName ) for deletion"
312+ # If it doesn't have containers then we can skip the explicit clean-up of this storage account
313+ if ($Account.Kind -eq " FileStorage" ) { return }
314+
315+ $containers = New-AzStorageContext - StorageAccountName $Account.StorageAccountName | Get-AzStorageContainer
316+ $blobs = $containers | Get-AzStorageBlob
317+ $deleteNow = @ ()
318+
319+ try {
320+ foreach ($blob in $blobs ) {
321+ $shouldDelete = EnableBlobDeletion - Blob $blob - StorageAccountName $Account.StorageAccountName - ResourceGroupName $Account.ResourceGroupName
322+ if ($shouldDelete ) {
323+ $deleteNow += $blob
324+ }
325+ }
326+ } catch {
327+ Write-Warning " Ensure user has 'Storage Blob Data Owner' RBAC permission on subscription or resource group"
328+ Write-Error $_
329+ throw
330+ }
331+
332+ # Blobs with legal holds or immutability policies must be deleted individually
333+ # before the container/account can be deleted
334+ foreach ($blobToDelete in $deleteNow ) {
335+ try {
336+ $blobToDelete | Remove-AzStorageBlob - Force
337+ } catch {
338+ Write-Host " Blob removal failed: $ ( $Blob.Name ) , account: $ ( $Account.storageAccountName ) , group: $ ( $Account.ResourceGroupName ) "
339+ Write-Warning " Ignoring the error and trying to delete the storage account"
340+ Write-Warning $_
341+ }
342+ }
343+
344+ foreach ($container in $containers ) {
345+ if ($container.BlobContainerProperties.HasImmutableStorageWithVersioning ) {
346+ try {
347+ # Use AzRm cmdlet as deletion will only work through ARM with the immutability policies defined on the blobs
348+ Remove-AzRmStorageContainer - Name $container.Name - StorageAccountName $Account.StorageAccountName - ResourceGroupName $Account.ResourceGroupName - Force
349+ # $container | Remove-AzStorageContainer
350+ } catch {
351+ Write-Host " Container removal failed: $ ( $container.Name ) , account: $ ( $Account.storageAccountName ) , group: $ ( $Account.ResourceGroupName ) "
352+ Write-Warning " Ignoring the error and trying to delete the storage account"
353+ Write-Warning $_
354+ }
355+ }
356+ }
357+
358+ if ($containers ) {
359+ Remove-AzStorageAccount - StorageAccountName $Account.StorageAccountName - ResourceGroupName $Account.ResourceGroupName - Force
360+ }
361+ }
362+
363+ function EnableBlobDeletion ($Blob , $StorageAccountName , $ResourceGroupName ) {
364+ # Some properties like immutability policies require the blob to be
365+ # deleted before the container can be deleted
366+ $forceBlobDeletion = $false
367+
368+ # We can't edit blobs with customer encryption without using that key
369+ # so just try to delete them fully instead. It is unlikely they
370+ # will also have a legal hold enabled.
371+ if (($Blob | Get-Member ' ListBlobProperties' ) `
372+ -and $Blob.ListBlobProperties.Properties.CustomerProvidedKeySha256 ) {
373+ return $true
374+ }
375+
376+ if (! ($Blob | Get-Member ' BlobProperties' )) {
377+ return $false
378+ }
379+
380+ if ($Blob.BlobProperties.ImmutabilityPolicy.PolicyMode ) {
381+ Write-Host " Removing immutability policy - blob: $ ( $Blob.Name ) , account: $StorageAccountName , group: $ResourceGroupName "
382+ $null = $Blob | Remove-AzStorageBlobImmutabilityPolicy
383+ $forceBlobDeletion = $true
384+ }
385+
386+ if ($Blob.BlobProperties.HasLegalHold ) {
387+ Write-Host " Removing legal hold - blob: $ ( $Blob.Name ) , account: $StorageAccountName , group: $ResourceGroupName "
388+ $Blob | Set-AzStorageBlobLegalHold - DisableLegalHold | Out-Null
389+ $forceBlobDeletion = $true
390+ }
391+
392+ if ($Blob.BlobProperties.LeaseState -eq ' Leased' ) {
393+ Write-Host " Breaking blob lease: $ ( $Blob.Name ) , account: $StorageAccountName , group: $ResourceGroupName "
394+ $Blob.ICloudBlob.BreakLease ()
395+ }
396+
397+ return $forceBlobDeletion
398+ }
399+
404400function DoesSubnetOverlap ([string ]$ipOrCidr , [string ]$overlapIp ) {
405401 [System.Net.IPAddress ]$overlapIpAddress = $overlapIp
406402 $parsed = $ipOrCidr -split ' /'
0 commit comments