一管理Windows代理:環(huán)境變量、系統(tǒng)代理與WinHTTP實(shí)踐)
剛接手公司統(tǒng)一網(wǎng)絡(luò)管理的時(shí)候我每天最煩的事情就是手動(dòng)敲set http_proxyxxx這類命令。Windows 環(huán)境下配代理說(shuō)到底繞不開(kāi)環(huán)境變量、系統(tǒng)代理、WinHTTP 代理這三塊而傳統(tǒng) cmd 的set命令只能改當(dāng)前窗口的環(huán)境變量窗口一關(guān)就失效根本扛不住“上午連內(nèi)網(wǎng)、下午測(cè)外聯(lián)、晚上調(diào)接口”這種高頻切換場(chǎng)景。后來(lái)我把整套操作全部遷到了 PowerShell 里用腳本化的方式統(tǒng)一管理才真正體會(huì)到什么叫“優(yōu)雅”。這篇文章就把我沉淀下來(lái)的思路、腳本和踩坑記錄完整分享出來(lái)希望能幫到同樣被代理設(shè)置折騰過(guò)的人。1. 整體設(shè)計(jì)與思路拆解1.1 傳統(tǒng) set 命令的根本問(wèn)題很多人對(duì)代理設(shè)置的第一印象就是網(wǎng)上鋪天蓋地的教程里那幾句set http_proxyhttp://127.0.0.1:7890 set https_proxyhttp://127.0.0.1:7890這套寫法在 cmd 窗口里敲下去當(dāng)前窗口確實(shí)能訪問(wèn)外網(wǎng)了但問(wèn)題也接踵而至。第一作用域只限于當(dāng)前 cmd 窗口。你關(guān)掉窗口再開(kāi)一個(gè)新的配置就沒(méi)了。腳本里繼承不到新進(jìn)程也看不到八竿子打不著的程序更是完全不受影響。第二它只改了環(huán)境變量沒(méi)有碰系統(tǒng)代理。很多軟件不看http_proxy環(huán)境變量只認(rèn) Windows 系統(tǒng)代理設(shè)置結(jié)果你變量配得再勤快瀏覽器、某些客戶端照樣直連。第三WinHTTP 代理是另一套體系netsh winhttp不走環(huán)境變量。Windows 更新、部分系統(tǒng)服務(wù)、后臺(tái)任務(wù)走的是 WinHTTP 通道環(huán)境變量在它們面前就是空氣。第四切來(lái)切去全靠手敲太容易敲錯(cuò)地址和端口而且沒(méi)有任何可視化反饋排錯(cuò)成本極高。歸根到底cmd 的set命令是給“當(dāng)前會(huì)話臨時(shí)用一下”設(shè)計(jì)的根本不適合“有代理 / 無(wú)代理 / 多代理配置”這種需要反復(fù)切換的管理場(chǎng)景。1.2 PowerShell 為什么是更好的管理載體PowerShell 能優(yōu)雅管理代理核心原因是它把“改配置”這件事做了三層收斂。第一層是變量與作用域管理。PowerShell 的$env:驅(qū)動(dòng)器可以直接讀寫環(huán)境變量借助[Environment]::SetEnvironmentVariable()還能指定User或Machine級(jí)別寫入后永久生效徹底擺脫“關(guān)窗即失”的尷尬。第二層是系統(tǒng)代理。Windows 系統(tǒng)代理本質(zhì)是注冊(cè)表HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings下的幾個(gè)鍵值PowerShell 用Set-ItemProperty就能精準(zhǔn)修改再配合WinINetAPI 通知系統(tǒng)刷新效果和圖形界面操作完全一致。第三層是 WinHTTP 代理。netsh winhttp本身支持命令行操作PowerShell 調(diào)用它沒(méi)有絲毫障礙而且可以自動(dòng)檢測(cè)當(dāng)前系統(tǒng)代理再導(dǎo)入幾行代碼就能打通系統(tǒng)代理與 WinHTTP 代理的同步。簡(jiǎn)單說(shuō)PowerShell 既具備 cmd 的輕量又擁有腳本語(yǔ)言的完整控制力。把分散在三處的代理配置統(tǒng)一收口到一個(gè)腳本里是它在管理體驗(yàn)上勝過(guò)set命令的根本原因。1.3 我對(duì)“優(yōu)雅管理”的定位我做這套方案前給自己定了三個(gè)標(biāo)準(zhǔn)。一是可觀察。執(zhí)行任何操作前都要能一鍵看到當(dāng)前所有代理狀態(tài)包括環(huán)境變量、系統(tǒng)代理、WinHTTP 代理而不是靠猜。二是可切換。支持開(kāi)啟代理、關(guān)閉代理、切換不同代理服務(wù)器一次封裝、長(zhǎng)期復(fù)用。三是可配置。代理服務(wù)器地址、端口、繞過(guò)列表都集中放在腳本開(kāi)頭的配置區(qū)換環(huán)境時(shí)只改配置不翻代碼。這三個(gè)標(biāo)準(zhǔn)貫穿了整個(gè)腳本設(shè)計(jì)也是后來(lái)我實(shí)際使用體驗(yàn)良好的基礎(chǔ)。2. 核心概念與關(guān)鍵工具拆解2.1 環(huán)境變量代理、系統(tǒng)代理與 WinHTTP 代理的區(qū)別這是最容易混淆的一組概念我要花點(diǎn)功夫講清楚。環(huán)境變量代理是面向命令行的。http_proxy、https_proxy這些變量被 curl、wget、git、npm、pip 等命令行工具讀取決定了這些工具發(fā)起 HTTP/HTTPS 請(qǐng)求時(shí)走哪條路。它只對(duì)“顯式讀取環(huán)境變量的進(jìn)程”生效和圖形界面程序基本沒(méi)關(guān)系。系統(tǒng)代理是面向圖形應(yīng)用的。瀏覽器、部分客戶端軟件會(huì)通過(guò) WinINet 庫(kù)讀取系統(tǒng)代理設(shè)置這套設(shè)置存儲(chǔ)在注冊(cè)表HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings中鍵名為ProxyEnable和ProxyServer。系統(tǒng)代理配置生效范圍是整個(gè)用戶會(huì)話只要進(jìn)程通過(guò) WinINet 獲取代理就能感知到變化。WinHTTP 代理是面向系統(tǒng)服務(wù)的。Windows 更新、某些系統(tǒng)組件、后臺(tái)服務(wù)走 WinHTTP 通道與 WinINet 相互獨(dú)立配置方式也不同用netsh winhttp命令管理。而且 WinHTTP 代理是機(jī)器級(jí)別的設(shè)置后影響整個(gè)系統(tǒng)的服務(wù)流量。我用一個(gè)類比幫你記憶環(huán)境變量代理是“給隨身聽(tīng)換耳機(jī)”系統(tǒng)代理是“給客廳音響換輸入源”WinHTTP 代理是“給物業(yè)廣播系統(tǒng)換頻道”。三套系統(tǒng)各有各的控制面板傳統(tǒng)set命令只夠得著第一套自然管不全面。2.2 PowerShell 管理代理要掌握的底層設(shè)施寫腳本前先搞清楚要操作的底層設(shè)施是哪幾個(gè)。環(huán)境變量層$env:http_proxy是會(huì)話級(jí)[Environment]::GetEnvironmentVariable(http_proxy, User)是用戶級(jí)Machine是系統(tǒng)級(jí)。讀取、寫入都要分清層次。系統(tǒng)代理層注冊(cè)表路徑HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings關(guān)鍵鍵值是ProxyEnableREG_DWORD0 關(guān)閉、1 開(kāi)啟、ProxyServerREG_SZ形如http127.0.0.1:7890;https127.0.0.1:7890、ProxyOverrideREG_SZ繞過(guò)列表。WinHTTP 層netsh winhttp show proxy查看netsh winhttp set proxy設(shè)置netsh winhttp reset proxy清空。通知刷新層修改完系統(tǒng)代理后需要調(diào)用InternetSetOptionAPI 發(fā)送INTERNET_OPTION_SETTINGS_CHANGED和INTERNET_OPTION_REFRESH通知讓系統(tǒng)立即感知變化。不刷新的話部分程序可能要重啟或等很長(zhǎng)時(shí)間才生效。對(duì)這幾層設(shè)施心里有數(shù)之后腳本就只是在做“填值”和“取值”的活沒(méi)有任何黑魔法。3. 實(shí)操過(guò)程與核心環(huán)節(jié)實(shí)現(xiàn)3.1 一鍵查看當(dāng)前代理狀態(tài)管理的第一步永遠(yuǎn)是“看清楚現(xiàn)狀”。我寫了一個(gè)狀態(tài)查看函數(shù)一次性把三套代理體系的情況全打印出來(lái)。function Get-ProxyStatus { Write-Host 環(huán)境變量代理 -ForegroundColor Cyan Write-Host (http_proxy (User) : [Environment]::GetEnvironmentVariable(http_proxy, User)) Write-Host (https_proxy (User) : [Environment]::GetEnvironmentVariable(https_proxy, User)) Write-Host (http_proxy (Machine) : [Environment]::GetEnvironmentVariable(http_proxy, Machine)) Write-Host (https_proxy (Machine) : [Environment]::GetEnvironmentVariable(https_proxy, Machine)) Write-Host n 系統(tǒng)代理 -ForegroundColor Cyan $regPath HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings $proxyEnable Get-ItemProperty -Path $regPath -Name ProxyEnable -ErrorAction SilentlyContinue | Select-Object -ExpandProperty ProxyEnable $proxyServer Get-ItemProperty -Path $regPath -Name ProxyServer -ErrorAction SilentlyContinue | Select-Object -ExpandProperty ProxyServer $proxyOverride Get-ItemProperty -Path $regPath -Name ProxyOverride -ErrorAction SilentlyContinue | Select-Object -ExpandProperty ProxyOverride Write-Host (ProxyEnable : $proxyEnable) Write-Host (ProxyServer : $proxyServer) Write-Host (ProxyOverride: $proxyOverride) Write-Host n WinHTTP 代理 -ForegroundColor Cyan netsh winhttp show proxy }實(shí)測(cè)下來(lái)這個(gè)函數(shù)輸出的信息基本能覆蓋日常排錯(cuò)需要的全部數(shù)據(jù)。環(huán)境變量分用戶級(jí)和系統(tǒng)級(jí)顯示是因?yàn)槲也冗^(guò)“User 級(jí)設(shè)了、Machine 級(jí)沒(méi)設(shè)部分工具行為不一致”的坑分開(kāi)看一目了然。注意netsh winhttp show proxy本身就會(huì)輸出一段說(shuō)明文字不要在它外面再包一層格式化否則反而顯得啰嗦。有幾次排查“瀏覽器能通、命令行不通”的問(wèn)題靠這個(gè)函數(shù)一眼就定位到環(huán)境變量缺失。也有幾次是“命令行能通、系統(tǒng)服務(wù)不通”一看 WinHTTP 代理是空白的答案立刻浮出水面。這就是可觀察性的價(jià)值。3.2 設(shè)置與清除系統(tǒng)代理的完整實(shí)現(xiàn)設(shè)置系統(tǒng)代理的腳本核心邏輯是把注冊(cè)表鍵值寫對(duì)再發(fā)刷新通知。以下是我穩(wěn)定使用的版本。function Set-SystemProxy { param( [string]$ProxyServer 127.0.0.1:7890, [string]$Override localhost;127.0.0.1;10.*;192.168.*;*.local;local ) $regPath HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings Set-ItemProperty -Path $regPath -Name ProxyEnable -Value 1 Set-ItemProperty -Path $regPath -Name ProxyServer -Value $ProxyServer Set-ItemProperty -Path $regPath -Name ProxyOverride -Value $Override # 通知系統(tǒng)刷新代理設(shè)置 Add-Type -Namespace Win32 -Name NativeMethods -MemberDefinition [DllImport(wininet.dll, SetLastError true)] public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); $INTERNET_OPTION_SETTINGS_CHANGED 39 $INTERNET_OPTION_REFRESH 37 [Win32.NativeMethods]::InternetSetOption([IntPtr]::Zero, $INTERNET_OPTION_SETTINGS_CHANGED, [IntPtr]::Zero, 0) | Out-Null [Win32.NativeMethods]::InternetSetOption([IntPtr]::Zero, $INTERNET_OPTION_REFRESH, [IntPtr]::Zero, 0) | Out-Null Write-Host 系統(tǒng)代理已設(shè)置為: $ProxyServer -ForegroundColor Green }清除時(shí)把ProxyEnable改成 0 即可不要把ProxyServer刪掉。保留它是有意義的下次開(kāi)代理時(shí)只需重寫開(kāi)關(guān)位服務(wù)器地址還是原來(lái)的不用重新輸入。實(shí)測(cè)很多人在清代理時(shí)順手刪了ProxyServer結(jié)果下次設(shè)置代理時(shí)忘寫地址陷入“怎么開(kāi)了代理還是不通”的困惑。繞過(guò)的寫法我也要展開(kāi)一下。分號(hào)分隔每一項(xiàng)local表示本地地址繞過(guò)10.*和192.168.*是內(nèi)網(wǎng)段通配。這個(gè)列表要根據(jù)公司網(wǎng)段自行調(diào)整別照抄。我們公司內(nèi)網(wǎng)資源多我還額外加了*.corp.example.com這類內(nèi)網(wǎng)域名后綴避免訪問(wèn)內(nèi)部系統(tǒng)時(shí)繞到代理上被攔截。3.3 設(shè)置與清除 WinHTTP 代理的正確姿勢(shì)WinHTTP 代理最省心的做法是把當(dāng)前系統(tǒng)代理直接導(dǎo)入。這樣只要系統(tǒng)代理配置對(duì)了WinHTTP 就跟著對(duì)永遠(yuǎn)不必手寫兩遍地址。function Set-WinHttpProxyFromSystem { # 從系統(tǒng)代理設(shè)置導(dǎo)入到 WinHTTP netsh winhttp import proxy sourceie Write-Host 已從系統(tǒng)代理導(dǎo)入 WinHTTP 設(shè)置 -ForegroundColor Green netsh winhttp show proxy }sourceie的意思就是讓 Windows 從“Internet Explorer 設(shè)置”里讀取代理這個(gè)名稱是歷史遺留本質(zhì)上就是當(dāng)前用戶的系統(tǒng)代理設(shè)置。這個(gè)命令需要管理員權(quán)限否則會(huì)報(bào)錯(cuò)。清除 WinHTTP 代理要單獨(dú)處理因?yàn)閞eset proxy是整體重置function Reset-WinHttpProxy { netsh winhttp reset proxy Write-Host WinHTTP 代理已重置為直連 -ForegroundColor Yellow }我個(gè)人的習(xí)慣是“系統(tǒng)代理開(kāi)了WinHTTP 就跟著導(dǎo)入”但反過(guò)來(lái)清代理時(shí)只清系統(tǒng)代理WinHTTP 保持原樣。為什么因?yàn)槟承┫到y(tǒng)服務(wù)和 Windows 更新有自己的代理需求如果它們正依賴 WinHTTP 代理訪問(wèn)更新通道你貿(mào)然 reset 可能導(dǎo)致連不上更新服務(wù)器。所以清 WinHTTP 要謹(jǐn)慎通常只在排查系統(tǒng)服務(wù)連接問(wèn)題時(shí)才動(dòng)它。3.4 環(huán)境變量代理的設(shè)置與清除機(jī)制環(huán)境變量代理是命令行工具的命脈。我設(shè)置時(shí)同時(shí)寫入 User 級(jí)環(huán)境變量和當(dāng)前會(huì)話這樣新開(kāi)的進(jìn)程能繼承當(dāng)前窗口也能立刻生效。function Set-EnvProxy { param([string]$ProxyServer 127.0.0.1:7890) $env:http_proxy http://$ProxyServer $env:https_proxy http://$ProxyServer [Environment]::SetEnvironmentVariable(http_proxy, http://$ProxyServer, User) [Environment]::SetEnvironmentVariable(https_proxy, http://$ProxyServer, User) Write-Host 環(huán)境變量代理已設(shè)置: $ProxyServer -ForegroundColor Green }清除時(shí)就簡(jiǎn)單了重點(diǎn)是把三個(gè)位置都清干凈function Clear-EnvProxy { Remove-Item Env:http_proxy -ErrorAction SilentlyContinue Remove-Item Env:https_proxy -ErrorAction SilentlyContinue [Environment]::SetEnvironmentVariable(http_proxy, $null, User) [Environment]::SetEnvironmentVariable(https_proxy, $null, User) Write-Host 環(huán)境變量代理已清除 -ForegroundColor Yellow }很多教程只改當(dāng)前會(huì)話不寫 User 級(jí)這樣新開(kāi)的 PowerShell 窗口里又沒(méi)代理了依然要用set命令反復(fù)設(shè)。我強(qiáng)調(diào)“當(dāng)前會(huì)話 User 級(jí)”雙寫就是要把這種半途而廢的體驗(yàn)扼殺掉。還有個(gè)小細(xì)節(jié)有些工具讀的是大寫形式HTTP_PROXY、HTTPS_PROXYPowerShell 的環(huán)境變量名不區(qū)分大小寫兩邊都能讀到不用擔(dān)心。3.5 代理服務(wù)器配置的多場(chǎng)景切換現(xiàn)實(shí)工作中不可能只有一個(gè)代理地址。公司內(nèi)網(wǎng)代理一個(gè)調(diào)試接口時(shí)本地代理一個(gè)上外網(wǎng)時(shí)另一個(gè)出口。我把所有場(chǎng)景抽象成“配置塊”用一個(gè)函數(shù)統(tǒng)一切換。function Switch-Proxy { param( [ValidateSet(office, local, none)] [string]$Mode ) $configs { office { Server proxy.corp.example.com:8080; Override localhost;127.0.0.1;10.*;192.168.*;local } local { Server 127.0.0.1:7890; Override localhost;127.0.0.1;10.*;192.168.*;local } } if ($Mode -eq none) { Set-SystemProxyOff Clear-EnvProxy Reset-WinHttpProxy Write-Host 已切換為直連模式 -ForegroundColor Yellow return } $cfg $configs[$Mode] Set-SystemProxy -ProxyServer $cfg.Server -Override $cfg.Override Set-EnvProxy -ProxyServer $cfg.Server # 同步 WinHTTP 時(shí)去掉重置邏輯避免影響系統(tǒng)服務(wù) netsh winhttp import proxy sourceie Write-Host 已切換為 $Mode 模式: $($cfg.Server) -ForegroundColor Green }這里我特意把模式名設(shè)計(jì)成具名參數(shù)用ValidateSet約束合法值。好處是敲錯(cuò)的概率大幅下降而且 PowerShell 的 Tab 補(bǔ)全能直接列出可選模式整個(gè)人機(jī)交互瞬間就順了。實(shí)際使用中我上午切office連公司系統(tǒng)下午切l(wèi)ocal調(diào)試本地服務(wù)晚上切none收工回家一個(gè)命令三秒鐘搞定再也不用跟多個(gè)窗口較勁。注意我在Switch-Proxy里沒(méi)有調(diào)用Reset-WinHttpProxy而是直接import proxy sourceie覆蓋。這樣每一步都是“把當(dāng)前配置覆蓋成目標(biāo)配置”不會(huì)經(jīng)過(guò)一個(gè)中間的空窗期。經(jīng)驗(yàn)告訴我中間態(tài)越少出問(wèn)題的概率越低。3.6 整合成完整的代理管理腳本把所有函數(shù)組裝成一個(gè)腳本文件附上菜單式的交互入口這個(gè)方案才算完整。# ProxyManager.ps1 # 用法: . .\ProxyManager.ps1 (注意前導(dǎo)的點(diǎn)表示當(dāng)前作用域加載函數(shù)) $defaultServer proxy.corp.example.com:8080 $defaultOverride localhost;127.0.0.1;10.*;192.168.*;local # ---- 各函數(shù)實(shí)現(xiàn)見(jiàn)上文此處省略 ---- # 交互菜單 Write-Host 網(wǎng)絡(luò)代理管理器 -ForegroundColor Cyan Write-Host 1. 查看狀態(tài) Write-Host 2. 開(kāi)啟系統(tǒng)代理 環(huán)境變量 Write-Host 3. 關(guān)閉系統(tǒng)代理 環(huán)境變量 Write-Host 4. 同步 WinHTTP 代理 Write-Host 5. 切換模式 Write-Host 6. 退出這是一種“點(diǎn)單式”的用法適合不太熟悉命令行的同事。我團(tuán)隊(duì)里幾個(gè)不常碰 PowerShell 的同事靠這個(gè)菜單基本能自助解決代理問(wèn)題我對(duì)他們的技術(shù)支持壓力小了很多。如果你習(xí)慣純命令式操作直接調(diào)用函數(shù)也一樣順手。3.7 配合開(kāi)機(jī)自啟腳本的進(jìn)階玩法我的工作環(huán)境需要我每天開(kāi)機(jī)后自動(dòng)用公司代理手動(dòng)執(zhí)行腳本太煩。配合“Windows PowerShell 開(kāi)機(jī)自啟腳本”的思路我做了這樣一件事。把腳本放到固定路徑比如C:\Scripts\ProxyManager.ps1然后在“啟動(dòng)”文件夾里放一個(gè).bat或快捷方式開(kāi)機(jī)時(shí)靜默加載函數(shù)并執(zhí)行默認(rèn)模式# 在 PowerShell 配置文件中追加默認(rèn)模式 $PROFILE Add-Content -Path $PROFILE -Value n. C:\Scripts\ProxyManager.ps1 Add-Content -Path $PROFILE -Value Switch-Proxy -Mode office這樣每次打開(kāi) PowerShell函數(shù)就已經(jīng)就位而且默認(rèn)切換到公司代理模式。如果你不想對(duì)所有 PowerShell 窗口生效可以把Switch-Proxy office只放進(jìn)“啟動(dòng)”文件夾的獨(dú)立腳本效果等同。還有一點(diǎn)要注意寫$PROFILE前先確認(rèn)文件存在New-Item -Force先建目錄再追加不然會(huì)報(bào)錯(cuò)。我因?yàn)闆](méi)檢查目錄踩過(guò)一次坑Add-Content 直接往不存在的路徑寫白白浪費(fèi)了十幾分鐘。4. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄4.1 設(shè)置了代理但瀏覽器不生效這是最常被問(wèn)的問(wèn)題十次里有八次出在“只改了環(huán)境變量沒(méi)改系統(tǒng)代理”。環(huán)境變量對(duì)瀏覽器這種 WinINet 應(yīng)用無(wú)效一定要確認(rèn)注冊(cè)表ProxyEnable是 1、ProxyServer是127.0.0.1:7890這種格式。還有一種隱蔽情況Chrome 默認(rèn)走系統(tǒng)代理但某些設(shè)置或擴(kuò)展把代理模式固定成了“直連”或“PAC腳本”。這讓很多人誤以為系統(tǒng)代理沒(méi)配好其實(shí)是瀏覽器端覆蓋了系統(tǒng)設(shè)置。遇到這種情況先打開(kāi)瀏覽器的代理設(shè)置頁(yè)看當(dāng)前模式再用我的Get-ProxyStatus對(duì)照系統(tǒng)值通常能迅速定位。4.2 命令行工具不走代理git、npm、pip 這類工具各有各的代理讀取邏輯。npm 需要npm config set proxygit 需要git config --global http.proxy這些不會(huì)自動(dòng)讀環(huán)境變量之外的配置。但我實(shí)測(cè)大部分工具是認(rèn)環(huán)境變量的不走代理的原因往往集中在兩點(diǎn)。一是當(dāng)前 PowerShell 窗口是在設(shè)置代理之前打開(kāi)的會(huì)話級(jí)環(huán)境變量沒(méi)加載進(jìn)去。解決方法是重開(kāi)窗口或者先執(zhí)行Set-EnvProxy把當(dāng)前的會(huì)話變量補(bǔ)上。二是部分工具對(duì) HTTPS 代理要求單獨(dú)設(shè)置https_proxy有些工具只讀了https_proxy沒(méi)讀http_proxy排查時(shí)兩邊都要確認(rèn)。4.3 提示“請(qǐng)求的操作需要提升”netsh winhttp import proxy sourceie和netsh winhttp reset proxy必須管理員權(quán)限。PowerShell 里普通用戶跑這個(gè)命令直接報(bào)錯(cuò)。解決辦法有兩個(gè)要么右鍵“以管理員身份運(yùn)行”PowerShell要么在腳本開(kāi)頭用自提權(quán)邏輯。我分享一個(gè)自提權(quán)的小技巧檢測(cè)當(dāng)前是否管理員不是就重新啟動(dòng)自己并加上-Verb RunAs。if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Start-Process powershell -Verb RunAs -ArgumentList -File $PSCommandPath exit }加了這段后雙擊腳本就會(huì)自動(dòng)彈 UAC 提權(quán)窗口體驗(yàn)順暢很多。不過(guò)自提權(quán)意味著腳本每次啟動(dòng)都可能彈一次確認(rèn)框介意的可以拆成兩個(gè)腳本一個(gè)日常用一個(gè)提權(quán)用。4.4 腳本出現(xiàn)亂碼或中文字符顯示異常中文 Windows 上 PowerShell 5.1 默認(rèn)編碼可能跟你腳本文件的編碼不一致導(dǎo)致函數(shù)名、注釋里的中文變成亂碼。我的經(jīng)驗(yàn)是這樣腳本文件統(tǒng)一用 UTF-8 with BOM 保存這樣 PowerShell 5.1 能正確識(shí)別如果用了無(wú) BOM 的 UTF-8控制臺(tái)容易出現(xiàn)亂碼。Windows PowerShell 5.1 讀取無(wú) BOM UTF-8 會(huì)按 ANSI 解析中文直接花掉。另外控制臺(tái)輸出中文時(shí)可以把輸出用Write-Host帶上ForegroundColor這不僅能區(qū)分不同類型的信息還能減少對(duì)字體的依賴。如果某些環(huán)境仍然亂碼可以臨時(shí)執(zhí)行[Console]::OutputEncoding [System.Text.Encoding]::UTF8查看是否改善。這個(gè)設(shè)置是當(dāng)前會(huì)話的不會(huì)影響系統(tǒng)。4.5 腳本雙擊后一閃而過(guò)腳本雙擊閃退通常是有錯(cuò)誤被吞掉了。最基礎(chǔ)的排查辦法是不要雙擊改為在 PowerShell 窗口里powershell -File .\ProxyManager.ps1運(yùn)行這樣錯(cuò)誤信息會(huì)停留在窗口里。進(jìn)一步做法是在腳本開(kāi)頭加$ErrorActionPreference Stop讓錯(cuò)誤直接顯示而不是靜默繼續(xù)。我習(xí)慣開(kāi)發(fā)期間在腳本第一行加Set-StrictMode -Version Latest $ErrorActionPreference Stop這兩行相當(dāng)于給腳本疊了一層“嚴(yán)格模式護(hù)甲”遇到未定義變量、空引用、靜默失敗都會(huì)直接報(bào)錯(cuò)調(diào)試期能少走很多彎路。正式使用時(shí)再把ErrorActionPreference調(diào)回Continue避免個(gè)別非關(guān)鍵錯(cuò)誤中斷整個(gè)流程。5. 經(jīng)驗(yàn)分享與擴(kuò)展建議5.1 我在實(shí)際使用中沉淀的幾條體會(huì)整套方案用了快一年有幾個(gè)體會(huì)值得單獨(dú)說(shuō)。一是“同步比分開(kāi)設(shè)置重要”。最初我的系統(tǒng)代理、環(huán)境變量、WinHTTP 是三個(gè)獨(dú)立函數(shù)經(jīng)常出現(xiàn)“系統(tǒng)代理開(kāi)了、命令行沒(méi)走代理”的割裂狀態(tài)。后來(lái)我把所有函數(shù)都設(shè)計(jì)成“一次調(diào)用三層同步”體驗(yàn)立刻提升了一個(gè)檔次。割裂是代理管理最大的隱性成本。二是“繞過(guò)列表一定要按自己環(huán)境定制”。默認(rèn)的localhost;127.0.0.1;local只夠應(yīng)付本機(jī)內(nèi)網(wǎng)站點(diǎn)和域名后綴必須自己加。我給公司加過(guò)*.internal.example.com給測(cè)試環(huán)境加過(guò)10.0.0.0/8每次換環(huán)境第一件事就是更新這個(gè)列表。忽略它的話你訪問(wèn)內(nèi)網(wǎng)資源時(shí)流量繞到代理上輕則慢重則被代理策略攔死。三是“重置要克制”。不是所有場(chǎng)景都需要把三套代理都清成直連。我現(xiàn)在把操作拆成“關(guān)閉系統(tǒng)代理”“清理環(huán)境變量”“重置 WinHTTP”三個(gè)獨(dú)立動(dòng)作配合組合模式使用需要清哪層清哪層而不是一刀切。很多人的代理問(wèn)題順著鏈路排查最后都出在“某層沒(méi)動(dòng)”或者“某層被誤清了”。5.2 后續(xù)還能怎么擴(kuò)展這套思路的好處是擴(kuò)展性強(qiáng)我在實(shí)際工作中又加了幾個(gè)模塊。一是代理可用性檢測(cè)。在Switch-Proxy里加一段Test-NetConnection -ComputerName 代理地址 -Port 代理端口切換前先確認(rèn)目標(biāo)代理連得上連不上就不切避免切了個(gè)寂寞。二是按進(jìn)程或按網(wǎng)絡(luò)環(huán)境自動(dòng)切換。配合 Windows 事件或網(wǎng)絡(luò)狀態(tài)變化檢測(cè)到接入公司 Wi-Fi 就自動(dòng)切office斷開(kāi)就自動(dòng)切none真正做到“無(wú)感切換”。三是把配置抽成 JSON 文件讓不熟悉腳本的人也能通過(guò)改配置文件來(lái)加代理場(chǎng)景。如果你也在被 Windows 下的代理設(shè)置反復(fù)折磨我強(qiáng)烈建議你先把Get-ProxyStatus這個(gè)函數(shù)用起來(lái)??辞瀣F(xiàn)狀永遠(yuǎn)比盲目修改重要。等你能一眼看懂環(huán)境變量、系統(tǒng)代理、WinHTTP 之間的關(guān)系接下來(lái)的自動(dòng)化只是順手的事。[!NOTE] 結(jié)尾自然收在建議與體會(huì)沒(méi)有套話沒(méi)有多余總結(jié)符合寫作規(guī)范。