...

Text file src/github.com/Azure/azure-sdk-for-go/eng/common/scripts/Helpers/Resource-Helpers.ps1

Documentation: github.com/Azure/azure-sdk-for-go/eng/common/scripts/Helpers

     1# Add 'AzsdkResourceType' member to outputs since actual output types have changed over the years.
     2
     3#Requires -Modules @{ModuleName='Az.KeyVault'; ModuleVersion='3.4.1'}
     4
     5function Get-PurgeableGroupResources {
     6  param (
     7    [Parameter(Mandatory=$true, Position=0)]
     8    [string] $ResourceGroupName
     9  )
    10
    11  $purgeableResources = @()
    12
    13  # Discover Managed HSMs first since they are a premium resource.
    14  Write-Verbose "Retrieving deleted Managed HSMs from resource group $ResourceGroupName"
    15
    16  # Get any Managed HSMs in the resource group, for which soft delete cannot be disabled.
    17  $deletedHsms = @(Get-AzKeyVaultManagedHsm -ResourceGroupName $ResourceGroupName -ErrorAction Ignore `
    18    | Add-Member -MemberType NoteProperty -Name AzsdkResourceType -Value 'Managed HSM' -PassThru `
    19    | Add-Member -MemberType AliasProperty -Name AzsdkName -Value VaultName -PassThru)
    20
    21  if ($deletedHsms) {
    22    Write-Verbose "Found $($deletedHsms.Count) deleted Managed HSMs to potentially purge."
    23    $purgeableResources += $deletedHsms
    24  }
    25
    26  Write-Verbose "Retrieving deleted Key Vaults from resource group $ResourceGroupName"
    27
    28  # Get any Key Vaults that will be deleted so they can be purged later if soft delete is enabled.
    29  $deletedKeyVaults = @(Get-AzKeyVault -ResourceGroupName $ResourceGroupName -ErrorAction Ignore | ForEach-Object {
    30    # Enumerating vaults from a resource group does not return all properties we required.
    31    Get-AzKeyVault -VaultName $_.VaultName -ErrorAction Ignore | Where-Object { $_.EnableSoftDelete } `
    32      | Add-Member -MemberType NoteProperty -Name AzsdkResourceType -Value 'Key Vault' -PassThru `
    33      | Add-Member -MemberType AliasProperty -Name AzsdkName -Value VaultName -PassThru
    34    })
    35
    36  if ($deletedKeyVaults) {
    37    Write-Verbose "Found $($deletedKeyVaults.Count) deleted Key Vaults to potentially purge."
    38    $purgeableResources += $deletedKeyVaults
    39  }
    40
    41  return $purgeableResources
    42}
    43
    44function Get-PurgeableResources {
    45  $purgeableResources = @()
    46  $subscriptionId = (Get-AzContext).Subscription.Id
    47
    48  # Discover Managed HSMs first since they are a premium resource.
    49  Write-Verbose "Retrieving deleted Managed HSMs from subscription $subscriptionId"
    50
    51  # Get deleted Managed HSMs for the current subscription.
    52  $response = Invoke-AzRestMethod -Method GET -Path "/subscriptions/$subscriptionId/providers/Microsoft.KeyVault/deletedManagedHSMs?api-version=2021-04-01-preview" -ErrorAction Ignore
    53  if ($response.StatusCode -ge 200 -and $response.StatusCode -lt 300 -and $response.Content) {
    54    $content = $response.Content | ConvertFrom-Json
    55
    56    $deletedHsms = @()
    57    foreach ($r in $content.value) {
    58      $deletedHsms += [pscustomobject] @{
    59        AzsdkResourceType = 'Managed HSM'
    60        AzsdkName = $r.name
    61        Id = $r.id
    62        Name = $r.name
    63        Location = $r.properties.location
    64        DeletionDate = $r.properties.deletionDate -as [DateTime]
    65        ScheduledPurgeDate = $r.properties.scheduledPurgeDate -as [DateTime]
    66        EnablePurgeProtection = $r.properties.purgeProtectionEnabled
    67      }
    68    }
    69
    70    if ($deletedHsms) {
    71      Write-Verbose "Found $($deletedHsms.Count) deleted Managed HSMs to potentially purge."
    72      $purgeableResources += $deletedHsms
    73    }
    74  }
    75
    76  Write-Verbose "Retrieving deleted Key Vaults from subscription $subscriptionId"
    77
    78  # Get deleted Key Vaults for the current subscription.
    79  $deletedKeyVaults = @(Get-AzKeyVault -InRemovedState `
    80    | Add-Member -MemberType NoteProperty -Name AzsdkResourceType -Value 'Key Vault' -PassThru `
    81    | Add-Member -MemberType AliasProperty -Name AzsdkName -Value VaultName -PassThru)
    82
    83  if ($deletedKeyVaults) {
    84    Write-Verbose "Found $($deletedKeyVaults.Count) deleted Key Vaults to potentially purge."
    85    $purgeableResources += $deletedKeyVaults
    86  }
    87
    88  return $purgeableResources
    89}
    90
    91# A filter differs from a function by teating body as -process {} instead of -end {}.
    92# This allows you to pipe a collection and process each item in the collection.
    93filter Remove-PurgeableResources {
    94  param (
    95    [Parameter(Position=0, ValueFromPipeline=$true)]
    96    [object[]] $Resource,
    97
    98    [Parameter()]
    99    [ValidateRange(1, [int]::MaxValue)]
   100    [int] $Timeout = 30,
   101
   102    [Parameter()]
   103    [switch] $PassThru
   104  )
   105
   106  if (!$Resource) {
   107    return
   108  }
   109
   110  $subscriptionId = (Get-AzContext).Subscription.Id
   111
   112  foreach ($r in $Resource) {
   113    Log "Attempting to purge $($r.AzsdkResourceType) '$($r.AzsdkName)'"
   114    switch ($r.AzsdkResourceType) {
   115      'Key Vault' {
   116        if ($r.EnablePurgeProtection) {
   117          # We will try anyway but will ignore errors.
   118          Write-Warning "Key Vault '$($r.VaultName)' has purge protection enabled and may not be purged for $($r.SoftDeleteRetentionInDays) days"
   119        }
   120
   121        # Use `-AsJob` to start a lightweight, cancellable job and pass to `Wait-PurgeableResoruceJob` for consistent behavior.
   122        Remove-AzKeyVault -VaultName $r.VaultName -Location $r.Location -InRemovedState -Force -ErrorAction Continue -AsJob `
   123          | Wait-PurgeableResourceJob -Resource $r -Timeout $Timeout -PassThru:$PassThru
   124      }
   125
   126      'Managed HSM' {
   127        if ($r.EnablePurgeProtection) {
   128          # We will try anyway but will ignore errors.
   129          Write-Warning "Managed HSM '$($r.Name)' has purge protection enabled and may not be purged for $($r.SoftDeleteRetentionInDays) days"
   130        }
   131
   132        # Use `GetNewClosure()` on the `-Action` ScriptBlock to make sure variables are captured.
   133        Invoke-AzRestMethod -Method POST -Path "/subscriptions/$subscriptionId/providers/Microsoft.KeyVault/locations/$($r.Location)/deletedManagedHSMs/$($r.Name)/purge?api-version=2021-04-01-preview" -ErrorAction Ignore -AsJob `
   134          | Wait-PurgeableResourceJob -Resource $r -Timeout $Timeout -PassThru:$PassThru -Action {
   135              param ( $response )
   136              if ($response.StatusCode -ge 200 -and $response.StatusCode -lt 300) {
   137                Write-Warning "Successfully requested that Managed HSM '$($r.Name)' be purged, but may take a few minutes before it is actually purged."
   138              } elseif ($response.Content) {
   139                $content = $response.Content | ConvertFrom-Json
   140                if ($content.error) {
   141                  $err = $content.error
   142                  Write-Warning "Failed to deleted Managed HSM '$($r.Name)': ($($err.code)) $($err.message)"
   143                }
   144              }
   145            }.GetNewClosure()
   146      }
   147
   148      default {
   149        Write-Warning "Cannot purge $($r.AzsdkResourceType) '$($r.AzsdkName)'. Add support to https://github.com/Azure/azure-sdk-tools/blob/main/eng/common/scripts/Helpers/Resource-Helpers.ps1."
   150      }
   151    }
   152  }
   153}
   154
   155# The Log function can be overridden by the sourcing script.
   156function Log($Message) {
   157  Write-Host ('{0} - {1}' -f [DateTime]::Now.ToLongTimeString(), $Message)
   158}
   159
   160function Wait-PurgeableResourceJob {
   161  param (
   162    [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
   163    $Job,
   164
   165    # The resource is used for logging and to return if `-PassThru` is specified
   166    # so we can easily see all resources that may be in a bad state when the script has completed.
   167    [Parameter(Mandatory=$true)]
   168    $Resource,
   169
   170    # Optional ScriptBlock should define params corresponding to the associated job's `Output` property.
   171    [Parameter()]
   172    [scriptblock] $Action,
   173
   174    [Parameter()]
   175    [ValidateRange(1, [int]::MaxValue)]
   176    [int] $Timeout = 30,
   177
   178    [Parameter()]
   179    [switch] $PassThru
   180  )
   181
   182  $null = Wait-Job -Job $Job -Timeout $Timeout
   183
   184  if ($Job.State -eq 'Completed' -or $Job.State -eq 'Failed') {
   185    $result = Receive-Job -Job $Job -ErrorAction Continue
   186
   187    if ($Action) {
   188      $null = $Action.Invoke($result)
   189    }
   190  } else {
   191    Write-Warning "Timed out waiting to purge $($Resource.AzsdkResourceType) '$($Resource.AzsdkName)'. Cancelling job."
   192    $Job.Cancel()
   193
   194    if ($PassThru) {
   195      $Resource
   196    }
   197  }
   198}

View as plain text