vscode中ssh自动登录脚本

脚本作用:
在使用ssh进行远程开发的时候,一键设置windwos和远程服务器的密码

这是powershell脚本:通用命名vscode_ssh_setup.ps1

# VS Code SSH 通用配置脚本
# 此脚本用于设置Windows与Linux之间的SSH无密码登录
# 并配置VS Code的远程开发环境

# 默认设置
$defaultSettings = @{
    RemoteIP = "192.168.1.252"
    RemoteUser = "root"
    RemotePort = 22
    KeyType = "rsa"
    KeySize = 4096
    KeyPath = "$env:USERPROFILE\.ssh\id_rsa"
    ConfigPath = "$env:USERPROFILE\.ssh\config"
}

# 显示标题
function Show-Title {
    Clear-Host
    Write-Host "===============================================" -ForegroundColor Cyan
    Write-Host "   VS Code SSH 远程开发环境配置工具" -ForegroundColor Cyan
    Write-Host "===============================================" -ForegroundColor Cyan
    Write-Host ""
}

# 收集用户设置
function Get-UserSettings {
    Write-Host "请配置SSH连接参数(直接回车使用默认值)" -ForegroundColor Yellow
    Write-Host ""

    # 远程服务器IP
    $remoteIP = Read-Host "远程服务器IP地址 [默认: $($defaultSettings.RemoteIP)]"
    if ([string]::IsNullOrEmpty($remoteIP)) { $remoteIP = $defaultSettings.RemoteIP }

    # 远程服务器用户名
    $remoteUser = Read-Host "远程服务器用户名 [默认: $($defaultSettings.RemoteUser)]"
    if ([string]::IsNullOrEmpty($remoteUser)) { $remoteUser = $defaultSettings.RemoteUser }

    # 远程服务器端口
    $remotePortInput = Read-Host "SSH端口 [默认: $($defaultSettings.RemotePort)]"
    $remotePort = $defaultSettings.RemotePort
    if (![string]::IsNullOrEmpty($remotePortInput)) {
        try {
            $remotePort = [int]$remotePortInput
        } catch {
            Write-Host "端口必须是数字,使用默认端口: $($defaultSettings.RemotePort)" -ForegroundColor Yellow
        }
    }

    # 密钥类型
    $keyType = Read-Host "密钥类型 (rsa/ed25519) [默认: $($defaultSettings.KeyType)]"
    if ([string]::IsNullOrEmpty($keyType)) { $keyType = $defaultSettings.KeyType }
    elseif ($keyType -ne "rsa" -and $keyType -ne "ed25519") {
        Write-Host "不支持的密钥类型,使用默认: $($defaultSettings.KeyType)" -ForegroundColor Yellow
        $keyType = $defaultSettings.KeyType
    }

    # 密钥大小
    $keySizeInput = Read-Host "密钥大小 [RSA默认: $($defaultSettings.KeySize), ED25519无需指定]"
    $keySize = $defaultSettings.KeySize
    if (![string]::IsNullOrEmpty($keySizeInput) -and $keyType -eq "rsa") {
        try {
            $keySize = [int]$keySizeInput
        } catch {
            Write-Host "密钥大小必须是数字,使用默认: $($defaultSettings.KeySize)" -ForegroundColor Yellow
        }
    }

    # 密钥位置
    $keyPathSuggestion = "$env:USERPROFILE\.ssh\id_$keyType"
    $keyPath = Read-Host "密钥存储位置 [默认: $keyPathSuggestion]"
    if ([string]::IsNullOrEmpty($keyPath)) { $keyPath = $keyPathSuggestion }

    # 返回设置
    return @{
        RemoteIP = $remoteIP
        RemoteUser = $remoteUser
        RemotePort = $remotePort
        KeyType = $keyType
        KeySize = $keySize
        KeyPath = $keyPath
        ConfigPath = $defaultSettings.ConfigPath
    }
}

# 主函数
function Main {
    Show-Title

    $settings = Get-UserSettings

    # 显示配置信息
    Write-Host "`n配置信息预览:" -ForegroundColor Green
    Write-Host "远程服务器: $($settings.RemoteUser)@$($settings.RemoteIP):$($settings.RemotePort)" -ForegroundColor White
    Write-Host "密钥类型: $($settings.KeyType) $(if($settings.KeyType -eq 'rsa'){"($($settings.KeySize)位)"})" -ForegroundColor White
    Write-Host "密钥路径: $($settings.KeyPath)" -ForegroundColor White
    Write-Host "配置文件: $($settings.ConfigPath)" -ForegroundColor White

    $confirm = Read-Host "`n确认以上设置并继续? (y/n) [默认: y]"
    if ($confirm -eq "n") {
        Write-Host "`n已取消操作" -ForegroundColor Yellow
        return
    }

    # 确保.ssh目录存在
    $sshDir = Split-Path -Path $settings.KeyPath -Parent
    if (!(Test-Path $sshDir)) {
        New-Item -ItemType Directory -Path $sshDir | Out-Null
        Write-Host "已创建目录: $sshDir" -ForegroundColor Green
    }

    # 生成SSH密钥
    $pubKeyPath = "$($settings.KeyPath).pub"
    if (!(Test-Path $settings.KeyPath)) {
        Write-Host "`n正在生成SSH密钥..." -ForegroundColor Yellow

        if ($settings.KeyType -eq "rsa") {
            ssh-keygen -t $settings.KeyType -b $settings.KeySize -f $settings.KeyPath -N '""'
        } else {
            ssh-keygen -t $settings.KeyType -f $settings.KeyPath -N '""'
        }

        if ($LASTEXITCODE -ne 0) {
            Write-Host "密钥生成失败,错误代码: $LASTEXITCODE" -ForegroundColor Red
            return
        }

        Write-Host "密钥生成成功!" -ForegroundColor Green
    } else {
        Write-Host "`n检测到密钥已存在: $($settings.KeyPath)" -ForegroundColor Cyan
    }

    # 读取公钥
    if (Test-Path $pubKeyPath) {
        $publicKey = Get-Content $pubKeyPath -Raw
        Write-Host "`n公钥内容:" -ForegroundColor Yellow
        Write-Host $publicKey -ForegroundColor Gray

        # 上传公钥到服务器
        $uploadKey = Read-Host "`n是否将公钥上传到远程服务器? (y/n) [默认: y]"
        if ($uploadKey -ne "n") {
            Write-Host "`n上传公钥到 $($settings.RemoteUser)@$($settings.RemoteIP)..." -ForegroundColor Yellow

            # 密码认证方式
            $usePassword = Read-Host "`n需要使用密码登录来上传密钥吗? (y/n) [默认: y]"

            if ($usePassword -ne "n") {
                # 请求输入密码(不显示在屏幕上)
                $securePassword = Read-Host "请输入远程服务器密码" -AsSecureString
                $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePassword)
                $password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
                [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)

                # 创建临时脚本
                $tempScriptPath = [System.IO.Path]::GetTempFileName()
                $tempScriptPath = $tempScriptPath -replace ".tmp", ".sh"

                "mkdir -p ~/.ssh" | Out-File -FilePath $tempScriptPath -Encoding ASCII
                "chmod 700 ~/.ssh" | Out-File -FilePath $tempScriptPath -Encoding ASCII -Append
                "echo `"$publicKey`" >> ~/.ssh/authorized_keys" | Out-File -FilePath $tempScriptPath -Encoding ASCII -Append
                "chmod 600 ~/.ssh/authorized_keys" | Out-File -FilePath $tempScriptPath -Encoding ASCII -Append
                "echo 'Public key added to authorized_keys'" | Out-File -FilePath $tempScriptPath -Encoding ASCII -Append

                # 准备使用sshpass
                $sshpassExists = $false
                try {
                    $sshpassCheck = Invoke-Expression "sshpass -V" -ErrorAction SilentlyContinue
                    $sshpassExists = $true
                } catch {
                    $sshpassExists = $false
                }

                if ($sshpassExists) {
                    # 使用sshpass上传
                    $sshPort = "-p $($settings.RemotePort)"
                    $remoteHost = "$($settings.RemoteUser)@$($settings.RemoteIP)"

                    try {
                        Invoke-Expression "sshpass -p `"$password`" scp $sshPort $tempScriptPath $remoteHost:/tmp/add_key.sh"
                        Invoke-Expression "sshpass -p `"$password`" ssh $sshPort $remoteHost 'chmod +x /tmp/add_key.sh && /tmp/add_key.sh && rm /tmp/add_key.sh'"
                        Write-Host "公钥已成功上传到服务器!" -ForegroundColor Green
                    } catch {
                        Write-Host "上传公钥失败: $_" -ForegroundColor Red
                        Write-Host "请尝试手动上传公钥" -ForegroundColor Yellow
                    }
                } else {
                    # sshpass不可用,使用手动复制方式
                    Write-Host "`nsshpass工具未安装,请手动执行以下操作:" -ForegroundColor Yellow
                    Write-Host "1. 复制以下公钥内容:" -ForegroundColor White
                    Write-Host $publicKey -ForegroundColor Cyan
                    Write-Host "2. 登录到服务器: ssh $($settings.RemoteUser)@$($settings.RemoteIP) -p $($settings.RemotePort)" -ForegroundColor White
                    Write-Host "3. 执行以下命令:" -ForegroundColor White
                    Write-Host "   mkdir -p ~/.ssh" -ForegroundColor Cyan
                    Write-Host "   chmod 700 ~/.ssh" -ForegroundColor Cyan
                    Write-Host "   echo '复制的公钥内容' >> ~/.ssh/authorized_keys" -ForegroundColor Cyan
                    Write-Host "   chmod 600 ~/.ssh/authorized_keys" -ForegroundColor Cyan

                    $continue = Read-Host "`n完成手动上传后按Enter继续,或输入n取消 [默认: 继续]"
                    if ($continue -eq "n") {
                        Write-Host "已取消配置" -ForegroundColor Yellow
                        Remove-Item -Path $tempScriptPath -Force -ErrorAction SilentlyContinue
                        return
                    }
                }

                # 删除临时脚本
                Remove-Item -Path $tempScriptPath -Force -ErrorAction SilentlyContinue
            } else {
                # 使用现有密钥尝试登录
                $sshPort = "-p $($settings.RemotePort)"
                $remoteHost = "$($settings.RemoteUser)@$($settings.RemoteIP)"

                # 创建临时脚本
                $tempScriptPath = [System.IO.Path]::GetTempFileName()
                $tempScriptPath = $tempScriptPath -replace ".tmp", ".sh"

                "mkdir -p ~/.ssh" | Out-File -FilePath $tempScriptPath -Encoding ASCII
                "chmod 700 ~/.ssh" | Out-File -FilePath $tempScriptPath -Encoding ASCII -Append
                "echo `"$publicKey`" >> ~/.ssh/authorized_keys" | Out-File -FilePath $tempScriptPath -Encoding ASCII -Append
                "chmod 600 ~/.ssh/authorized_keys" | Out-File -FilePath $tempScriptPath -Encoding ASCII -Append
                "echo 'Public key added to authorized_keys'" | Out-File -FilePath $tempScriptPath -Encoding ASCII -Append

                try {
                    # 构造正确的SCP命令
                    $scpTarget = "$remoteHost`:/tmp/add_key.sh"
                    scp $sshPort $tempScriptPath $scpTarget
                    ssh $sshPort $remoteHost "chmod +x /tmp/add_key.sh && /tmp/add_key.sh && rm /tmp/add_key.sh"
                    Write-Host "公钥已成功上传到服务器!" -ForegroundColor Green
                } catch {
                    Write-Host "上传公钥失败: $_" -ForegroundColor Red
                    Write-Host "请检查您的SSH连接设置或尝试手动上传" -ForegroundColor Yellow
                }

                # 删除临时脚本
                Remove-Item -Path $tempScriptPath -Force -ErrorAction SilentlyContinue
            }
        }

        # 配置VS Code
        $configureVSCode = Read-Host "`n是否配置VS Code的SSH连接设置? (y/n) [默认: y]"
        if ($configureVSCode -ne "n") {
            # 确保配置文件目录存在
            $configDir = Split-Path -Path $settings.ConfigPath -Parent
            if (!(Test-Path $configDir)) {
                New-Item -ItemType Directory -Path $configDir | Out-Null
            }

            # 检查配置文件是否存在
            if (!(Test-Path $settings.ConfigPath)) {
                "# SSH Config File" | Out-File -FilePath $settings.ConfigPath -Encoding UTF8
                Write-Host "已创建SSH配置文件: $($settings.ConfigPath)" -ForegroundColor Green
            }

            # 读取现有配置
            $configContent = ""
            if (Test-Path $settings.ConfigPath) {
                $configContent = Get-Content $settings.ConfigPath -Raw
            }

            # 构造主机名(IP或别名)
            $hostName = Read-Host "`n请为此连接指定一个名称 [默认: $($settings.RemoteIP)]"
            if ([string]::IsNullOrEmpty($hostName)) { $hostName = $settings.RemoteIP }

            # 检查是否已存在配置
            if ($configContent -match "Host\s+$hostName") {
                $updateConfig = Read-Host "已存在名为 '$hostName' 的配置,是否更新? (y/n) [默认: y]"
                if ($updateConfig -eq "n") {
                    Write-Host "已跳过VS Code配置" -ForegroundColor Yellow
                    return
                }

                # 从配置中删除现有配置
                $configLines = Get-Content $settings.ConfigPath
                $newConfig = @()
                $skipLines = $false

                foreach ($line in $configLines) {
                    if ($line -match "Host\s+$hostName") {
                        $skipLines = $true
                        continue
                    }

                    if ($skipLines -and $line -match "^Host\s+") {
                        $skipLines = $false
                    }

                    if (!$skipLines) {
                        $newConfig += $line
                    }
                }

                $newConfig | Out-File -FilePath $settings.ConfigPath -Encoding UTF8
                Write-Host "已删除现有配置" -ForegroundColor Yellow
            }

            # 构造新配置
            $newHostConfig = @"

Host $hostName
  HostName $($settings.RemoteIP)
  User $($settings.RemoteUser)
  Port $($settings.RemotePort)
  IdentityFile $($settings.KeyPath)
  PreferredAuthentications publickey
  ServerAliveInterval 60

"@

            # 添加到配置文件
            Add-Content -Path $settings.ConfigPath -Value $newHostConfig
            Write-Host "VS Code SSH配置已更新!" -ForegroundColor Green

            # 显示VS Code使用说明
            Write-Host "`nVS Code连接说明:" -ForegroundColor Green
            Write-Host "1. 打开VS Code" -ForegroundColor White
            Write-Host "2. 按F1或Ctrl+Shift+P打开命令面板" -ForegroundColor White
            Write-Host "3. 输入并选择 'Remote-SSH: Connect to Host...'" -ForegroundColor White
            Write-Host "4. 选择 '$hostName'" -ForegroundColor White
        }
    } else {
        Write-Host "错误: 找不到公钥文件 $pubKeyPath" -ForegroundColor Red
        return
    }

    # 检查VS Code是否已安装Remote SSH扩展
    Write-Host "`n检查VS Code扩展..." -ForegroundColor Yellow
    $hasRemoteSSH = $false

    try {
        $extensions = Invoke-Expression "code --list-extensions" -ErrorAction SilentlyContinue
        $hasRemoteSSH = $extensions -contains "ms-vscode-remote.remote-ssh"
    } catch {
        $hasRemoteSSH = $false
    }

    if ($hasRemoteSSH) {
        Write-Host "已安装VS Code Remote-SSH扩展" -ForegroundColor Green
    } else {
        Write-Host "未检测到VS Code Remote-SSH扩展,请安装此扩展:" -ForegroundColor Yellow
        Write-Host "1. 打开VS Code" -ForegroundColor White
        Write-Host "2. 打开扩展面板 (Ctrl+Shift+X)" -ForegroundColor White
        Write-Host "3. 搜索 'Remote - SSH'" -ForegroundColor White
        Write-Host "4. 安装 'Remote - SSH' 扩展" -ForegroundColor White
    }

    # 完成
    Write-Host "`n===============================================" -ForegroundColor Cyan
    Write-Host "      VS Code SSH 远程开发环境配置完成!" -ForegroundColor Cyan
    Write-Host "===============================================" -ForegroundColor Cyan
}

# 执行主函数
Main 

标签

发表评论