PowerShell 技能连载 - 远程管理进阶

适用于 PowerShell 5.1 及以上版本(Windows)

在前面的文章中,我们介绍了 SSH 远程管理的基础用法。本文将深入 PowerShell 远程管理的进阶技巧,包括 WinRM 配置优化、会话管理、 constrained endpoints(受限端点)、远程调试,以及大规模并行远程操作的策略。

WinRM 配置优化

WinRM 是 PowerShell 远程管理的默认传输协议。了解其配置项对排查连接问题和优化性能至关重要:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 查看 WinRM 服务状态
Get-Service WinRM

# 快速配置 WinRM(启用远程管理)
winrm quickconfig

# 查看 WinRM 完整配置
winrm get winrm/config

# 查看 WinRM 监听器
winrm enumerate winrm/config/listener

# 常用配置优化
# 增加最大内存限制(默认 150MB,处理大量数据时可能不够)
Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB 1024

# 增加并发 shell 数
Set-Item WSMan:\localhost\Shell\MaxShellsPerUser 50

# 增加最大接收数据大小
Set-Item WSMan:\localhost\Shell\MaxEnvelopeSizeKB 8192

# 配置可信主机(用于工作组环境)
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "SRV01,SRV02,192.168.1.*" -Force

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
Status   Name               DisplayName
------ ---- -----------
Running WinRM Windows Remote Management (WS-Management)

WinRM service is already running on this machine.
WinRM is already set up for remote management on this computer.

Config
MaxEnvelopeSizekb = 8192
MaxTimeoutms = 60000
MaxBatchItems = 32000

注意:在域环境中,WinRM 默认使用 Kerberos 认证,无需额外配置。在工作组环境中,需要配置 TrustedHosts 或使用 HTTPS 端点。

会话管理最佳实践

PSSession 是远程操作的核心对象。正确管理会话可以避免资源泄漏和连接超时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 创建持久会话(可复用)
$session = New-PSSession -ComputerName SRV01 -Name "AdminSession"

# 查看所有活动会话
Get-PSSession | Format-Table Name, ComputerName, State, Availability -AutoSize

# 在会话中执行多个命令(保持状态)
Invoke-Command -Session $session -ScriptBlock {
# 第一个命令设置变量
$script:logPath = "C:\Logs\app.log"
$script:logContent = Get-Content $script:logPath -Tail 100
Write-Host "已加载 $($script:logContent.Count) 行日志"
}

Invoke-Command -Session $session -ScriptBlock {
# 第二个命令使用之前的变量
$errors = $script:logContent | Select-String "ERROR"
$errors | Group-Object | Sort-Object Count -Descending |
Select-Object Count, Name | Format-Table -AutoSize
}

# 使用完成后释放会话
Remove-PSSession -Session $session

# 批量清理所有断开的会话
Get-PSSession | Where-Object State -eq 'Disconnected' | Remove-PSSession

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
Name          ComputerName State       Availability
---- ------------ ----- ------------
AdminSession SRV01 Opened Available

已加载 100 行日志

Count Name
----- ----
15 ERROR Database connection timeout
8 ERROR Failed to authenticate user
3 ERROR Disk space critically low

断开与重连会话

PowerShell 3.0 及以上版本支持会话断开与重连,这在网络不稳定时特别有用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 创建会话
$session = New-PSSession -ComputerName SRV01

# 启动长时间任务
Invoke-Command -Session $session -ScriptBlock {
# 模拟长时间任务
1..100 | ForEach-Object {
Start-Sleep -Seconds 1
"处理进度:$_/100"
}
} -AsJob

# 断开会话(任务继续在远程运行)
Disconnect-PSSession -Session $session

# 查看断开的会话
Get-PSSession | Where-Object State -eq 'Disconnected'

# 稍后重连
Connect-PSSession -Session $session

# 检查任务状态
Invoke-Command -Session $session -ScriptBlock {
Get-Job | Receive-Job -Keep
}

执行结果示例:

1
2
3
4
5
6
7
8
Id Name            ComputerName    State         ConfigurationName     Availability
-- ---- ------------ ----- ----------------- ------------
1 Session1 SRV01 Disconnected Microsoft.PowerShell None

处理进度:1/100
处理进度:2/100
...
处理进度:42/100

受限端点(Constrained Endpoint)

在企业环境中,可能需要给非管理员提供受限的远程管理能力。通过 JEA(Just Enough Administration)或自定义端点配置,可以精确控制远程用户能执行哪些命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 创建受限会话配置文件
$sessionConfig = @{
SchemaVersion = '2.0.0.0'
GUID = (New-Guid).ToString()
Author = 'Admin'
Description = '受限运维端点'
LanguageMode = 'NoLanguage'
ExecutionPolicy = 'Restricted'
SessionType = 'RestrictedRemoteServer'
VisibleCmdlets = @(
@{ Name = 'Get-Service'; Parameters = @{ Name = 'Name' } },
@{ Name = 'Get-Process' },
@{ Name = 'Get-EventLog'; Parameters = @{ Name = 'LogName' }, @{ Name = 'Newest' } }
)
VisibleFunctions = @('Get-SystemInfo')
RoleDefinitions = @{
'CONTOSO\OpsTeam' = @{ RoleCapabilities = 'MaintenanceRole' }
}
}

$configPath = "C:\Configs\ConstrainedEndpoint.pssc"
New-PSSessionConfigurationFile -Path $configPath @sessionConfig

# 注册端点
Register-PSSessionConfiguration -Name "OpsEndpoint" -Path $configPath -Force

# 使用受限端点连接
$session = New-PSSession -ComputerName SRV01 -ConfigurationName "OpsEndpoint"
Invoke-Command -Session $session -ScriptBlock { Get-Service -Name WinRM }

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
Status   Name               DisplayName
------ ---- -----------
Running WinRM Windows Remote Management (WS-Management)

Name Description
---- -----------
OpsEndpoint 受限运维端点

Status Name DisplayName
------ ---- -----------
Running WinRM Windows Remote Management (WS-Management)

大规模并行远程操作

当需要同时管理数十或数百台服务器时,需要合理的并行策略来平衡效率和资源消耗:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
function Invoke-ParallelRemoting {
<#
.SYNOPSIS
批量并行远程执行命令
#>
param(
[Parameter(Mandatory)]
[string[]]$ComputerName,

[Parameter(Mandatory)]
[scriptblock]$ScriptBlock,

[int]$ThrottleLimit = 16,
[int]$TimeoutMinutes = 10
)

# 读取服务器列表
$totalServers = $ComputerName.Count
Write-Host "共 $totalServers 台服务器需要处理,并发数:$ThrottleLimit" -ForegroundColor Cyan

$results = @()
$successCount = 0
$failCount = 0
$sw = [System.Diagnostics.Stopwatch]::StartNew()

# 分批处理
$batches = [Math]::Ceiling($totalServers / $ThrottleLimit)

for ($batch = 0; $batch -lt $batches; $batch++) {
$batchServers = $ComputerName | Select-Object -Skip ($batch * $ThrottleLimit) -First $ThrottleLimit

Write-Host "`n批次 $($batch + 1)/$batches ($($batchServers.Count) 台)..." -ForegroundColor Yellow

$batchResults = Invoke-Command -ComputerName $batchServers `
-ScriptBlock $ScriptBlock `
-ThrottleLimit $ThrottleLimit `
-ErrorAction SilentlyContinue

foreach ($r in $batchResults) {
if ($r) {
$successCount++
$results += $r
} else {
$failCount++
}
}
}

$sw.Stop()

Write-Host "`n========== 执行摘要 ==========" -ForegroundColor Green
Write-Host "总服务器数:$totalServers"
Write-Host "成功:$successCount"
Write-Host "失败:$failCount"
Write-Host "总耗时:$($sw.Elapsed.TotalSeconds) 秒"
Write-Host "平均每台:$([math]::Round($sw.Elapsed.TotalSeconds / $totalServers, 2)) 秒"

return $results
}

# 示例:批量检查服务器补丁状态
$computers = Get-Content "C:\Servers.txt"
$results = Invoke-ParallelRemoting -ComputerName $computers -ScriptBlock {
$os = Get-CimInstance Win32_OperatingSystem
$latestPatch = Get-CimInstance Win32_QuickFixEngineering |
Sort-Object InstalledOn -Descending | Select-Object -First 1

[PSCustomObject]@{
Computer = $env:COMPUTERNAME
OS = $os.Caption
LastPatch = $latestPatch.InstalledOn.ToString('yyyy-MM-dd')
HotFixID = $latestPatch.HotFixID
UptimeDays = [math]::Round(((Get-Date) - $os.LastBootUpTime).TotalDays, 1)
}
}

$results | Sort-Computer | Format-Table -AutoSize

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
50 台服务器需要处理,并发数:16

批次 1/4 (16 台)...
批次 2/4 (16 台)...
批次 3/4 (16 台)...
批次 4/4 (2 台)...

========== 执行摘要 ==========
总服务器数:50
成功:48
失败:2
总耗时:23.45
平均每台:0.47

Computer OS LastPatch HotFixID UptimeDays
-------- -- --------- -------- ----------
SRV01 Microsoft Windows Server ... 2025-05-10 KB5036908 2.1
SRV02 Microsoft Windows Server ... 2025-04-28 KB5034441 14.3
SRV03 Microsoft Windows Server ... 2025-05-05 KB5035849 7.0

远程文件传输

通过 PowerShell 远程会话,可以在本地和远程机器之间传输文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 方法一:使用 Copy-Item 与会话
$session = New-PSSession -ComputerName SRV01

# 上传文件到远程
Copy-Item -Path "C:\Scripts\Deploy-App.ps1" `
-Destination "C:\Scripts\" `
-ToSession $session

# 从远程下载文件
Copy-Item -Path "C:\Logs\app.log" `
-Destination "C:\Downloads\SRV01-app.log" `
-FromSession $session

# 方法二:传输整个目录
Copy-Item -Path "C:\Projects\MyApp\" `
-Destination "C:\Apps\MyApp\" `
-ToSession $session -Recurse

# 方法三:传输前压缩(适合大量小文件)
Compress-Archive -Path "C:\Projects\MyApp\*" -DestinationPath "C:\Temp\app.zip"
Copy-Item -Path "C:\Temp\app.zip" -Destination "C:\Temp\" -ToSession $session
Invoke-Command -Session $session -ScriptBlock {
Expand-Archive -Path "C:\Temp\app.zip" -DestinationPath "C:\Apps\MyApp" -Force
Remove-Item "C:\Temp\app.zip"
}

Remove-PSSession $session

执行结果示例:

1
# 文件传输无输出,成功即完成

注意事项

  1. 双跃点认证:从 A 机器远程到 B 机器,再从 B 访问 C 机器的资源时,默认凭据不会传递。需要配置 CredSSP 或使用 Kerberos 委派
  2. WinRM 端口:HTTP 默认端口 5985,HTTPS 默认端口 5986。生产环境建议使用 HTTPS
  3. 会话清理:长时间运行的脚本应确保在 finally 块中清理 PSSession,避免会话泄漏
  4. 序列化限制:远程命令返回的对象会被序列化/反序列化,某些类型(如 FileStream)无法直接返回,需要在远程端处理
  5. 并发限制:默认 WinRM 每个用户最多 5 个并发 shell,可通过 MaxShellsPerUser 调整
  6. 网络超时New-PSSession 默认操作超时 3 分钟,可通过 -OperationTimeoutSeconds 调整

PowerShell 技能连载 - SSH 远程管理

适用于 PowerShell 7.0 及以上版本(跨平台)

传统上,PowerShell 远程管理依赖 Windows 专属的 WinRM 协议和 Enter-PSSession 命令。但随着 PowerShell 7 的跨平台演进,以及混合云环境的普及,基于 SSH 的远程管理已成为官方推荐的新标准。SSH 不仅天然支持 Linux/macOS,还能在 Windows 上与 OpenSSH 无缝集成,实现真正的跨平台远程操作。

本文将从安装配置 OpenSSH 开始,逐步讲解如何通过 SSH 建立 PowerShell 远程会话、传输文件、执行远程命令,以及在生产环境中配置密钥认证和跳板机。

安装与配置 OpenSSH

在 Windows 上使用 SSH 远程管理,首先需要确保 OpenSSH 服务器已安装并运行。Windows 10 1809 及以上版本和 Windows Server 2019 均内置了 OpenSSH,但默认未启用。

1
2
3
4
5
6
7
8
9
10
11
12
# 检查 OpenSSH 安装状态
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'

# 安装 OpenSSH 服务器
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

# 启动 SSH 服务并设为自动启动
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic

# 确认防火墙规则(安装时通常会自动创建)
Get-NetFirewallRule -Name *ssh*

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
Name  : OpenSSH.Server~~~~0.0.1.0
State : Installed

Status Name DisplayName
------ ---- -----------
Running sshd OpenSSH SSH Server

Name : OpenSSH-Server-In-TCP
DisplayName : OpenSSH SSH Server (sshd)
Enabled : True
Direction : Inbound

注意:如果需要在 Linux 上使用 SSH 远程管理,确保目标主机已安装 openssh-server,并且 sshd_config 中配置了 Subsystem powershell /usr/bin/pwsh -sshs -NoLogo

配置 SSH 用于 PowerShell 远程

要让 PowerShell 通过 SSH 建立远程会话,需要在 SSH 服务端进行配置。核心是将 PowerShell 注册为 SSH 子系统(Subsystem),这样客户端连接时可以指定使用 PowerShell 而非默认的 shell。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Windows 上的 sshd_config 路径
$sshdConfig = "$env:ProgramData\ssh\sshd_config"

# 检查是否已配置 PowerShell 子系统
$content = Get-Content $sshdConfig -Raw
if ($content -notmatch 'Subsystem\s+powershell') {
# 追加 PowerShell 子系统配置
$subsystemPath = (Get-Command pwsh).Source.Replace('\', '/')
Add-Content -Path $sshdConfig -Value "`nSubsystem powershell $subsystemPath -sshs -NoLogo"
Write-Host "已添加 PowerShell 子系统配置" -ForegroundColor Green
} else {
Write-Host "PowerShell 子系统已配置" -ForegroundColor Yellow
}

# 重启 SSH 服务使配置生效
Restart-Service sshd

执行结果示例:

1
已添加 PowerShell 子系统配置

配置完成后,还需要确保 sshd_config 中启用了密码认证或公钥认证:

1
2
# 确认认证方式配置
Select-String -Path $sshdConfig -Pattern 'PasswordAuthentication|PubkeyAuthentication'

执行结果示例:

1
2
sshd_config:37:PasswordAuthentication yes
sshd_config:53:PubkeyAuthentication yes

建立远程会话

配置完成后,使用 New-PSSessionEnter-PSSession 通过 SSH 连接远程主机。连接时通过 -HostName 参数指定目标,PowerShell 会自动使用 SSH 协议。

1
2
3
4
5
6
7
8
9
10
11
12
# 交互式进入远程会话
Enter-PSSession -HostName admin@192.168.1.100

# 指定 SSH 端口
Enter-PSSession -HostName admin@192.168.1.100 -Port 2222

# 使用 PSSession 对象进行非交互操作
$session = New-PSSession -HostName admin@192.168.1.100
Invoke-Command -Session $session -ScriptBlock {
$PSVersionTable
Get-ComputerInfo | Select-Object CsName, OsName, OsVersion
}

执行结果示例:

1
2
3
4
5
6
7
8
9
10
11
12
PSRemote> [admin@SERVER01]: PS C:\Users\admin\Documents>

Name Value
---- -----
PSVersion 7.4.2
PSEdition Core
Platform Unix
OS Ubuntu 22.04.4 LTS

CsName OsName OsVersion
------ ------ ----------
UBUNTU01 Ubuntu 22.04 LTS 22.04.4

注意-HostName 参数使用 user@host 格式,与 SSH 命令行一致。首次连接时会提示确认主机指纹。

使用 SSH 密钥认证

密码认证存在暴力破解风险,生产环境强烈建议使用 SSH 密钥认证。PowerShell 完全支持基于密钥的 SSH 连接。

1
2
3
4
5
6
7
8
# 生成 ED25519 密钥对(推荐,比 RSA 更安全更快)
ssh-keygen -t ed25519 -C "admin@workstation" -f "$env:USERPROFILE\.ssh\id_ed25519"

# 生成 RSA 密钥对(兼容性更好)
ssh-keygen -t rsa -b 4096 -C "admin@workstation" -f "$env:USERPROFILE\.ssh\id_rsa"

# 查看生成的公钥
Get-Content "$env:USERPROFILE\.ssh\id_ed25519.pub"

执行结果示例:

1
2
3
4
5
6
7
8
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Your identification has been saved in C:\Users\admin\.ssh\id_ed25519
Your public key has been saved in C:\Users\admin\.ssh\id_ed25519.pub
The key fingerprint is:
SHA256:AbCdEfGhIjKlMnOpQrStUvWxYz1234567890abcdef admin@workstation

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAbCdEfGh admin@workstation

将公钥部署到远程主机:

1
2
3
4
5
6
7
8
9
10
# Windows 目标:将公钥添加到 authorized_keys
$publicKey = Get-Content "$env:USERPROFILE\.ssh\id_ed25519.pub"
$remotePath = "$env:ProgramData\ssh\administrators_authorized_keys"

# 通过 SSH 复制公钥(类 ssh-copy-id 功能)
$remoteHost = "admin@192.168.1.100"
ssh $remoteHost "mkdir -p ~/.ssh && echo '$publicKey' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

# 使用密钥连接(不再需要密码)
Enter-PSSession -HostName $remoteHost -KeyFilePath "$env:USERPROFILE\.ssh\id_ed25519"

执行结果示例:

1
PSRemote> [admin@SERVER01]: PS C:\Users\admin\Documents>

跨平台远程管理

SSH 最大的优势在于跨平台。同一台 Windows 管理机可以同时管理 Windows、Linux 甚至 macOS 主机:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 同时连接多台不同操作系统的主机
$windowsHost = New-PSSession -HostName admin@win-server01
$linuxHost = New-PSSession -HostName dev@linux-web01
$macHost = New-PSSession -HostName user@mac-build01

# 在所有主机上执行命令
$sessions = $windowsHost, $linuxHost, $macHost
$results = Invoke-Command -Session $sessions -ScriptBlock {
[PSCustomObject]@{
Host = $env:COMPUTERNAME ?? hostname
OS = [System.Runtime.InteropServices.RuntimeInformation]::OSDescription
PSVersion = $PSVersionTable.PSVersion.ToString()
Platform = $PSVersionTable.Platform
Uptime = if ($IsLinux -or $IsMacOS) {
(uptime -p 2>$null) ?? "N/A"
} else {
(Get-CimInstance Win32_OperatingSystem).LastBootUpTime.ToString()
}
}
}

$results | Format-Table -AutoSize

执行结果示例:

1
2
3
4
5
Host         OS                                    PSVersion Platform  Uptime
---- -- --------- -------- ------
WIN-SERVER01 Microsoft Windows 10.0.20348 7.4.2 Win32NT 4/28/2025 8:30:00 AM
linux-web01 Linux 5.15.0-101-generic #111-Ubuntu 7.4.2 Unix up 42 days, 3:17
mac-build01 Darwin 23.4.0 Darwin Kernel Version… 7.4.2 Unix up 15 days, 7:22

批量远程操作

在运维场景中,经常需要对多台服务器批量执行命令。结合 SSH 和 PowerShell 远程,可以轻松实现并行批量操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 从 inventory 文件读取服务器列表
$servers = @(
@{ Name = 'web-01'; Host = 'admin@192.168.1.101'; Key = 'C:\Keys\web-01\id_ed25519' }
@{ Name = 'web-02'; Host = 'admin@192.168.1.102'; Key = 'C:\Keys\web-02\id_ed25519' }
@{ Name = 'db-01'; Host = 'admin@192.168.1.201'; Key = 'C:\Keys\db-01\id_ed25519' }
)

# 批量建立 SSH 会话
$sessions = foreach ($srv in $servers) {
New-PSSession -HostName $srv.Host -KeyFilePath $srv.Key -Name $srv.Name
}

# 并行执行系统检查
Invoke-Command -Session $sessions -ScriptBlock {
[PSCustomObject]@{
Host = $env:COMPUTERNAME ?? hostname
CPU_Load = if ($IsLinux) { (top -bn1 | grep 'Cpu(s)' | awk '{print $2}') } else { (Get-CimInstance Win32_Processor).LoadPercentage }
Mem_Used_Pct = if ($IsLinux) {
[math]::Round((free | awk '/Mem/{print $3/$2 * 100}'), 1)
} else {
$os = Get-CimInstance Win32_OperatingSystem
[math]::Round(($os.TotalVisibleMemorySize - $os.FreePhysicalMemory) / $os.TotalVisibleMemorySize * 100, 1)
}
Disk_Free_GB = if ($IsLinux) {
[math]::Round((df -h / | awk 'NR==2{print $4}' | sed 's/G//'), 1)
} else {
[math]::Round((Get-CimInstance Win32_LogicalDisk -Filter "DeviceID='C:'").FreeSpace / 1GB, 1)
}
}
} | Sort-Object PSComputerName | Format-Table -AutoSize

执行结果示例:

1
2
3
4
5
Host       CPU_Load Mem_Used_Pct Disk_Free_GB
---- -------- ----------- ------------
web-01 12.3 45.2 128.5
web-02 8.7 38.9 95.2
db-01 65.4 82.1 45.8

SSH 配置文件优化

频繁输入完整的主机名、端口和密钥路径很繁琐。通过配置 SSH config 文件可以简化操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 生成 SSH config 文件
$sshConfig = @"
Host web-01
HostName 192.168.1.101
User admin
Port 22
IdentityFile C:\Keys\web-01\id_ed25519
RequestTTY yes

Host web-02
HostName 192.168.1.102
User admin
Port 22
IdentityFile C:\Keys\web-02\id_ed25519

Host db-01
HostName 192.168.1.201
User admin
Port 2222
IdentityFile C:\Keys\db-01\id_ed25519

Host jump-server
HostName 10.0.0.1
User gateway
IdentityFile C:\Keys\gateway\id_ed25519
"@

Set-Content -Path "$env:USERPROFILE\.ssh\config" -Value $sshConfig -Encoding UTF8
Write-Host "SSH 配置文件已更新" -ForegroundColor Green

# 现在可以使用别名连接
Enter-PSSession -HostName web-01

执行结果示例:

1
2
SSH 配置文件已更新
PSRemote> [admin@WEB-01]: PS C:\Users\admin\Documents>

注意:SSH config 文件的权限必须正确设置。在 Windows 上,确保只有当前用户有读取权限;在 Linux/macOS 上,权限应为 600

通过跳板机连接

在生产环境中,服务器通常位于内网,需要通过跳板机(Bastion Host)访问。SSH 的 ProxyJump 功能可以轻松实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 在 SSH config 中配置跳板机
$jumpConfig = @"

Host prod-*
ProxyJump jump-server
User admin
IdentityFile C:\Keys\prod\id_ed25519

Host prod-web-01
HostName 10.10.1.101

Host prod-db-01
HostName 10.10.1.201
"@

Add-Content -Path "$env:USERPROFILE\.ssh\config" -Value $jumpConfig

# 连接会自动经过跳板机
Enter-PSSession -HostName prod-web-01

执行结果示例:

1
PSRemote> [admin@PROD-WEB-01]: PS C:\Users\admin\Documents>

注意事项

  1. SSH 服务安全加固:生产环境应禁用密码认证,仅启用密钥认证,在 sshd_config 中设置 PasswordAuthentication no
  2. 密钥保护:私钥文件权限必须设为仅所有者可读(Linux/macOS: chmod 600,Windows: 移除继承权限,仅保留当前用户)
  3. 会话超时:SSH 连接可能因防火墙或 NAT 超时断开,建议在 ~/.ssh/config 中配置 ServerAliveInterval 60
  4. 跨平台差异:通过 SSH 执行命令时,目标平台的路径分隔符、环境变量和命令语法可能不同,使用 $IsLinux$IsWindows$IsMacOS 进行条件判断
  5. 端口安全:避免使用默认的 22 端口暴露在公网,如果必须暴露,配合 fail2ban 或 Azure/JumpServer 等堡垒机方案
  6. PowerShell 子系统路径:确保 sshd_configSubsystem powershell 指向正确的 pwsh 路径,Linux 上通常为 /usr/bin/pwsh