远程管理
PowerShell Remoting 是 PowerShell 的核心功能之一,允许管理员在远程计算机上执行命令和脚本。通过 WinRM(Windows Remote Management)或 SSH,可以实现跨服务器的批量管理和自动化运维。
远程管理概述
支持的远程协议
PowerShell 支持多种远程连接协议:
WinRM:Windows 原生远程管理协议,基于 WS-Management 标准。Windows 环境下的首选方式。
SSH:跨平台远程协议,PowerShell 6+ 支持,适用于 Linux/macOS 和混合环境。
远程管理模式
1:1 远程会话:使用 Enter-PSSession 进入交互式远程会话。
1: 多远程执行:使用 Invoke-Command 在多台计算机上执行命令。
启用 WinRM 远程管理
检查 WinRM 状态
Get-Service WinRM
Test-WSMan
启用远程管理
在目标计算机上运行:
Enable-PSRemoting -Force
此命令会:
- 启动 WinRM 服务
- 设置服务自动启动
- 创建 WinRM 监听器
- 配置防火墙规则
配置可信主机
在工作组环境中,需要配置可信主机:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "192.168.1.100" -Force
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
查看当前配置:
Get-Item WSMan:\localhost\Client\TrustedHosts
防火墙配置
确保防火墙允许 WinRM 连接:
Enable-NetFirewallRule -Name "WINRM-HTTP-In-TCP"
Enable-NetFirewallRule -Name "WINRM-HTTPS-In-TCP"
交互式远程会话
Enter-PSSession
进入远程交互式会话:
Enter-PSSession -ComputerName "Server01"
Enter-PSSession -ComputerName "192.168.1.100" -Credential (Get-Credential)
会话中执行命令:
[Server01]: PS C:\Users\admin\Documents> Get-Process
[Server01]: PS C:\Users\admin\Documents> Get-Service
退出会话:
[Server01]: PS C:\Users\admin\Documents> Exit-PSSession
使用会话对象
创建并复用会话:
$session = New-PSSession -ComputerName "Server01" -Credential (Get-Credential)
Enter-PSSession -Session $session
Exit-PSSession
Invoke-Command -Session $session -ScriptBlock { Get-Process }
Remove-PSSession -Session $session
远程命令执行
Invoke-Command
在远程计算机上执行命令:
Invoke-Command -ComputerName "Server01" -ScriptBlock { Get-Process }
传递凭据:
$cred = Get-Credential
Invoke-Command -ComputerName "Server01" -Credential $cred -ScriptBlock {
Get-Service
}
批量执行
在多台计算机上执行:
$servers = "Server01", "Server02", "Server03"
Invoke-Command -ComputerName $servers -ScriptBlock {
Get-Service -Name "WinRM"
}
传递本地变量
使用 -ArgumentList 传递参数:
$path = "C:\Logs"
Invoke-Command -ComputerName "Server01" -ScriptBlock {
param($p)
Get-ChildItem $p
} -ArgumentList $path
使用 $using: 作用域(PowerShell 3.0+):
$path = "C:\Logs"
Invoke-Command -ComputerName "Server01" -ScriptBlock {
Get-ChildItem $using:path
}
执行本地脚本
在远程计算机上执行本地脚本文件:
Invoke-Command -ComputerName "Server01" -FilePath "C:\Scripts\Check-System.ps1"
会话管理
New-PSSession
创建持久会话:
$session = New-PSSession -ComputerName "Server01"
创建多个会话:
$sessions = New-PSSession -ComputerName "Server01", "Server02", "Server03"
Get-PSSession
查看当前会话:
Get-PSSession
Get-PSSession -ComputerName "Server01"
Remove-PSSession
断开会话:
Remove-PSSession -Id 1
Remove-PSSession -ComputerName "Server01"
Get-PSSession | Remove-PSSession
Disconnect-PSSession / Connect-PSSession
断开并重新连接会话:
$session = New-PSSession -ComputerName "Server01"
Disconnect-PSSession -Session $session
Connect-PSSession -Session $session
SSH 远程连接
配置 SSH 远程
在 Linux/macOS 或 Windows 上使用 SSH:
Enter-PSSession -HostName "192.168.1.100" -UserName "admin"
使用 SSH 配置文件:
Enter-PSSession -HostName "server01.example.com" -UserName "admin" -KeyFilePath "~/.ssh/id_rsa"
SSH 远程执行
Invoke-Command -HostName "server01", "server02" -UserName "admin" -ScriptBlock {
Get-Process
}
高级远程配置
配置会话配置
查看会话配置:
Get-PSSessionConfiguration
注册自定义会话配置:
Register-PSSessionConfiguration -Name "AdminSession" -MaximumReceivedObjectSizeMB 50
使用自定义配置:
New-PSSession -ComputerName "Server01" -ConfigurationName "AdminSession"
约束委派
使用 CredSSP 进行凭据委派:
Enable-WSManCredSSP -Role Client -DelegateComputer "Server01"
Enable-WSManCredSSP -Role Server
Invoke-Command -ComputerName "Server01" -Authentication CredSSP -Credential $cred -ScriptBlock {
}
Just Enough Administration (JEA)
JEA 限制远程用户可执行的命令:
Register-PSSessionConfiguration -Name "JEA_DNS" -Path "C:\JEA\JEAConfig.pssc"
远程管理最佳实践
使用 SSL 加密
配置 HTTPS 监听器:
$cert = New-SelfSignedCertificate -DnsName "Server01" -CertStoreLocation "Cert:\LocalMachine\My"
New-Item -Path WSMan:\localhost\Listener -Transport HTTPS -Address * -CertificateThumbprint $cert.Thumbprint -Force
连接使用 SSL:
New-PSSession -ComputerName "Server01" -UseSSL -SessionOption (New-PSSessionOption -SkipCACheck)
会话限制
限制并发会话数:
Set-Item WSMan:\localhost\Shell\MaxConcurrentUsers 10
Set-Item WSMan:\localhost\Shell\MaxShellsPerUser 5
错误处理
try {
$session = New-PSSession -ComputerName "Server01" -ErrorAction Stop
Invoke-Command -Session $session -ScriptBlock { Get-Process }
}
catch {
Write-Error "远程连接失败: $_"
}
finally {
if ($session) {
Remove-PSSession -Session $session
}
}
实用示例
批量获取服务器状态
$servers = Get-Content -Path "C:\Servers.txt"
$results = Invoke-Command -ComputerName $servers -ScriptBlock {
[PSCustomObject]@{
ComputerName = $env:COMPUTERNAME
OS = (Get-CimInstance Win32_OperatingSystem).Caption
CPU = (Get-CimInstance Win32_Processor).Name
FreeMemory = [math]::Round((Get-CimInstance Win32_OperatingSystem).FreePhysicalMemory / 1MB, 2)
DiskFree = (Get-Volume -DriveLetter C).SizeRemaining / 1GB
Uptime = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
}
} -ErrorAction SilentlyContinue
$results | Format-Table -AutoSize
远程部署服务
$servers = "Web01", "Web02", "Web03"
$sourcePath = "\\FileServer\Deploy\MyService"
$destPath = "C:\Services\MyService"
Invoke-Command -ComputerName $servers -ScriptBlock {
param($source, $dest)
if (!(Test-Path $dest)) {
New-Item -Path $dest -ItemType Directory -Force
}
Copy-Item -Path "$source\*" -Destination $dest -Recurse -Force
$service = Get-Service -Name "MyService" -ErrorAction SilentlyContinue
if ($service) {
Restart-Service -Name "MyService" -Force
} else {
New-Service -Name "MyService" -BinaryPathName "$dest\MyService.exe" -StartupType Automatic
Start-Service -Name "MyService"
}
Write-Host "部署完成: $env:COMPUTERNAME"
} -ArgumentList $sourcePath, $destPath
远程日志收集
$servers = "Server01", "Server02"
$logPath = "C:\CollectedLogs"
if (!(Test-Path $logPath)) {
New-Item -Path $logPath -ItemType Directory -Force
}
foreach ($server in $servers) {
$session = New-PSSession -ComputerName $server
$logs = Invoke-Command -Session $session -ScriptBlock {
Get-ChildItem -Path "C:\Logs" -Filter "*.log" -Recurse |
Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) }
}
foreach ($log in $logs) {
$remotePath = $log.FullName
$localPath = Join-Path $logPath "$($server)_$($log.Name)"
Invoke-Command -Session $session -ScriptBlock {
param($path)
Get-Content $path
} -ArgumentList $remotePath | Out-File -FilePath $localPath
}
Remove-PSSession -Session $session
}
下一步
掌握了远程管理后,接下来学习 脚本安全,了解 PowerShell 的安全最佳实践。