feat(shell): add universal proxy management scripts

This commit is contained in:
2026-06-21 22:23:29 +08:00
parent 2e7546c225
commit c9382a8a83
2 changed files with 622 additions and 0 deletions
+353
View File
@@ -0,0 +1,353 @@
<#
.SYNOPSIS
通用代理管理脚本 (PowerShell 版)
.DESCRIPTION
source/加载后使用 proxy 命令管理代理开/关/状态/测试
.NOTES
File: proxy.ps1
用法:
. .\proxy.ps1 # 加载脚本
proxy on # 开启代理
proxy off # 关闭代理
proxy status # 查看代理状态
proxy test # 测试代理连通性
proxy set <host> <port> [type] # 临时设置代理地址
proxy toggle # 切换开/关
proxy help # 显示帮助
#>
# -------------------- 默认配置 --------------------
if (-not $env:_PROXY_HOST) { $env:_PROXY_HOST = "127.0.0.1" }
if (-not $env:_PROXY_PORT) { $env:_PROXY_PORT = "7890" }
if (-not $env:_PROXY_TYPE) { $env:_PROXY_TYPE = "http" } # http | socks5 | socks4
$global:NO_PROXY_LIST = "localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
# -------------------- 辅助:构建代理 URL --------------------
function _BuildProxyUrl {
$type = $env:_PROXY_TYPE
$host_addr = $env:_PROXY_HOST
$port = $env:_PROXY_PORT
switch ($type.ToLower()) {
"http" { return "http://$host_addr`:$port" }
"socks5" { return "socks5://$host_addr`:$port" }
"socks4" { return "socks4://$host_addr`:$port" }
default { return "$type`://$host_addr`:$port" }
}
}
# -------------------- 辅助:控制台 WinINET 代理 (系统级 IE/Edge) --------------------
function _SetWinInetProxy([string]$proxyUrl) {
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
if ($proxyUrl) {
Set-ItemProperty -Path $regPath -Name ProxyEnable -Value 1
Set-ItemProperty -Path $regPath -Name ProxyServer -Value ($proxyUrl -replace '^\w+://', '')
Set-ItemProperty -Path $regPath -Name ProxyOverride -Value $global:NO_PROXY_LIST
} else {
Set-ItemProperty -Path $regPath -Name ProxyEnable -Value 0
}
# 广播 WM_SETTINGCHANGE,让其他程序感知代理变更
$sig = @'
[DllImport("wininet.dll", SetLastError=true)]
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam, uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
'@
try {
Add-Type -MemberDefinition $sig -Namespace WinAPI -Name ProxyHelper -ErrorAction SilentlyContinue
[WinAPI.ProxyHelper]::InternetSetOption([IntPtr]::Zero, 39, [IntPtr]::Zero, 0) | Out-Null # PROXY_SETTINGS_CHANGED
$HWND_BROADCAST = [IntPtr]0xffff
$WM_SETTINGCHANGE = 0x1A
$result = [UIntPtr]::Zero
[WinAPI.ProxyHelper]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [UIntPtr]::Zero, "Environment", 2, 2000, [ref]$result) | Out-Null
} catch {}
}
# ====================================================================
# 开启代理
# ====================================================================
function Proxy-On {
$url = _BuildProxyUrl
# --- 进程级环境变量 ---
$env:http_proxy = $url
$env:HTTP_PROXY = $url
$env:https_proxy = $url
$env:HTTPS_PROXY = $url
$env:all_proxy = $url
$env:ALL_PROXY = $url
$env:no_proxy = $global:NO_PROXY_LIST
$env:NO_PROXY = $global:NO_PROXY_LIST
$env:ftp_proxy = $url
$env:FTP_PROXY = $url
$env:rsync_proxy = $url
# --- 用户级环境变量(持久化,新开终端也生效)---
[Environment]::SetEnvironmentVariable("http_proxy", $url, "User")
[Environment]::SetEnvironmentVariable("https_proxy", $url, "User")
[Environment]::SetEnvironmentVariable("all_proxy", $url, "User")
[Environment]::SetEnvironmentVariable("no_proxy", $global:NO_PROXY_LIST, "User")
# --- Git ---
git config --global http.proxy $url 2>$null
git config --global https.proxy $url 2>$null
# --- NPM ---
npm config set proxy $url 2>$null
npm config set https-proxy $url 2>$null
# --- Yarn ---
yarn config set proxy $url 2>$null
yarn config set https-proxy $url 2>$null
# --- Windows 系统 WinINET (IE/Edge/Chrome 等) ---
_SetWinInetProxy $url
Write-Host "[✓] 代理已开启 → " -ForegroundColor Green -NoNewline
Write-Host $url -ForegroundColor White
Write-Host " NO_PROXY → " -ForegroundColor Green -NoNewline
Write-Host $global:NO_PROXY_LIST -ForegroundColor White
}
# ====================================================================
# 关闭代理
# ====================================================================
function Proxy-Off {
# --- 进程级环境变量 ---
$vars = @("http_proxy","HTTP_PROXY","https_proxy","HTTPS_PROXY","all_proxy","ALL_PROXY",
"no_proxy","NO_PROXY","ftp_proxy","FTP_PROXY","rsync_proxy")
foreach ($v in $vars) { Remove-Item -Path "Env:$v" -ErrorAction SilentlyContinue }
# --- 用户级环境变量 ---
foreach ($v in @("http_proxy","https_proxy","all_proxy","no_proxy")) {
[Environment]::SetEnvironmentVariable($v, $null, "User")
}
# --- Git ---
git config --global --unset http.proxy 2>$null
git config --global --unset https.proxy 2>$null
# --- NPM ---
npm config delete proxy 2>$null
npm config delete https-proxy 2>$null
# --- Yarn ---
yarn config delete proxy 2>$null
yarn config delete https-proxy 2>$null
# --- Windows 系统 WinINET ---
_SetWinInetProxy $null
Write-Host "[✓] 代理已关闭" -ForegroundColor Red
}
# ====================================================================
# 查看代理状态
# ====================================================================
function Proxy-Status {
Write-Host ""
Write-Host "========== 代理状态 ==========" -ForegroundColor White
# 环境变量
Write-Host "`n[环境变量]" -ForegroundColor White
$envVars = @("http_proxy", "https_proxy", "all_proxy", "no_proxy", "ftp_proxy")
foreach ($v in $envVars) {
$val = [Environment]::GetEnvironmentVariable($v, "Process")
if ($val) {
Write-Host (" {0,-14} → {1}" -f $v, $val) -ForegroundColor Green
} else {
Write-Host (" {0,-14} → (未设置)" -f $v) -ForegroundColor DarkGray
}
}
# 用户级环境变量
Write-Host "`n[用户级环境变量 (持久化)]" -ForegroundColor White
foreach ($v in @("http_proxy", "https_proxy", "all_proxy", "no_proxy")) {
$val = [Environment]::GetEnvironmentVariable($v, "User")
if ($val) {
Write-Host (" {0,-14} → {1}" -f $v, $val) -ForegroundColor Green
} else {
Write-Host (" {0,-14} → (未设置)" -f $v) -ForegroundColor DarkGray
}
}
# Git
Write-Host "`n[Git 配置] (global)" -ForegroundColor White
$gitHttp = git config --global --get http.proxy 2>$null
$gitHttps = git config --global --get https.proxy 2>$null
if ($gitHttp -or $gitHttps) {
if ($gitHttp) { Write-Host " http.proxy → $gitHttp" -ForegroundColor Green }
if ($gitHttps) { Write-Host " https.proxy → $gitHttps" -ForegroundColor Green }
} else {
Write-Host " (未配置)" -ForegroundColor DarkGray
}
# NPM
if (Get-Command npm -ErrorAction SilentlyContinue) {
Write-Host "`n[NPM 配置]" -ForegroundColor White
$npmProxy = npm config get proxy 2>$null
$npmHttps = npm config get https-proxy 2>$null
if ($npmProxy -and $npmProxy -ne "null" -and $npmProxy -ne "undefined") {
Write-Host " proxy → $npmProxy" -ForegroundColor Green
} else {
Write-Host " proxy → (未设置)" -ForegroundColor DarkGray
}
if ($npmHttps -and $npmHttps -ne "null" -and $npmHttps -ne "undefined") {
Write-Host " https-proxy → $npmHttps" -ForegroundColor Green
} else {
Write-Host " https-proxy → (未设置)" -ForegroundColor DarkGray
}
}
# Windows 系统代理
Write-Host "`n[Windows 系统 WinINET 代理]" -ForegroundColor White
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
if (Test-Path $regPath) {
$enabled = (Get-ItemProperty -Path $regPath -Name ProxyEnable -ErrorAction SilentlyContinue).ProxyEnable
$server = (Get-ItemProperty -Path $regPath -Name ProxyServer -ErrorAction SilentlyContinue).ProxyServer
if ($enabled -eq 1) {
Write-Host " ProxyEnable → 1" -ForegroundColor Green
Write-Host " ProxyServer → $server" -ForegroundColor Green
} else {
Write-Host " ProxyEnable → 0 (已禁用)" -ForegroundColor DarkGray
}
} else {
Write-Host " (无法读取注册表)" -ForegroundColor DarkGray
}
Write-Host ""
}
# ====================================================================
# 测试代理连通性
# ====================================================================
function Proxy-Test {
$url = _BuildProxyUrl
Write-Host "[测试代理] $url`n" -ForegroundColor White
# Google (通过代理)
Write-Host " Google (proxy) → " -NoNewline
try {
$r = Invoke-WebRequest -Uri "https://www.google.com" -Proxy $url -TimeoutSec 5 -UseBasicParsing -ErrorAction Stop
if ($r.StatusCode -in 200,301,302) { Write-Host "✓ OK ($($r.StatusCode))" -ForegroundColor Green }
else { Write-Host "✗ FAIL ($($r.StatusCode))" -ForegroundColor Red }
} catch { Write-Host "✗ FAIL" -ForegroundColor Red }
# GitHub (通过代理)
Write-Host " GitHub (proxy) → " -NoNewline
try {
$r = Invoke-WebRequest -Uri "https://github.com" -Proxy $url -TimeoutSec 5 -UseBasicParsing -ErrorAction Stop
if ($r.StatusCode -in 200,301,302) { Write-Host "✓ OK ($($r.StatusCode))" -ForegroundColor Green }
else { Write-Host "✗ FAIL ($($r.StatusCode))" -ForegroundColor Red }
} catch { Write-Host "✗ FAIL" -ForegroundColor Red }
# 本地直连 (不走代理)
Write-Host " Baidu (direct) → " -NoNewline
try {
$r = Invoke-WebRequest -Uri "https://www.baidu.com" -TimeoutSec 3 -UseBasicParsing -NoProxy -ErrorAction Stop
if ($r.StatusCode -in 200,301,302) { Write-Host "✓ OK ($($r.StatusCode))" -ForegroundColor Green }
else { Write-Host "✗ FAIL ($($r.StatusCode))" -ForegroundColor Red }
} catch {
# PowerShell 5.1 不支持 -NoProxy,退而用 curl
try {
$code = (curl.exe -s -o NUL -w "%{http_code}" --max-time 3 --noproxy "*" https://www.baidu.com 2>$null)
if ($code -match "200|301|302") { Write-Host "✓ OK ($code)" -ForegroundColor Green }
else { Write-Host "✗ FAIL" -ForegroundColor Red }
} catch { Write-Host "✗ FAIL" -ForegroundColor Red }
}
Write-Host ""
}
# ====================================================================
# 临时设置代理地址
# ====================================================================
function Proxy-Set {
param(
[Parameter(Position=0)][string]$ProxyHost,
[Parameter(Position=1)][string]$ProxyPort,
[Parameter(Position=2)][string]$ProxyType = "http"
)
if (-not $ProxyHost -or -not $ProxyPort) {
Write-Host "用法: proxy set <host> <port> [http|socks5]" -ForegroundColor Yellow
Write-Host '示例: proxy set 192.168.1.100 1080 socks5' -ForegroundColor Yellow
return
}
$env:_PROXY_HOST = $ProxyHost
$env:_PROXY_PORT = $ProxyPort
$env:_PROXY_TYPE = $ProxyType
Write-Host "[✓] 代理地址已设置为 ${ProxyType}://${ProxyHost}:${ProxyPort}" -ForegroundColor Green
Write-Host " 执行 'proxy on' 启用新的代理地址" -ForegroundColor Green
}
# ====================================================================
# 主入口:proxy 命令
# ====================================================================
function proxy {
param(
[Parameter(Position=0)][string]$Action = "help",
[Parameter(Position=1, ValueFromRemainingArguments)][string[]]$Args
)
switch ($Action.ToLower()) {
"on" { Proxy-On }
"off" { Proxy-Off }
"status" { Proxy-Status }
"test" { Proxy-Test }
"toggle" {
if ($env:http_proxy) { Proxy-Off } else { Proxy-On }
}
"set" {
if ($Args -and $Args.Count -ge 2) {
$type = if ($Args.Count -ge 3) { $Args[2] } else { "http" }
Proxy-Set -ProxyHost $Args[0] -ProxyPort $Args[1] -ProxyType $type
} else {
Proxy-Set
}
}
"help" {
Write-Host @"
========== proxy.ps1 ==========
:
. .\proxy.ps1 # Dot-Source
proxy on # ( + WinINET + git + npm)
proxy off #
proxy status #
proxy test #
proxy toggle # /
proxy set <host> <port> [type]#
proxy help #
():
_PROXY_HOST = $($env:_PROXY_HOST)
_PROXY_PORT = $($env:_PROXY_PORT)
_PROXY_TYPE = $($env:_PROXY_TYPE) (http | socks5 | socks4)
:
`$env:_PROXY_HOST = "10.0.0.5" #
`$env:_PROXY_PORT = "1080" #
proxy on #
"@ -ForegroundColor Cyan
}
default {
Write-Host "未知命令: $Action (使用 'proxy help' 查看帮助)" -ForegroundColor Red
}
}
}
# -------------------- 加载提示 --------------------
if ($MyInvocation.Line -notmatch '\$\s*\(?\s*\.\s+.*proxy\.ps1') {
# 被直接执行而非 dot-source 时
if ($args.Count -eq 0) {
# 无参数直接执行,先 dot-source 自己
Write-Host "[proxy.ps1] 请使用 '. .\proxy.ps1' 来加载脚本。" -ForegroundColor Yellow
Write-Host "[proxy.ps1] 如果要直接执行命令, 请运行: .\proxy.ps1 on" -ForegroundColor Yellow
}
} else {
Write-Host "[proxy.ps1] 已加载。使用 'proxy help' 查看用法。" -ForegroundColor Cyan
}