From 3485cae16406a2060873bd34b7121305188e0c0a Mon Sep 17 00:00:00 2001 From: LeonL <132875948+Lenrul@users.noreply.github.com> Date: Fri, 6 Nov 2026 10:21:11 -0800 Subject: [PATCH] update ps1 to prompt change to different hostname --- git-ssh-setup.ps1 | 106 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 3 deletions(-) diff --git a/git-ssh-setup.ps1 b/git-ssh-setup.ps1 index bd511fd..17a9b75 100644 --- a/git-ssh-setup.ps1 +++ b/git-ssh-setup.ps1 @@ -6,6 +6,11 @@ for the passphrase every time, and signs Gitea's key-verification token. .DESCRIPTION + The script asks which SSH host to set up. The first time the answer is + blank; after that it offers the host you used last, so press Enter to keep + it or type another one to add a second server. You can type a bare host + (git.example.com), host:port, or paste an SSH clone URL. + Safe to re-run: an existing key is reused (unless -Force), a key already in the agent is not added again, and an existing Host entry in ~/.ssh/config is never modified. @@ -21,7 +26,8 @@ powershell -NoProfile -ExecutionPolicy Bypass -File .\git-ssh-setup.ps1 .EXAMPLE - powershell -NoProfile -ExecutionPolicy Bypass -File .\git-ssh-setup.ps1 -Comment "you@example.com" + # Skip the host prompt. + powershell -NoProfile -ExecutionPolicy Bypass -File .\git-ssh-setup.ps1 -HostName git.example.com -Port 2222 .EXAMPLE # Verify the key later: click Verify next to it in Gitea and pass the token it shows. @@ -32,12 +38,14 @@ #> [CmdletBinding()] param( - # Host to add to ~/.ssh/config and test against. Use -HostName "" to skip both. - [string]$HostName = "tea.lenrui.net", + # SSH host for Git. If omitted, the script asks and remembers the answer. + # Use -HostName "" to skip the ~/.ssh/config entry and the connection test. + [string]$HostName, # SSH user for the host (Gitea, GitHub and GitLab all use "git"). [string]$User = "git", + # SSH port. Defaults to 22, or to the port typed as host:port at the prompt. [ValidateRange(1, 65535)] [int]$Port = 22, @@ -70,6 +78,55 @@ function Stop-Setup([string]$Message) { exit 1 } +# Turns what the user typed into a host name and an optional port. Accepts a +# bare host, host:port, git@host, git@host:owner/repo.git, or +# ssh://git@host:port/owner/repo.git. Returns $null if it isn't usable. +function ConvertTo-SshTarget([string]$Text) { + $t = "$Text".Trim() + $t = $t -replace '^[A-Za-z][A-Za-z0-9+.-]*://', '' # ssh:// or https:// + $t = $t -replace '^[^@/]*@', '' # git@ + $t = ($t -split '/')[0] # any path + $p = $null + if ($t -match '^(.+):(\d+)$') { + if ($Matches[2].Length -gt 5) { return $null } + $t = $Matches[1] + $p = [int]$Matches[2] + if ($p -lt 1 -or $p -gt 65535) { return $null } + } elseif ($t.Contains(':')) { + $t = $t.Substring(0, $t.IndexOf(':')) # host:owner/repo.git + } + if ($t -notmatch '^[A-Za-z0-9]([A-Za-z0-9.-]*[A-Za-z0-9])?$') { return $null } + return [pscustomobject]@{ HostName = $t.ToLowerInvariant(); Port = $p } +} + +# The last host used is kept in a small file in your user profile. +$stateDir = if ($env:APPDATA) { Join-Path $env:APPDATA 'git-ssh-setup' } else { Join-Path $HOME '.git-ssh-setup' } +$stateFile = Join-Path $stateDir 'last-host.json' + +function Read-LastHost { + try { + if (Test-Path $stateFile) { + $saved = Get-Content -Path $stateFile -Raw | ConvertFrom-Json + if ($saved.HostName) { + $savedPort = 22 + if ($saved.Port) { $savedPort = [int]$saved.Port } + return [pscustomobject]@{ HostName = [string]$saved.HostName; Port = $savedPort } + } + } + } catch { } + return $null +} + +function Save-LastHost([string]$Name, [int]$PortNumber) { + try { + New-Item -ItemType Directory -Path $stateDir -Force | Out-Null + $json = [pscustomobject]@{ HostName = $Name; Port = $PortNumber } | ConvertTo-Json + [IO.File]::WriteAllText($stateFile, $json, (New-Object Text.UTF8Encoding($false))) + } catch { + Write-Note "Couldn't remember the host for next time: $($_.Exception.Message)" + } +} + # Signs $Text exactly as given and returns the armored signature, or $null if # ssh-keygen failed. The text is written to a file with no trailing newline and # no BOM: piping it into ssh-keygen from PowerShell would add a newline and @@ -96,6 +153,49 @@ if ($Token -and $Token -notmatch '^[0-9a-fA-F]+$') { Stop-Setup "-Token should be just the hex string from Gitea's Token box." } +# --- 0. SSH host ------------------------------------------------------------- +$target = $null +if ($PSBoundParameters.ContainsKey('HostName')) { + if ($HostName) { + $target = ConvertTo-SshTarget $HostName + if (-not $target) { Stop-Setup "'$HostName' isn't a host name the script can use." } + } +} else { + Write-Step "Choosing the SSH host" + $last = Read-LastHost + $suggested = '' + if ($last) { + $suggested = $last.HostName + if ($last.Port -ne 22) { $suggested = "$($last.HostName):$($last.Port)" } + Write-Host " Press Enter to keep the last host, or type a different one." + } else { + Write-Host " Type the host name from your SSH clone URL, e.g. git.example.com" + Write-Host " (add :port if the server doesn't use 22)." + } + while ($true) { + $label = if ($suggested) { " SSH host [$suggested]" } else { " SSH host" } + $answer = "$(Read-Host $label)".Trim() + if (-not $answer) { + if ($suggested) { $answer = $suggested } else { Write-Note "A host name is needed."; continue } + } + $target = ConvertTo-SshTarget $answer + if ($target) { + if ($answer -match '^https?://') { + Write-Note "That was a web address. Make sure '$($target.HostName)' is the host in your SSH" + Write-Note "clone URL; a site behind Cloudflare's proxy won't accept SSH." + } + break + } + Write-Note "'$answer' doesn't look like a host name. Try something like git.example.com or git.example.com:2222" + } +} +if ($target) { + $HostName = $target.HostName + if ($target.Port -and -not $PSBoundParameters.ContainsKey('Port')) { $Port = $target.Port } + Save-LastHost $HostName $Port + Write-Ok "Using $User@${HostName}, port $Port" +} + $openSshDir = Join-Path $env:WINDIR 'System32\OpenSSH' $sshExe = Join-Path $openSshDir 'ssh.exe' $keygenExe = Join-Path $openSshDir 'ssh-keygen.exe'