Windows PowerShell 设置 HTTP 代理:系统级配置完整教程

简介: Windows代理无“总开关”!浏览器、PowerShell、后台服务各走一套配置:WinINET(用户级)、WinHTTP(系统级)、环境变量(跨平台工具)。本文详解三者 PowerShell 配置、验证与恢复,助你精准穿透代理迷雾。

上周我给一台 Windows 11 测试机配置代理时,又碰到了那个很典型的问题:浏览器已经能走代理,PowerShell 下载脚本却还是直连;把 PowerShell 调通后,后台服务又不认。

问题不一定出在代理本身,而是 Windows 并不存在一个能让所有程序同时生效的“代理总开关”。

通常所说的 Windows 系统代理,至少涉及三套配置:

配置位置 主要影响范围 是否需要管理员权限
Windows Internet 设置,也叫 WinINET Edge、Chrome及使用系统 Internet 设置的桌面程序 否,默认只影响当前用户
WinHTTP 使用 WinHTTP 的服务、后台程序和部分系统组件
HTTP_PROXYHTTPS_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_PROXY
  • HTTPS_PROXY
  • NO_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

TcpTestSucceededTrue,只能说明端口可达,不能说明 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 已经设置代理,但某个程序不生效”时,我一般按这个顺序检查:

  1. Test-NetConnection确认代理地址和端口可达。
  2. 用带-Proxy的请求确认代理服务本身能工作。
  3. 检查当前用户 Internet 设置。
  4. 检查netsh winhttp show proxy
  5. 检查用户级、计算机级和当前进程的代理环境变量。
  6. 重新启动 PowerShell 和目标程序。
  7. 最后再排查组策略、VPN客户端及安全软件是否覆盖配置。

Windows 的代理问题看起来零散,实际上大多是配置层级没有对上。先确认目标程序读取 WinINET、WinHTTP 还是环境变量,再决定修改哪一层,比反复开关“使用代理服务器”更有效。

常见问题

Q:为什么浏览器能走代理,PowerShell 还是直连?

浏览器可能读取的是当前用户 Internet 设置,而 PowerShell 版本、具体模块或底层 HTTP 库读取的配置不同。

Windows PowerShell 5.1通常优先使用系统 Internet 设置。PowerShell 7除系统设置外,还可以通过HTTP_PROXYHTTPS_PROXYNO_PROXY环境变量配置。修改系统代理后,最好重新启动 PowerShell 会话。

Q:为什么 PowerShell 能访问,Windows 后台服务不行?

你可能只设置了环境变量,或者只修改了当前用户的代理。后台服务往往不读取当前用户环境,需要单独检查 WinHTTP:

netsh winhttp show proxy

Q:为什么代理设置重启后又被改回去了?

常见原因包括组策略、终端管理软件、VPN 客户端、安全软件或本地代理程序重新写入配置。

可以先检查:

gpresult /h "$env:USERPROFILE\Desktop\gp-report.html"

如果设备由公司统一管理,不建议持续用脚本覆盖策略,应先确认管理员下发的代理规则。

Q:NO_PROXYProxyOverride为什么写法不同?

它们属于不同配置体系:

  • ProxyOverride通常使用分号分隔。
  • NO_PROXY通常使用逗号分隔。

为了兼容多套工具,脚本中应分别设置,不要直接复制同一个字符串。

Q:SOCKS5代理能否直接设为Windows系统代理?

部分程序支持,但不能假定 WinINET、WinHTTP 和所有命令行工具都会以相同方式处理 SOCKS5。

如果只有 SOCKS5 出口,我通常会先通过本地代理客户端将其转换成 HTTP 代理端口,再把该 HTTP 端口配置给 Windows 和 PowerShell。这样排查起来更直接。

相关文章
人工智能 缓存 前端开发
11591 56
人工智能 JavaScript 开发工具
4579 17
开发工具 Swift git
1849 5
Web App开发 人工智能 API
1078 1
人工智能 Java BI
1214 1
人工智能 JavaScript 测试技术
2032 2
人工智能 JavaScript 测试技术
1030 4
缓存 JavaScript Shell
2027 3