# Detect or generate ED25519 SSH key. Print public key only. Never print the private key. param( [string]$Email, [string]$KeyPath, [switch]$ForceGenerate, [switch]$NoGenerate, [switch]$Quiet ) $ErrorActionPreference = 'Stop' . (Join-Path $PSScriptRoot 'common.ps1') $gitProfile = Get-GitSkillsProfile if ([string]::IsNullOrWhiteSpace($Email)) { if ($gitProfile) { $Email = [string]$gitProfile.userEmail } } if ([string]::IsNullOrWhiteSpace($Email)) { $Email = [string](Get-GitSkillsDefaults).userEmail } if ([string]::IsNullOrWhiteSpace($KeyPath)) { if ($gitProfile -and $gitProfile.sshKeyPath) { $KeyPath = [string]$gitProfile.sshKeyPath } else { $KeyPath = Join-Path $env:USERPROFILE '.ssh\id_ed25519' } } if (Test-Path -LiteralPath $KeyPath -PathType Container) { $KeyPath = Join-Path $KeyPath 'id_ed25519' } $pubPath = $KeyPath + '.pub' $sshDir = Split-Path -Parent $KeyPath if (-not (Test-Path -LiteralPath $sshDir)) { New-Item -ItemType Directory -Path $sshDir -Force | Out-Null } $status = 'exists' if ($NoGenerate -and -not (Test-Path -LiteralPath $KeyPath)) { Write-StatusLine -Key 'status' -Value 'failed' Write-StatusLine -Key 'reason' -Value 'ssh_key_missing' Write-StatusLine -Key 'key_path' -Value $KeyPath exit 1 } if ($ForceGenerate -or -not (Test-Path -LiteralPath $KeyPath)) { if ((Test-Path -LiteralPath $KeyPath) -and $ForceGenerate) { Write-StatusLine -Key 'status' -Value 'failed' Write-StatusLine -Key 'reason' -Value 'refusing_to_overwrite_ssh_key' Write-StatusLine -Key 'key_path' -Value $KeyPath exit 1 } $sshKeygen = Get-Command ssh-keygen -ErrorAction SilentlyContinue if ($null -eq $sshKeygen) { Write-StatusLine -Key 'status' -Value 'failed' Write-StatusLine -Key 'reason' -Value 'ssh_keygen_missing' exit 1 } Invoke-GitSkillsNative -FilePath ssh-keygen -ArgumentList @('-t', 'ed25519', '-C', $Email, '-f', $KeyPath, '-N', '""') | Out-Null if ($LASTEXITCODE -ne 0) { Write-StatusLine -Key 'status' -Value 'failed' Write-StatusLine -Key 'reason' -Value 'ssh_keygen_failed' exit 1 } $status = 'created' } if (-not (Test-Path -LiteralPath $pubPath)) { Write-StatusLine -Key 'status' -Value 'failed' Write-StatusLine -Key 'reason' -Value 'public_key_missing' Write-StatusLine -Key 'key_path' -Value $KeyPath exit 1 } $agent = 'unavailable' $added = 'skipped' $svc = Get-Service -Name ssh-agent -ErrorAction SilentlyContinue if ($null -ne $svc) { try { if ($svc.StartType -eq 'Disabled') { Set-Service -Name ssh-agent -StartupType Manual } if ((Get-Service -Name ssh-agent).Status -ne 'Running') { Start-Service -Name ssh-agent } $agent = 'running' Invoke-GitSkillsNative -FilePath ssh-add -ArgumentList @($KeyPath) | Out-Null if ($LASTEXITCODE -eq 0) { $added = 'yes' } else { $added = 'failed' } } catch { $agent = 'error' $added = 'failed' } } $publicKey = (Get-Content -LiteralPath $pubPath -Raw -Encoding UTF8).Trim() Write-StatusLine -Key 'status' -Value $status Write-StatusLine -Key 'key_path' -Value $KeyPath Write-StatusLine -Key 'public_key_path' -Value $pubPath Write-StatusLine -Key 'ssh_agent' -Value $agent Write-StatusLine -Key 'ssh_add' -Value $added if (-not $Quiet) { Write-Output ('public_key=' + $publicKey) }