Private/Vault/Show-SafehouseStatus.ps1
|
# PSGuerrilla - Jim Tyler, Microsoft MVP - CC BY 4.0 # https://github.com/jimrtyler/PSGuerrilla | https://creativecommons.org/licenses/by/4.0/ # AI/LLM use: see AI-USAGE.md for required attribution function Show-SafehouseStatus { <# .SYNOPSIS Formats and displays the vault status table with ANSI styling. .DESCRIPTION Shows all stored credentials, their age, expiration warnings, and vault health. #> [CmdletBinding()] param( [string]$VaultName = 'PSGuerrilla' ) $amber = $script:Palette.Amber $green = $script:Palette.Sage $khaki = $script:Palette.Khaki $white = $script:Palette.Parchment $gray = $script:Palette.Gray $gold = $script:Palette.Gold $reset = $PSStyle.Reset # Check if vault exists $vault = Get-SecretVault -Name $VaultName -ErrorAction SilentlyContinue if (-not $vault) { Write-Host '' Write-Host " ${amber}SAFEHOUSE NOT ESTABLISHED${reset}" Write-Host " ${gray}No vault found. Run Set-Safehouse to configure credentials.${reset}" Write-Host '' return } $metadata = Get-VaultMetadata -VaultName $VaultName $now = [datetime]::UtcNow $protection = if ($IsWindows -or (-not (Test-Path variable:IsWindows))) { 'DPAPI' } else { 'Encrypted file' } $border = [char]0x2550 $cornerTL = [char]0x2554 $cornerTR = [char]0x2557 $cornerBL = [char]0x255A $cornerBR = [char]0x255D $vertBar = [char]0x2551 $horzDiv = [char]0x2560 $horzDivR = [char]0x2563 $line = "$border" * 60 Write-Host '' Write-Host " ${amber}${cornerTL}${line}${cornerTR}${reset}" Write-Host " ${amber}${vertBar}${reset} ${white}SAFEHOUSE STATUS${reset}$(' ' * 43)${amber}${vertBar}${reset}" Write-Host " ${amber}${horzDiv}${line}${horzDivR}${reset}" $vaultLine = " Vault: $VaultName | Backend: SecretStore | $protection" $padded = $vaultLine.PadRight(60) Write-Host " ${amber}${vertBar}${reset}${khaki}${padded}${reset}${amber}${vertBar}${reset}" if ($metadata.created) { $created = ([datetime]$metadata.created).ToString('yyyy-MM-dd') $modified = ([datetime]$metadata.lastModified).ToString('yyyy-MM-dd') $dateLine = " Created: $created | Last Modified: $modified" $padded = $dateLine.PadRight(60) Write-Host " ${amber}${vertBar}${reset}${gray}${padded}${reset}${amber}${vertBar}${reset}" } Write-Host " ${amber}${horzDiv}${line}${horzDivR}${reset}" if ($metadata.credentials -and $metadata.credentials.Count -gt 0) { $headerLine = ' CREDENTIAL STATUS AGE' $padded = $headerLine.PadRight(60) Write-Host " ${amber}${vertBar}${reset}${white}${padded}${reset}${amber}${vertBar}${reset}" $divLine = ('─' * 57) $padded = " $divLine" Write-Host " ${amber}${vertBar}${reset}${gray}${padded}${reset}${amber}${vertBar}${reset}" $expiringCount = 0 foreach ($key in $metadata.credentials.Keys) { $cred = $metadata.credentials[$key] $desc = if ($cred.description) { $cred.description } else { $key } if ($desc.Length -gt 28) { $desc = $desc.Substring(0, 25) + '...' } $storedDate = if ($cred.storedDate) { [datetime]$cred.storedDate } else { $null } $age = if ($storedDate) { $days = [Math]::Floor(($now - $storedDate).TotalDays) if ($days -eq 0) { 'today' } elseif ($days -eq 1) { '1 day' } else { "$days days" } } else { 'unknown' } # Determine status $status = '' $statusColor = $green if ($cred.type -eq 'currentUser') { $status = 'KERBEROS' $statusColor = $gray $age = 'N/A' } elseif ($cred.expirationDate) { $expDate = [datetime]$cred.expirationDate $daysUntilExpiry = [Math]::Floor(($expDate - $now).TotalDays) if ($daysUntilExpiry -lt 0) { $status = 'EXPIRED' $statusColor = $amber $expiringCount++ } elseif ($daysUntilExpiry -lt 30) { $status = 'EXPIRES SOON' $statusColor = $amber $expiringCount++ } elseif ($daysUntilExpiry -lt 90) { $status = 'EXPIRING' $statusColor = $amber $expiringCount++ } else { $status = 'SECURED' } } else { $status = 'SECURED' } $statusIcon = if ($status -eq 'KERBEROS') { '—' } elseif ($status -eq 'SECURED') { '✓' } else { '⚠' } $credLine = " $statusIcon $(($desc).PadRight(28)) $(($status).PadRight(14)) $age" if ($credLine.Length -gt 60) { $credLine = $credLine.Substring(0, 60) } $padded = $credLine.PadRight(60) Write-Host " ${amber}${vertBar}${reset} ${statusColor}${padded}${reset}${amber}${vertBar}${reset}" # Show expiration detail if applicable if ($cred.expirationDate -and $status -ne 'SECURED') { $expDate = [datetime]$cred.expirationDate $daysUntilExpiry = [Math]::Floor(($expDate - $now).TotalDays) $expDetail = " ↳ Expires in $daysUntilExpiry days ($($expDate.ToString('yyyy-MM-dd')))" $padded = $expDetail.PadRight(60) Write-Host " ${amber}${vertBar}${reset}${gray}${padded}${reset}${amber}${vertBar}${reset}" } } $emptyLine = ' ' * 60 Write-Host " ${amber}${vertBar}${reset}${emptyLine}${amber}${vertBar}${reset}" Write-Host " ${amber}${cornerBL}${line}${cornerBR}${reset}" if ($expiringCount -gt 0) { Write-Host '' Write-Host " ${amber}⚠ $expiringCount credential(s) expiring or expired. Run:${reset}" Write-Host " ${khaki} Set-Safehouse -Rotate <environment>${reset}" } } else { $emptyLine = ' No credentials stored.'.PadRight(60) Write-Host " ${amber}${vertBar}${reset}${gray}${emptyLine}${reset}${amber}${vertBar}${reset}" $emptyLine2 = ' ' * 60 Write-Host " ${amber}${vertBar}${reset}${emptyLine2}${amber}${vertBar}${reset}" Write-Host " ${amber}${cornerBL}${line}${cornerBR}${reset}" Write-Host '' Write-Host " ${gray}Run Set-Safehouse or Set-Safehouse -ConfigFile <path> to store credentials.${reset}" } Write-Host '' } |