Public/Get-Fido2SshKey.ps1
|
function Get-Fido2SshKey { <# .SYNOPSIS Lists resident FIDO2 SSH keys currently configured in the local SSH directory. .DESCRIPTION Scans `-SshDirectory` (default `%USERPROFILE%\.ssh` on Windows and `$HOME/.ssh` on Linux/macOS) for files matching `id_*_sk_rk*.pub` and returns one object per match. The command surfaces canonical filename metadata (key type, label, thumbprint) and whether the matching private-key handle file exists. .PARAMETER SshDirectory Source folder. Defaults to `%USERPROFILE%\.ssh` on Windows and `$HOME/.ssh` on Linux/macOS. .PARAMETER Label Optional case-insensitive substring filter against the parsed label segment of the canonical filename. .EXAMPLE Get-Fido2SshKey .EXAMPLE Get-Fido2SshKey -Label work #> [CmdletBinding()] [OutputType([pscustomobject])] param( [string]$SshDirectory = (Get-Fido2DefaultSshDirectory), [string]$Label ) if (-not (Test-Path -LiteralPath $SshDirectory)) { Write-Verbose "SSH directory not found: $SshDirectory" return } $pubFiles = @(Get-ChildItem -Path $SshDirectory -File -Filter 'id_*_sk_rk*.pub' -ErrorAction SilentlyContinue) foreach ($pub in ($pubFiles | Sort-Object Name)) { $baseName = [System.IO.Path]::GetFileNameWithoutExtension($pub.Name) $privatePath = Join-Path $pub.DirectoryName $baseName $keyType = $null $parsedLabel = $null $thumbprint = $null if ($baseName -match '^id_(?<typeSuffix>ed25519_sk|ecdsa_sk)_rk(?:_(?<label>.+))?_(?<thumb>[A-Za-z0-9]{12})$') { $keyType = switch ($matches['typeSuffix']) { 'ed25519_sk' { 'ed25519-sk' } 'ecdsa_sk' { 'ecdsa-sk' } default { $null } } $parsedLabel = $matches['label'] $thumbprint = $matches['thumb'].ToLowerInvariant() } $labelValue = if ($null -ne $parsedLabel) { $parsedLabel } else { '' } if ($Label -and ($labelValue -notlike "*$Label*")) { continue } $line = Get-Content -LiteralPath $pub.FullName -TotalCount 1 -ErrorAction SilentlyContinue $algorithm = $null $comment = $null if (-not [string]::IsNullOrWhiteSpace($line)) { $parts = $line -split '\s+' if ($parts.Count -ge 1) { $algorithm = $parts[0] } if ($parts.Count -ge 3) { $comment = ($parts[2..($parts.Count - 1)] -join ' ') } } $result = [pscustomobject]@{ Name = $baseName KeyType = $keyType Label = $parsedLabel Thumbprint = $thumbprint Algorithm = $algorithm Comment = $comment PublicKeyPath = $pub.FullName PrivateKeyPath = $privatePath HasPrivateKey = (Test-Path -LiteralPath $privatePath) } $defaultDisplay = New-Object System.Management.Automation.PSPropertySet( 'DefaultDisplayPropertySet', [string[]]@('Label', 'Algorithm') ) $result | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value ([System.Management.Automation.PSMemberInfo[]]@($defaultDisplay)) $result } } |