title: 使用PowerShell通過不同網路(網卡)訪問不同網站 date: 2022-03-26 categories: 編程 tags: - PowerShell - 網路 - Windows 前言 在學校生活時經常有一種需求:訪問某些網站(如校內系統)時需要使用校園網,訪問另一些網站(如 ...
title: 使用PowerShell通過不同網路(網卡)訪問不同網站
date: 2022-03-26
categories: 編程
tags:
- PowerShell
- 網路
- Windows
前言
在學校生活時經常有一種需求:訪問某些網站(如校內系統)時需要使用校園網,訪問另一些網站(如Steam、Github等)校園網很慢,需要使用手機瀏覽器等其他網路加速。此時我就覺得如果能同時使用兩個網路該多好。
本文就介紹如何用PowerShell[1]實現這個功能(需要Windows平臺,版本XP及以上)。
原理
首先需要明確,同一張網卡是無法同時連接兩個網路的(除非同時使用多個代理達到這種效果)。幸運的是,現在絕大多數電腦都同時擁有有線和無線兩張網卡,所以可以實現這個效果。
其次,一般應用程式無法直接指定網卡上網(例如虛擬機軟體除外),不過我們有代替的方法:設置路由表。
路由表的基本原理是:要求IP的某些網段,走指定的網關。而網關又和網路有密不可分的聯繫,從而實現隱式地指定網卡。
查看電腦信息
首先可以同時連上有線和無線網,方便查看
網路適配器
一臺電腦上會有多個網路適配器,其中有物理網卡,也有虛擬網卡。我們要找出其中物理網卡裡的有線和無線網卡:首先鍵入ipconfig
,可以對此有一個大致印象:
十分明顯地看到,有好多適配器。但比如說名字裡帶virtual的,或者vEthernet這種顯然是虛擬網卡。剩下很快就能發現有線和無線網路適配器分別是:乙太網和WLAN(不同電腦可能名字不一樣,連接狀態也不盡相同)。
PS C:\Users\poker> ipconfig
Windows IP 配置
乙太網適配器 乙太網:
連接特定的 DNS 尾碼 . . . . . . . : hgd
本地鏈接 IPv6 地址. . . . . . . . : XXXX::XXXX:XXXX:XXXX:XXXX%XX
IPv4 地址 . . . . . . . . . . . . : XXX.XXX.XXX.XXX
子網掩碼 . . . . . . . . . . . . : XXX.XXX.XXX.XXX
預設網關. . . . . . . . . . . . . : XXX.XXX.XXX.XXX
無線區域網適配器 本地連接* 5:
媒體狀態 . . . . . . . . . . . . : 媒體已斷開連接
連接特定的 DNS 尾碼 . . . . . . . :
無線區域網適配器 本地連接* 6:
媒體狀態 . . . . . . . . . . . . : 媒體已斷開連接
連接特定的 DNS 尾碼 . . . . . . . :
無線區域網適配器 WLAN:
連接特定的 DNS 尾碼 . . . . . . . :
本地鏈接 IPv6 地址. . . . . . . . : XXXX::XXXX:XXXX:XXXX:XXXX%XX
IPv4 地址 . . . . . . . . . . . . : XXX.XXX.XXX.XXX
子網掩碼 . . . . . . . . . . . . : XXX.XXX.XXX.XXX
預設網關. . . . . . . . . . . . . : XXX.XXX.XXX.XXX
乙太網適配器 藍牙網路連接 3:
媒體狀態 . . . . . . . . . . . . : 媒體已斷開連接
連接特定的 DNS 尾碼 . . . . . . . :
接下來使用Get-NetIPConfiguration
指令,就可以看到物理網卡的信息了:
其中我們要註意Gateway的項,這就是網關。
PS C:\Users\poker> Get-NetIPConfiguration
InterfaceAlias : 乙太網
InterfaceIndex : 18
InterfaceDescription : Realtek PCIe GbE Family Controller
NetProfile.Name : XXXXXXXXXXXXXXX
IPv4Address : XXX.XXX.XXX.XXX
IPv6DefaultGateway :
IPv4DefaultGateway : XXX.XXX.XXX.XXX
DNSServer : XXX.XXX.XXX.XXX
XXX.XXX.XXX.XXX
XXX.XXX.XXX.XXX
XXX.XXX.XXX.XXX
XXX.XXX.XXX.XXX
XXX.XXX.XXX.XXX
InterfaceAlias : WLAN
InterfaceIndex : 14
InterfaceDescription : Intel(R) Wi-Fi 6 AX200 160MHz
NetProfile.Name : XXXXXXXXXXXXXXX
IPv4Address : XXX.XXX.XXX.XXX
IPv6DefaultGateway :
IPv4DefaultGateway : XXX.XXX.XXX.XXX
DNSServer : XXX.XXX.XXX.XXX
InterfaceAlias : 藍牙網路連接 3
InterfaceIndex : 10
InterfaceDescription : Bluetooth Device (Personal Area Network) #3
NetAdapter.Status : Disconnected
其他相關指令:netsh interface show interface
、Get-NetAdapter
,感興趣可以看看。
路由
使用Get-NetRoute
指令(或route print
)可以查看路由表:
表中每一條代表一個路由,註意他所有的屬性:
-
ifIndex
(interface index)(介面序號):即和上圖同名的屬性。 -
DestinationPrefix
(目標首碼):即指定的網段,屬於這個網段的會找對應的網關(其中前面四段句點分開的是IP,斜杠後的是子網掩碼從左往右數1的位數)。 -
NextHop
(下一跳):即指定的網關。 -
兩個
Metric
(躍點):大致表示這個路由的優先順序,數字越小越優先。 -
PolicyStore
(存儲策略):表示這是臨時路由(ActiveStore
)還是永久路由(PersistentStore
),其中臨時路由會在重啟後刪除重設。
PS C:\Users\poker> Get-NetRoute
ifIndex DestinationPrefix NextHop RouteMetric ifMetric PolicyStore
------- ----------------- ------- ----------- -------- -----------
10 255.255.255.255/32 0.0.0.0 256 65 ActiveStore
13 255.255.255.255/32 0.0.0.0 256 25 ActiveStore
11 255.255.255.255/32 0.0.0.0 256 25 ActiveStore
18 255.255.255.255/32 0.0.0.0 256 25 ActiveStore
14 255.255.255.255/32 0.0.0.0 256 50 ActiveStore
1 255.255.255.255/32 0.0.0.0 256 75 ActiveStore
10 224.0.0.0/4 0.0.0.0 256 65 ActiveStore
13 224.0.0.0/4 0.0.0.0 256 25 ActiveStore
11 224.0.0.0/4 0.0.0.0 256 25 ActiveStore
18 224.0.0.0/4 0.0.0.0 256 25 ActiveStore
14 224.0.0.0/4 0.0.0.0 256 50 ActiveStore
1 224.0.0.0/4 0.0.0.0 256 75 ActiveStore
14 192.168.1.255/32 0.0.0.0 256 50 ActiveStore
14 192.168.1.226/32 0.0.0.0 256 50 ActiveStore
14 192.168.1.0/24 0.0.0.0 256 50 ActiveStore
18 172.19.73.255/32 0.0.0.0 256 25 ActiveStore
18 172.19.73.29/32 0.0.0.0 256 25 ActiveStore
18 172.19.73.0/24 0.0.0.0 256 25 ActiveStore
1 127.255.255.255/32 0.0.0.0 256 75 ActiveStore
1 127.0.0.1/32 0.0.0.0 256 75 ActiveStore
1 127.0.0.0/8 0.0.0.0 256 75 ActiveStore
14 0.0.0.0/0 XXX.XXX.XXX.XXX 0 50 ActiveStore
18 0.0.0.0/0 XXX.XXX.XXX.XXX 0 25 ActiveStore
10 ff00::/8 :: 256 65 ActiveStore
13 ff00::/8 :: 256 25 ActiveStore
11 ff00::/8 :: 256 25 ActiveStore
18 ff00::/8 :: 256 25 ActiveStore
14 ff00::/8 :: 256 50 ActiveStore
1 ff00::/8 :: 256 75 ActiveStore
13 fe80::ddf5:310e:d09b:1326/128 :: 256 25 ActiveStore
10 fe80::8b75:5968:ee8a:42d6/128 :: 256 65 ActiveStore
18 fe80::5c8c:97bf:72c:71e9/128 :: 256 25 ActiveStore
11 fe80::4fbb:4f7c:2d3c:426a/128 :: 256 25 ActiveStore
14 fe80::3c65:d5a8:6d1:95cd/128 :: 256 50 ActiveStore
10 fe80::/64 :: 256 65 ActiveStore
13 fe80::/64 :: 256 25 ActiveStore
11 fe80::/64 :: 256 25 ActiveStore
18 fe80::/64 :: 256 25 ActiveStore
14 fe80::/64 :: 256 50 ActiveStore
1 ::1/128 :: 256 75 ActiveStore
18 ::/0 XXXX::XXXX:XXXX:XXXX:XXXX 256 25 ActiveStore
註意NextHop
不為空的路由(一般Metric
也最小),這就是有線和無線網預設的路由,我們新建路由時為避免衝突,要先刪除這個(不用擔心失誤,重啟後會恢復)
這些路由前面網段都是0.0.0.0/0(或::/0),表示全網段都可以使用這個路由。
從Metric
可以發現,絕大多數電腦同時連有線和無線網時,都是有線網的Metric
比較小,這也是為什麼路由總是會優先選擇有線網連接。Windows預設開啟了AutomaticMetric
,會按照帶寬網速自動設定Metric
[2],有需要可以去設置關閉
設備地址
輸入指令Get-CimInstance Win32_NetworkAdapterConfiguration | Select-Object Description, SettingID
,可以看到網卡以及對應的Guid
我們將來可以通過這個Guid,從註冊表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\{對應設備Guid}\Connection
的PnPInstanceId
項判斷是不是物理網卡(值以PCI
開頭是物理網卡,BTH
開頭是藍牙網卡,其他是虛擬網卡)
PS C:\Users\poker> Get-CimInstance Win32_NetworkAdapterConfiguration | Select-Object Description, SettingID
Description SettingID
----------- ---------
Microsoft Kernel Debug Network Adapter {2A714150-362D-497E-AC8B-A9F963B02478}
Realtek PCIe GbE Family Controller {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
Intel(R) Wi-Fi 6 AX200 160MHz {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
Microsoft Wi-Fi Direct Virtual Adapter {33A4093B-99C7-478F-AF06-FD0A698B1FF5}
Microsoft Wi-Fi Direct Virtual Adapter {F1F71D7B-D35B-4C65-8A91-DC94EE7C0A2E}
WAN Miniport (SSTP) {FA29F161-184C-4773-898D-A104510EE7F5}
WAN Miniport (IKEv2) {9859D6F0-2451-47BB-8748-7B1C5C542200}
WAN Miniport (L2TP) {EF4DCC46-BE1D-4FC7-8CFB-CF00F37AB9C8}
WAN Miniport (PPTP) {5E553B27-3FA5-445B-8A15-8249DF31AF3F}
WAN Miniport (PPPOE) {91899BE4-723E-43A6-8006-6BB2AFA4FC32}
WAN Miniport (IP) {CD5DD751-23AA-44F2-940F-4B565365892D}
WAN Miniport (IPv6) {DC0056A3-472D-4178-901C-131B8D8261E9}
WAN Miniport (Network Monitor) {218400DD-182F-4BC4-A266-EBDB68EDD6DF}
Bluetooth Device (Personal Area Network) {2CA478BD-DADE-48B3-949B-66A882E18A72}
實現思路
接下來就是實現環節了,雖然指定網關聽起來很容易。但如果切換網路之後,不僅網關可能會變,而且介面別名(InterfaceAlias)也會變,到時候再調整比較麻煩。
如果可以指定網卡,並指定網段就很方便了。實際上我們確實可以這樣做,因為Get-NetIPConfiguration
(或Get-NetAdapter
)可以看出來:介面描述(InterfaceDescription
)、介面別名(InterfaceAlias
)和網關(Gateway
)幾乎是一一對應的關係,所以我們可以通過PowerShell(或C/C++)從介面描述查找網關,並設置路由,就可以達成目的。
至於網段分配,一般校園網都是連續的網段,比如說172.18.XXX.XXX都是校園網IP,那麼就設置目標首碼(DestinationPrefix)為172.18.0.0/16,表示子網掩碼是255.255.0.0,即前16位是固定的,後面可以變化。將這段路由優先順序設最高,然後再設置剩下的路由(直接用0.0.0.0/0)全部走另一個網路(優先順序第二高)。
另外還可以結合Proxifier等軟體管理,如用Proxifier強大的代理篩選功能將校園網所有IP或程式都代理到某一臺學校的伺服器上,這樣路由規則就可以只要指定一個IP了(如172.18.6.57/32)。
腳本代碼
需要使用PowerShell7及以上運行。
在使用的時候,只需要按照需要修改# Main
部分。
# NetAdapterInfo
class NetAdapterInfo {
[guid] $SettingID
[string] $Description
[string] $DefaultIPGateway
NetAdapterInfo (
[guid] $settingID,
[string] $description,
[string] $defaultIPGateway
) {
$this.SettingID = $settingID
$this.Description = $description
$this.DefaultIPGateway = $defaultIPGateway
}
}
# Functions
function Test-PhysicalNic {
param (
[Parameter(
Mandatory,
ValueFromPipeline
)]
[NetAdapterInfo]
$Info
)
$str = Get-ItemProperty `
-Path "HKLM:\SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\{$($Info.SettingID)}\Connection" `
-Name PnPInstanceId
$str.PnPInstanceId.StartsWith("PCI")
}
function Get-PhysicalNics {
Get-CimInstance `
-Class Win32_NetworkAdapterConfiguration `
| ForEach-Object {
[NetAdapterInfo]::new(
$_.SettingID,
$_.Description,
$_.DefaultIPGateway
)
} `
| Where-Object { Test-PhysicalNic $_ }
}
function Remove-AdapterRoute {
param (
[string]
$DestinationPrefix = "0.0.0.0/0"
)
Remove-NetRoute $DestinationPrefix
}
function Set-AdapterRoute {
param (
[NetAdapterInfo[]]
$List,
[string]
$AdapterDescription,
[string]
$DestinationPrefix = "0.0.0.0/0",
[UInt16]
$RouteMetric = 0,
[bool]
$PersistentStore = $false
)
$Private:NextHop = ($List | Where-Object Description -EQ $AdapterDescription)[0].DefaultIPGateway
New-NetRoute `
$DestinationPrefix `
-InterfaceAlias $AdapterDescription `
-NextHop $Private:NextHop `
-PolicyStore ($PersistentStore ? "PersistentStore" : "ActiveStore")
}
function Set-AdapterRoute {
param (
[NetAdapterInfo[]]
$List,
[string]
$InterfaceDescription,
[string]
$DestinationPrefix = "0.0.0.0/0",
[string]
$IsIpv4 = $true,
[UInt16]
$RouteMetric = 0,
[bool]
$PersistentStore = $false
)
$InterfaceAlias = (Get-NetAdapter | Where-Object Name -EQ $InterfaceDescription)[0].Name
$gateways = ($List | Where-Object Description -EQ $InterfaceAlias)[0].DefaultIPGateway
if ($gateways -EQ "") {
return
}
foreach ($gateway in $gateways.Split(' ')) {
if (($IsIpv4 -and ([System.Net.IPAddress]::Parse($gateway).AddressFamily -EQ [System.Net.Sockets.AddressFamily]::InterNetwork)) -or `
(!$IsIpv4 -and ([System.Net.IPAddress]::Parse($gateway).AddressFamily -EQ [System.Net.Sockets.AddressFamily]::InterNetworkV6))) {
New-NetRoute `
$DestinationPrefix `
-InterfaceAlias $InterfaceAlias `
-NextHop $gateway `
-PolicyStore ($PersistentStore ? "PersistentStore" : "ActiveStore") `
-RouteMetric $RouteMetric
return
}
}
}
# Main
$info = Get-PhysicalNics
Remove-AdapterRoute
Remove-AdapterRoute ::/0
Set-AdapterRoute $info "Realtek PCIe GbE Family Controller" 172.18.6.57/32
Set-AdapterRoute $info "Intel(R) Wi-Fi 6 AX200 160MHz" 0.0.0.0/0
我的代碼倉庫[3]里包含完整PowerShell腳本和部分C++方法。