# PowerShell 批量远程执行 ## 场景 几十台 Windows 服务器要统一查磁盘、重启服务、改注册表。 ## 前置条件 - 目标机开启 WinRM - 执行账号在目标机有管理员权限 - 网络能到 5985(HTTP)或 5986(HTTPS) ## 配置 目标机开启 WinRM: ```powershell Enable-PSRemoting -Force Set-Item WSMan:\localhost\Client\TrustedHosts -Value "10.0.0.*" -Force ``` 本机批量执行: ```powershell $servers = Get-Content .\hosts.txt Invoke-Command -ComputerName $servers -ThrottleLimit 16 -ScriptBlock { [pscustomobject]@{ Host = $env:COMPUTERNAME C_Free = [math]::Round((Get-PSDrive C).Free / 1GB, 1) Uptime = (Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime } } | Sort-Object C_Free | Format-Table -AutoSize ``` 改服务: ```powershell Invoke-Command -ComputerName $servers -ScriptBlock { Restart-Service -Name Spooler -Force } ``` PowerShell 7 的并行写法: ```powershell $servers | ForEach-Object -Parallel { Invoke-Command -ComputerName $_ -ScriptBlock { hostname } } -ThrottleLimit 16 ``` ## 验证 ```powershell Test-WSMan -ComputerName 10.0.0.21 Invoke-Command -ComputerName 10.0.0.21 -ScriptBlock { $env:COMPUTERNAME } ``` ## 回滚 批量操作前先导出: ```powershell Invoke-Command -ComputerName $servers -ScriptBlock { Get-Service | Export-Csv "C:\temp\services_$env:COMPUTERNAME.csv" -NoTypeInformation } ``` ## 坑 - **`Invoke-Command` 里的脚本在目标机执行**,本地变量要 `-ArgumentList` 传进去。 - 返回对象经过序列化,方法和部分属性会丢。 - WinRM 默认 HTTP,跨网段要配 HTTPS 或 TrustedHosts。 - 凭据不能直接传字符串,用 `$cred = Get-Credential` 或 PSCredential 对象。 - 大批量时不开 `-ThrottleLimit`,默认只并发 32,其实还好但目标机可能受不了。 - 改注册表/服务的脚本先在一台上验证,别一次推全网。