windows
Windows
配置代理#
环境变量:别用 SetEnvironmentVariable 改 PATH#
环境变量存在注册表两级:
登录时合并,PATH 是特例:机器级在前、用户级在后(其他变量是用户级覆盖机器级)。
值类型决定 %VAR% 能不能展开:
[System.Environment]::SetEnvironmentVariable 写的是 REG_SZ。 用它改一次 PATH,里面所有 %VAR% 引用就被烤成绝对路径 —— 这就是「环境变量一改,路径全展开了」的根源。系统属性面板里那个 GUI 编辑器同样会展开。
正确写法是显式指定类型:
读未展开的原始值(否则你看到的已经是展开后的结果):
改完广播一下,已运行的进程才会重新读取(新进程才生效,已开的终端不会变):
该用变量的地方用变量#
stock Windows 的机器级 PATH 本来就是变量形式,被 GUI 展开过的机器会变成写死的绝对路径。恢复过来,换 JDK 或 CUDA 版本时只需改一个变量:
用户级同理,全部走 %USERPROFILE%\…。
但 Program Files 不要换成 %ProgramFiles% —— 32 位进程里它会展开成 Program Files (x86),会引入很难查的问题。stock Windows 自己也只对系统目录用变量。
CUDA 用 %CUDA_PATH% 而不是 %CUDA_PATH_V12_9%:前者指向当前启用的版本,后者是版本锁定的别名,用后者就失去意义了。
改动前后务必比对展开后的值是否一致,不一致就回滚:
安装器会把它改回去#
改好之后不是一劳永逸的。[Environment]::SetEnvironmentVariable 是 .NET 里最顺手的那个
API,第三方安装器普遍拿它往用户 PATH 里写东西 —— 哪怕只是「读一遍、确认自己已经在里面、
再原样写回」,也足以把类型打回 REG_SZ、把所有 %VAR% 烤成字面量。
判断是不是被改了,看用户级这几项就够(机器级安装器很少碰):
想找是谁改的,对比注册表键的最后写入时间和最近安装的程序目录 —— 时间通常就差一两分钟:
与其反复手修,不如在 $PROFILE 里放一段自愈 —— 开 shell 时检测到就改回来。只改表示形式,
展开后的值不变,所以是幂等的;平时只多一次注册表读取:
那个「展开后必须一致才写」的判断别省 —— 万一条目里有本就该保留的字面量家目录路径, 这一步能防止误改。
SSH 会话里的「不受信任的装入点」#
在 Windows 11 24H2 及以后的版本上,通过 SSH 登录后运行某些命令会报:
原因是这一代 Windows 收紧了 SSH 会话对 reparse point(符号链接 / junction)的穿透。 本地开终端不受影响,所以问题只在 ssh 过去时出现。
先确认是不是这一类#
看到「不受信任的装入点」或 untrusted mount point 就是它,不用往别处查。
关键变量是系统版本,不是配置:
三项配置全同、只有系统版本不同,所以这不是哪里配错了。
两条弯路可以省掉:fsutil behavior set SymlinkEvaluation R2L:1 对这个场景无效
(L2L/R2L 指的是链接和目标各自在本地还是网络路径,两端都在 C: 盘时属于 L2L,本来就是启用的);
登录令牌类型也不是原因,Win10 那台同样是 NETWORK 令牌却一切正常。
三种修法#
一、junction 被拦 → 用原生 API 重建。 mklink /J 建出来的能正常穿透,
各语言的库自己写 reparse 数据建出来的则不一定:
二、WinGet 的 shim 被拦 → 把真实包目录前置到 PATH。
WinGet\Links 下全是符号链接,绕开它直接指向 WinGet\Packages\<包 ID>:
三、装 / 升级这类操作到本地或 RDP 做。 pnpm 的 node_modules 就是靠大量 junction 搭起来的,
在 SSH 会话里读不了自己刚建的链接,安装必然失败。已经装好的东西正常使用不受影响。
不建议为此改用密码认证 —— 那样能拿到完整令牌,但要放弃免密登录,不划算。