All scripts
Azure AI 619
Get-AzureKeyVaultExpiringSecretsReport
Scans one or more Azure Key Vaults for secrets and certificates that are expiring soon, so you can rotate them on your own schedule instead of finding out when an app breaks in production.
Get-AzureKeyVaultExpiringSecretsReport.ps1
<#
.SYNOPSIS
Reports Key Vault secrets and certificates that are expiring soon.
.DESCRIPTION
Connects to Azure, scans one or more Key Vaults for secrets and certificates,
and lists any that expire within a given number of days. Run this on a
schedule so nothing quietly expires and breaks an app in production.
.AUTHOR
Shehryar Hassan
.EXAMPLE
.\Get-AzureKeyVaultExpiringSecretsReport.ps1 -VaultNames "prod-vault","shared-vault" -DaysThreshold 30
#>
param(
[Parameter(Mandatory = $true)]
[string[]]$VaultNames,
[int]$DaysThreshold = 30
)
if (-not (Get-Module -ListAvailable -Name Az.KeyVault)) {
Write-Error "Az.KeyVault module is not installed. Run: Install-Module Az.KeyVault -Scope CurrentUser"
exit 1
}
Import-Module Az.KeyVault -ErrorAction Stop
$context = Get-AzContext
if (-not $context) {
Write-Host "No active Azure session found, connecting now."
Connect-AzAccount | Out-Null
}
$cutoff = (Get-Date).AddDays($DaysThreshold)
$results = @()
foreach ($vaultName in $VaultNames) {
Write-Host "Checking vault: $vaultName"
try {
$secrets = Get-AzKeyVaultSecret -VaultName $vaultName -ErrorAction Stop
} catch {
Write-Warning "Could not read secrets from $vaultName. Check access policy or RBAC role. $($_.Exception.Message)"
continue
}
foreach ($secret in $secrets) {
if ($secret.Expires -and $secret.Expires -le $cutoff) {
$results += [PSCustomObject]@{
VaultName = $vaultName
ItemType = "Secret"
Name = $secret.Name
Expires = $secret.Expires
DaysLeft = [math]::Round(($secret.Expires - (Get-Date)).TotalDays, 1)
Enabled = $secret.Enabled
}
}
}
try {
$certificates = Get-AzKeyVaultCertificate -VaultName $vaultName -ErrorAction Stop
} catch {
Write-Warning "Could not read certificates from $vaultName. $($_.Exception.Message)"
continue
}
foreach ($cert in $certificates) {
if ($cert.Expires -and $cert.Expires -le $cutoff) {
$results += [PSCustomObject]@{
VaultName = $vaultName
ItemType = "Certificate"
Name = $cert.Name
Expires = $cert.Expires
DaysLeft = [math]::Round(($cert.Expires - (Get-Date)).TotalDays, 1)
Enabled = $cert.Enabled
}
}
}
}
if ($results.Count -eq 0) {
Write-Host "Nothing expiring within $DaysThreshold days across $($VaultNames.Count) vault(s)."
} else {
$results = $results | Sort-Object Expires
$results | Format-Table -AutoSize
$exportPath = ".\KeyVaultExpiringItems_$(Get-Date -Format 'yyyyMMdd').csv"
$results | Export-Csv -Path $exportPath -NoTypeInformation
Write-Host "Report saved to $exportPath"
}
Read it before you run it, and test in a safe tenant first.