Private/Get-RotationSecret.ps1
|
function Get-RotationSecret { <# .SYNOPSIS Reads secret metadata, distinguishing "does not exist" from "cannot read". .DESCRIPTION This distinction is the single most important piece of error handling in the project. Get-AzKeyVaultSecret returns $null when a secret is absent and throws when the call itself fails - a denied role assignment, throttling, a firewall, a transient network fault. Treating both as "no secret, therefore rotate" is how you end up changing a VM password and then failing to store it. This function returns Exists=$false only for a genuine absence and rethrows everything else, so a permissions problem surfaces as a failure instead of a rotation. Note that -IncludeVersions is not used: metadata is enough to decide, and not reading the value keeps this call out of the SecretGet audit trail that the access-triggered rotation depends on. A disabled secret is a third case, and it is not obvious: Key Vault answers a read with 403 "Operation get is not allowed on a disabled secret". That looks exactly like a permissions failure, so without special handling a single disabled secret anywhere in the vault aborts discovery for the whole subscription - which is precisely what happened on a live run. .OUTPUTS PSCustomObject with Exists, Disabled and Secret (the Key Vault secret, or $null). #> [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory)][string]$VaultName, [Parameter(Mandatory)][string]$Name ) try { $secret = Get-AzKeyVaultSecret -VaultName $VaultName -Name $Name -ErrorAction Stop return [pscustomobject]@{ Exists = $null -ne $secret Disabled = $false Secret = $secret } } catch { # Az surfaces a missing secret as $null, but be explicit in case a future # version starts throwing: only a genuine 404 counts as absent. $isNotFound = $_.Exception.Message -match 'SecretNotFound' -or $_.Exception.Response.StatusCode -eq 404 if ($isNotFound) { return [pscustomobject]@{ Exists = $false; Disabled = $false; Secret = $null } } # Disabled: the secret exists but cannot be read. Not a permissions problem, # and not a reason to stop. if ($_.Exception.Message -match 'disabled secret') { return [pscustomobject]@{ Exists = $true; Disabled = $true; Secret = $null } } throw "Cannot read secret metadata '$Name' from vault '$VaultName'. Refusing to treat this as a missing secret. $($_.Exception.Message)" } } |