上周我给一台 Windows 11 测试机配置代理时,又碰到了那个很典型的问题:浏览器已经能走代理,PowerShell 下载脚本却还是直连;把 PowerShell 调通后,后台服务又不认。
问题不一定出在代理本身,而是 Windows 并不存在一个能让所有程序同时生效的“代理总开关”。
通常所说的 Windows 系统代理,至少涉及三套配置:
| 配置位置 | 主要影响范围 | 是否需要管理员权限 |
|---|---|---|
| Windows Internet 设置,也叫 WinINET | Edge、Chrome及使用系统 Internet 设置的桌面程序 | 否,默认只影响当前用户 |
| WinHTTP | 使用 WinHTTP 的服务、后台程序和部分系统组件 | 是 |
HTTP_PROXY、HTTPS_PROXY 环境变量 |
PowerShell 7、Git、Python、Node.js 等主动读取变量的程序 | 用户级不需要,计算机级需要 |
所以,如果目标是让浏览器、PowerShell 命令行工具和后台程序尽可能使用同一个代理,不能只改 Windows 设置页面里的一个开关。
先确定代理地址格式
下面以本机代理为例:
$ProxyServer = "127.0.0.1:7890"
$BypassList = "localhost;127.0.0.1;<local>"
如果使用远程 HTTP 代理,把地址替换成实际的服务器和端口:
$ProxyServer = "proxy.example.com:8080"
这里不要直接写账号和密码。带认证的代理应由具体程序通过凭据参数完成认证,避免把密码明文留在注册表、脚本或环境变量中。
配置当前用户的 Windows 系统代理
Windows 10 和 Windows 11 设置页面中的“手动设置代理”,对应的主要是当前用户 Internet 设置。可以通过 PowerShell 修改:
$ProxyServer = "127.0.0.1:7890"
$BypassList = "localhost;127.0.0.1;<local>"
$InternetSettings = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
Set-ItemProperty `
-Path $InternetSettings `
-Name ProxyEnable `
-Type DWord `
-Value 1
Set-ItemProperty `
-Path $InternetSettings `
-Name ProxyServer `
-Type String `
-Value $ProxyServer
Set-ItemProperty `
-Path $InternetSettings `
-Name ProxyOverride `
-Type String `
-Value $BypassList
执行后,可以到以下位置核对:
设置 → 网络和 Internet → 代理 → 手动设置代理
也可以直接在 PowerShell 中读取:
Get-ItemProperty `
-Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" |
Select-Object ProxyEnable, ProxyServer, ProxyOverride
需要注意,这套配置虽然在 Windows 页面里常被称为“系统代理”,但默认仍然属于当前登录用户,并不等于整台电脑上所有账户和服务都会使用。
如果以另一个管理员账号运行 PowerShell,HKCU 指向的也是那个管理员账号,而不是原来的登录用户。批量部署时,这个细节很容易导致配置位置不对。
配置计算机级 WinHTTP 代理
需要让使用 WinHTTP 的后台程序访问代理时,应在管理员 PowerShell 中执行:
netsh winhttp set proxy `
proxy-server="127.0.0.1:7890" `
bypass-list="localhost;127.0.0.1;<local>"
查询当前配置:
netsh winhttp show proxy
正常情况下会看到代理服务器和绕过列表。如果显示:
Direct access (no proxy server).
说明 WinHTTP 仍然采用直连。
也可以先在 Windows 设置页面配好当前用户代理,再将该配置导入 WinHTTP:
netsh winhttp import proxy source=ie
命令中的 ie 是历史名称。即使 Windows 11 已经不再使用 Internet Explorer,它仍表示 Windows Internet 设置。
微软官方文档将 WinHTTP 定义为应用程序发出 HTTP 请求时使用的一套 Windows API。它与当前用户 Internet 设置是两个不同的配置位置,因此浏览器能访问,不代表 WinHTTP 程序一定能访问。
设置计算机级代理环境变量
PowerShell 7、Git、Python、Node.js 和不少跨平台命令行工具会读取以下变量:
HTTP_PROXYHTTPS_PROXYNO_PROXY
在管理员 PowerShell 中,可以将变量写入计算机级环境:
$ProxyUrl = "http://127.0.0.1:7890"
$NoProxy = "localhost,127.0.0.1,::1"
[Environment]::SetEnvironmentVariable(
"HTTP_PROXY",
$ProxyUrl,
"Machine"
)
[Environment]::SetEnvironmentVariable(
"HTTPS_PROXY",
$ProxyUrl,
"Machine"
)
[Environment]::SetEnvironmentVariable(
"NO_PROXY",
$NoProxy,
"Machine"
)
计算机级环境变量不会自动注入已经启动的程序。配置后,我一般会关闭原来的 PowerShell、VS Code、Git 客户端和终端窗口,再重新打开。
检查计算机级变量:
[Environment]::GetEnvironmentVariable("HTTP_PROXY", "Machine")
[Environment]::GetEnvironmentVariable("HTTPS_PROXY", "Machine")
[Environment]::GetEnvironmentVariable("NO_PROXY", "Machine")
只想在当前 PowerShell 窗口临时使用代理,可以设置进程级变量:
$env:HTTP_PROXY = "http://127.0.0.1:7890"
$env:HTTPS_PROXY = "http://127.0.0.1:7890"
$env:NO_PROXY = "localhost,127.0.0.1,::1"
窗口关闭后,这组临时变量就会消失。
一次配置三套代理
如果这是一台开发机或临时测试机,可以使用下面的脚本同时配置当前用户 Internet 设置、WinHTTP 和计算机级环境变量。
脚本需要在管理员 PowerShell 中执行:
param(
[string]$ProxyServer = "127.0.0.1:7890",
[string]$BypassList = "localhost;127.0.0.1;<local>"
)
$ErrorActionPreference = "Stop"
$InternetSettings = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
$ProxyUrl = "http://$ProxyServer"
Write-Host "正在配置当前用户 Windows 代理……"
Set-ItemProperty `
-Path $InternetSettings `
-Name ProxyEnable `
-Type DWord `
-Value 1
Set-ItemProperty `
-Path $InternetSettings `
-Name ProxyServer `
-Type String `
-Value $ProxyServer
Set-ItemProperty `
-Path $InternetSettings `
-Name ProxyOverride `
-Type String `
-Value $BypassList
Write-Host "正在配置 WinHTTP 代理……"
& netsh winhttp set proxy `
proxy-server="$ProxyServer" `
bypass-list="$BypassList"
Write-Host "正在配置计算机级环境变量……"
[Environment]::SetEnvironmentVariable(
"HTTP_PROXY",
$ProxyUrl,
"Machine"
)
[Environment]::SetEnvironmentVariable(
"HTTPS_PROXY",
$ProxyUrl,
"Machine"
)
[Environment]::SetEnvironmentVariable(
"NO_PROXY",
"localhost,127.0.0.1,::1",
"Machine"
)
Write-Host "代理配置完成。请重新打开 PowerShell 和相关应用。"
三套配置同时写入的好处是覆盖范围更广,但不代表所有程序都会强制使用代理。应用程序仍然可以使用自己的网络设置,或者完全忽略系统代理和环境变量。
验证代理是否真正生效
先检查代理服务器端口是否可以连接:
Test-NetConnection 127.0.0.1 -Port 7890
TcpTestSucceeded 为 True,只能说明端口可达,不能说明 HTTP 请求已经成功经过代理。
接着重新打开一个 PowerShell 窗口,查询出口 IP:
Invoke-RestMethod -Uri "https://api.ipify.org?format=json"
记录返回结果,再关闭代理重新测试。如果两次出口 IP 不同,通常说明请求已经切换到代理出口。
也可以显式指定代理,单独排除系统设置问题:
$Proxy = "http://127.0.0.1:7890"
Invoke-RestMethod `
-Uri "https://api.ipify.org?format=json" `
-Proxy $Proxy
如果显式指定代理可以访问,而不带 -Proxy 时仍然直连,问题一般在系统配置继承、PowerShell 会话缓存或应用兼容性上,不必急着更换代理地址。
对于需要账号密码认证的 HTTP 代理,可以临时读取凭据:
$Credential = Get-Credential
Invoke-WebRequest `
-Uri "https://example.com" `
-Proxy "http://proxy.example.com:8080" `
-ProxyCredential $Credential
这样至少不会把密码直接写进脚本。
关闭并恢复直连
取消当前用户的 Windows 代理:
$InternetSettings = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
Set-ItemProperty `
-Path $InternetSettings `
-Name ProxyEnable `
-Type DWord `
-Value 0
重置 WinHTTP:
netsh winhttp reset proxy
清除计算机级环境变量:
[Environment]::SetEnvironmentVariable("HTTP_PROXY", $null, "Machine")
[Environment]::SetEnvironmentVariable("HTTPS_PROXY", $null, "Machine")
[Environment]::SetEnvironmentVariable("NO_PROXY", $null, "Machine")
清除当前 PowerShell 窗口中的临时变量:
Remove-Item Env:HTTP_PROXY -ErrorAction SilentlyContinue
Remove-Item Env:HTTPS_PROXY -ErrorAction SilentlyContinue
Remove-Item Env:NO_PROXY -ErrorAction SilentlyContinue
最后关闭并重新打开相关程序。否则旧进程可能继续使用启动时缓存的代理信息。
我实际采用的判断顺序
遇到“Windows 已经设置代理,但某个程序不生效”时,我一般按这个顺序检查:
- 用
Test-NetConnection确认代理地址和端口可达。 - 用带
-Proxy的请求确认代理服务本身能工作。 - 检查当前用户 Internet 设置。
- 检查
netsh winhttp show proxy。 - 检查用户级、计算机级和当前进程的代理环境变量。
- 重新启动 PowerShell 和目标程序。
- 最后再排查组策略、VPN客户端及安全软件是否覆盖配置。
Windows 的代理问题看起来零散,实际上大多是配置层级没有对上。先确认目标程序读取 WinINET、WinHTTP 还是环境变量,再决定修改哪一层,比反复开关“使用代理服务器”更有效。
常见问题
Q:为什么浏览器能走代理,PowerShell 还是直连?
浏览器可能读取的是当前用户 Internet 设置,而 PowerShell 版本、具体模块或底层 HTTP 库读取的配置不同。
Windows PowerShell 5.1通常优先使用系统 Internet 设置。PowerShell 7除系统设置外,还可以通过HTTP_PROXY、HTTPS_PROXY和NO_PROXY环境变量配置。修改系统代理后,最好重新启动 PowerShell 会话。
Q:为什么 PowerShell 能访问,Windows 后台服务不行?
你可能只设置了环境变量,或者只修改了当前用户的代理。后台服务往往不读取当前用户环境,需要单独检查 WinHTTP:
netsh winhttp show proxy
Q:为什么代理设置重启后又被改回去了?
常见原因包括组策略、终端管理软件、VPN 客户端、安全软件或本地代理程序重新写入配置。
可以先检查:
gpresult /h "$env:USERPROFILE\Desktop\gp-report.html"
如果设备由公司统一管理,不建议持续用脚本覆盖策略,应先确认管理员下发的代理规则。
Q:NO_PROXY和ProxyOverride为什么写法不同?
它们属于不同配置体系:
ProxyOverride通常使用分号分隔。NO_PROXY通常使用逗号分隔。
为了兼容多套工具,脚本中应分别设置,不要直接复制同一个字符串。
Q:SOCKS5代理能否直接设为Windows系统代理?
部分程序支持,但不能假定 WinINET、WinHTTP 和所有命令行工具都会以相同方式处理 SOCKS5。
如果只有 SOCKS5 出口,我通常会先通过本地代理客户端将其转换成 HTTP 代理端口,再把该 HTTP 端口配置给 Windows 和 PowerShell。这样排查起来更直接。