## 甲1 杀软实名泛化(6 行) `主流杀软 / 杀软 / 360` → 「主流杀毒软件 / 杀软」: - docs/REMOTE-LIMITS.md:标题 + 正文 + 表格两处(保留"会拦什么"的实操信息,去掉具体厂牌) - scripts/release.mjs:278:Release 正文模板里的信任区提示 - apps/cli/src/cmd/ops.ts:398:部署失败排查提示 ## 甲2 网卡名示例泛化(13 行) 「Ethernet」→ `Ethernet`(示例)/泛化为"中文网卡名"(讲原理时): - docs/REMOTE-LIMITS.md 网络适配器表格、ROADMAP 该项标记为已完成 - scripts/rescue-network.ps1 参数说明、automation.ts 的 interface 描述 - apps/agent/src/capabilities/network.ts 注释:改为"脚本里的非 ASCII 字符(如中文网卡名)" —— **保留"为什么"的教训,去掉具体实况** - tests/unit/net-scripts.test.mjs:8 处测试数据与正则断言同步改为 Ethernet ## 验证 工作区残留「主流杀软/杀软/Ethernet」= **0 处**;单测 273 全绿;7 包构建通过。
150 lines
7.2 KiB
PowerShell
150 lines
7.2 KiB
PowerShell
<#
|
||
.SYNOPSIS
|
||
nodeagent 网络救援脚本 —— 被控端因网络变更失联后的本地恢复。
|
||
|
||
.DESCRIPTION
|
||
背景:`system.net.apply` 是两阶段提交(未确认自动回滚),但**如果回滚本身也失败**
|
||
(例如变更脚本把地址删掉了却没加上),机器可能落到 APIPA(169.254.x.x)而彻底失联。
|
||
这个脚本就是为那一天准备的:在**被控端本机**以管理员运行,把网络恢复到可用状态。
|
||
|
||
它做的事:
|
||
1. 列出所有网卡与当前地址(先看清现状)
|
||
2. 找出「有物理连接、但没有有效 IPv4」的网卡(典型的失联状态)
|
||
3. 把指定/自动识别的网卡设回给定静态地址,或切回 DHCP
|
||
4. 用**原生 NetTCPIP cmdlet** 按安全顺序执行:
|
||
先加地址 → 再清其它地址与残留默认路由 → 最后补默认路由
|
||
(顺序颠倒会踩 Windows 的「already exists」而再次失败 —— 真机事故根因)
|
||
|
||
.PARAMETER Interface
|
||
网卡别名(如 'Ethernet';中文系统常见为「网络」类名称)。省略则自动选取「已连接但无有效 IPv4」的那块。
|
||
|
||
.PARAMETER Ip / PrefixLength / Gateway / Dns
|
||
要恢复的静态配置;省略 Ip 则切回 DHCP。
|
||
|
||
.PARAMETER ListOnly
|
||
只看现状,不做任何变更。
|
||
|
||
.EXAMPLE
|
||
# 先看现状
|
||
powershell -ExecutionPolicy Bypass -File rescue-network.ps1 -ListOnly
|
||
|
||
.EXAMPLE
|
||
# 恢复为原静态地址(最常用)
|
||
powershell -ExecutionPolicy Bypass -File rescue-network.ps1 `
|
||
-Interface 'Ethernet' -Ip 192.168.1.100 -PrefixLength 24 -Gateway 192.168.1.1
|
||
|
||
.EXAMPLE
|
||
# 切回 DHCP(家里路由器会重新分配地址)
|
||
powershell -ExecutionPolicy Bypass -File rescue-network.ps1 -Interface 'Ethernet'
|
||
#>
|
||
[CmdletBinding()]
|
||
param(
|
||
[string]$Interface,
|
||
[string]$Ip,
|
||
[int]$PrefixLength = 24,
|
||
[string]$Gateway,
|
||
[string[]]$Dns,
|
||
[switch]$ListOnly
|
||
)
|
||
|
||
$ErrorActionPreference = 'Continue'
|
||
|
||
function Write-Step($m) { Write-Host "[*] $m" -ForegroundColor Cyan }
|
||
function Write-Ok($m) { Write-Host "[+] $m" -ForegroundColor Green }
|
||
function Write-Warn2($m) { Write-Host "[!] $m" -ForegroundColor Yellow }
|
||
function Write-Err2($m) { Write-Host "[x] $m" -ForegroundColor Red }
|
||
|
||
Write-Host ""
|
||
Write-Host " nodeagent 网络救援" -ForegroundColor White
|
||
Write-Host " ------------------" -ForegroundColor DarkGray
|
||
|
||
# ---------- 1. 现状 ----------
|
||
Write-Step "当前网卡与地址:"
|
||
$adapters = Get-NetAdapter | Sort-Object ifIndex
|
||
foreach ($a in $adapters) {
|
||
$addrs = @(Get-NetIPAddress -InterfaceIndex $a.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
||
Where-Object { $_.PrefixOrigin -ne 'WellKnown' } | ForEach-Object { "$($_.IPAddress)/$($_.PrefixLength)" })
|
||
$dhcp = (Get-NetIPInterface -InterfaceIndex $a.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue).Dhcp
|
||
$mark = if ($a.Status -eq 'Up' -and $addrs.Count -eq 0) { ' <== 已连接但无地址(疑似失联)' } else { '' }
|
||
Write-Host (" {0,-22} {1,-8} dhcp={2,-8} {3}{4}" -f $a.Name, $a.Status, $dhcp, ($addrs -join ', '), $mark)
|
||
}
|
||
|
||
$gw = @(Get-NetRoute -AddressFamily IPv4 -DestinationPrefix '0.0.0.0/0' -ErrorAction SilentlyContinue |
|
||
ForEach-Object { "$($_.NextHop) (ifIndex $($_.ifIndex))" })
|
||
# 注意:PowerShell 5.1 的 if 不能当表达式内联在括号里 —— 必须先算好再拼(写错会直接语法错误)
|
||
$gwText = if ($gw.Count -gt 0) { $gw -join ', ' } else { '(无 —— 这就是回包发不出去的原因)' }
|
||
Write-Step ("默认路由: " + $gwText)
|
||
|
||
if ($ListOnly) { Write-Host ""; Write-Ok "仅查看模式,未做任何变更"; exit 0 }
|
||
|
||
# ---------- 2. 选目标网卡 ----------
|
||
if (-not $Interface) {
|
||
$cand = $adapters | Where-Object {
|
||
$_.Status -eq 'Up' -and
|
||
@(Get-NetIPAddress -InterfaceIndex $_.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
||
Where-Object { $_.PrefixOrigin -ne 'WellKnown' }).Count -eq 0
|
||
} | Select-Object -First 1
|
||
if (-not $cand) {
|
||
$cand = $adapters | Where-Object { $_.Status -eq 'Up' } | Select-Object -First 1
|
||
}
|
||
if (-not $cand) { Write-Err2 "找不到可用的已连接网卡,请用 -Interface 指定"; exit 1 }
|
||
$Interface = $cand.Name
|
||
Write-Warn2 "未指定网卡,自动选用:$Interface"
|
||
}
|
||
|
||
if (-not (Get-NetAdapter -Name $Interface -ErrorAction SilentlyContinue)) {
|
||
Write-Err2 "网卡不存在:$Interface"; exit 1
|
||
}
|
||
|
||
# ---------- 3. 执行 ----------
|
||
if (-not $Ip) {
|
||
Write-Step "切回 DHCP:$Interface"
|
||
Set-NetIPInterface -InterfaceAlias $Interface -Dhcp Enabled -ErrorAction SilentlyContinue
|
||
Set-DnsClientServerAddress -InterfaceAlias $Interface -ResetServerAddresses -ErrorAction SilentlyContinue
|
||
Write-Ok "已切回 DHCP(稍等几秒应拿到地址)"
|
||
} else {
|
||
Write-Step "恢复静态地址 $Ip/$PrefixLength (网卡 $Interface)"
|
||
Set-NetIPInterface -InterfaceAlias $Interface -Dhcp Disabled -ErrorAction SilentlyContinue
|
||
|
||
# ⚠️ 顺序不可颠倒:先加新地址(过渡期链路不断),再清旧地址/残留路由,最后补路由。
|
||
# 颠倒会触发 Windows 的「实例已存在」→ 地址加不上 → 再次失联(真机事故根因)。
|
||
New-NetIPAddress -InterfaceAlias $Interface -IPAddress $Ip -PrefixLength $PrefixLength -ErrorAction SilentlyContinue | Out-Null
|
||
|
||
Get-NetRoute -InterfaceAlias $Interface -DestinationPrefix '0.0.0.0/0' -ErrorAction SilentlyContinue |
|
||
Remove-NetRoute -Confirm:$false -ErrorAction SilentlyContinue
|
||
|
||
Get-NetIPAddress -InterfaceAlias $Interface -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
||
Where-Object { $_.IPAddress -ne $Ip -and $_.PrefixOrigin -ne 'WellKnown' } |
|
||
ForEach-Object { Remove-NetIPAddress -IPAddress $_.IPAddress -InterfaceAlias $Interface -Confirm:$false -ErrorAction SilentlyContinue }
|
||
|
||
if ($Gateway) {
|
||
New-NetRoute -InterfaceAlias $Interface -DestinationPrefix '0.0.0.0/0' -NextHop $Gateway -ErrorAction SilentlyContinue | Out-Null
|
||
}
|
||
if ($Dns -and $Dns.Count -gt 0) {
|
||
Set-DnsClientServerAddress -InterfaceAlias $Interface -ServerAddresses $Dns -ErrorAction SilentlyContinue
|
||
}
|
||
}
|
||
|
||
Start-Sleep -Seconds 3
|
||
|
||
# ---------- 4. 自检 ----------
|
||
Write-Step "自检:"
|
||
$now = @(Get-NetIPAddress -InterfaceAlias $Interface -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
||
Where-Object { $_.PrefixOrigin -ne 'WellKnown' } | ForEach-Object { "$($_.IPAddress)/$($_.PrefixLength)" })
|
||
$nowGw = @(Get-NetRoute -InterfaceAlias $Interface -AddressFamily IPv4 -DestinationPrefix '0.0.0.0/0' -ErrorAction SilentlyContinue |
|
||
ForEach-Object { $_.NextHop })
|
||
|
||
if ($now.Count -gt 0) {
|
||
Write-Ok ("地址: " + ($now -join ', '))
|
||
if ($Ip -and $nowGw.Count -eq 0) {
|
||
Write-Warn2 "没有默认路由 —— 只能同网段互访;请补 -Gateway"
|
||
} elseif ($nowGw.Count -gt 0) {
|
||
Write-Ok ("默认路由: " + ($nowGw -join ', '))
|
||
}
|
||
Write-Host ""
|
||
Write-Ok "网络已恢复。可在 Mac 上执行: nodeagent connect $($now[0].Split('/')[0]) --port 8765 --key <PSK> --insecure"
|
||
} else {
|
||
Write-Err2 "仍然没有有效地址 —— 请检查网线/交换机,或尝试: rescue-network.ps1 -Interface '$Interface'(不带 -Ip,切回 DHCP)"
|
||
exit 1
|
||
}
|