# P0-05 本机 NX 环境残留清理方案

> 脚本：`D:\NX_AI\tools\cleanup_residue.ps1`（UTF-8 BOM，PS5.1）
> 产出：备份目录 `D:\NX_AI\backup\<时间戳>\`
> 状态：**本方案只生成脚本 + DryRun 输出，未执行 -Apply**

---

## 一、实测到的 4 处残留

| # | 残留 | 当前值 | 影响 | 实测来源 |
|---|---|---|---|---|
| 1 | `UGII_VENDOR_DIR`(用户级) | `E:\...\NX2412\UGII\vendor` | 单值硬指向 NX2412，NX2212 的 `vendor\` 目录被忽略，里面的 `NxCamWizard` 形同虚设 | `GetEnvironmentVariable('UGII_VENDOR_DIR','User')` |
| 2 | `UGII_LOCAL_USER_DEFAULTS`(用户级) | `...\Roaming\NxCamWizard\nx_user.dpv` | 这个 dpv 文件**永久关闭了整机 NXOpen 签名过期警告**（NxCamWizard 安装器的副作用） | Registry + `Test-Path` |
| 3 | `UGII_USER_DIR`(用户级) | `NxCamToolkit\bridge` | bridge 目录里有 40 文件（2 DLL + 22 Python + 1 .men），**实测无 NxCamWizard 文件混装**（任务书描述的混装情况不存在）。但 bridge 目录是旧项目遗留（NxAiBridge.dll v0.0.0.0） | `Get-ChildItem -Recurse` |
| 4 | 两个 `NxCamWizard.dll` 版本不一致 | NX2212=9/5 14:22 (SHA256=`dc534001`) vs NX2412=8/31 17:29 (SHA256=`dc59d169`) | 两个 DLL FileVersion 都显示 `1.0.0.0`，但哈希确实不同（编译时间差了 5 天）。多版本共存没问题，但要知道它们不是同一份编译产物 | `Get-FileHash` |

**额外残留**（脚本只报告不清）：
- `UGII_BASE_DIR`(机器级) = `E:\Program Files\Siemens\NX2412` — 可能是 NX 启动必需，不动

---

## 二、脚本用法

```powershell
# DryRun（默认）——只打印将要做的事，零写操作
powershell -NoProfile -ExecutionPolicy Bypass -File D:\NX_AI\tools\cleanup_residue.ps1

# Apply —— 自动备份 + 二次确认后执行真实清理
# 注意：首次运行会在 D:\NX_AI\backup\下创建带时间戳的备份目录
powershell -NoProfile -ExecutionPolicy Bypass -File D:\NX_AI\tools\cleanup_residue.ps1 -Apply

# Restore —— 从备份完整还原环境变量和 NxCamWizard 目录
powershell -NoProfile -ExecutionPolicy Bypass -File D:\NX_AI\tools\cleanup_residue.ps1 -Restore "D:\NX_AI\backup\20261016140414"

# -Force —— 跳过二次确认（配合 -Apply 或 -Restore）
powershell -NoProfile -ExecutionPolicy Bypass -File D:\NX_AI\tools\cleanup_residue.ps1 -Apply -Force
```

### 备份目录结构（-Apply 执行前自动创建）

```
D:\NX_AI\backup\yyyyMMddHHmmss\
├── env_vars.json              ← 全部 UGII_* 环境变量快照（8 个）
├── NX2212_NxCamWizard\       ← NX2212 vendor\NxCamWizard 完整副本（13 文件）
├── NX2412_NxCamWizard\       ← NX2412 vendor\NxCamWizard 完整副本（13 文件）
├── dpv\                      ← nx_user.dpv + nx_user.xsl 副本
└── cleanup_manifest.json     ← 本次清理动作记录（Apply 完成后写入）
```

### DryRun vs Apply 行为差异

| 动作 | DryRun | Apply |
|---|---|---|
| 创建备份目录 | ❌ 不创建 | ✅ 创建并写入 4 类备份 |
| 清用户级 `UGII_VENDOR_DIR` | ❌ 不执行 | ✅ 执行（二次确认） |
| 清用户级 `UGII_LOCAL_USER_DEFAULTS` | ❌ 不执行 | ✅ 执行（二次确认） |
| 隔离 dpv / xsl | ❌ 不执行 | ✅ 移动到 `*.isolated_<时间戳>` |
| 报告 `UGII_USER_DIR` | ✅ 打印 | ✅ 打印（不清理） |
| DLL 版本差异报告 | ✅ 打印 | ✅ 打印 |

---

## 三、清理动作逐条说明

### 动作 1：清除用户级 `UGII_VENDOR_DIR`

| 项目 | 内容 |
|---|---|
| **动什么** | `[Environment]::SetEnvironmentVariable('UGII_VENDOR_DIR', $null, 'User')` |
| **为什么** | 单值硬指向 NX2412，NX 启动时读进程里 `UGII_VENDOR_DIR` 优先；如果进程级没注入，就回退到这个单值，NX2212 的 vendor 目录被忽略。清掉后，NX 自动读 `<NX>\UGII\vendor\`（每个版本天然隔离） |
| **回滚** | `-Restore <备份目录>` 自动从 `env_vars.json` 读旧值写回 `[Environment]::SetEnvironmentVariable('UGII_VENDOR_DIR', 原值, 'User')` |
| **风险等级** | 🟢 低。进程级注入框架（nx_launch.ps1）会临时注入；不注入时 NX 自动用 `<NX>\UGII\vendor\`。唯一风险是如果有其他老插件**依赖这个单值**（实测没发现） |
| **备份** | 旧值写入 `env_vars.json` 的 `vars[].user` 字段 |

### 动作 2：清除用户级 `UGII_LOCAL_USER_DEFAULTS` + 隔离 dpv/xsl

| 项目 | 内容 |
|---|---|
| **动什么** | ① `[Environment]::SetEnvironmentVariable('UGII_LOCAL_USER_DEFAULTS', $null, 'User')`；② 把 `nx_user.dpv` 和 `nx_user.xsl` 移到同目录下 `*.isolated_<时间戳>` |
| **为什么** | 这个 dpv 文件是 NxCamWizard 安装器写的，用来**永久关闭整机的 NXOpen 签名过期警告**。它影响所有 NX 版本的所有用户。清掉后恢复 NX 默认警告行为 |
| **回滚** | `-Restore <备份目录>` 从备份目录拷回 dpv/xsl 原位置 + 恢复环境变量 |
| **风险等级** | 🟢 低。dpv 只是用户默认设置文件，不是系统文件。隔离而不是删除，随时能恢复 |
| **备份** | dpv/xsl 完整副本写入 `dpv\` 子目录 |

### 动作 3：保留 `UGII_USER_DIR`，报告 bridge 目录

| 项目 | 内容 |
|---|---|
| **动什么** | **只报告，不清理** |
| **为什么** | 任务书明确"保留 UGII_USER_DIR"。bridge 目录里有 40 文件（NxAiBridge.dll v0.0.0.0 + 22 Python probe 脚本），**实测无 NxCamWizard 文件混装**。bridge 目录是旧项目（NxAiBridge）遗留，后续 P0-07/P0-09 要重写文件信箱 IPC 协议时可能要动它 |
| **回滚** | N/A（只报告） |
| **风险等级** | 🟢 零（不做任何写操作） |

### 动作 4：两个 NxCamWizard DLL 版本差异报告

| 项目 | 内容 |
|---|---|
| **动什么** | **只报告，不清理** |
| **为什么** | 实测两个 DLL 哈希不同但 FileVersion 都是 1.0.0.0。多版本共存没问题（各 NX 读自己 vendor 目录里的）。但作为风险告知——旧 NxCamWizard 插件在不同 NX 版本上可能行为不一致 |
| **回滚** | N/A（只报告） |
| **风险等级** | 🟡 中（如果用户同时开两个 NX 版本用旧插件，行为可能不一致。但本方案不删任何 NX 安装目录文件） |

---

## 四、实测 DryRun 输出

```
[14:04:14] === cleanup_residue.ps1  模式: DRY-RUN  2026-10-16T14:04:14+08:00
[14:04:14] 检测到 NX 版本: 2212, 2412

--- Step 0: 备份 ---
[DRY] 将创建目录: D:\NX_AI\backup\20261016140414
[DRY] 将备份: env_vars.json, NX2212_NxCamWizard\, NX2412_NxCamWizard\, dpv\

--- Step 1: UGII_VENDOR_DIR 清理 ---
[WARN] 当前 = E:\...\NX2412\UGII\vendor
[DRY] 将执行: SetEnvironmentVariable('UGII_VENDOR_DIR', $null, 'User')

--- Step 2: UGII_LOCAL_USER_DEFAULTS + dpv 隔离 ---
[WARN] 当前 = ...\Roaming\NxCamWizard\nx_user.dpv
[DRY] 将隔离: nx_user.dpv -> nx_user.dpv.isolated_20261016140414
[DRY] 将隔离: nx_user.xsl -> nx_user.xsl.isolated_20261016140414

--- Step 3: UGII_USER_DIR 报告（保留）---
UGII_USER_DIR = C:\Users\Administrator\AppData\Local\NxCamToolkit\bridge
bridge 总文件数: 40  DLL: 2  Python: 22  .men: 1
✅ 无 NxCamWizard 文件混装

--- Step 4: 两个 NxCamWizard DLL 对比 ---
NX2212  [application]  243712B  2026-09-05 14:22  SHA256=dc534001...
NX2412  [application]  243712B  2026-08-31 17:29  SHA256=dc59d169...
⚠ SHA256 不一致（编译时间差 5 天）

--- Step 5: 额外残留报告 ---
机器级 UGII_BASE_DIR = NX2412（只报告不清）

=== DRY-RUN 完成（零写操作） ===
```

**DryRun 后零写验证**（已完成）：
- ✅ `D:\NX_AI\backup\20261016140414` 未创建
- ✅ `UGII_VENDOR_DIR(用户级)` 仍指向 NX2412
- ✅ `nx_user.dpv` 和 `nx_user.xsl` 仍在原位

---

## 五、人工执行清单（**不自动执行，需人工决策**）

### 时机建议
- 建议在**不运行任何 NX 的空闲时段**执行
- 执行前先手动跑一次 **NX2212 和 NX2412 各启动一次**（不用开 GUI，用 run_journal.exe 探活），确认 NX 本身没问题

### 执行步骤

```powershell
# ========== Step 1: DryRun 再次确认 ==========
powershell -NoProfile -ExecutionPolicy Bypass -File D:\NX_AI\tools\cleanup_residue.ps1

# ========== Step 2: Apply（会二次确认）==========
powershell -NoProfile -ExecutionPolicy Bypass -File D:\NX_AI\tools\cleanup_residue.ps1 -Apply
# → 脚本提示 "⚠  即将执行..." 时输入 Y 确认
# → 脚本提示二次确认环境变量清理时再次输入 Y
# → 脚本输出备份目录路径：D:\NX_AI\backup\yyyyMMddHHmmss\

# ========== Step 3: 执行后验证 ==========
powershell -NoProfile -Command "
  Write-Host '环境变量验证:'
  Write-Host ('  UGII_VENDOR_DIR(User) = ' + [Environment]::GetEnvironmentVariable('UGII_VENDOR_DIR','User'))
  Write-Host ('  UGII_LOCAL_USER_DEFAULTS(User) = ' + [Environment]::GetEnvironmentVariable('UGII_LOCAL_USER_DEFAULTS','User'))
  Write-Host ('  UGII_USER_DIR(User) = ' + [Environment]::GetEnvironmentVariable('UGII_USER_DIR','User'))
  Write-Host ''
  Write-Host 'dpv 文件验证（应看到 .isolated_* 后缀的文件）:'
  Get-ChildItem 'C:\Users\Administrator\AppData\Roaming\NxCamWizard' -Filter '*isolated*' | ForEach-Object { Write-Host ('  ' + $_.Name) }
  Write-Host ''
  Write-Host '备份目录验证（应存在且包含 env_vars.json）:'
  Get-ChildItem 'D:\NX_AI\backup' -Directory | Sort-Object LastWriteTime -Descending | Select-Object -First 1 | ForEach-Object {
    Write-Host ('  最新备份: ' + $_.FullName)
    Test-Path (Join-Path $_.FullName 'env_vars.json')
  }
"

# ========== Step 4: 紧急回滚（如需）==========
# 假设备份目录是 D:\NX_AI\backup\20261016140414
powershell -NoProfile -ExecutionPolicy Bypass -File D:\NX_AI\tools\cleanup_residue.ps1 -Restore "D:\NX_AI\backup\20261016140414"
```

### 执行后的预期状态

| 项目 | 执行前 | 执行后 |
|---|---|---|
| `UGII_VENDOR_DIR`(用户级) | `E:\...\NX2412\UGII\vendor` | **空**（NX 自动用 `<NX>\UGII\vendor\`） |
| `UGII_LOCAL_USER_DEFAULTS`(用户级) | `...\NxCamWizard\nx_user.dpv` | **空** |
| `nx_user.dpv` / `nx_user.xsl` | 原位存在 | `*.isolated_<时间戳>` 后缀（原位置无此文件） |
| `UGII_USER_DIR`(用户级) | bridge 目录 | **不变**（保留） |
| `UGII_BASE_DIR`(机器级) | NX2412 | **不变**（不动） |
| 两个 vendor\NxCamWizard | 各 13 文件 | **不变**（不动 NX 安装目录） |
| `D:\NX_AI\backup\<时间戳>\` | 不存在 | **存在**（含完整备份） |

---

## 六、关于"任务书里提到的 4 个残留"与"实测差异"的说明

| 任务书描述 | 实测情况 | 结论 |
|---|---|---|
| "两个 NX 的 vendor\NxCamWizard 里 DLL 版本不一致（NX2212 是 9/5 版，NX2412 是 8/31 版）" | ✅ 确认。NX2212 DLL 9/5 14:22、NX2412 DLL 8/31 17:29，哈希不同但 FileVersion 都 1.0.0.0 | 任务书描述准确 |
| "UGII_USER_DIR 指向 NxCamToolkit\bridge，而 NxCamWizard 的安装器会'检测到它就再装一份'，两个插件的文件混在同一个 startup\ 目录里" | ❌ 实测 bridge 目录里**没有 NxCamWizard 文件**（只有 NxAiBridge.dll + Python probe 脚本） | 混装情况当前不存在。bridge 目录是旧项目（NxAiBridge），NxCamWizard 的文件只在 vendor 目录里 |
| "UGII_LOCAL_USER_DEFAULTS 指向 nx_user.dpv，永久关闭了整机的 NXOpen 签名过期警告" | ✅ 确认。dpv/xsl 都在 Roaming\NxCamWizard 下，UGII_LOCAL_USER_DEFAULTS 指向它 | 任务书描述准确 |

---

## 七、安全性声明

1. **DryRun 模式零写操作**：已实测验证。脚本不会创建备份目录、不会修改任何环境变量、不会移动任何文件
2. **Apply 模式先备份再清理**：备份目录包含所有被清理内容的完整副本
3. **Restore 与 Apply 严格对称**：环境变量按原值写回、NxCamWizard 目录从备份还原、dpv/xsl 从备份拷回原位
4. **不动 NX 安装目录文件**：脚本不删除/修改任何 `<NX>\` 下的官方文件或用户文件（NxCamWizard DLL 只备份不清理）
5. **二次确认机制**：Apply 执行时每个清理动作前都会提示确认（可手动 Y/N 或用 -Force 跳过）
6. **UTF-8 编码**：环境变量快照 JSON 用 UTF-8 无 BOM；脚本本身 UTF-8 有 BOM（PS5.1 正确解析中文必需）
