quick-ssh 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/Quick-SSH.psm1 +409 -0
- package/README.md +224 -0
- package/index.js +186 -0
- package/package.json +38 -0
- package/qssh-tui.js +778 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CCE-Li
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/Quick-SSH.psm1
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
# Quick-SSH.psm1 - PowerShell SSH Connection Manager
|
|
2
|
+
# 仿 Docker 命令行风格的 SSH 连接管理工具
|
|
3
|
+
# 配置文件路径: %USERPROFILE%\.quickssh\hosts.json
|
|
4
|
+
|
|
5
|
+
# ============================================================
|
|
6
|
+
# 内部函数 - 配置管理
|
|
7
|
+
# ============================================================
|
|
8
|
+
|
|
9
|
+
$Script:ConfigDir = Join-Path $env:USERPROFILE ".quickssh"
|
|
10
|
+
$Script:ConfigFile = Join-Path $Script:ConfigDir "hosts.json"
|
|
11
|
+
$Script:ModuleRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
12
|
+
$Script:TUIScript = Join-Path $Script:ModuleRoot "qssh-tui.js"
|
|
13
|
+
|
|
14
|
+
# 初始化配置目录和空 JSON 文件
|
|
15
|
+
function Initialize-QuickSSHConfig {
|
|
16
|
+
if (-not (Test-Path $Script:ConfigDir)) {
|
|
17
|
+
New-Item -Path $Script:ConfigDir -ItemType Directory -Force | Out-Null
|
|
18
|
+
}
|
|
19
|
+
if (-not (Test-Path $Script:ConfigFile)) {
|
|
20
|
+
'[]' | Set-Content -Path $Script:ConfigFile -Encoding UTF8 -NoNewline
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# 读取全部主机配置
|
|
25
|
+
function Get-QuickSSHHosts {
|
|
26
|
+
Initialize-QuickSSHConfig
|
|
27
|
+
try {
|
|
28
|
+
$raw = Get-Content -Path $Script:ConfigFile -Raw -Encoding UTF8
|
|
29
|
+
if ([string]::IsNullOrWhiteSpace($raw)) { return @() }
|
|
30
|
+
$data = $raw | ConvertFrom-Json
|
|
31
|
+
# 兼容单个对象 { ... } 和数组 [{ ... }, { ... }]
|
|
32
|
+
if ($data -is [array]) { return $data }
|
|
33
|
+
return @($data)
|
|
34
|
+
} catch {
|
|
35
|
+
return @()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# 保存全部主机配置
|
|
40
|
+
function Save-QuickSSHHosts($Hosts) {
|
|
41
|
+
$Hosts | ConvertTo-Json -Depth 10 | Set-Content -Path $Script:ConfigFile -Encoding UTF8
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# ============================================================
|
|
45
|
+
# 内部函数 - 颜色输出
|
|
46
|
+
# ============================================================
|
|
47
|
+
|
|
48
|
+
function Write-QSSuccess { Write-Host $args[0] -ForegroundColor Green }
|
|
49
|
+
function Write-QSWarning { Write-Host $args[0] -ForegroundColor Yellow }
|
|
50
|
+
function Write-QSError { Write-Host $args[0] -ForegroundColor Red }
|
|
51
|
+
|
|
52
|
+
# ============================================================
|
|
53
|
+
# 子命令实现
|
|
54
|
+
# ============================================================
|
|
55
|
+
|
|
56
|
+
# qssh ps [关键词] - 列出所有已保存的 SSH 连接
|
|
57
|
+
function Invoke-QuickSSHPs {
|
|
58
|
+
param([string]$Keyword = "")
|
|
59
|
+
|
|
60
|
+
$hosts = Get-QuickSSHHosts
|
|
61
|
+
if ($hosts.Count -eq 0) {
|
|
62
|
+
Write-QSWarning "当前没有已保存的 SSH 连接。使用 'qssh add' 添加一个。"
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if ($Keyword) {
|
|
67
|
+
$kw = $Keyword.ToLower()
|
|
68
|
+
$hosts = $hosts | Where-Object {
|
|
69
|
+
$_.alias.ToLower().Contains($kw) -or
|
|
70
|
+
$_.host.ToLower().Contains($kw) -or
|
|
71
|
+
$_.user.ToLower().Contains($kw)
|
|
72
|
+
}
|
|
73
|
+
if ($hosts.Count -eq 0) {
|
|
74
|
+
Write-QSWarning "没有匹配 '$Keyword' 的 SSH 连接。"
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
$hosts | Format-Table -Property @(
|
|
80
|
+
@{ Label = "别名"; Expression = { $_.alias } },
|
|
81
|
+
@{ Label = "IP 地址"; Expression = { $_.host } },
|
|
82
|
+
@{ Label = "账号"; Expression = { $_.user } },
|
|
83
|
+
@{ Label = "端口"; Expression = { $_.port } },
|
|
84
|
+
@{ Label = "私钥路径"; Expression = { $_.key } }
|
|
85
|
+
) -AutoSize
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# qssh add [别名] [用户名@IP:端口] --key 私钥路径
|
|
89
|
+
function Invoke-QuickSSHAdd {
|
|
90
|
+
param(
|
|
91
|
+
[string]$Alias,
|
|
92
|
+
[string]$UserAtHost, # user@host 或 user@host:port
|
|
93
|
+
[string]$KeyPath = ""
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if ((-not $Alias) -or (-not $UserAtHost)) {
|
|
97
|
+
Write-QSError "错误:用法 → qssh add <别名> <用户名@IP:端口> [--key <私钥路径>]"
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# 解析 user@host:port
|
|
102
|
+
$user = ""
|
|
103
|
+
$hostname = ""
|
|
104
|
+
$port = 22
|
|
105
|
+
|
|
106
|
+
if ($UserAtHost -match '^(.+)@(.+):(\d+)$') {
|
|
107
|
+
$user = $matches[1]
|
|
108
|
+
$hostname = $matches[2]
|
|
109
|
+
$port = [int]$matches[3]
|
|
110
|
+
} elseif ($UserAtHost -match '^(.+)@(.+)$') {
|
|
111
|
+
$user = $matches[1]
|
|
112
|
+
$hostname = $matches[2]
|
|
113
|
+
} else {
|
|
114
|
+
Write-QSError "错误:格式无效,请使用「用户名@主机:端口」或「用户名@主机」格式。"
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (-not $KeyPath) {
|
|
119
|
+
$KeyPath = Join-Path $env:USERPROFILE ".ssh" "id_rsa"
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# 检查别名重复
|
|
123
|
+
$hosts = Get-QuickSSHHosts
|
|
124
|
+
$existing = $hosts | Where-Object { $_.alias -eq $Alias }
|
|
125
|
+
if ($existing) {
|
|
126
|
+
Write-QSError "错误:别名 '$Alias' 已存在,请使用其他名称。"
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
$entry = @{
|
|
131
|
+
alias = $Alias
|
|
132
|
+
host = $hostname
|
|
133
|
+
user = $user
|
|
134
|
+
port = $port
|
|
135
|
+
key = $KeyPath
|
|
136
|
+
}
|
|
137
|
+
$hosts += $entry
|
|
138
|
+
Save-QuickSSHHosts $hosts
|
|
139
|
+
|
|
140
|
+
Write-QSSuccess "✔ 已添加 SSH 连接 '$Alias' → $user@$hostname`:$port"
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
# qssh rm [别名] - 删除指定别名的 SSH 连接
|
|
144
|
+
function Invoke-QuickSSHRm {
|
|
145
|
+
param([string]$Alias)
|
|
146
|
+
|
|
147
|
+
if (-not $Alias) {
|
|
148
|
+
Write-QSError "错误:用法 → qssh rm <别名>"
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
$hosts = Get-QuickSSHHosts
|
|
153
|
+
$target = $hosts | Where-Object { $_.alias -eq $Alias }
|
|
154
|
+
if (-not $target) {
|
|
155
|
+
Write-QSError "错误:别名 '$Alias' 不存在。使用 'qssh ps' 查看可用连接。"
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
$hosts = $hosts | Where-Object { $_.alias -ne $Alias }
|
|
160
|
+
Save-QuickSSHHosts $hosts
|
|
161
|
+
|
|
162
|
+
Write-QSSuccess "✔ 已删除 SSH 连接 '$Alias'。"
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
# qssh [别名] - 一键连接 SSH 服务器
|
|
166
|
+
function Invoke-QuickSSHConnect {
|
|
167
|
+
param([string]$Alias)
|
|
168
|
+
|
|
169
|
+
if (-not $Alias) {
|
|
170
|
+
Invoke-QuickSSHTUI
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
$hosts = Get-QuickSSHHosts
|
|
175
|
+
$target = $hosts | Where-Object { $_.alias -eq $Alias }
|
|
176
|
+
if (-not $target) {
|
|
177
|
+
Write-QSError "错误:别名 '$Alias' 不存在。使用 'qssh ps' 查看可用连接。"
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
$sshExe = if (Get-Command "ssh.exe" -ErrorAction SilentlyContinue) { "ssh.exe" } else { "ssh" }
|
|
182
|
+
|
|
183
|
+
$cmd = "$sshExe -i `"$($target.key)`" -p $($target.port) -o HostKeyAlgorithms=+ssh-rsa $($target.user)@$($target.host)"
|
|
184
|
+
|
|
185
|
+
Write-QSSuccess "正在连接到 '$Alias' ($($target.user)@$($target.host):$($target.port)) ..."
|
|
186
|
+
Write-Host ""
|
|
187
|
+
|
|
188
|
+
# 使用 cmd /c 避免 PowerShell 拦截 SSH 交互
|
|
189
|
+
$encoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($cmd))
|
|
190
|
+
cmd /c "powershell -NoProfile -EncodedCommand $encoded"
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# qssh export [文件路径] - 导出全部主机配置到 JSON 文件
|
|
194
|
+
function Invoke-QuickSSHExport {
|
|
195
|
+
param([string]$FilePath)
|
|
196
|
+
|
|
197
|
+
if (-not $FilePath) {
|
|
198
|
+
Write-QSError "错误:用法 → qssh export <文件路径>"
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
$hosts = Get-QuickSSHHosts
|
|
203
|
+
if ($hosts.Count -eq 0) {
|
|
204
|
+
Write-QSWarning "没有可导出的 SSH 连接。"
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
$hosts | ConvertTo-Json -Depth 10 | Set-Content -Path $FilePath -Encoding UTF8
|
|
209
|
+
Write-QSSuccess "✔ 已导出 $($hosts.Count) 个连接到 '$FilePath'。"
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
# qssh import [文件路径] - 从 JSON 文件批量导入连接(自动去重)
|
|
213
|
+
function Invoke-QuickSSHImport {
|
|
214
|
+
param([string]$FilePath)
|
|
215
|
+
|
|
216
|
+
if (-not $FilePath) {
|
|
217
|
+
Write-QSError "错误:用法 → qssh import <文件路径>"
|
|
218
|
+
return
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (-not (Test-Path $FilePath)) {
|
|
222
|
+
Write-QSError "错误:文件 '$FilePath' 不存在。"
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
$imported = Get-Content -Path $FilePath -Raw -Encoding UTF8 | ConvertFrom-Json
|
|
228
|
+
} catch {
|
|
229
|
+
Write-QSError "错误:无法解析 JSON 文件,请检查格式。"
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if ($imported.Count -eq 0) {
|
|
234
|
+
Write-QSWarning "文件中没有有效的连接配置。"
|
|
235
|
+
return
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
$existing = Get-QuickSSHHosts
|
|
239
|
+
$added = 0
|
|
240
|
+
$skipped = 0
|
|
241
|
+
|
|
242
|
+
foreach ($h in $imported) {
|
|
243
|
+
$dup = $existing | Where-Object { $_.alias -eq $h.alias }
|
|
244
|
+
if (-not $dup) {
|
|
245
|
+
$existing += $h
|
|
246
|
+
$added++
|
|
247
|
+
} else {
|
|
248
|
+
$skipped++
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
Save-QuickSSHHosts $existing
|
|
253
|
+
Write-QSSuccess "✔ 导入完成:新增 $added 个,跳过 $skipped 个(别名重复)。"
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
# ============================================================
|
|
257
|
+
# TUI 终端界面
|
|
258
|
+
# ============================================================
|
|
259
|
+
|
|
260
|
+
function Invoke-QuickSSHTUI {
|
|
261
|
+
# 检测 Node.js 是否可用
|
|
262
|
+
$nodePath = (Get-Command "node" -ErrorAction SilentlyContinue).Source
|
|
263
|
+
if (-not $nodePath) {
|
|
264
|
+
Write-QSError "错误:启动 TUI 需要 Node.js,请先安装 Node.js (https://nodejs.org)"
|
|
265
|
+
Write-QSError "或者使用命令行模式: qssh help"
|
|
266
|
+
return
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (-not (Test-Path $Script:TUIScript)) {
|
|
270
|
+
Write-QSError "错误:未找到 TUI 脚本: $Script:TUIScript"
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
# 启动 TUI,等待退出后返回
|
|
275
|
+
Write-Host "正在启动 Quick-SSH TUI ..." -ForegroundColor Cyan
|
|
276
|
+
& "node" $Script:TUIScript
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
# ============================================================
|
|
280
|
+
# 帮助信息
|
|
281
|
+
# ============================================================
|
|
282
|
+
|
|
283
|
+
function Show-QuickSSHHelp {
|
|
284
|
+
Write-Host ""
|
|
285
|
+
Write-Host "Quick-SSH - PowerShell SSH 连接管理工具" -ForegroundColor Cyan
|
|
286
|
+
Write-Host ""
|
|
287
|
+
Write-Host "用法:" -ForegroundColor Yellow
|
|
288
|
+
Write-Host " qssh 启动 TUI 终端界面(推荐,类似 yazi 操作体验)"
|
|
289
|
+
Write-Host " qssh ps [关键词] 列出所有已保存的 SSH 连接(对应 docker ps)"
|
|
290
|
+
Write-Host " qssh add <别名> <用户@主机:端口> [--key <私钥路径>]" -ForegroundColor Gray
|
|
291
|
+
Write-Host " 添加新 SSH 连接(端口默认 22,私钥默认 ~/.ssh/id_rsa)"
|
|
292
|
+
Write-Host " qssh rm <别名> 删除指定别名的 SSH 连接(对应 docker rm)"
|
|
293
|
+
Write-Host " qssh <别名> 一键连接 SSH 服务器"
|
|
294
|
+
Write-Host " qssh export <文件> 导出全部主机配置到 JSON 文件"
|
|
295
|
+
Write-Host " qssh import <文件> 从 JSON 文件批量导入连接"
|
|
296
|
+
Write-Host " qssh help 显示本帮助信息"
|
|
297
|
+
Write-Host ""
|
|
298
|
+
Write-Host "示例:" -ForegroundColor Yellow
|
|
299
|
+
Write-Host " qssh # 启动 TUI 界面"
|
|
300
|
+
Write-Host " qssh ps"
|
|
301
|
+
Write-Host " qssh ps 生产"
|
|
302
|
+
Write-Host " qssh add my-server root@192.168.1.100:22 --key D:\.ssh\id_rsa"
|
|
303
|
+
Write-Host " qssh add my-vm admin@10.0.0.5"
|
|
304
|
+
Write-Host " qssh my-server"
|
|
305
|
+
Write-Host " qssh rm my-vm"
|
|
306
|
+
Write-Host " qssh export D:\backup\hosts.json"
|
|
307
|
+
Write-Host " qssh import D:\backup\hosts.json"
|
|
308
|
+
Write-Host ""
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
# ============================================================
|
|
312
|
+
# 主入口 - qssh 命令分发
|
|
313
|
+
# ============================================================
|
|
314
|
+
|
|
315
|
+
function global:qssh {
|
|
316
|
+
param(
|
|
317
|
+
[Parameter(Position = 0, Mandatory = $false)]
|
|
318
|
+
[string]$Command,
|
|
319
|
+
|
|
320
|
+
[Parameter(ValueFromRemainingArguments = $true)]
|
|
321
|
+
[string[]]$ArgsList
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
# 首次调用自动初始化
|
|
325
|
+
Initialize-QuickSSHConfig
|
|
326
|
+
|
|
327
|
+
if (-not $Command) {
|
|
328
|
+
Invoke-QuickSSHTUI
|
|
329
|
+
return
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
switch -Wildcard ($Command) {
|
|
333
|
+
"ps" {
|
|
334
|
+
$keyword = if ($ArgsList.Count -gt 0) { $ArgsList[0] } else { "" }
|
|
335
|
+
Invoke-QuickSSHPs -Keyword $keyword
|
|
336
|
+
}
|
|
337
|
+
"add" {
|
|
338
|
+
$alias = $null
|
|
339
|
+
$userAtHost = $null
|
|
340
|
+
$keyPath = $null
|
|
341
|
+
$i = 0
|
|
342
|
+
while ($i -lt $ArgsList.Count) {
|
|
343
|
+
if ($ArgsList[$i] -eq "--key" -or $ArgsList[$i] -eq "-k") {
|
|
344
|
+
$i++
|
|
345
|
+
if ($i -lt $ArgsList.Count) { $keyPath = $ArgsList[$i] }
|
|
346
|
+
} elseif (-not $alias) {
|
|
347
|
+
$alias = $ArgsList[$i]
|
|
348
|
+
} elseif (-not $userAtHost) {
|
|
349
|
+
$userAtHost = $ArgsList[$i]
|
|
350
|
+
}
|
|
351
|
+
$i++
|
|
352
|
+
}
|
|
353
|
+
Invoke-QuickSSHAdd -Alias $alias -UserAtHost $userAtHost -KeyPath $keyPath
|
|
354
|
+
}
|
|
355
|
+
"rm" {
|
|
356
|
+
$alias = if ($ArgsList.Count -gt 0) { $ArgsList[0] } else { "" }
|
|
357
|
+
Invoke-QuickSSHRm -Alias $alias
|
|
358
|
+
}
|
|
359
|
+
"export" {
|
|
360
|
+
$file = if ($ArgsList.Count -gt 0) { $ArgsList[0] } else { "" }
|
|
361
|
+
Invoke-QuickSSHExport -FilePath $file
|
|
362
|
+
}
|
|
363
|
+
"import" {
|
|
364
|
+
$file = if ($ArgsList.Count -gt 0) { $ArgsList[0] } else { "" }
|
|
365
|
+
Invoke-QuickSSHImport -FilePath $file
|
|
366
|
+
}
|
|
367
|
+
"help" {
|
|
368
|
+
Show-QuickSSHHelp
|
|
369
|
+
}
|
|
370
|
+
default {
|
|
371
|
+
# 未知命令当作别名尝试连接
|
|
372
|
+
Invoke-QuickSSHConnect -Alias $Command
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
# ============================================================
|
|
378
|
+
# Tab 自动补全 - qssh 后按 Tab 可补全子命令和主机别名
|
|
379
|
+
# ============================================================
|
|
380
|
+
|
|
381
|
+
Register-ArgumentCompleter -CommandName "qssh" -ScriptBlock {
|
|
382
|
+
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
|
|
383
|
+
|
|
384
|
+
$subCommands = @("ps", "add", "rm", "export", "import", "help")
|
|
385
|
+
|
|
386
|
+
# 获取已保存的主机别名
|
|
387
|
+
$aliases = @()
|
|
388
|
+
try {
|
|
389
|
+
$cfg = Join-Path $env:USERPROFILE ".quickssh" "hosts.json"
|
|
390
|
+
if (Test-Path $cfg) {
|
|
391
|
+
$raw = Get-Content -Path $cfg -Raw -Encoding UTF8
|
|
392
|
+
if ($raw) {
|
|
393
|
+
$hosts = $raw | ConvertFrom-Json
|
|
394
|
+
$aliases = @($hosts | ForEach-Object { $_.alias })
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
} catch {}
|
|
398
|
+
|
|
399
|
+
$allCompletions = $subCommands + $aliases
|
|
400
|
+
$allCompletions | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
|
|
401
|
+
[System.Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_)
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
# ============================================================
|
|
406
|
+
# 模块加载时自动导出 qssh 函数
|
|
407
|
+
# ============================================================
|
|
408
|
+
|
|
409
|
+
Export-ModuleMember -Function "qssh"
|
package/README.md
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Quick-SSH 🚀
|
|
2
|
+
|
|
3
|
+
> 仿 Docker 命令行风格的 PowerShell SSH 连接管理工具
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
一键保存、管理、连接 SSH 服务器,告别记忆繁琐的 IP、端口和密钥路径。
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 安装
|
|
14
|
+
|
|
15
|
+
### 方式一:npm 全局安装(推荐)
|
|
16
|
+
|
|
17
|
+
```powershell
|
|
18
|
+
npm install -g quick-ssh
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
安装完成后,**重启 PowerShell 终端**即可使用 `qssh` 命令。
|
|
22
|
+
|
|
23
|
+
> 安装脚本会自动将 `Import-Module` 写入你的 PowerShell 配置文件 (`$PROFILE`),重启终端后永久生效。
|
|
24
|
+
|
|
25
|
+
### 方式二:手动加载
|
|
26
|
+
|
|
27
|
+
```powershell
|
|
28
|
+
# 下载本仓库,在 Quick-SSH.psm1 所在目录执行:
|
|
29
|
+
Import-Module .\Quick-SSH.psm1 -DisableNameChecking
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 快速入门
|
|
35
|
+
|
|
36
|
+
```powershell
|
|
37
|
+
# 添加一个 SSH 连接
|
|
38
|
+
qssh add my-server root@192.168.1.100:22 --key C:\Users\You\.ssh\id_rsa
|
|
39
|
+
|
|
40
|
+
# 一键连接
|
|
41
|
+
qssh my-server
|
|
42
|
+
|
|
43
|
+
# 列出所有连接
|
|
44
|
+
qssh ps
|
|
45
|
+
|
|
46
|
+
# 删除连接
|
|
47
|
+
qssh rm my-server
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 命令参考
|
|
53
|
+
|
|
54
|
+
### `qssh ps [关键词]`
|
|
55
|
+
|
|
56
|
+
列出所有已保存的 SSH 连接(对应 `docker ps`)。
|
|
57
|
+
|
|
58
|
+
| 列 | 说明 |
|
|
59
|
+
|----|------|
|
|
60
|
+
| 别名 | 连接的自定义名称 |
|
|
61
|
+
| IP 地址 | 服务器主机名或 IP |
|
|
62
|
+
| 账号 | 登录用户名 |
|
|
63
|
+
| 端口 | SSH 端口(默认 22) |
|
|
64
|
+
| 私钥路径 | 认证私钥文件路径 |
|
|
65
|
+
|
|
66
|
+
**示例:**
|
|
67
|
+
|
|
68
|
+
```powershell
|
|
69
|
+
# 列出全部连接
|
|
70
|
+
qssh ps
|
|
71
|
+
|
|
72
|
+
# 筛选包含 "生产" 的连接
|
|
73
|
+
qssh ps 生产
|
|
74
|
+
|
|
75
|
+
# 无连接时的提示
|
|
76
|
+
# → 当前没有已保存的 SSH 连接。使用 'qssh add' 添加一个。
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### `qssh add <别名> <用户名@IP:端口> [--key <私钥路径>]`
|
|
80
|
+
|
|
81
|
+
新增 SSH 连接记录(对应 `docker run` 的添加语义)。
|
|
82
|
+
|
|
83
|
+
**参数说明:**
|
|
84
|
+
|
|
85
|
+
| 参数 | 必填 | 默认值 | 说明 |
|
|
86
|
+
|------|------|--------|------|
|
|
87
|
+
| 别名 | ✅ | - | 连接的唯一标识名 |
|
|
88
|
+
| 用户名@IP:端口 | ✅ | - | `root@192.168.1.100` 或 `root@192.168.1.100:2222` |
|
|
89
|
+
| `--key` / `-k` | ❌ | `%USERPROFILE%\.ssh\id_rsa` | 私钥文件路径 |
|
|
90
|
+
|
|
91
|
+
**示例:**
|
|
92
|
+
|
|
93
|
+
```powershell
|
|
94
|
+
# 使用默认端口 22 和默认密钥
|
|
95
|
+
qssh add my-vm root@10.0.0.5
|
|
96
|
+
|
|
97
|
+
# 指定端口和密钥
|
|
98
|
+
qssh add prod-server deploy@192.168.1.100:2222 --key D:\keys\prod_id_rsa
|
|
99
|
+
|
|
100
|
+
# 支持 -k 简写
|
|
101
|
+
qssh add test-vm admin@172.16.0.10 -k C:\Users\Me\.ssh\test_rsa
|
|
102
|
+
|
|
103
|
+
# 别名重复会报错
|
|
104
|
+
# → 错误:别名 'my-vm' 已存在,请使用其他名称。
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### `qssh rm <别名>`
|
|
108
|
+
|
|
109
|
+
删除指定别名的 SSH 主机配置(对应 `docker rm`)。
|
|
110
|
+
|
|
111
|
+
```powershell
|
|
112
|
+
qssh rm my-vm
|
|
113
|
+
# → ✔ 已删除 SSH 连接 'my-vm'。
|
|
114
|
+
|
|
115
|
+
qssh rm unknown
|
|
116
|
+
# → 错误:别名 'unknown' 不存在。使用 'qssh ps' 查看可用连接。
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### `qssh <别名>`
|
|
120
|
+
|
|
121
|
+
一键连接 SSH 服务器。自动读取保存的 IP、账号、端口、私钥发起会话。
|
|
122
|
+
|
|
123
|
+
> 内置兼容老旧 `ssh-rsa` 密钥协商参数 `-o HostKeyAlgorithms=+ssh-rsa`,无需手动添加。
|
|
124
|
+
|
|
125
|
+
```powershell
|
|
126
|
+
qssh my-server
|
|
127
|
+
# → 正在连接到 'my-server' (root@192.168.1.100:22) ...
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### `qssh export <文件路径>`
|
|
131
|
+
|
|
132
|
+
将全部主机配置导出到指定 JSON 文件。
|
|
133
|
+
|
|
134
|
+
```powershell
|
|
135
|
+
qssh export D:\backup\ssh-hosts.json
|
|
136
|
+
# → ✔ 已导出 3 个连接到 'D:\backup\ssh-hosts.json'。
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `qssh import <文件路径>`
|
|
140
|
+
|
|
141
|
+
从外部 JSON 文件批量导入连接,自动跳过别名重复的记录。
|
|
142
|
+
|
|
143
|
+
```powershell
|
|
144
|
+
qssh import D:\backup\ssh-hosts.json
|
|
145
|
+
# → ✔ 导入完成:新增 5 个,跳过 2 个(别名重复)。
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `qssh help`
|
|
149
|
+
|
|
150
|
+
显示帮助信息。
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Tab 自动补全
|
|
155
|
+
|
|
156
|
+
输入 `qssh` 后按 <kbd>Tab</kbd> 键,可自动补全:
|
|
157
|
+
|
|
158
|
+
- **子命令**:`ps`、`add`、`rm`、`export`、`import`、`help`
|
|
159
|
+
- **已保存的主机别名**:快速选择要连接的服务器
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 配置文件
|
|
164
|
+
|
|
165
|
+
所有连接数据存储在以下位置,**不会在卸载时删除**:
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
%USERPROFILE%\.quickssh\hosts.json
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
示例配置文件内容:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
[
|
|
175
|
+
{
|
|
176
|
+
"alias": "my-server",
|
|
177
|
+
"host": "192.168.1.100",
|
|
178
|
+
"user": "root",
|
|
179
|
+
"port": 22,
|
|
180
|
+
"key": "C:\\Users\\You\\.ssh\\id_rsa"
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 卸载
|
|
188
|
+
|
|
189
|
+
```powershell
|
|
190
|
+
npm uninstall -g quick-ssh
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
卸载时:
|
|
194
|
+
- ✅ 自动从 `$PROFILE` 中移除 `Import-Module` 配置
|
|
195
|
+
- ✅ **保留** `%USERPROFILE%\.quickssh\hosts.json` 用户配置数据
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 颜色输出说明
|
|
200
|
+
|
|
201
|
+
| 颜色 | 含义 |
|
|
202
|
+
|------|------|
|
|
203
|
+
| 🟢 绿色 | 操作成功 |
|
|
204
|
+
| 🟡 黄色 | 提示 / 警告 |
|
|
205
|
+
| 🔴 红色 | 错误 |
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## 项目文件结构
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
quick-ssh/
|
|
213
|
+
├── Quick-SSH.psm1 # 核心 PowerShell 模块(全部逻辑)
|
|
214
|
+
├── index.js # npm 生命周期钩子(安装/卸载自动配置)
|
|
215
|
+
├── package.json # npm 包配置
|
|
216
|
+
├── README.md # 本文档
|
|
217
|
+
└── LICENSE # MIT 许可证
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
[MIT](LICENSE)
|