Public/Test-NSPSecretStore.ps1

function Test-NSPSecretStore {
    <#
    .SYNOPSIS
        Reports the local secret-store setup: what's installed, what's registered, and whether
        the vault is actually reachable right now. Diagnostic only - never touches secret values.

    .DESCRIPTION
        Checks, in order:
          - Is Microsoft.PowerShell.SecretManagement installed for this PowerShell edition?
            (Get-NSPSecret's vault lookup silently skips itself if not - this is usually why
            "it works in 5.1 but not pwsh" or vice versa; see NSP-Bootstrap\SECRETS.md.)
          - Is a vault named -Vault registered, and which module backs it (SecretStore,
            Az.KeyVault, etc.)?
          - Is the vault actually reachable right now - Get-SecretInfo against it, discarding the
            result? This is what surfaces a locked or misconfigured SecretStore before a script
            hits it mid-run, rather than failing on the first real Get-NSPSecret call.
          - Is the %LOCALAPPDATA%\NSP\Secrets DPAPI fallback directory present, and how many
            entries does it hold?

    .PARAMETER Vault
        SecretManagement vault name to check. Defaults to 'NSP'.

    .EXAMPLE
        Test-NSPSecretStore

    .EXAMPLE
        Test-NSPSecretStore | Format-List
    #>

    [CmdletBinding()]
    [OutputType([pscustomobject])]
    param(
        [string]$Vault = $script:NSPVaultName
    )

    $secretManagementInstalled = [bool](Get-Module -ListAvailable -Name 'Microsoft.PowerShell.SecretManagement')
    $secretStoreInstalled      = [bool](Get-Module -ListAvailable -Name 'Microsoft.PowerShell.SecretStore')

    $vaultRegistered = $false
    $vaultModule     = $null
    $vaultReachable  = $false
    $vaultError      = $null

    if ($secretManagementInstalled) {
        try { Import-Module Microsoft.PowerShell.SecretManagement -ErrorAction Stop } catch {
            Write-Verbose "Test-NSPSecretStore: SecretManagement present but failed to import ($_)."
        }
        $vaultInfo = $null
        try { $vaultInfo = Get-SecretVault -Name $Vault -ErrorAction Stop } catch { $vaultInfo = $null }

        if ($vaultInfo) {
            $vaultRegistered = $true
            $vaultModule = $vaultInfo.ModuleName
            try {
                # Discard the result on purpose - this call's only job is to prove the vault
                # will actually answer (unlocked, reachable, correctly configured), not to list
                # anything. An empty vault answering with zero results is still success.
                $null = Get-SecretInfo -Vault $Vault -ErrorAction Stop
                $vaultReachable = $true
            } catch {
                $vaultError = $_.Exception.Message
            }
        }
    }

    $fallbackDir = Join-Path $env:LOCALAPPDATA 'NSP\Secrets'
    $fallbackCount = 0
    if (Test-Path -LiteralPath $fallbackDir) {
        $fallbackCount = @(Get-ChildItem -LiteralPath $fallbackDir -Filter '*.sec' -File -ErrorAction SilentlyContinue).Count
    }

    [pscustomobject]@{
        SecretManagementInstalled = $secretManagementInstalled
        SecretStoreInstalled      = $secretStoreInstalled
        VaultName                 = $Vault
        VaultRegistered           = $vaultRegistered
        VaultBackend              = $vaultModule
        VaultReachable            = $vaultReachable
        VaultError                = $vaultError
        DpapiFallbackDir          = $fallbackDir
        DpapiFallbackCount        = $fallbackCount
    }
}